in the template and page I have the following template (masterLayout.xhtml):

Faces JSF 2 <f: metadata / "> in the template and page

I have the following template (masterLayout.xhtml):

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <f:view contentType="text/html"> <ui:insert name="metadata"/> <h:head> <title><ui:insert name="windowTitle"/> | MySite</title> </h:head> <h:body> <div id="container"> <div id="header"> <ui:insert name="header"> <ui:include src="/WEB-INF/templates/header.xhtml"/> </ui:insert> </div> <div id="content"> <ui:insert name="content"/> </div> <div id="footer"> <ui:insert name="footer"> <ui:include src="/WEB-INF/templates/footer.xhtml"/> </ui:insert> </div> </div> </h:body> </f:view> </html> 

and the page that uses it (search.xhtml):

 <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:f="http://java.sun.com/jsf/core"> <h:head> <title></title> </h:head> <h:body> <ui:composition template="/WEB-INF/templates/masterLayout.xhtml"> <ui:define name="metadata"> <f:metadata> <f:viewParam name="address" value="#{searchBean.address}"/> <f:event type="preRenderView" listener="#{userSessionBean.preRenderViewCookieLogin(e)}"/> <f:event type="preRenderView" listener="#{searchBean.preRenderView(e)}"/> </f:metadata> </ui:define> <ui:define name="windowTitle">#{searchBean.address}</ui:define> <ui:define name="content"> <!-- Content goes here --> </ui:define> </ui:composition> </h:body> </html> 

The problem is that I want to place the call to userSessionBean.preRenderViewCookieLogin(e) in the template, because there are many other pages. This method verifies that the user is logged in (according to the state of the session), and if not, checks if a cookie is available that can be used to log the user into the system, and if so (and if it is valid), automatically registers the user, The system works in the code above, but when I try to insert this into the template, my view settings are no longer set.

Here's the modified version above, with userSessionBean.preRenderViewCookieLogin(e) pushed to the template.

masterLayout.xhtml:

 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <f:view contentType="text/html"> <f:metadata> <f:event type="preRenderView" listener="#{userSessionBean.preRenderViewCookieLogin(e)}"/> <ui:insert name="metadata"/> </f:metadata> <h:head> <title><ui:insert name="windowTitle"/> | MySite</title> </h:head> <h:body> <div id="container"> <div id="header"> <ui:insert name="header"> <ui:include src="/WEB-INF/templates/header.xhtml"/> </ui:insert> </div> <div id="content"> <ui:insert name="content"/> </div> <div id="footer"> <ui:insert name="footer"> <ui:include src="/WEB-INF/templates/footer.xhtml"/> </ui:insert> </div> </div> </h:body> </f:view> </html> 

search.xhtml

 <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:f="http://java.sun.com/jsf/core"> <h:head> <title></title> </h:head> <h:body> <ui:composition template="/WEB-INF/templates/masterLayout.xhtml"> <ui:define name="metadata"> <f:viewParam name="address" value="#{searchBean.address}"/> <f:event type="preRenderView" listener="#{searchBean.preRenderView(e)}"/> </ui:define> <ui:define name="windowTitle">#{searchBean.address}</ui:define> <ui:define name="content"> <!-- Content goes here --> </ui:define> </ui:composition> </h:body> </html> 

Notice that I moved the <f:metadata/> to the template. This is the only problem, since deleting userSessionBean.preRenderViewCookieLogin(e) does not matter. I also tried a version of the code that worked to just move userSessionBean.preRenderViewCookieLogin(e) to the template, which means that it cannot be inside the <f:metadata/> . In this case, this method was executed after all the view parameters and was called searchBean.preRenderView(e) . I want userSessionBean.preRenderViewCookieLogin(e) called before any preRenderView(e) page is preRenderView(e) , and not after. And just for fun, I tried placing <f:metadata/> around userSessionBean.preRenderViewCookieLogin(e) , which called this method but didn't set the view options.

So, I would like to know:

  • Why is this happening and is there a way to fix it?
  • Is there a better way to ensure that the same method is called for each page first?

Edit: I just tried something else - a phase event: <f:view contentType="text/html" beforePhase="#{userSessionBean.beforePhase(e)}"> This is in the masterLayout.xhtml file. It is not called at all; not for any phase.

Edit: Removed e (damn it! NetBeans!): <f:view contentType="text/html" beforePhase="#{userSessionBean.beforePhase}"> This is called only until the render response phase, which, of course, means that it is called after the preRenderView event.

+8
facelets jsf-2
source share
2 answers

Why is this happening and is there a way to fix it?

From the <f:metadata> tag documentation (highlighting the second paragraph is mine):

Declare a metadata facet for this view. This must be a child of <f:view> . This tag must be in the top-level XHTML file for the given viewId or in the template client, but not in the template. The implementation should ensure that the direct child of the facet is a UIPanel , even if there is only one child of the facet. The implementation should set the UIPanel id as the value of the symbolic constant UIViewRoot.METADATA_FACET_NAME .

Thus, it really should go in the top view, and not in the template.


Is there a better way to ensure that the same method is called for each page first?

In your specific case, store the registered user as a property of a managed bean session, not a cookie, and use filter on the appropriate URL pattern to check it. The beans managed session is in the filter, available as HttpSession attributes. Homemade cookies are not needed since you basically invent HttpSession here. If you do not need the “remember me” object, but this should not be solved in this way. Do this in the filter.

See also:

  • Prevent access to a restricted page without logging in to Jsf2
+13
source share

I got this working using PhaseListener instead.

 public class CookieLoginPhaseListener implements PhaseListener { @Override public void beforePhase(PhaseEvent event) { } @Override public void afterPhase(PhaseEvent event) { UserSessionBean userSessionBean = Util.lookupCdiBean("userSessionBean"); userSessionBean.handleAuthCookie(); } @Override public PhaseId getPhaseId() { return PhaseId.RESTORE_VIEW; } } 

and a bit of bean search magic is here:

 public static <T> T lookupCdiBean(String name) { return (T) FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet(FacesContext.getCurrentInstance(), "#{" + name + "}", Object.class); } 

Thanks @BalusC for this: JSF - get a managed bean by name . Since I use CDI, I cannot use the more declarative @ManagedProperty parameter. However, it doesn’t matter.

0
source share

All Articles