I have strange problem on my simple form in JSF 2.0. In this form, I use two selects, if the first select is chosen, the second should be reload with new options. I use the same mechanism as on Primefaces demo page : Primefaces demo page. My bean is #ViewScoped. I also run my app on jetty-maven plugin by "mvn jetty:run". No problem so far. My form works well.
The problem occurs when I change something while my server is running, jetty is reloading. And after that these two selects don't work - if I choose option on the firts one, second one isnt responding. I have to clear all session by logout in Spring Security and after that my form come back to work.
When i changed my bean to #SessionScoped, problem disappeared.
Is this working proper? I dont want to have my form on session scoped, I prefer ViewScoped.
Try to check your context is postback like this on postConstruct in your bean.
#PostConstruct
public void init() {
if (!FacesContext.getCurrentInstance().isPostback()) {
//Write your code here...
}
Or try close to partial state saving on your web.xml if jsf version is 2.0, but with this method, your application may need more memory allocation
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
Good Luck!
Related
I am trying to invoke a method annotated with #PreDestroy in a #ViewScoped bean when the user leaves the page associated with that bean in a rather large JSF powered web application.
After reading https://stackoverflow.com/a/15391453/5467214 and several other questions and answers on SO as well as https://showcase.omnifaces.org/cdi/ViewScoped, I came to the understanding that the OmniFaces ViewScoped annotation provides exactly that behavior by utilizing the unload page event as well as sendBeacon on modern browsers.
So I used the #ViewScoped annotation from OmniFaces in my bean:
import javax.annotation.PreDestroy;
import org.omnifaces.cdi.ViewScoped;
#Named("DesktopForm")
#ViewScoped
public class DesktopForm implements Serializable {
...
}
and annotated the method I want to invoke with the PreDestroy annotation:
#PreDestroy
public void close() {
System.out.println("Destroying view scoped desktop bean");
...
}
Unfortunately, this "close" method is not called when I click some link or leave the page
by entering an entirely new URL. Instead, the network analysis of my browser (a current Firefox) shows me that a POST request is send when leaving the page that returns with an 403 http error code:
As you can see in the screenshot, the "Initiator" of the POST request seems to be an unload.js.jsf script with a beacon mentioned in parentheses, which I assume is part of the OmniFaces library. So presumably the functionality described in the OmniFaces ViewScoped documentation is somehow triggered, but does not result in the expected behavior for me.
The browser still navigates to the new page, but the PreDestroy annotated method was not triggered. When I switch to the standard version of ViewScoped (javax.faces.view.ViewScoped instead of org.omnifaces.cdi.ViewScoped), naturally the method still does not get invoked, but there is also no POST method resulting in a 403 error status when leaving the page in the network analysis of my browser (because the standard ViewScoped annotation of Java does not try to invoke any bean side action on unload events, I guess)
I am using MyFaces 2.3.10 in combination with OmniFaces 2.7.18 (and PrimeFaces 8.0.5, I don't know if that is relevant), Spring Security 5.7.3 and Java 11.
Since "403" is the http status for "forbidden", could this have something to do with using "http" instead of "https" in my local development environment? Does this "send beacon" only work with secure connections?
Any help appreciated!
Edit: I also consulted the official documentation of the OmniFaces ViewScoped annotation under https://omnifaces.org/docs/javadoc/2.7/index.html?org/omnifaces/cdi/ViewScoped.html but could not find a reason for the problem I encounter.
With the help of BalusC's comment to my question above, I was able to solve my problem.
What it came down to was that unload events were not processed correctly by our filter chain. Specifically, they were denied access in the doFilter method of our class extending org.springframework.web.filter.GenericFilterBean.
Therefore I added
if (ViewScopeManager.isUnloadRequest(httpServletRequest)) {
chain.doFilter(request, response);
}
to the doFilter method of the mentioned class and then it worked.
On a side note, I had to update my OmniFaces library from 2.7.18 to 3.13.3, because the ViewScopeManager class of OmniFaces 2 only has one isUnloadRequest method that accepts an FacesContext as parameter, which I did not have available in the our GenericFilterBean extension. OmniFaces 3.1 on the other hand provides another method with the same name that works with an HttpServletRequest instance instead, which I had access to and therefore resolved the issue
I have my own realm classes extends AppservPasswordLoginModule and AppservRealm where I get user and roles from my own table in database. In web.xml I defined access to pages and it works.
I have some mechanism to read main menu from my menu.xml file in my bean with #SessionScoped annotation.
I want to use rules from web.xml to display only this items, which user has acces to (defined in web.xml), without repeating configuration in my menu.xml file.
I imagine that the solution might be to check the access to the page when I create menu item for this page in my SessionScoped bean, but I don't know how it could be checked easily.
What is the best solution for this situation?
I'm using glassfish 4.1 and jsf 2.2.
I solved this by the following method:
In my ServletListener
#WebListener
public class implements ServletListener ServletContextListener {...}
I read security-constraint from web.xml, parsing them and store it in my #ApplicationScoped bean.
In #SessionScoped bean, in #PostConstruct annotated method I get all roles stored in #ApplicationScoped bean and checked each individual by
FacesContext.getCurrentInstance().GetExternalContext().IsUserInRole(role);
method.
So I have all current user roles. Then, in my #SessionScoped bean, for each menu item I check whether the resource represented by the url of this menu item is available for roles that current user has.
EDIT: The bad side of this solution is that I analyzing the web.xml file only, without annotations
I'm using spring boot with jsf (primefaces). here you can find sample of my application. When I invoke this application using mvn spring-boot:run and access application with jsf or with xhtml everything works ok. But when I deploy this application to tomcat, xhtml page is not rendered properly. I can see page source (xhtml source, not html), but this is not wanted. I want to be able to display the same with .jsf and .xhtml.
Can anybody tell me what am I missing?
Edit:
as I reviewd this issue and it was not helpfull (I also have *.xhtml mapping for faces servlet and as I wrote before, this is working on spring-boot embedded tomcat but not on classic tomcat), I think the problem will be more related to the spring configuration, but I'm not sure what and where to change.
Thanks
Problem in spring config. Add this to file Application.java:
#Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/view/");
resolver.setSuffix(".xhtml");
return resolver;
}
our customer doesn't want to have session handling with cookies and it also will cause problems with an Apache/mod_rewrite gateway, so i tried to use
<tracking-mode>URL</tracking-mode>
in our web.xml. That should be all with Glassfish3/Servlet 3.0. However now i get ViewExpiredExceptions when trying to log in(it's not an AJAX request):
<p:commandButton id="submit"
value="${msg['Login.submit.label']}"
action="#{loginBean.login}"
ajax="false"/>
I also tried to save the session on the client side, than i can see the JSESSIONID in the URL but that throws NotSerializableExceptions for my #EJBs. Any ideas? Do i miss something? It used to work fine with the cookies.
UPDATE: LoginBean.login returns "Home.xhtml?faces-redirect=true", expected behaviour when clicking the commandButton: POST on Login.xhtml, my login page, redirect and GET on Home.xhtml.
SECOND UPDATE:
Looks like my action never gets called, i'm directly getting the ViewExpiredException and a HTTP 500 error code.
THIRD UPDATE:
Looks like the HttpSession is always null with tracking mode set to URL, with cookies the HttpSession is correctly created. Shouldn't the FacesServlet create a session and append the JSESSIONID in the URL if there is no session?
ANOTHER UPDATE:
With
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
the session will be created on postback. But than i'm running into
java.io.NotSerializableException
.
The other option is to set restore view compability to true.
Edit your web.xml and add following code and try.
<context-param>
<param-name>com.sun.faces.enableRestoreView11Compatibility</param-name>
<param-value>true</param-value>
</context-param>
Updated:
Reference
com.sun.faces.enableRestoreView11Compatibility is a JSF 1.2 setting that tells JSF 1.2 to behave like JSF 1.1.
com.sun.faces.enableRestoreView11Compatibility == true means "do not throw a ViewExpiredException; instead, just create a new view if the old one has expired."
The IBM notes on the JSF 1.1 behaviour say:
This can have adverse behaviors because it is a new view, and items that are usually in the view, such as state, are no longer be there.
The default JSF 1.2 behaviour is defined in the spec as this:
If the request is a postback, call ViewHandler.restoreView(), passing the FacesContext instance for the current request and the view identifier, and returning a UIViewRoot for the restored view. If the return from ViewHandler.restoreView() is null, throw a ViewExpiredException with an appropriate error message. javax.faces.application.ViewExpiredException is a FacesException` that must be thrown to signal to the application that the expected view was not returned for the view identifier. An application may choose to perform some action based on this exception.
To have a ViewExpiredException thrown when the view expires, remove the com.sun.faces.enableRestoreView11Compatibility parameter or set it to false.
The com.sun namespace suggests that the parameter is a Sun/Mojarra and derived implementation-specific setting, so it probably will not work with all JSF implementations.
Fixed by updating Mojarra. My Glassfish 3.1.2.2 came with Mojarra 2.1.6 and this bug:
https://java.net/jira/browse/JAVASERVERFACES-2143
Updated to 2.1.22 and everything works.
I am developing a web app using jsf technology. I want a method of my backing bean to be
invoked when the home page of my app is displayed. Usually, a backing bean method
gets involved when a user clicks on a link or a button.
In short I want my backing bean to get some data from the database and send it to the
jsf page, and I want this to occur when a user invokes the home page link
of my app.
Here is how I wanted to solve the problem: use a servlet that is executed when
the expected link is invoked, and call the backing bean from that servlet; but the problem
is I am having some difficulties with the url-pattern of the servlet in the web.xml file. The home page link of my app is: home.jsf. The name of my servlet is
HomeServlet and here is how I configured it in the web.xml file:
<servlet>
<servlet-name>HomeServlet</servlet-name>
<servlet-class>utils.HomeServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HomeServlet</servlet-name>
<url-pattern>/home.jsf</url-pattern>
</servlet-mapping>
So when I run the app, the servlet is executed, but my home.jsf page is empty (completely blank). I don't know why.
So what I want to know is:
Am I using the right approach for this issue?
If yes, which url-pattern should I use?
No, this is definitely not the right approach. You're working your way around JSF. You're supposed to do the job just in the constructor or #PostConstruct method of the request or view scoped JSF managed bean associated with the view.
E.g.
#ManagedBean
#RequestScoped
public class Home {
public Home() {
// Here.
}
#PostConstruct
public void init() {
// Or here. This will be invoked *after* any dependency injections,
// such as #EJB, #ManagedProperty, #Inject, #Resource, etc.
}
// ...
}
Whenever JSF encounters a #{home.someproperty} reference in the home.xhtml (or home.jsp) for the first time, then the bean will just be constructed.
When developing with JSF, you shouldn't have any need to develop other servlets. In JSF, the FacesServlet is the sole servlet which already does all the necessary request/response and model/view controlling job.