JSF 1.2 to 2.0 annotation change - jsf

I migrated from 1.2 to 2.0 and I moved my managed bean names and scopes from the faces-config.xml to the beans using annotations.
One bean(sessionscoped) has an instance variable which gets the current session as such:
private HttpSession httpsess = (HttpSession)FacesContext.getCurrentInstance().getExternalContext().getSession(false);
And then I call the httpsess variable in any instance method to add stuff to the session. But once I made the annotation changes. The httpsess variable returns null. When I create the variable as a local variable it works fine. Why would this happen?

In JSF 2.x, the creation of HttpSession is postponed as much as possible to avoid unnecessary session creation. It will only be created when it is really needed. It's apparently not been created yet at the point you're calling it. Passing false to getSession() means that the container shouldn't auto-create it if it doesn't exist. So if it doesn't exist yet, it will just return null.
You need to pass true to getSession() instead.
HttpSession httpsess = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true);
See also:
ExternalContext#getSession(boolean) javadoc
Unrelated to the concrete problem, this is a code smell. What exactly do you need the HttpSession for? To get/set some attributes? Why not just make it a property of the current session scoped managed bean? A JSF session scoped managed bean is by itself already stored as a session attribute anyway.

Related

Why FaceletViewHandlingStrategy.renderView force http session creation [duplicate]

I am running Mojarra 2.2.0.
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
The managed bean action method is-
public void action() {
HttpSession session = (HttpSession) FacesContext.getCurrentInstance()
.getExternalContext().getSession(false);
System.out.println(session.getId()); // not null for stateful views
}
For stateless views session.getId() throws NPE
For views which are not stateless-
Firing a GET request, there is JSESSIONID=340041C96D5AA446D761C3602F54A76D
I read it here that-
For client side state saving mechanism, JSF won't create the session
and will store the view state in a hidden input field with the name
javax.faces.ViewState in the form whenever necessary.
Further, it's mentioned here that
JSF will indeed autocreate the session because the JSF view state has
to be stored over there. If you set the JSF state saving method to
client instead of server, then it won't be stored in session and hence
no session needs to be created
I think the above line is a source for trouble for me.
If you set the JSF state saving method to client instead of server,
then it won't be stored in session // FULLY AGREED
and
hence no session needs to be created. // This confuses because for
client side saving mechanism, a session id gets generated by the
servlet container & hence there is a session associated with the
request.
In reference to the discussion which I had with BalusC in this question,
I created a HttpSessionListener-
#WebListener
public class MyHttpSessionListener implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent event) {
Thread.dumpStack();
}
public void sessionDestroyed(HttpSessionEvent event) {
}
}
See below attached screenshots(these 2 screenshots are for version 2.0.3, there must have been an old bug due to which the session was getting created)-
Libraby (Mojarra 2.2.0)-
When does JSF creates a session
Eaiest way to naildown this is creating a HttpSessionListener, putting a debug breakpoint on sessionCreated() method and inspecting the call stack who needed to get the session for the first time (and thus implicitly needs to create it).
In below example you will see a chain of getSession() calls in the call stack. You will see that FaceletViewHandlingStrategy.renderView() method is the one calling it for the first time.
After you click on FaceletViewHandlingStrategy.renderView() line in debugger's call stack, you will get into its source code (Maven will load source code automatically, otherwise you need to manually attach it).
You see, when server side state saving is enabled and the view to render is not transient (stateless), then JSF will implicitly create the session, just to ensure it's created on time in order to save the view (if the session was created later, e.g. during render response phase, you would otherwise risk exceptions like this Adding <h:form> causes java.lang.IllegalStateException: Cannot create a session after the response has been committed).
You'll in the source code also immediately see that when the state saving method is set to client, or when the view is stateless as in <f:view transient="true">, then JSF won't anymore implicitly create the session. Older JSF versions may do that as you figured, but this is to be accounted as a bug and ought to be fixed in a newer version.
If you would like to ensure statelessness and avoid accidental/unforeseen session creation, then you could just throw new IllegalStateException() inside sessionCreated() method. When that happens, you just have to look in call stack who's responsible for creating the session and then fix/change the code to not do that anymore.
what does it puts in a session map?
Under the covers, ExternalContext#getSessionMap() delegates to HttpSession#setAttribute()/getAttribute()/removeAttribute(). You can listen on those methods using a HttpSessionAttributeListener.
In below example you will see that ViewScopeContextManager.getContextMap() line calls SessionMap#put() method in order to put something in the session map. When you unfold the event argument, you will see the session attribute name and value, which is com.sun.faces.application.view.activeViewContexts and an empty ConcurrentHashMap respectively.
Indeed, I was using a #Named #ViewScoped which was referenced by an value expression on the particular page (you see EL resolver and Weld resolver further down in call stack). When you click ViewScopeContextManager.getContextMap() line in call stack, you'll see that it was just preparing a map in session scope in order to store view scoped beans.
That's just one example. There are more things which could be stored in the session. Using a debugger this way and inspecting the associated source code will tell a lot about the Why.

Are JSF managed beans Singleton in nature? [duplicate]

could some explain what a none scope is and purpose of it?
Suppose if i have a bean in
request scope as r1
session scope as s1
application scope a1
and say i inject none scope bean n1 in to each of above scopes then i find that n1 gets
instantiated for each parent bean when ever its parent bean[r1/s1/a1] is instantiated.
none scope bean in a1 is available throughout in a1 since a1 is appl scope.
none scope bean in s1 is available only until s1 is not destroyed and when s1 is created
again n1 is instanciated and made available to it.
Is it correct?
and what the purpose of using it? only to avoid creating such bean our self?
many thanks
A bean with a <managed-bean-scope> of none or a #NoneScoped annotation will be created on every single EL expression referencing the bean. It isn't been stored by JSF anywhere. The caller has got to store the evaluated reference itself, if necessary.
E.g. the following in the view
<p>#{noneScopedBean.someProperty}</p>
<p>#{noneScopedBean.someProperty}</p>
<p>#{noneScopedBean.someProperty}</p>
on a none-scoped bean will construct the bean 3 (three) times during a request. Every access to the bean gives a completely separate bean which is been garbaged immediately after the property access.
However, the following in for example a session scoped bean
#ManagedProperty("#{noneScopedBean}")
private NoneScopedBean noneScopedBean;
will make it to live as long as the session scoped bean instance. You should only make sure that you access it in the view by #{sessionScopedBean.noneScopedBean.someProperty} instead.
So it may be useful when you want scope-less data being available as a managed property in an arbitrary bean.
I'm using #nonescoped when my "view logic" dont need to be in any scope but be referenced by another ManagedBean.
I'm working with Liferay, as I want to make my architecture and design independent of liferay, I create my services interfaces and Dto, but when you need to persistence data, Liferay need that the companyId and companyGroupId be sended from the view layer (in this case JSF).
To maintain independence, I did a "Adapter pattern" creating a ServiceLayer ManagedBean with #noneScope with an interface independent from Liferay. This way I can get the companyId and the companyGroupId needed by the Liferay Apis.
The advantage of using #noneScope is that you can use it as a #ManagedProperty in any bean of any scope.
#NoneScoped would be beneficial in the following scenario.
Assume that we have to inject the same bean in two different scoped beans, we can mark that bean as #NoneScoped. Say a bean BeanOne with #NoneScoped can be easily injected in any bean with any scope like #Request or #Session.
Without using #NoneScoped for BeanOne, we may have to duplicate the bean with different scopes and inject them accordingly.

overriding a session-scoped Managed Bean with a subclass

In a JSF 1.2 application, can I override a session-scoped Managed Bean returned with a subclass?
Class structure
I have a session-scoped Managed Bean, MainViewMB, and its subclass, RestrictedViewMB:
faces-config.xml
<managed-bean>
<managed-bean-name>mainViewMB</managed-bean-name>
<managed-bean-class>com.example.MainViewMB</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
Problem statement
The EL expression #{mainViewMB} returns an instance of MainViewMB.
I would like to rebind the name #{mainViewMB} with an instance of RestrictedViewMB, so that the EL expression #{mainViewMB} returns an instance of the subclass for the rest of the session.
Is there a way to accomplish my goal?
Motivating example
MainViewMB handles the GUI logic behind the application's main page. When a user enters the application from a special-purpose login page, I need to provide a restricted, simplified view of the main page. Overriding some of MainViewMB's properties in a subclass seems the obvious solution.
Do it manually at the moment you can/need to do it.
externalContext.getSessionMap().put("mainViewMB", new RestrictedViewMB());
This puts a new instance of RestrictedViewMB in the session scope with the name mainViewMB, effectively making it a session scoped managed bean.
You only need to take into account that managed properties and #PostConstruct/#PreDestroy are not invoked this way, you'd also have to do it manually.

Open serval pages without replacing Property in ManagedBean

I have a problem but do not know exactly for what I should look. I do not think I'm the first one has this problem!
It is a Java SE application with JSF & Co, basic frameworks.
The application can be submitted comments to threads. I write a comment and then I open another thread (another Browser-Tab) so the comment is posted in the newly opened thread.
I have a ManagedBean with the attribute "selectedThread". The error results from the fact that the property is replaced by the newer one. How can I fix this problem?
I have several of ideas, but all produce the same problem.
Thank you!
#ManagedBean
#SessionScoped
public class ViewBean {
private Thread selectedThread = new Thread(); //Current opened Threas
private String threadId=""; //ThreadId read out from Database by Id convert to Object
private Comment selectedThreadComment = new Comment(); //Comment to be made
Working/Failure steps:
Open:thread_detail.xhtml?id=10
ThreadId and selected Trip setted
Write a comment (selectedThreadComment setted)
Open:thread_detail.xhtml?id=11
Commit Comment
Comment is understandably persisted for id 11 instead of id 10.
It does not matter which Scope i use. There must be a way to save the Comment according to which site is opened.
I hope now my problem is better-defined!
It sounds like as if the scope of the managed bean is too broad for the data it holds. The symptoms indicate that the managed bean is been placed in the session scope, while the data it holds is specific to a single HTTP request or a single view. A session scoped managed bean instance lives as long as the browser session is established. It is been shared across all requests/views within the same session. Any change initiated by one window/tab would get reflected in another window/tab in the same session.
You should then be placing the bean in the request or the view scope instead if it holds solely request or view scoped data. If you have some data which should surely be kept in the session scope, e.g. the logged-in user, then you should split the current session scoped managed bean out into two managed beans, each in the right scope. The session scoped one is then to be used to hold the data representing the logged-in user and the request/view scoped one is then to be used to hold the data representing the submitted form data and/or the view state. You can use #ManagedProperty to inject the session scoped one into the request/view scoped one.
See also:
How to choose the right bean scope?
How do servlets work? Instantiation, sessions, shared variables and multithreading (to better understand "under the hoods" working of JSF request/session/application scope)

Basic question about backing beans for Composite Components

I can't find any guidance on this question. I am writing a composite component that needs its own backing bean because it interacts with a data base.
The new component also needs to be able to set a value in some other backing bean as the result of some user action.
To do this, the question is do I have to write a #FacesComponent java class or a regular #Model/#Named (I use CDI annotations) type of bean? If you can use either, what is the advantage of one or the other?
Secondary question: will I be able to use CDI #Inject into a #FacesComponent to get my DAOs and such?
Update: I discovered that I can access cc.attr objects with the following code in a regular backing bean:
FacesContext fc = FacesContext.getCurrentInstance();
Object obj = fc.getApplication().evaluateExpressionGet(fc,
"#{cc.attrs.model.location}", Location.class);
So this allows me to obtain attributes. I haven't found out how I can write them yet.
So it seems that the only real reason to do a #FacesComponent is if you want to write rendering code that will output something the normal Facelets tags won't render. Is this correct?
I think BalusC responded to this basic question in this thread.
The main advantage is the ability of a #FacesComponent to access attributes that a UIComponent normally has access to, rather than trying to tie in with EL expressions executed in the bean.

Resources