Why does <h:link> change destination extension from .html to .xhtml? - jsf

I'm using JSF 2.1 and I'm experiencing some problems with the <h:link> tag. I'm trying to have the link's outcome point from my XHTML file to a plain HTML file. However, when I run my web application, the .html extension in link's generated URL is automatically converted to a .xhtml extension.
Here is my Facelet file:
<h:body>
<h:form>
<h:link value="animation" outcome="#{contentForm.ccAnimationLink}"/>
</h:form>
<h:body>
Here is my contentForm bean:
package my.app.content;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
#ManagedBean
#RequestScoped
public class ContentForm implements Serializable {
private static final long serialVersionUID = -8463354828156798513L;
private String ccAnimationLink = "";
#PostConstruct
public void init() {
ccAnimationLink = "/content/cc/CC_animation/story.html";
}
public String getCcAnimationLink() {
return ccAnimationLink;
}
public void setCcAnimationLink(String ccAnimationLink) {
this.ccAnimationLink = ccAnimationLink;
}
}
Now, when I run this application, I get the following error:
Unable to find matching navigation case from view ID '/content/modifiedcc.xhtml' for outcome '/content/cc/CC_animation/story.html'
I made sure that I had the URL correct, so I created a story.xhtml file in that location as well. With that file there it runs without errors.
If I pull the source for the generated page, I can see that the <h:link> was correctly changed to an "a href" tag, as follows:
animation
For some reason though the URL changes from story.html, like I have it in my bean, to story.xhtml.
How can I make sure that it stays as story.html and not change it to xhtml?
Here is my web.xml file as well:
<display-name>MyWebApp</display-name>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<welcome-file-list>
<welcome-file>jsf/login/login.xhtml</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
</web-app>
I tried adding the following to the web.xml, this didn't make a difference:
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
I'm sure this has a very simple solution which I'm just missing right now. Help would be highly appreciated. I hope the question is clear.

JSF 2.0+ has introduced <h:link> component that takes a navigation case outcome in its outcome attribute and autogenerates the right URL on its own. This is why you had the error without adding yet another mapping for the faces servlet: just reread the error. It is useful for creation of inter-JSF application navigation.
Alternatively, there has always been a <h:outputLink> component that takes an URL in its value attribute instead. It is useful for creation of navigation external to a JSF application.
Be sure to read the classics from BalusC on the issue: When should I use h:outputLink instead of h:commandLink?.
That said, consider the following components:
<h:link outcome="/destination" value="link" />
<h:outputLink value="/destination.html">
outputLink
</h:outputLink>
The former component will translate its outcome into an actual URL, by appending a faces servlet mapping, while the latter one will leave its value as-is.
So, your problem will be solved by using the following component:
<h:outputLink value="#{contentForm.ccAnimationLink}">
Animation
</h:outputLink>

Related

<t:inputFileUpload> not working anymore after migration JSF 1.2 to JSF 2.2

I am upgrading my application from JSF 1.2 to JSF 2.2 and using Tomahawk 1.1.14 version.
After upgrading, <t:inputFileUpload> tag has stopped working and value of the component is not bound to backingbean property any more.
web.xml
<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>/WEB-INF/facelets/tags/tomahawk.taglib.xml</param-value>
</context-param>
However, I saw on myfaces site that the above parameter is deprecated. Is there any other way to include tag libraries or is it not even required with JSF 2.2?
<filter>
<filter-name>MyFacesExtensionsFilter</filter-name>
<filter-class>org.apache.myfaces.webapp.filter.ExtensionsFilter</filter-class>
<init-param>
<param-name>uploadMaxFileSize</param-name>
<param-value>50m</param-value>
</init-param>
<init-param>
<param-name>uploadThresholdSize</param-name>
<param-value>1024k</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>MyFacesExtensionsFilter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
<filter-mapping>
<filter-name>MyFacesExtensionsFilter</filter-name>
<url-pattern>/faces/myFacesExtensionResource/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>MyFacesExtensionsFilter</filter-name>
<url-pattern>*.faces</url-pattern>
</filter-mapping>
Before this filter, I do have another filter in my web.xml and it is
<filter>
<filter-name>AjaxAnywhere</filter-name>
<filter-class>org.ajaxanywhere.AAFilter</filter-class>
<init-param>
<param-name>preSendHandlerClass</param-name>
<param-value>org.ajaxanywhere.jsf.MyFacesClientStateSavingPreSendHandler</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>AjaxAnywhere</filter-name>
<url-pattern>*.faces</url-pattern>
</filter-mapping>
Can anyone please help me if I need to do any more configuration changes for Tomahawk to work with JSF 2.2?
Thanks!
Since JSF 2.2, the FacesServlet will automatically parse multipart/form-data requests all by itself with help of new Servlet 3.0 #MultiartConfig annotation. Also, since JSF 2.2 there is (finally!) a standard file upload component, the <h:inputFile>.
The MyFaces extensions filter and Tomahawk file upload component is basically incompatible with JSF 2.2. The filter would consume and parse the request its own way and the FacesServlet would end up getting no request data at all (and therefore not be able to continue the JSF lifecycle "as usual"). Removing the filter alone would also not work as <t:inputFileUpload> is internally relying on the semantics/specifics of the MyFaces extensions filter.
Your best bet is really to just remove the filter from the web.xml altogether and replace the <t:inputFileUpload> by <h:inputFile>. It must be bound to a javax.servlet.http.Part property which offers a.o. getInputStream() which you can just continue using the same way as before with <t:inputFileUpload>.
<h:inputFile value="#{bean.uploadedFile}" />
private Part uploadedFile;
public void save() {
String name = uploadedFile.getSubmittedFileName();
String type = uploadedFile.getContentType();
long size = uploadedFile.getSize();
InputStream content = uploadedFile.getInputStream();
// ...
}
The upload maximum and threshold size configuration of the filter can be migrated to <multipart-config> entry of the <servlet> entry of the FacesServlet in web.xml like below:
<servlet>
<servlet-name>facesServlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<multipart-config>
<max-file-size>52428800</max-file-size>
<file-size-threshold>1048576</file-size-threshold>
</multipart-config>
</servlet>
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
See also:
How to upload file using JSF 2.2 <h:inputFile>? Where is the saved File?
Unrelated to the concrete problem, the facelets.LIBRARIES is Facelets 1.x specific. During the JSF 1.x era, Facelets was a standalone view technology. Since JSF 2.0, Facelets is embedded in JSF itself and all its context parameters are migrated from facelets.XXX to javax.faces.FACELETS_XXX. You can find them all in a.o Overview of all JSF-related web.xml context parameter names and values. However, you don't need to explicitly register that Tomahawk taglib as well. Just get rid of it.

Using Primefaces Push to Update Datatable

I'm trying to update a datatable after a row is added using primepush. Meaning, I want user1 to update the datatable and user2 should see the added row without refreshing the page.
My Primefaces version is 5.2 and Atmosphere runtime version is 2.3.3
Here's my relevant code which I tried to implement based on Primefaces Showcase and the User Guide:
web.xml:
<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">
<display-name>PrimeFaces Web Application</display-name>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
<welcome-file-list>
<welcome-file>faces/index.xhtml</welcome-file>
</welcome-file-list>
<filter>
<filter-name>AccessFilter</filter-name>
<filter-class>view.AccessFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AccessFilter</filter-name>
<url-pattern>/secured/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>Push Servlet</servlet-name>
<servlet-class>org.primefaces.push.PushServlet</servlet-class>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Push Servlet</servlet-name>
<url-pattern>/primepush/*</url-pattern>
</servlet-mapping>
</web-app>
Backing Bean:
#ManagedBean
#ViewScoped
#PushEndpoint("/main")
public class MainBean implements Serializable{
...
public void addContact(ActionEvent event){
... // database operations
Contact con = new Contact();
contacts.add(con); // this is an ArrayList
EventBus eventBus = EventBusFactory.getDefault().eventBus();
eventBus.publish("/main", contacts);
}
#OnMessage(encoders = {JSONEncoder.class})
public ArrayList<Contact> getContacts(){
return contacts;
}
}
main.xhtml:
...
<p:commandButton value="Add Contact" update=":form:datatable"
actionListener="#{mainBean.addContact}" ajax="true"/>
<h:form id="form">
<p:dataTable id="datatable" var="contact" value="#{mainBean.contacts}"
selectionMode="single" rowKey="#{contact.firstName}"
selection="#{mainBean.selectedContact}">
<p:column headerText="First Name">
<h:outputText value="#{contact.firstName}"/>
</p:column>
<p:column headerText="Last Name">
<h:outputText value="#{contact.lastName}"/>
</p:column>
</p:dataTable>
</h:form>
<p:socket channel="/main">
<p:ajax event="message" update=":form:datatable"/>
</p:socket>
When I try to add a row to the table, no errors occur but some rows just get lost. When I refresh, the table reloads as the way it should. The added row is also not passed between different users. User2 still needs to refresh to see the changes after user1 adds a value to the table.
I've also tried the suggestions in this link with no success. I'm pretty new to primepush and the examples I found online (other than the User Guide) are for really old versions of Primefaces and push feature seems to changed a lot after Primefaces 5. Any help is appreciated.
Edit: I've also tried these links: link, link, link.
Edit 2: I've logged if the push is working and it seems that it is indeed. When I navigate to the page which has push enabled, I can observe on the console that it gets activated. However, when I try to update the table, the get method of the list which is filling the table is called three times consecutively after pushing...

fileUpload doesn't fire event in PrimeFaces 3.5 with JSF 2.2

I can't make fileUpload component on PrimeFaces 3.5 to fire the event. I have read many posts about that topic and followed advise there but still it doesn't work. I tried all of the modes (simple, auto, advanced) with no success.
If I use standard inputFile tag from the JSF specification it works properly.
This is my web.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" 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-app_3_1.xsd">
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>redmond</param-value>
</context-param>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>faces/home.xhtml</welcome-file>
</welcome-file-list>
</web-app>
And this is part of my view page with the fileUpload tag:
<h:form enctype="multipart/form-data">
<p:dialog id="basicDialog" header="Add pictures" widgetVar="dlg1" >
<p:fileUpload fileUploadListener="#{galleryManagedBean.addPicturesToGallery}" multiple="true"/>
</p:dialog>
</h:form>
The extract from managed bean with the method that is called from the tag:
#Named(value = "galleryManagedBean")
#RequestScoped
public class GalleryManagedBean {
public void addPicturesToGallery(FileUploadEvent event)
{
System.out.println("Triggered upload");
}
}
Also I would like to add that the Http POST request is fired properly after I checked it using the debugger tool in Chrome.
I have added necessary libraries to the classpath i.e. :
commons-fileupload-1.3.jar
commons-io-2.4.jar
This is caused by a change in FacesServlet of JSF 2.2. Since that version, FacesServlet natively supports file uploads (specifically: multipart/form-data HTTP requests) thanks to the presence of the new Servlet 3.0 specific #MultipartConfig annotation. Also, a new <h:inputFile> component was been introduced to offer a file upload component in the standard JSF component set.
This all conflicts with PrimeFaces file upload facility in older PrimeFaces 3.x versions which didn't take this new JSF 2.2 feature into account at all. The PrimeFaces 3.x file upload filter parsed and consumed the entire request while it should leave this job up to the FacesServlet. This caused the FacesServlet to be unable to properly decode the HTTP request (determining the submitted values and actions).
PrimeFaces 4.0, which is designed specifically for JSF 2.2, has taken this all into account. In this changeset of the PrimeFaces file upload filter you can see the changes done to recognize JSF 2.2 and bypass the parsing in the filter. Theoretically, it should also suffice to entirely remove the file upload filter registration from web.xml so that this isn't used anymore.
It should work fine if you upgrade to PrimeFaces 4.0. It has coincidentally been officially released just 2 days ago, so you're pretty on time for that. 

How to pass url parameters to JSF/xHTML?

I know this has been asked multiple times but mine is a slightly diff question.
I have a JSF page which queries a database and throws results, before i move to JSF, i used to do this in JSP and it was working fine.
When i was using JSP below is the link format i used to use
http://localhost:8080/blmdatabase/index.jsp?SearchString=Name&Category=Contact&Submit=Submit
My index.jsp used to capture the values using param.SearchString & param.Category, and 'Submit' used to activate the 'submit' button for the search.
How do i do the same for xHTML/JSF ?
Here is what i tried ...
http://localhost:8080/blmdatabase/index.xhtml?search=#{some search string}
In my index.xhtml
<td>
<f:metadata>
<f:viewParam name="search" value="#{databaseSearch.searchstring}" />
</f:metadata>
<p:inputText id="searchstring" size="20" maxlength="20" value="#{databaseSearch.searchstring}"/> <p:commandButton id="submit" icon="ui-icon-search" title="Search Database" update="panel" actionListener="#{databaseSearch.customerList}" />
</td>
in my databaseSearch.java
#ManagedBean(name = "databaseSearch")
#SessionScoped
public class databaseSearch implements Serializable {
public String searchstring;
//getter and setter for searchstring
}
Also, i would need it 'Submit' the form .... I am new to this, so please excuse me if this was already discussed before ...
Also if i specific index.html , my jsf components would not load, just a blank page. like if i go
http://localhost:8080/blmdatabase/
my primefaces components load fine, but if i do
http://localhost:8080/blmdatabase/index.xhtml
it does not, so now i am wondering how to pass the parameters :(
Web.xml
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>faces/index.xhtml</welcome-file>
</welcome-file-list>
You could 'submit' your form adding <f:event type="preRenderView"> inside the <f:metadata> tag.
<f:metadata>
<f:viewParam name="search" value="#{databaseSearch.searchstring}" />
<f:event type="preRenderView" listener="#{databaseSearch.doSearch}" />
</f:metadata>
This way, you could implement how your bean will search for this specific query string
public void doSearch(ComponentSystemEvent event) {
if(!searchString.isEmpty()) {
// Do your search here
}
}
Your Faces Servlet maps to anything that's hold in the faces virtual folder:
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
So http://localhost:8080/blmdatabase/index.xhtml URL won't be parsed through Faces Servlet. You must use http://localhost:8080/blmdatabase/faces/index.xhtml, note the use of faces/ before your index.xhtml file, also note that your <welcome-file> also points to faces/index.xhtml.
The downside of this URL pattern is that Faces Servlet would also process non-facelets resources like JavaScript files (.js), Style files (.css), images (*.png, *.jpg) and others. A better Faces Servlet mapping would be:
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
In this way, Faces Servlet will process xhtml pages only and you won't need the faces virtual folder anymore. With this change, now you can access to http://localhost:8080/blmdatabase/index.xhtml with no problems.
you could use a method in the class dataBaseSearch:
if(searchString != null){
//execute a query in database
// return result to a variable(resultSet or list)
}
and use getter and setter to get the the resultSet or List
and render the result in a datatable.

JSF template not applied

I'm running into a problem with JSF and templating. I'm following this tutorial but the only output I see is the one I'm defining in my index.xhtml with
<ui:composition template="/WEB-INF/templates/BasicTemplate.xhtml">
<ui:define name="content">
my custom content
</ui:define>
without adding the footer and header even though I'm not defining/overwriting the default one in my index file.
If I view the source in the browser it's showing up the same way as in my index.xhtml with ui:composition etc. So it looks like it's not "converting" it to HTML.
The relevant parts of my web.xml:
<servlet>
<description>Controller Servlet for data input</description>
<display-name>InputServlet</display-name>
<servlet-name>InputServlet</servlet-name>
<servlet-class>form.controller.InputServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>InputServlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
My directory structure looks like this:
http://i.imgur.com/ZslOQNr.png
Thanks!
You're using the wrong servlet.
JSF comes with its own servlet, the FacesServlet.
Get rid of the InputServlet from web.xml altogether and map JSF's FacesServlet as follows:
<servlet>
<servlet-name>facesServlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
That should do it.
See also:
Our JSF wiki page - contains a Hello World and several links to sane tutorials

Resources