Im trying to use dynamic validationGroups
<h:inputText id="id" value="#{bean.char}" maxlength="8" alt="#{bean.displayName}">
<f:validateBean
validationGroups="#{bean.validationGroup}" />
</h:inputText>
However the #{bean.validationGroup} is always called before the
<f:event type="preRenderView" listener="#{bean.initView}" />
Is this a bug in Myfaces? I need to have #{bean.validationGroup} called after the prerenderview because preRender loads data from the db and validationGroups will be different. Im using Myfaces 2.1.5 with richfaces 4.1.
This is indeed specified behaviour. The <f:xxx> tags run during view build time. If you like to initialize properties before the view is been built, then you need to do the job in the (post)constructor method of the bean. The pre render view event runs right before the view is to be rendered, but long after the view is been built.
Remove the <f:event> altogether and make the initView a #PostConstruct method instead.
#PostConstruct
public void initView() {
// ...
}
It will run directly after bean's construction and finishing of all dependency injections like #ManagedProperty, #Inject, #EJB and so on.
#ManagedBean
#XScoped --sessionScope,viewScope
Public class Bean{
public void initView(){
if (!FacesContext.getCurrentInstance().isPostback(){
//put initView codes here
}
}
}
Related
I have a problem with a binding p:commandButton to a property in a backing bean. I've tried to simplify my code to show general idea.
ExampleBean is a backing bean
public class ExampleBean {
public String title;
List<ExampleWrapper> list;
// Getters and setters
}
ExampleWrapper is a POJO
public class Wrapper {
public String name;
public String description;
public CommandButton button;
// Listener which changes button state
// Getters and setters
}
index.xhtml is a main page:
<h:form>
<h:outputText value="Title" />
<p:inpurText value="#{exampleBean.title}"
<ui:include src="list.xhtml">
<ui:param name="bean" value="#{exampleBean}">
</ui:include>
</h:form>
list.xhtml is a fragment I want to be reused in a few places:
<ui:composition ...>
<ui:repeat id="list" var="exampleWrapper" value="#{bean.list}">
<h:outputText value="#{exampleWrapper.name}"/>
<h:outputTextarea value="#{exampleWrapper.description}"/>
<p:commandButton id="button" binding="#{exampleWrapper.button}"
value="Button" />
</ui:composition>
So, I get exception:
javax.el.PropertyNotFoundException: /list.xhtml ... binding="#{exampleWrapper.button}": Target Unreachable, identifier 'exampleWrapper' resolved to null
Without binding attribute everything works and displays fine
Could you explain why and how can I bind button to this POJO property? Any help will be appreciated
I'm using JSF 2.0.2 with Primefaces 3.0.1
The binding (and id) attribute of a JSF UI component is resolved during view build time. The #{exampleWrapper} instance is not available during the view build time. The view build time is that moment when the XHTML file is parsed into a JSF component tree. The #{exampleWrapper} is only available during the view render time. The view render time is the moment when the JSF component tree generates HTML output.
Basically, there's only one <p:commandButton> in the component tree which generates its HTML output multiple times as many as the <ui:repeat> iterates. You need to bind it to the #{bean} instead, or to use JSTL <c:forEach> instead of <ui:repeat>. The JSTL tags runs namely during view build time and the <c:forEach> will thus produce physically multiple JSF UI components. But, more than often, binding components to backing beans is unnecessary in JSF 2.x. Whatever functional requirement you've had in mind for which you thought that this is the solution, it can definitely be solved in a better way.
I have the following piece of code with a simple h:outputText pointing to a int and a p:commandLink to set a value:
<h:form id="f1">
<h:outputText id="text" value="#{testBean.index}"/>
<p:commandLink actionListener="#{testBean.test}" update="text">
<f:setPropertyActionListener target="#{testBean.index}" value="5" />
<h:graphicImage url="/images.png"/>
</p:commandLink>
</h:form>
The managed bean looks like this:
#javax.faces.bean.ManagedBean #ViewScoped
public class TestBean implements Serializable{
private int index; // getter/setter
#PostConstruct public void init() {
index = 0;log.log(Level.WARNING, "#PostConstruct");}
public void test(ActionEvent ae){
log.log(Level.WARNING, "Index: "+index);}
}
The bean is constructed correctly, and after the first click on the image the h:ouputText is updated to 5. But in my log message I only see Index: 0 during the first click on the image.
It's something similar like Jsf updates model value with old value, but I have the JSF #ManagedBean annotation.
Action listeners are invoked in the order they're definied in the view. You want to use action instead of actionListener. Even more, the action should in first place have been used to invoke a business action.
<p:commandLink action="#{testBean.test}" update="text">
<f:setPropertyActionListener target="#{testBean.index}" value="5" />
<h:graphicImage url="/images.png"/>
</p:commandLink>
See also:
Differences between action and actionListener
What is happening is that the test ActionEvent is getting fired before the request values have been applied.
To get a better understanding of the JSF phase lifecycle and when lifecycle events and ActionEvents fire, implement the Debug PhaseListener as specified in the following blog article.
http://balusc.blogspot.com/2006/09/debug-jsf-lifecycle.html
This should help you understand when request values are being applied, and when events are being fired.
My main question is : Is there a "good practice" to serve binary files (PDF, docs, etc) using JSF 2 with CDI, and using bookmarkable URLs ?
I've read the JSF 2 spec (JSR 314) and I see it exists a "Resource Handling" paragraph. But it seems to be used only to serve static files put in the war or jar files. I didn't really understood if it exists a way to interact here by registering some specific ResourceHandler ...
Actually, I was used to Seam's 2 way to do that : extending the AbstractResource class with getResource(HttpServletRequest, HttpServletResponse) method and getResourcePath() to declare which path to serve after <webapp>/seam/resource/ URL prefix and declaring the SeamResourceServlet in the web.xml file.
Here is what I did.
I've first saw How to download a file stored in a database with JSF 2.0 and tried to implement it.
<f:view ...
<f:metadata>
<f:viewParam name="key" value="#{containerAction.key}"/>
<f:event listener="#{containerAction.preRenderView}" type="preRenderComponent" />
</f:metadata>
...
<rich:dataGrid columns="1" value="#{containerAction.container.files}" var="file">
<rich:panel>
<h:panelGrid columns="2">
<h:outputText value="File Name:" />
<h:outputText value="#{file.name}" />
</h:panelGrid>
<h:form>
<h:commandButton value="Download" action="#{containerAction.download(file.key)}" />
</h:form>
</rich:panel>
</rich:dataGrid>
And here is the beans :
#Named
#SessionScoped
public class ContainerAction {
private Container container;
/// Injections
#Inject #DefaultServiceInstance
private Instance<ContainerService> containerService;
/// Control methods
public void preRenderView(final ComponentSystemEvent event) {
container = containerService.get().loadFromKey(key);
}
/// Action methods
public void download(final String key) throws IOException {
final FacesContext facesContext = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();
final ContainerFile containerFile = containerService.get().loadFromKey(key);
final InputStream containerFileStream = containerService.get().read(containerFile);
response.setHeader("Content-Disposition", "attachment;filename=\""+containerFile.getName()+"\"");
response.setContentType(containerFile.getContentType());
response.setContentLength((int) containerFile.getSize());
IOUtils.copy(containerFileStream, response.getOutputStream());
response.flushBuffer();
facesContext.responseComplete();
}
/// Getters / setters
public Container getContainer() {
return container;
}
}
Here I had to switch to Tomcat 7 (I was using 6) in order to interpret correctly that EL expression. With #SessionScoped it worked, but not with #RequestScoped (when I clicked the button, nothing happend).
But then I wanted to use a link instead of a button.
I tried <h:commandLink value="Download" action="#{containerAction.download(file.key)}" /> but it generates some ugly javascript link (not bookmarkable).
Reading the JSF 2 spec, it seems that there is a "Bookmarkability" feature, but it is not realy clear how to use it.
Actually, it seems to work only with views, so I tried to create an empty view and created a h:link :
<h:link outcome="download.xhtml" value="Download">
<f:param name="key" value="#{file.key}"/>
</h:link>
<f:view ...>
<f:metadata>
<f:viewParam name="key" value="#{containerFileDownloadAction.key}"/>
<f:event listener="#{containerFileDownloadAction.download}" type="preRenderComponent" />
</f:metadata>
</f:view>
#Named
#RequestScoped
public class ContainerFileDownloadAction {
private String key;
#Inject #DefaultServiceInstance
private Instance<ContainerService> containerService;
public void download() throws IOException {
final FacesContext facesContext = FacesContext.getCurrentInstance();
// same code as previously
...
facesContext.responseComplete();
}
/// getter / setter for key
...
}
But then, I had a java.lang.IllegalStateException: "getWriter()" has already been called for this response.
Logic as when a view initiates, it uses getWritter to initialize the response.
So I created a Servlet which does the work and created the following h:outputLink :
<h:outputLink value="#{facesContext.externalContext.request.contextPath}/download/">
<h:outputText value="Download"/>
<f:param name="key" value="#{file.key}"/>
</h:outputLink>
But even if that last technique gives me a bookmarkable URL for my file, it is not really "JFS 2" ...
Do you have some advice ?
I agree with BalusC. Typically an application is not purely a JSF application but a Java EE application.
It's not for nothing that other things than JSF views exist for handling http requests in Java EE. In Java EE 6, your named CDI bean can btw also directly be mapped to a path using JAX-RS. This is an alternative to using Servlets. In that case you would use #Produces and #Path (see e.g. Input and Output binary streams using JERSEY?).
On the other hand, one advantage of <f:viewParam> in JSF is that you can easily attach validators to it. Neither Servlets nor JAX-RS resources have support for that at the moment.
<h:link> is also more comfortable to use than writing <h:outputLink value="#{facesContext.externalContext.request.contextPath}/..."> all the time. This can however be mitigated by wrapping this part in a Facelets tag or composite component.
(It would be great I think if a future version of the spec provided a link tag in JSF to link directly to JAX-RS resources (with optional container startup validation to ensure the link is legal)).
JSF is from the beginning on designed to be a MVC framework, not to be some REST file service.
A servlet is perfectly fine for the job. Annotate it with #WebServlet to get a better Java EE 6 feeling.
There is in fact a direct solution to this problem using PrettyFaces URLRewriteFilter -> http://ocpsoft.org/prettyfaces/serving-dynamic-file-content-with-prettyfaces/
This blog explains how to do exactly what you want to do, without having to use an entirely new MVC framework.
I have a little issue regarding submit of forms in jsf 2:
In my webapp I got a function that updates entities in my db. This function gets the relative data out of a managed bean.
So, my issue is that changes in my view are not passed to the managedBean. To make that clear for you, here an example:
public String updateProject() {
projectService.updateProject(projectData.getProjectDTO());
return ("overview.xhtml");
}
prjectData is my ManagedBean. This one doesn't work! No updates are been made.
public String deleteProject() {
projectData.getProjectDTO().setDeleted(true);
projectService.updateProject(projectData.getProjectDTO());
return ("overview.xhtml");
}
Here, when I change a value by code it works! So I guess my values out of the view are not passed to my managedBean.
Where could be a mistake? Is there maybe an action I have to invoke to make the data pass my view to the managedBean?
Answer to Gabor's comment:
My page looks like:
<h:form>
<h:commandLink action="#{controller.updateProject}" value="Edit" />
<h:outputLabel for="title" value="Titel" />
<h:inputText id="title" value="#{projectData.projectDTO.title}" />
</h:form>
If I change the title here and press update nothing happens ;-)
My Controller looks like:
#ManagedBean
#RequestScoped
public class Controller {
#ManagedProperty(value = "#{projectData}")
private ProjectData projectData;
...
For unknown reason my debug mode in eclipse doesn't work anymore it ignores my breakpoints all the time. I gonna fix that and then I'll check about the instances. Sry -.-
Either projectData or projectDTO is not the right instance as you expect it to be. It's a completely different instance. Aren't you eagerly recreating/overriding beans? Don't you have multiple beans in the scope? Shouldn't it for example be #{controller.projectData.projectDTO.title}? Shouldn't the projectData instance in the controller be a managed property?
Is your projectData bean also RequestScoped? Try to change to ViewScoped. RequestScoped beans are recreated for each request, also ajax request. And what is scope of projectService?
I would like to add buttons dynamically from a backing bean to a JSF page (supporting Rich Faces as well).
The value of the buttons needs to be determined in run time and returned to the backing bean when the button is pressed. (Hence the title - I am actually trying to be able to do something like "#{beans.run(3)}", i.e - set a fixed parameter to be used when clicking a button)
So for example, if the user creates a button (on run time) and gives the button a value. This value should be returned to the backing bean to be analysed.
My question - How do I assign a button (the button is a JSF component with a4j:support child) with a value at runtime? (I tried using a4j:actionParam, but couldn't manage to work it out)
P.S - I've overhauled this question to be shorter and more to the point from the original-too-long-question
There are a number of opions:
use JSF 2.0
use JBoss EL extension
use <f:setPropertyActionListener value="3" target="#{bean.propety>, where propety is later read by the run() method.
<h:commandButton action="#{bean.run}">
<f:setPropertyActionListener target="#{bean.property}"
value="#{pageVariable}" />
</h:commandButton>
<!-- pageVariable contains the number you are passing -->
public class Bean {
private int property; // with setters and getters
public void run() {
// do something with property
}
}
use Facelets functions (here's an example for such a function) (not applicable in all cases)