I'm introducing a JSF Faces flow into my application. This works, following the oracle documentation. But, only in the root folder.
Is it possible to place the JSF flow folder in a sub folder, else that root?
I can't get this working. That's all folks!
I solved this one myself.
A JSF flow definition can be done in 2 ways:
with configuration file: flowname-flow.xml
with configuration class: flowname.java
The first one can only define a flow-name, with the location defaulting to the root folder.
The second can define a location deeper in your folder structure.
Configuration file example: testflow.flow.xml
Only the id="testFlow" can be added to the definition, and not the path. This defaults to testFlow/testFlow.xhtml for the first page.
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
<flow-definition id="testFlow">
<flow-return id="returnFromTestFlow">
<from-outcome>#{testFlow.returnValue}</from-outcome>
</flow-return>
</flow-definition>
</faces-config>
Configuration class example: TestFlow.java
Add the fully qualified path to the view node within this flow.
public class TestFlow implements Serializable {
private static final long serialVersionUID = 1L;
#Produces
#FlowDefinition
public Flow defineFlow(#FlowBuilderParameter FlowBuilder flowBuilder) {
String flowId = "testFlow";
flowBuilder.id("", flowId);
flowBuilder.viewNode(flowId,
"/other/location/flow/" + flowId + ".xhtml").
markAsStartNode();
flowBuilder.viewNode("testFlow2", "/other/location/flow/testFlow2.xhtml");
flowBuilder.viewNode("testFlow3", "/other/location/flow/testFlow3.xhtml");
...
That's all folks!
Related
I have a very tricky problem when overriding JSF-renderers.
This is a part of my faces-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
<render-kit>
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.MenubarRenderer</renderer-type>
<renderer-class>de.mycompany.web.MenuRenderer</renderer-class>
</renderer>
</render-kit>
<factory>
<exception-handler-factory>de.mycompany.web.ValidationExceptionHandlerFactory</exception-handler-factory>
</factory>
</faces-config>
The structure of my web-project is following
webapp (building war), Dependencies to core and gui
core (building jar)
gui (building jar), Dependencies to core, containing xhtmls and #Named Beans, Dependency to com.sun.faces:jsf-impl Version 2.1.25
When I place the content of the faces-config.xml in
webapp/src/main/webapp/META-INF or
core/src/main/webapp/META-INF
both, the MenuRenderer and the ValidationExceptionHandlerFactory, are getting used. Yeah.
When I place the content of the faces-config in
gui/src/main/webapp/META-INF
the ValidationExceptionHandlerFactory is getting used, but not the MenuRenderer. WTF?
Also all other features (phase-listeners, system-event-listeners I use in my faces-config are working except ones in the render-kit-nodes.
What am I doing wrong?
You're trying to override a renderer supplied by another external library, not a standard renderer.
The loading order of faces-config.xml provided by external libraries is by default undefined. In your specific case, your library is apparently loaded before PrimeFaces library is loaded.
You can explicitly specify the loading order via <ordering> element in faces-config.xml. The name of the PrimeFaces library is primefaces. So, just add the below entry to your faces-config.xml. Make sure you supply your library a name too so that endusers can in turn reorder in their own faces-config.xml if necessary.
<name>yourlibrary</name>
<ordering>
<after>
<name>primefaces</name>
</after>
</ordering>
A real world example can be found in e.g. OptimusFaces which also extends PrimeFaces.
I built my site to be Multi-language. I want the language code to be embedded in the address of page according to the locale. I have the following:
http://localhost:8080/Wirote/index
I want to have it as the following:
http://localhost:8080/Wirote/de/index --- display German content
http://localhost:8080/Wirote/en/index --- display English content
http://localhost:8080/Wirote/ar/index --- display Arabic content
To achieve this I followed the step in :
multi-language url rewiting. Is it possible?
pretty-config.xml
<url-mapping id="base">
<pattern value="/#{localeManger.language}"/>
</url-mapping>
<url-mapping id="index" parentId="base">
<pattern value="/index"/>
<view-id value="/index.xhtml"/>
</url-mapping>
faces-config.xml
<application>
<locale-config>
<default-locale>de</default-locale>
<supported-locale>en</supported-locale>
<supported-locale>ar</supported-locale>
</locale-config>
<resource-bundle>
<base-name>I18n.lang</base-name>
<var>sprache</var>
</resource-bundle>
</application>
LocaleManger.java
#ManagedBean(name = "localeManger")
#SessionScoped
public class LocaleManger implements Serializable{
private Locale locale;
private static final long serialVersionUID = 2756934361134603857L;
#PostConstruct
public void init() {
FacesContext.getCurrentInstance().getApplication().getDefaultLocale();
}
public Locale getLocale() {
return locale;
}
public String getLanguage() {
return locale.getLanguage();
}
public void setLanguage(String language) {
locale = new Locale(language);
FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);
}}
Now when I run the project, I got only:
http://localhost:8080/Wirote/index
also the page is stuck, so I can't navigate to another using links in the index.xtml
alternative I add the following to the index.xhtml:
<f:metadata>
<f:viewParam name="locale" value="#{localeManger.language}"/>
</f:metadata>
pretty-config.xml
<url-mapping id="index">
<pattern value="/#{locale}/index"/>
<view-id value="/index.xhtml"/>
</url-mapping>
Now when I run the project, I get the following:
http://localhost:8080/Wirote/de/index
But when I try to change the language, by clicking on English or Arabic language switcher, it doesn't work correctly, the content of the page change, but the address page is not. But if I change it manually to
http://localhost:8080/Wirote/en/index or
http://localhost:8080/Wirote/ar/index
it display the correct content in Arabic and English, but I need the address to be changed automatically not manually.
How can I get the correct address related to current locale?
I'm not sure if this helps you, since you're attempting to do this using PrettyFaces, but Rewrite (the library PrettyFaces is based on) has a dedicated feature for internationalizing URLs:
https://github.com/ocpsoft/rewrite/blob/master/documentation/src/main/asciidoc/configuration/i18n.asciidoc
This might help you and if you are using PrettyFaces based on Rewrite, then you already have access to this feature.
It is not so much a question, more of a note.
With Glassfish4, in a JEE7 application I tried to use the flow scope using programmatic flow definition (java class annotated with #Produces #FlowDefinition).
I navigated to the start page of the flow with a h:commandButton (just as it is done in the JEE7 tutorial example https://svn.java.net/svn/javaeetutorial~svn/trunk/examples/web/jsf/checkout-module.
When I pressed the button it stayed on the same page, where the button was, instead of going to the flow's start page.
After many hours of suffering, I realized that the problem is in the beans.xml, in my beans.xml I had this:
bean-discovery-mode="annotated"
which is the recommended setting according to the documentation (http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/javaee/beans_1_1.xsd).
When I changed this to
bean-discovery-mode="all"
it started to work.
Somehow CDI does not recognize the flow definition as an annotated class. I tried to make it a #Named class, or a #ApplicationScoped class, but non of these helped.
I don't know if it is the intended behavior, or a bug.
Hope it saves a few ours to someone.
This is related to how CDI detects bean archives. When bean-discovery-mode="annotated", only classes annotated with bean defining annotations are picked up by CDI; note that #Named and #FlowScoped aren't on that list.
Because of this, as you've documented here, using Flow annotations requires bean-discovery-mode="all" to be set.
There's a spec issue open to discuss if this is a desired behavior.
Thank you!
Of course you can always fallback to using an XML declaration for your view. Such as creating a file example/example-flow.xml with contents such as
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.2"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
<flow-definition id="example">
<flow-return id="actionId" >
<from-outcome>#{somebean.returnValue}</from-outcome>
</flow-return>
</flow-definition>
</faces-config>
How do I render JSF components based on a logged in user's role? I know the external context exposes the principals, but how should I do the rendering properly in JSF? In JSP it would be something like
<% isUserInRole(Roles.ADMIN) { %>
<button>Edit!</button>
<% } %>
How do I write this in JSF the best possible way? My best guess is the rendered attribute tied to a backing bean's method that returns a boolean, but that would introduce an irrelevant backing bean if I have to render some navigation items only for admins...
Glassfish V3.1, JSF 2.x
If your web.xml is declared as Servlet 3.0 (which implicitly relates to JSP/EL 2.2)
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
then you can take benefit of being able to invoke methods with arguments in EL like as ExternalContext#isUserInRole():
rendered="#{facesContext.externalContext.isUserInRole('ADMIN')}"
Note that this requires a Servlet 3.0 capable container, but since you're using Glassfish 3 (which supports Servlet 3.0), it should work without any issues.
Also note that if you're using Facelets instead of JSP, then you've the HttpServletRequest available as #{request} in EL, allowing you the following shorter expression:
rendered="#{request.isUserInRole('ADMIN')}"
Conditionally displaying JSF components
Conditional rendering of non-JSF components (plain vanilla HTML and template text)
JSF: How control access and rights in JSF?
In response to #wasimbhalli, there are two reasons I have found that the expression would always return false:
The role name is case sensitive.
rendered="#{facesContext.externalContext.isUserInRole('ADMIN')}" may return false, but try
rendered="#{facesContext.externalContext.isUserInRole('admin')}", or rendered="#{facesContext.externalContext.isUserInRole('Admin')}".
You have to define your roles in both web.xml (or as annotations) and map it in glassfish-web.xml.
The following is how to specify a role in web.ml
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<security-role>
<role-name>admin</role-name>
</security-role>
</web-app>
The following is how to map the authentication group to the role in glassfish-web.xml.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app>
<security-role-mapping>
<role-name>admin</role-name> <!-- name defined in web.xml or annotations -->
<group-name>admin</group-name><!-- name from authentication mechanism -->
</security-role-mapping>
</glassfish-web-app>
In my testing it was necessary to do the mapping even when the names were the same, as I show in my example code. Also in my testing, I tried to only define the mapping and only to define the role in web.xml, and neither worked. I needed both, as specifying the role name in the correct case.
Store role in session attribute and just compare that using rendered attribute.
e.g. rendered="#{yoursessionbean.userRole == Roles.ADMIN}"
Defining custom components in Facelets is easy and quick but there's one thing I can't figure out.
Is it possible with Facelets to define what attributes my custom component has? I.e: I've created a component which is used in such a way:
<blue:modalWindow id="editFeesWizard" width="500" height="440" title="Wizard">
and is defined in taglib.xml as follows:
<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
"http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib>
<namespace>...</namespace>
<tag>
<tag-name>modalWindow</tag-name>
<source>components/modalWindow.xhtml</source>
</tag>
</facelet-taglib>
Taglib doesn't contain any information on component's attributes (id, width, height, title) and IDE cannot therefore check my syntax nor can it suggest attributes while I'm typing.
I cannot find anything on this subject in Facelets documentation. Thought you could help. Thanks!
It seems there isn't a way. But even if there was, I don't think Eclipse (for example) would be able to handle it and offer autocomplete. That's why you can define a .tld, containing the attributes:
<?xml version="1.0" encoding="utf-8"?>
<taglib
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.1">
......
</taglib>
Just for the sake of autocompletion. Ugly, I know.
I don't know about before, but it is possible now. Just add:
<tag>
<tag-name>mycustomtag</tag-name>
<source>tags/mycustomtag.xhtml</source>
<attribute>
<description>What does this do?!</description>
<name>attribute</name>
</attribute>
</tag>
I'm looking forward to being able to create composite components using JSF 2 and facelets; from what I've read, it seems very quick and easy, and you define what attributes your composite component accepts.