Clear data of a session scoped bean when the view is revisited - java

Bean values are not getting removed when I come back to same screen.
I create user details and insert the data
I view all the listed users available in database
I search for particular user
when I come back to Create user page, I see data of searched user
How do I remove old data from bean? Managed bean is in session scope.

You need a good reason why you'd want to put a list of users into a session scoped bean. It may cause some trouble and in the end reflect outdated data in a multiuser environment. Make the bean #ViewScoped instead, and load all users, or a subset of users, in a #PostConstruct method.
As to the coherence when using a session scoped bean, my guess is that you didn't update a list of current users. Basically you need to double the operation in this case: the first operation is a database operation, and the second one is a list update operation. Like in the following code:
public void deleteUser() {
yourEJB.remove(user);
listOfUsers.remove(user);
}
Also, to have your UI updated, be sure to make a postback, by returning void/null from an action method, or update the needed component via AJAX, by specifying its client id in render attribute of <f:ajax> tag.

I think you're thinking about #Remove annotation, which should be on specific method (or I understand your problem wrong).
Reference: http://docs.oracle.com/javaee/5/api/javax/ejb/Remove.html

A couple things here: first, post a simple example: it allows us to run it to help you. But here's what is (probably) happening. Your bean is session scoped which means it will live for the entire time the user has a session. Unless you specifically destroy the session change the value it is going to "exist" for that seesion.
Using the JSF2 annotations try this:
#ManagedBean(name="seesionScopedBean")
#SessionScoped
public class SessionScopedBean { private String data;//create getter/setter}
#ManagedBean(name="viewScopedBean")
#ViewScoped
public class ViewScopedBean { private String data;}
#ManagedBean(name="requestScopedBean")
#RequestScoped
public class RequestScopedBean { private String data;}
Assuming your three scopes make a page that is basically
<f:view>
<h:form>
<h:inputText value="#{sessionScopedBean.data}" />
<h:inputText value="#{viewScopedBean.data}" />
<h:inputText value="#{requestScopedBean.data}" />
<!-- whatever listener/action to set things -->
</h::form>
</f:view>
You'll notice that the "SessionScoped" data stays until you log out, the view will stay as long as you interact with this view (not totally correct, but that's the gist of it. And the request scope lives in each request.
Basically your create user bean feels like it should have a Request or View scope (as stated in a previous answer). Hopefully this helps. It takes a bit of time to wrap your head around the life-cycle but JSF is rewarding to work with once you get the hang of it.

Related

#Async Spring gets recalled for every request of different sessions

I have a spring #Async annotated method in a bean, then in the controller I call that bean's method on a user request, and I do it this way so I can get a progress back from that bean, and it works fine for that.
But when I open it from another session the controller appears to restart the method and the progress is back again to the start point.
How to do this correctly, I have a progress count number as a field in the bean. and I increment it in the #Async method then get back via AJAX request to in a controller that retrieves it from the bean.
but its like the controller have only one bean injected to it. or there is only one controller for the whole app, whats is wrong here ?
EDIT
I tested in with opening two different browsers and running the task but it gets reloaded in both.
Apparently Spring Controllers are singletons per web app (and when you think about it they should be), so they are not thread safe if you have a component wired to it.
Meaning that suppose you have bean A wired to controller AC if two users send requests to an AC method that uses bean A at the same time, you'll have wrong values for both or you'll have bean reconstructing at each call, so if user1 starts the task and after a while before the task is finished user2 comes into play and wants to start it too, then user1' values will reset and so on.
To avoid this I found that you should make beans that are wired to controllers annotated with Session Scoped using annotations or xml.
in my case I used
#Scope("session")
You should never annotate the controller, as it won't work and if it does it will give weird behavior.
you should also (if using annotations like me) add scoped-proxy="targetClass" in your <context:component-scan /> element

Spring 3 MVC: form backing object has to be in session? How can I avoid this?

I read a few tutorials about forms and submission in Spring 3 MVC. All these examples indicate that storing the backing object in the session the following way:
#SessionAttributes({"command"})
I used old versions of Spring in which there is a formBacking method if a controller inherits SimpleFormController.
protected Object formBackingObject(HttpServletRequest request)
If my understanding is right, the old version approach loads the form backing object on the fly when the form submits and there is no need of storing this object in session.
If my understanding about Spring 3 MVC is right, then I don't like the session approach because it consumes lot of memory in case of large users and the object stored in session might be outdated at the time of form submission.
Can I avoid storing the form backing object in session in Spring 3's MVC? Any pointer?
Thanks for any input and please correct me if I am wrong.
Regards.
Anyone else knows whether my understanding is right?
the GET controller adding the object to the model equates to adding it to session. How can Spring remember the object as the backing object when a form is submitted? Cheers.
How can the form backing object added to the model in the GET controller survive a round trip between the server and client when a form is submitted? Does Spring serialize it on disk? I am guessing...
Thanks for any input!
If you simply do not list your command among the #SessionAttributes, it will be instantiated every time.
In the old Controller API, implementations could decide whether or not they want to keep their command objects on the session: see AbstractFormController.isSessionForm(). SimpleFormController returned false, while AbstractWizardFormController returned true, as it actually required the command to be stored on the session.
You can check how a model attribute is bound in the HandlerMethodInvoker.resolveModelAttribute(...) private method:
if (implicitModel.containsKey(name)) {
// ...
} else if (this.methodResolver.isSessionAttribute(name, paramType)) {
// ...
else {
bindObject = BeanUtils.instantiateClass(paramType);
}
So obviously, the binder will use a fresh instance if you don't explicitely declare it as session attribute; exactly the same as returning false from AbstractFormController.isSessionForm().
How can the form backing object added to the model in the GET controller survive a round trip between the server and client when a form is submitted? Does Spring serialize it on disk? I am guessing...
Spring does not (always) need to store the backing object between form view and form submission. If everything that you need in order to populate your command object comes with the request, Spring can simply instantiate a new command object (either itself or let you do it if you provide a proper method) and then bind the request to that fresh instance.
See above the comparison with the old API regarding the difference between SimpleFormController and AbstractWizardFormController implementations. The first does not need to store anything on the session and it will bind the submit request to a newly created object. With the new annotated handlers, the flow is the same; if you don't want to store it, it will be recreated on submit: BeanUtils.instantiateClass(...) or your own custom factory method.
You need to add the backing object to the model, not to the Session. Here's one tutorial... http://www.roseindia.net/tutorial/spring/spring3/web/spring-3-mvc-form-example.html

#PostConstruct called multiple time for #ConversationScoped bean

I have a #ConversationScoped bean, with a start method, like so:
#PostConstruct
public void start() {
if (conversation.isTransient()) {
conversation.begin();
log.debug("conversation.getId(): " + conversation.getId());
}
}
My problem is that every time the page is refreshed a new conversation is started, a new conversation is also started every time I have an AJAX call to a method in the bean (which is my main problem).
What I really want to happen is for the sam conversation to hang around until I manually call conversation.end(). What am I missing here?
Slightly off-topic, but hopefully valuable:
I'm not 100% sure that #PostConstruct is the right place to start a conversation. I'd rather use a faces-event like this:
<f:metadata>
<f:event type="javax.faces.event.PreRenderViewEvent"
listener="#{myBean.init}" />
</f:metadata>
and start the conversation if you are sure that you are not in a JSF-postback request.
public void init() {
if (!FacesContext.getCurrentInstance().isPostback() && conversation.isTransient()) {
conversation.begin();
}
}
If you use Seam 3, it's even easier:
<f:metadata>
<s:viewAction action="#{myBean.init}" if="#{conversation.transient}" />
</f:metadata>
Did you checked that the (AJAX) calls include the conversation ID parameter (cid)?
If that's missing, a new conversation is expected to start for each call.
The concept of the JSR-299 builtin Conversation is a bit broken. At least for JSF apps. Using the #PreRenderViewEvent would basically drop all the benefits of this approach as it would make every #ConversationScoped bean longRunning.
You might try to use Apache MyFaces CODI #ConversationScoped instead. CODI is a CDI Extension library which is known to work well with Apache OpenWebBeans and also with Weld.
It additionally also provides #ViewScoped, #ViewAccessScoped (kind of an auto-conversation) and #WindowScoped contexts.
More at: https://cwiki.apache.org/confluence/display/EXTCDI/Index
It's all in the docs:
The conversation scope is active:
during all standard lifecycle phases of any JSF faces or non-faces request.
The conversation context provides access to state associated with a particular conversation. Every JSF request has an associated conversation. This association is managed automatically by the container according to the following rules:
Any JSF request has exactly one associated conversation.
The conversation associated with a JSF request is determined at the beginning of the restore view phase and does not change during the request.
Any conversation is in one of two states: transient or long-running.
By default, a conversation is transient
A transient conversation may be marked long-running by calling Conversation.begin()
A long-running conversation may be marked transient by calling Conversation.end()
All long-running conversations have a string-valued unique identifier, which may be set by the application when the conversation is marked long-running, or generated by the container.
If the conversation associated with the current JSF request is in the transient state at the end of a JSF request, it is destroyed, and the conversation context is also destroyed.
If the conversation associated with the current JSF request is in the long-running state at the end of a JSF request, it is not destroyed. Instead, it may be propagated to other requests according to the following rules:
The long-running conversation context associated with a request that renders a JSF view is automatically propagated to any faces request (JSF form submission) that originates from that rendered page.
The long-running conversation context associated with a request that results in a JSF redirect (a redirect resulting from a navigation rule or JSF NavigationHandler) is automatically propagated to the resulting non-faces request, and to any other subsequent request to the same URL. This is accomplished via use of a GET request parameter named cid containing the unique identifier of the conversation.
The long-running conversation associated with a request may be propagated to any non-faces request via use of a GET request parameter named cid containing the unique identifier of the conversation. In this case, the application must manage this request parameter.
When no conversation is propagated to a JSF request, the request is associated with a new transient conversation. All long-running conversations are scoped to a particular HTTP servlet session and may not cross session boundaries. In the following cases, a propagated long-running conversation cannot be restored and reassociated with the request:
When the HTTP servlet session is invalidated, all long-running conversation contexts created during the current session are destroyed, after the servlet service() method completes.
The container is permitted to arbitrarily destroy any long-running conversation that is associated with no current JSF request, in order to conserve resources.
Author:
Gavin King, Pete Muir
IMHO CDI conversations are broken by design and struberg pointed out a promising alternative. In my App I've the same problem and currently I'm refactoring it to CDI + CODI 1 and it just feels right. #ConversationScoped solves all those problems. While refactoring my App I could solve a lot of nasty cases with #ViewAccessScoped. Thank you struberg for pointing us to it!
Oddly enough, if you add an event listener to your Facelet, even if it calls an empty method, the form action of the generated source will have the 'cid' parameter and therefore, the AJAX call will not create a new conversation. Without the event listener, the 'cid' is missing the in the form action.
<f:metadata>
<f:event listener="#{myBean.dummy}" type="preRenderView" />
</f:metadata>
MyBean.java
public void dummy() {}

Using SpEL and eval to call a controller method

I was wondering if it was possible to call a controller method using the tag from a JSP page, a bit like the way it's done in JSF.
My Controller
#Controller(value="planesController")
#RequestMapping({"/planes"})
public class PlanesController {
#Autowired
private PlanesDAO planesDAO;
public List<Plane> allPlanes(){
return planesDAO.getAll();
}
My JSP
<sf:form>
<s:eval expression="planesController.allPlanes()" var="planes" />
<sf:checkboxes items="${planes}" path="planes" id="avions"/>
</sf:form>
I keep getting the exception :
org.springframework.expression.spel.SpelEvaluationException: EL1007E:(pos 0): Field or property 'planesController' cannot be found on null
I know I can use model.addAttribute but I call this method from several JSP pages and I thought one of the of the tag was to allow access to beans from views.
I'm using Spring 3.0.5
Thanks in Advance
Letting the view call controller code is just plain wrong, no matter if it works or not. This is MVC backwards.
It would be better if you write a service to do what you want to do and give your view access to that service, but you'd still violate MVC. It would be even better to do all of these calls in your controller in the first place and pass the resulting model to the view without any service calls there.

How to access the session from a Java class

I need to write a small Java class that will enable me to add to and read from the current user session.
Everything I see refers to Servlets but I'd ideally like to just use a plain old class.
Can anyone please help this Java Newbie?
Thanks
The general concept of a "Session" is really just a data storage for an interaction between a HTTP client and server. Session management is automatically handled by all HTTP Servlets. What framework?
If you're just wanting to store information for a console app to remember information between runs, then consider using Xml to save/load data from a file.
Use a component based MVC framework which abstracts all the ugly Servlet API details away so that you ends up with zero javax.servlet imports. Examples of such are JSF2 and Struts2.
In JSF2 for example, you'd just declare User class as a session scoped managed bean:
#ManagedBean
#SessionScoped
public class User {
// ...
}
Then in the "action" bean which you're using to processing the form submit, reference it as managed property:
#ManagedBean
#RequestScoped
public class SomeFormBean {
#ManagedProperty(value="#{user}")
private User user;
public void submit() {
SomeData someData = user.getSomeData();
// ...
}
}
That's it.
If you'd like to stick to raw Servlet API, then you've to live with the fact that you have to pass the raw HttpServletRequest/HttpServletResponse objects around. Best what you can do is to homegrow some abstraction around it (but then you end up like what JSF2/Struts2 are already doing, so why would you homegrow -unless for hobby/self-learning purposes :) ).
Yes, just pass the HttpRequest to your class from your servlet.
In your servlet do something like this,
cmd.execute(request);
In your class do something like this,
public class Command implements ICommand {
.
.
public void execute(HttpServletRequest request){
HttpSession sess = request.getSession(false);
}
.
.
.
}
In general, as mentioned in the other answers, session in many ways acts as a store. So to interact wth a session from another class which is outside of the Servlet/JSP framework the reference to the session in question needs to be procured. There are few ways it can be achieved:
1) Passing the session as part of a method parameter (already mentioned in other answers)
2) Binding the session to a thread local variable on to the current thread executing (refer ThreadLocal). This method has the advantage of not declaring specific parameters on the method signature of the class that needs to use the session. In addition, if the calling thread goes through a library and then again calls some specific class e.g. Servlet->YourClass0 -> Apache Some Library -> YourClass1, the session will also be available to YourClass1.
However, the thread local also needs to be cleared when the executing thread returns through the initial component (servlet let's say) otherwise there certainly could be memory leaks.
In addition, please refer to your specific framework for treatement of sessions, the above mechanism works fine in Tomcat.

Categories