I have a session scoped managed bean, with a property current. If I have a method
public void resetCurrent() {
current = new Configuration();
}
in the bean, it gets called automatically every time I navigate to a new page in the application. Is this normal behavior? I am not calling the method anywhere in the code.
Considering that this approach to reset the session bean properties is, to say the least, less than ideal, which would be the right way to accomplish it?
Thank you.
JSF doesn't do that. It's your code which does that. Your view or another bean or maybe the bean itself is calling it. Putting a debug breakpoint on that line or adding Thread.dumpStack() should give you insights in who's calling it by reading the call stack. Or just rename the method to something else and check if you don't see compilation errors during build or get EL exceptions during runtime which should pinpoint the callers.
Considering that this approach to reset the session bean properties is, to say the least, less than ideal, which would be the right way to accomplish it?
Depends on the functional requirements. For example, if the bean is supposed to hold view scoped data, then put it in the view scope instead. Or if it is supposed to hold session scoped data (e.g. logged-in user) and you're basically logging out, then rather invalidate the session.
Related
I have a internet shop application. I wanted to improve "removing from the cart" feature. I don't want to ask an user if he wants to "really remove" the position from the cart, instead I'd like to allow him cancel the operation.
Currently when user clicks "X" button at the product in the cart, row of table changes to "removed, click to cancel". In the back there is a list of CartPosition objects every with flag removed. Removed product is still on list, but the flag is set to true. It makes product still visible in proper position on the list, but on the view side I can render it another way. When user clicks another "X", previous one is premamently removed from the list and new one is marked as removed.
Shopping cart is session scoped CDI bean. It means, when I mark some position removed and go somewhere else, then go back to the cart, I'll still have one row marked as removed. I just don't want this.
I thought about changing the bean to JSF one, then create another view scoped which could keep record marked as removed and check if it's empty, if so I could remove the one from list. I have no idea if it's going to work. I'll try this approach, but I'd rather keep my beans managed by CDI.
Is there a way to handle this without implementing my above idea?
EDIT: #BalusC, your assumptions are wrong. You should rather suppose, that I don't exactly know how can I mix CDI and JSF. I actually use JSF 2.2, what means that javax.faces.view.ViewScoped annotation is available for me. Anyway I still don't understand the idea. I understood, that I have to rely on some ViewScoped bean. It's clear, but how it has to be composed. Can you explain your idea? I tried few things, but it looked it didn't work correctly. For example my #PreDestroy method of ViewScoped bean was never called and it's constructed lazily only when I try to use it.
Do the actual remove job in #PreDestroy annotated method of the session or view scoped bean.
#PreDestroy
public void destroy() {
// Do the actual remove job here.
}
Given that your question implies that you don't have CDI based javax.faces.view.ViewScoped available, which is new since JSF 2.2, this in turn suggests that you're still on JSF 2.0/2.1 and thus only have JSF based javax.faces.bean.ViewScoped at hands, then it should be noted that its #PreDestroy is broken in several circumstances. You'd then best do the #PreDestroy in the CDI based #SessionScoped bean. Alternatively, you could use OmniFaces #ViewScoped which has fixed and improved the #PreDestroy of a #ViewScoped bean in several ways. It even gets invoked on window unload.
As far as I understood your problem is the session. One way to solve the problem is to set the list of removed products in a request attribute and remove it from the session bean so that on the next request they will disappear.
Hope that helps
I wanted to test to see if a session scope bean was in fact valid in a beforePageLoad event using SSJS. If I clear the session scopes using the Debug toolbar I get an error when trying to test the bean to see if it is null.
if (registrationBean == null){
The error is:
Error while executing JavaScript action expression
Script interpreter error, line=2, col=22: [ReferenceError] 'registrationBean' not found
Question is how to test the bean to see if it is instantiated??? If not, then I want to go to another XPage (redirect) to allow the user to enter the values that are used to populate the bean.
Or, is this only an issue because I used the Debug Toolbar to clear ALL session and application scopes?
Howard
Use a try/catch block. If you get the error, it's null.
I suspect it's only a problem because the applicationScope has been cleared. Usually the first attempt to reference the variable instantiates the object. However, clearing the whole of applicationScope can break a lot of XPages code in your application and should be avoided.
First, make sure that the bean is set up in faces_config.xml (but it seems this is the case). Then you should not be able to reference the bean before it is instantiated...
An easy way to see when the bean is instantiated is to put a System.out.println("....") in the constructor of the bean. That should bring you on the track. You could (should!) use the OpenNTF LogReader to see what is going on - this will show you any errors thrown by the page and bean.
And then of course clearing all the data via the debug toolbar may put the system in an "unknown" state - and you should probably try to reload the page subsequently to ensure it is well-defined/-instantiated.
/John
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)
I have the following button:
<h:commandButton
disabled="#{mybean.searching}"
binding="#{mybean.searchButton}"
actionListener="#{mybean.searchForLicenses}"
value="Search" />
When I debug I see that the actionListener is called twice first, then three times, next click four times and so on.
It seems like on every reload the actionListener is registered one more time.
I'm using Mojarra 2.1.3 (also tried 2.0.6) and Tomcat 7 with IceFaces.
The binding is done that way:
private javax.faces.component.UICommand searchButton;
public void setSearchButton(UICommand searchButton) {
this.searchButton = searchButton;
}
public UICommand getSearchButton() {
return searchButton;
}
That can happen if you've bound the component to a session or application scoped bean instead of a request scoped bean. This is simply a bad design. The very same component would be reused among multiple requests/views. You need to put the bean in the request scope, or to get rid of the component binding altogether.
Note that binding the component directly to a bean is often a sign of poor design somewhere in the code. What is it, the functional requirement and/or problem for which you thought that this is the solution? If you elaborate on that, we may be able to propose the right approach.
Also note that using an action listener alone is also a design smell. I'd expect "searchForLicenses" to be a normal action method. See also Differences between action and actionListener.
The similar issue takes place when component is using binding and validator or valueChangListener and backing bean is of View, Session or Application scope. Then corresponding listeners are called many times but not once during request (+1 time with every new request).
One possible solution is to override jsf class AttachedObjectListHolder which is used for storing component listeners. Current implementation simply add new listener to component even though the same listener is already there. So the proposed fix is to check that listener does not exist before adding it.
Details of the fix you can see here
We are using JSF in our project (im pretty new to it) were every page have a back bean Java file.
In order to move (redirect) from one page to another, i need to put all the parameters (search criteria) in the request scope before redirecting and then retrieve it back in the next page constructor. When you have few pages deep and you want to come back to the top, it becomes really annoying to maintain.
For example, if i have page 1 with advanced search filters, which redirects to page 2, depending on the chosen item, and from page 2, you get another list were you can go to page 3 for details. Now each time i need to put all the params in the request scope/read them again, store them in hidden fields and get them back.
Whats exactly wrong with this method and whats a better way to do it in JSF?
EDIT: the environment is IBM Rational Application Developer (RAD), which have its own JSF implementation. Not sure if that makes a difference.
Putting request scoped data in session scope will bite you (very) hard if you're going to open the same page in multiple windows/tabs. Only use the session scope if the data itself is also really session scoped (excellent examples are the "logged-in user" and the "shopping cart", you want it to be exactly the same throughout the entire session). Again, don't put request scoped data in the session scope. It hurts both you and the enduser.
Just design your beans smart (it makes no sense to have different beans containing the same data) and make use of h:inputHidden where needed, if necessary in combination with managed property injection. It's indeed a bit a pain to code and maintain. You can on the other hand also just grab Tomahawk <t:saveState> if the to-be-passed data is actually as big as a "whole" managed bean. It costs only a single line in the JSF page and has always been of great assistance.
*For example, if i have page 1 with advanced search filters, which redirects to page 2, depending on the chosen item, and from page 2, you get another list were you can go to page 3 for details. Now each time i need to put all the params in the request scope/read them again, store them in hidden fields and get them back.
Whats exactly wrong with this method and whats a better way to do it in JSF?*
There's nothing wrong with this method. Maybe you coded it the wrong way which caused that it looks unnecessarily overcomplicated. I can't tell much as long as you don't post details about the code used.
As per your edit:
EDIT: the environment is IBM Rational Application Developer (RAD), which have its own JSF implementation. Not sure if that makes a difference.
This is not true. IBM doesn't have any JSF implementation. It has just a component library (the poorly maintained hx prefixed components, also known as "Faces Client Framework"). WSAD/RAD ships with Sun JSF RI (Mojarra) as standard JSF implementation, although it's usually a heavily outdated version. Ensure that you keep it updated.
I'm only starting out with JSF too to be honest, but I thought you can save managed beans in the session scope, thus being able to access the bean on each request? You can also save the state client-side avoiding nastiness about session stickyness and stuff.
So you could save the data you are currently passing as request parameters in a session-scoped managed bean, and it will be available to any requests in that user's session, destroyed when the session times out or is deliberately invalidated (say on user logout).
I don't think JSF currently supports conversation state which I think might be the exact solution to your problem, maybe a session scoped managed bean would be the pragmatic solution?
Make your managed-bean session scoped.
If you are using MyFaces you can use PageFlowScope. If using Seam then use Conversation scope.
If pageflowscope or conversation scope is not available, then use session scoped beans. In addition you can use PhaseListener to initialize or execute specific methods before the page gets called. In you case if the flow is page1 -> page2 -> page3, then initialize the session scoped bean in PhaseListener if page1 gets called.
I'll update with more info if you need.