JSF 2 : Accessing managed bean's instance in the phase listener object? - jsf

Is it possible to get a reference to the to-be-executed managedbean in the before-invokeApplication-phaselistener ?
Before the invoke application phase, it should be clear which managedBean that is going to execute the method.
For the sake of the example, assume there's 1 main manage bean to handle 1 jsf page.
So what i need is basically :
The user access the program from the menu
Because it's accessed from the menu, the main manage bean's init() method gets called to initialize stuffs like preparing data, doing authorization checks
Subsequent submits dont need to call the init() method anymore until it's reaccessed from the menu
To implement the point #2, im thinking of intercepting one of the phases
I've checked the API docs about getting the managed bean in the phases implementation, but i couldnt seem to find any.
After typing this question, i realize i could do this in #PostConstruct or the managed bean's constructor, but that would do only at the first time the bean is constructed, and my need is to call the method everytime the jsf is being accessed from the menu.
Any suggestions ?
Regards,
Albert Kam

You can access your managed beans via the ELContext/ELResolver. This is explained nicely in the MyFaces wiki (also works in vanilla JSF).
For example:
ELContext elContext = FacesContext.getCurrentInstance().getELContext();
NeededBean neededBean = (NeededBean) FacesContext.getCurrentInstance().getApplication()
.getELResolver().getValue(elContext, null, "neededBean");
See the MyFaces wiki entry for further explanation, and implementations for other JSF versions.
Your idea of using #PostConstruct is a good one. Consider changing your scope to something liked #ViewScoped, so the logic is executed everytime you navigate to that view.
Also, have a look at the PreRenderViewEvent (for JSF 2). This code is embedded in your facelet page:
<f:metadata>
<f:viewParam name="foo" value="#{bean.foo}"/>
<f:event type="preRenderView" listener="#{bean.doSomething}"/>
</f:metadata>
The f:event listener is executed before every page view.

Related

How to instantiate a backing bean on page load

For a project we are migrating some java applications to WebSphere 8.5. In the process we are trying to get rid of some legacy frameworks. One of them is shale (apache attic). The only component from shale that is used is the view controller to instantiate a request scoped jsf managed beans for every page. Every bean has an init method that is called on page load. I'd like to use #PostConstruct on this method. The only problem I have that the bean gets instantiated when a method on the bean is called. Unfortunately the bean is not always called and the init method does populate data on a session scoped bean. There is a naming convention that links pages and beans so we could use a listener to instantiate the bean based on the request. Another solution might be changing the scope to viewscope (probably to much a hassle on websphere 8.5).
I was wondering if there is something I can do to make the PostConstruct work? And are there other options I'm missing?
edit:
I have a PhaseListener in place that performs the basic functionality. It matches the requested page to the corresponding bean (by naming convention). The following is used to instantiate the bean but it looks a bit ugly.
expressionFactory.createValueExpression(elContext, "#{" + managedBeanName + "}", Object.class)
Is there a more elegant way to do this?
Perhaps you could try using <f:event/> ?
In your view, you could add this to the page.
<f:event type="postAddToView" listener="#{backingBean.myInitMethod()"/>
https://stackoverflow.com/a/14004230/4706826
Gives you info on when the events get executed.
Put a #PostConstruct annotated method in the backing bean. This annotation tells the bean to execute the annotated method every time its constructor is being called.
Example:
#ManagedBean
#ViewScoped
public class MyManagedBean{
#PostConstruct
public void initView() throws Exception{
...initialize page values, execute database queries, etc.
}

Get url parameter into facelets view after user session timeout

I am building a CRUD web application using JSF. I have a problem with loading a page after the user session has timed out. That is i lose the parameters I need to construct the view (even though the parameters are still visible in the url like so: 'someurl/view.xhtml?pid=5'.
In the .xhtml file the parameter pid is used to load some content from an underlying database when constructing the view. When the user has been inactive for a while their session times out, and if they try to reload the page in the browser they are forwarded to the login page (the 'someurl/view.xhtml?pid=5' still intact) and on succesful login go back to the view.xhtml page where I wan't the view to be constructed as if their session had never timedout.
However this does not happen because the 'pid' parameter is no longer set in the view. But since the 'pid' parameter is still visible in the url I feel like I should be able to get it into the view and load the protein with this id from the database.
These are the things I've tried:
#{protein.setProteinById(param.pid)}
and
#{protein.setProteinById(param['pid'])}
and
#{protein.setProteinById(request.getParameter('pid'))}
and
<c:set value="${request.getParameter('pid')}" var="pid" />
#{protein.setProteinById(pid)}
Is this possible to do? Then how?
I'm no expert, but wouldn't you set it in the managed bean?
As far as I know there are two methods for doing this.
One method is using in your facelet to push a view parameter back into a bean (I have a scenario where this doesn't work because of other things, so have no experience with it)
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
I have a prerender method, which is always called before a render
<f:metadata>
<f:event type="preRenderView" listener="#{MyController.prerenderMethod}" />
</f:metadata>
And inside the method, I look at the parameters:
public void prerender(ComponentSystemEvent event) {
value = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("key");
}

jsf navigation to another method

I am developing an application using jsf 2.0 and i have the following situation:
I have 2 managed beans.
On the first managed bean i have a method that process some data and then store the result in session.After the data was stored in session i need to invoke a method on the second bean that will display the information from session.
The problem is that if i return a string from the first bean method that correspond to the seconds bean method view the data is not processed, and of course not displayed.
What i need is some navigation rule that from the first bean would redirect me to the second bean method, and the second bean method would return a string with the corresponding view name.
update
maybe a
<f:event listener="#{secondBean.methodToBeInvoked}" type="preRenderView" />
would help me achieve that.
Is this the right approach ?

View-scoped bean recreated on POST when URL parameters not used

I have a view-scoped JSF-managed bean that's backing an xhtml view where I read one parameter from the URL using f:viewParam.
The view presents a form to the user. However, when the user submits the form by pressing the p:commandButton it seems that the view-scoped bean is recreated (I added a #PostConstruct annotation to verify this) and so doesn't remember the instance variable read from the f:viewParam (invId in the code below).
I originally navigate to the view with a GET that includes a URL parameter but the POST message that's send when the user presses the p:commandButton doesn't include the URL parameter. So I am thinking that when the JSF runtime doesn't see the URL parameter on the POST it considers this to be a different view and is recreating the JSF-managed bean. When I change the view scope to session-scoped the code works.
Here's the code:
view
<f:metadata>
<f:viewParam name="invId" value="#{registerBean.invId}"/>
</f:metadata>
<h:form id="registrationForm">
....
<p:commandButton value="register" action="#{registerBean.register}"
icon="ui-icon ui-icon-newwin" ajax="false"/>
</h:form>
backing bean
#ManagedBean
#ViewScoped
public class RegisterBean implements Serializable {
#ManagedProperty(value="#{invId}")
private String invId;
...
update
It turns out that this wasn't related to the URL parameters at all. Following BalusC advice below I removed the c:when tags my view was using (relying on rendered attributes instead for the same effect), and now the view-scoped bean is no longer recreated and the invId field is properly retained.
The problem is not visible in the code posted so far, but it's for JSF 2.0/2.1 a known issue that a view scoped bean will be recreated when one of its properties is been bound to an attribute of a taghandler like JSTL <c:if> or Facelets <ui:include> or a view build time attribute of JSF component, such as id and binding, while partial state saving is enabled (as by default).
The background explanation is that any EL expressions in those attributes are executed during building and restoring the view. As view scoped beans are stored in the view and thus only available after restoring the view, such an EL expression evaluation would cause a brand new and separate view scoped bean to be created. This is basically a chicken-egg issue. It's fixed in the upcoming JSF 2.2.
There are basically 3 solutions:
Change the view accordingly so that those EL expressions are only evaluated during view render time. E.g. replace <c:if>/<c:choose> by rendered.
Or bind those attributes to a request scoped bean (design notice: you can just inject a view scoped bean as a managed property of a request scoped bean).
Turn off partial state saving, if necessary only for the particular view.
See also:
JSTL in JSF2 Facelets... makes sense?
#ViewScoped fails in taghandlers

JSF and richfaces: h:commandlink in richfaces table not working properly

When using h:commandlink(or commandbutton) inside a rich:dataTable, the action specified is never invoked, neither is the corresponding managed bean instantiated(whether it is at request or session scope)...
instead, the same request is performed.. (page reloads)..
have seen what appeared to be similar issue on forums, but is not actually the problem i am having..
the h:commandlink /button work ok outside of the rich:datatable..
Does anyone have any advice?
here is a code snippet:
<h:commandLink id="commLink" actionListener="#{hBean.test}" action="#{hBean.viewTranslation}">
<h:outputText value="#{trans.translationName}"/>
</h:commandLink>
</rich:column>
The bean is apparently request scoped and the datamodel is not been loaded during bean's construction (at least, during apply request values phase of the subsequent request). You need to preserve the same datamodel for the subsequent request, else JSF cannot locate the row item associated with the clicked link. The most straightforward way is to load the datamodel in the bean's constructor or #PostConstruct method.
A quick fix/test is to put bean in session scope. The datamodel will then be saved in the session scope and be available in the subsequent request. But this has more impact on user experience (e.g. unexpected results when having the same page opened in different browser windows/tabs in the same session). If you're already on JSF 2.0 (which is likely not the case since you're using RichFaces), then the new view scope would have been the solution.
Related questions:
h:commandLink is not been invoked - contains an overview of all possible causes of this behaviour.
If you are using RichFaces 3.0.0 through 3.3.3, use the tag a4j:keepAlive. It will works even with request scope.

Resources