Implicit or explicit navigation using p|h:commandXxx with action [duplicate] - jsf

I am having trouble navigating between my JSF pages. Most of my navigation happens when you click a command button. The action of the command button returns a string.
My log in page is my welcome page. Here it is in my web.xml:
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>faces/pages/index.xhtml</welcome-file>
</welcome-file-list>
In my browser's address bar, the page appears as:
http://localhost:8080/ui/faces/pages/index.xhtml
Once authentication happens, the function returns this String:
"/ui/faces/pages/home.xhtml"
The file I want to navigate to is located at:
pages/home.xhtml
However when navigation is supposed to happen, I get this error:
Unable to find matching navigation case with from-view-id '/pages/index.xhtml' for action '#{indexPageController.login()}' with outcome '/ui/faces/pages/home.xhtml'
Can anyone help me understand the relative path I need to correctly navigate to the page?

You should not include the context path /ui nor the FacesServlet mapping /faces in the navigation case outcome. It should just represent the sole view ID, which is basically just the path to the physical view file absolute to the webcontent root or relative to the current view ID.
So, absolute (starting with /) to the webcontent root:
/pages/home.xhtml
Or relative (not starting with /) to the current view ID (assuming that you're in /pages/index.xhtml):
home.xhtml
Do note that dot-slash ./ and double-dot-slash ../ notations are not supported.
Or even without file extension; JSF will imply the Facelets default suffix which defaults to .xhtml and is configureable by javax.faces.DEFAULT_SUFFIX context parameter:
/pages/home
home
It makes after all also sense if you realize that the context path /ui and the FacesServlet mapping /faces/* are not controllable from inside the webapp on! If they ever change externally, then you'd theoretically need to change all navigation case outcomes in the entire codebase and rebuild the webapp. This would not make any sense. JSF takes thus already care of them for you.
See also:
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Difference between h:button and h:commandButton
When should I use h:outputLink instead of h:commandLink?
What URL to use to link / navigate to other JSF pages

Related

When does mojarra adds a naming container to the list of optional parameters?

In the source of the class AjaxBehaviorRenderer (line 260) there is a line that apparently appends the NamingContainer Id to the list of optional parameters of mojarra.ab(...). I've never come across it so I'm curious as to when it is used:
RenderKitUtils.appendProperty(ajaxCommand, "com.sun.faces.namingContainerId", namingContainerId, true);
line 260
While working on spec issue 790 last week, which should solve a.o. Rendering other form by ajax causes its view state to be lost, how do I add this back?, this was explained to me by Neil Griffin, a portlet guy.
It appears that portlets can have multiple JSF views rendering to the same HTML document, each with its own view state. In portlets, there's a special UIViewRoot instance which implements NamingContainer. During regular rendering, all forms, inputs and commands will have IDs and names prefixed with the view's own client ID. This will work fine during synchronous postbacks. The portlet can this way identify the exact view to restore.
However, during asynchronous postbacks, the jsf.js will create a bunch of additional ajax-specific request parameters such as javax.faces.source, javax.faces.partial.event, etc. Those request parameter names are not prefixed with the view's own client ID. Therefore the portlet cannot associate them with a specific view. Hence the impl issue 3031.
There was another problem of view state identifiers in ajax responses not being properly namespaced this way. Therefore the portlet implementation had to customize the partial response writer in the so-called "JSF bridge". This will be taken into account during implementing spec issue 790. Instead of sniffing a "portlet environment" as in current implementation, there will be checks on UIViewRoot instanceof NamingContainer which is more flexible and portlet-independent. The Mojarra-specific com.sun.faces.namingContainerId will also be removed. Instead, this value will be rendered to <partial-response id="..."> so that the jsf.js can just extract from there.
All in all, not really important if you're only targeting servlet based environments.
As per balusC comment :
It's only interesting for portlet based apps (not servlet based apps).
I can't exactly explain why and what it is used for (a portlet/liferay
guy might), but the portlet specific feature is called "namespaced
parameters". See https://web.liferay.com/web/meera.success/blog/-/blogs/liferay-requires-name-spaced-parameters

JSF2 - Navigating to a .xhtml file in a parent-folder [duplicate]

I am having trouble navigating between my JSF pages. Most of my navigation happens when you click a command button. The action of the command button returns a string.
My log in page is my welcome page. Here it is in my web.xml:
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>faces/pages/index.xhtml</welcome-file>
</welcome-file-list>
In my browser's address bar, the page appears as:
http://localhost:8080/ui/faces/pages/index.xhtml
Once authentication happens, the function returns this String:
"/ui/faces/pages/home.xhtml"
The file I want to navigate to is located at:
pages/home.xhtml
However when navigation is supposed to happen, I get this error:
Unable to find matching navigation case with from-view-id '/pages/index.xhtml' for action '#{indexPageController.login()}' with outcome '/ui/faces/pages/home.xhtml'
Can anyone help me understand the relative path I need to correctly navigate to the page?
You should not include the context path /ui nor the FacesServlet mapping /faces in the navigation case outcome. It should just represent the sole view ID, which is basically just the path to the physical view file absolute to the webcontent root or relative to the current view ID.
So, absolute (starting with /) to the webcontent root:
/pages/home.xhtml
Or relative (not starting with /) to the current view ID (assuming that you're in /pages/index.xhtml):
home.xhtml
Do note that dot-slash ./ and double-dot-slash ../ notations are not supported.
Or even without file extension; JSF will imply the Facelets default suffix which defaults to .xhtml and is configureable by javax.faces.DEFAULT_SUFFIX context parameter:
/pages/home
home
It makes after all also sense if you realize that the context path /ui and the FacesServlet mapping /faces/* are not controllable from inside the webapp on! If they ever change externally, then you'd theoretically need to change all navigation case outcomes in the entire codebase and rebuild the webapp. This would not make any sense. JSF takes thus already care of them for you.
See also:
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Difference between h:button and h:commandButton
When should I use h:outputLink instead of h:commandLink?
What URL to use to link / navigate to other JSF pages

Path to a file up in the hierarchy

Here is file structure of my JSF application.
User directory is secured & one needs to authenticate to see user/success.xhtml. user/success.xhtml has a button which is used to logout. That button submits form to following method.
public String logout(){
HttpSession session = (HttpSession)FacesContext.getCurrentInstance().getExternalContext().getSession(false);
session.invalidate();
return "index";
}
Last line of above method is there to redirect user to index.xhtml, as index.xhtml is not in the same directory as user/success.xhtml so I am getting following error.
Unable to find matching navigation case with from-view-id
'/user/success.xhtml' for action '#{AccContrl.logout()}' with outcome
'index'
How can I redirect to a file present up in the hierarchy?
I tried return "/../index"; but it didn't work.
The navigation outcome represents a view ID. If it does not start with /, then it is interpreted relative to the current path. If it starts with /, then it is interpreted relative to the web root.
So, just use /index.
return "/index";
Unrelated to the concrete problem, you should be redirecting here, not navigating. Not only because you should always perform a redirect when you intend to naviage away after POST, but also because the invalidated session is still present in the current request/response, but only not anymore in the next one.
return "/index?faces-redirect=true";
See also:
What is the difference between redirect and navigation/forward and when to use what?
How to navigate in JSF? How to make URL reflect current page (and not previous one)
How to invalidate session in JSF 2.0?

View declared in <protected-views> still accessible after manipulating CSRF token

I'm exploring the new features in JSF 2.2 (pretty cool so far) but I still don't understand how Protected Views works, I created a facelet1 with a link to facelet2, like this:
<h:link styleClass="link" value="Go to protected page" id="link1"
outcome="/protected/facelet2.xhtml"></h:link>
and in my faces-config.xml I added this:
<protected-views>
<url-pattern>/protected/facelet2.xhtml</url-pattern>
</protected-views>
Now when I run the page a token is added in the url:
http://localhost:8080/<project>/protected/facelet2.faces?javax.faces.Token=1426608965211
According to the documentation, if the token does not match with the one in the server, the GET request is not processed (is my understanding correct?).
But if I modify the token (using Firebug or the dev tools included in the browser) the request is still processed, even if the token was modified.
Am I doing something wrong?
This is caused because your FacesServlet is apparently mapped on JSF 1.0-style URL pattern of *.faces instead of JSF 2.0-style URL pattern of *.xhtml. The <protected-views><url-pattern> must match the actual URL pattern as you see in browser's address bar.
So, given an actual URL of /protected/facelet2.faces, you need to configure it as below:
<protected-views>
<url-pattern>/protected/facelet2.faces</url-pattern>
</protected-views>
However, while at it, I discovered some nasty issues in current Mojarra 2.2.10 implementation:
It does actually not do a prefix/suffix match as per Servlet 12.1 specification (there's even a vague comment in source code indicating that!). It does merely an exact match. This means, you can't use wildcard URL patterns like /protected/*.
When generating the <h:link>, it does not compare the protected view URL pattern to the resolved URL, but to the JSF view ID. And, when checking an incoming request, it does not compare the request URL to the JSF view ID (like as during link generation), but to the <url-pattern>. This thus never matches, totally explaining why you could simply access it without a valid token.
Basically, you need the following configuration if you need to keep the JSF 1.0-style URL pattern of *.faces.
<protected-views>
<url-pattern>/protected/facelet2.xhtml</url-pattern>
<url-pattern>/protected/facelet2.faces</url-pattern>
</protected-views>
It'll then properly throw javax.faces.application.ProtectedViewException when being accessed without a valid token. Much better is to just map the FacesServlet explicitly on *.xhtml in web.xml.
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
This way you never need to deal with virtual URLs.
I've reported this to Mojarra guys as issue 3837.
See also:
Sometimes I see JSF URL is *.jsf, sometimes *.xhtml and sometimes /faces/*. Why?

Liferay: Render portlet contents differently based on view mode

I'd like to have different contents displayed when a portlet is in "normal mode" as opposed to "maximized mode". I'm using JSF as the view technology. Is there a check I can perform on the JSF end to check which view is currently being used?
Digging around on my own, I found out that #{request.windowState} gives you normal, maximized or minimized based on current view. Using this, there can be multiple solutions:
Do a #{request.windowState == 'normal'} check and conditionally
display content.
Use <ui:include src="#{request.windowState}.xhtml"
/> in my main view and then create normal.xhtml and maximized.xhtml
ui:composition files.

Resources