Components not reloading on url change in Wicket 1.5(.2)? - java

I navigate to my application the first time with following URL:
.../homepage/?0&user=x
In debug mode I see wicket is nicely instantiating my panels and such (obviously).
if I change the URL to:
.../homepage/?0&user=y
then nothing happens, the panels are not re-initialized (for the new user => data of user x is still shown) nor are LoadableDetachable -or other models invoked.
However, if I change the URL to:
.../homepage/?1&user=y
then all panels are nicely initialized for user y
One step further, if you change the URL back to
.../homepage/?0&user=y
then again the data for user x is displayed.
It seems that Wicket does not care that arguments have changed in the URL to decide whether or not to reload components. AFAIK this was working fine in Wicket 1.4. I think I understand the logic behind this behavior but am not sure. Also, I would like to know how to force Wicket to reload if custom parameters change and how to remove that 'ugly' ?0 from the URL (if possible)?

This is the stateful nature of Wicket. The page is instantiated once, the parameters are parsed and so on. Later you pass different parameters to the already instantiated page but this time its constructor is not called at all and thus PageParameters are not updated. Changing to ?1 asks Wicket for page with id 1 and since there is no such Wicket instantiates a new instance and passes the new parameters. If you want to always have the latest request parameters then use getRequest().getRequestParameter("user") which will give you what you need.
Makes sense ?

To amend martin-g's answer: you should retrieve the request parameter in your model, and retrieve the correct user with the request parameter. Something like:
setModel(new LoadableDetachableModel<User>(){
public User load() {
String username = getRequest().getRequestParameter("user");
return userservice.byUsername(username);
}
}));
When you need dynamic data, almost always use models to solve your problem.

I think you can use onRender or onConfigure

Related

BeforeLeaveObserver is not invoked after page reload in Vaadin

I have a problem:
BeforeLeaveObserver is not invoked after ui.getPage().reload();
I need to reload view after the user change the application language, so this action is invoked after the user change and save. Then the view is translated to another language dynamically.
After that another functionality which is using BeforeLeaveObserver is not invoked.
Any ideas how to make observer work again? Or maybe there is another way which will work?
I was trying with LocaleChangeObserver a had a trouble to refresh layout and translate it - it's too complicated.
You can only rely on BeforeLeaveObserver for situations when the user navigates from one view to another in the same UI. Reloading the page causes a new UI to be created which means that BeforeLeaveObserver isn't triggered. The old UI instance is still there with the old view active.
The framework could in theory detect the situation specifically for a reload that is triggered from code but it's not trivially detectable when the user reloads through the web browser. It would be just as confusing if different types of reloading would lead to different outcomes.
For you case, you might want to instead redirect the user to a URL that contains a parameter that you can use to identify the custom configuration that the new UI is supposed to adopt.

How do I guarantee a single session?

I need to prevent the situation where either
1. Two different JSESSIONID's exist for the same user account or,
2. Two tabs of a single browser reference the same JSESSIONID.
Any suggestions? If an existing session is detected, the user can either:
a) Quit the second attempt
b) Kill the existing session (an assassin!) and start a new session.
The preference is for a sever-side solution. That is, I don't want to depend on user's turning cookies off which forces the JSESSIONID into the URL.
Embeding a hidden input field with a unique token in each page sounds like the only solution for a problem like this. This seems to be like the only way to tell one tab from another, even if they're the exact same URL.
Keep in mind though, that what you're doing seems like pretty bad practice; any particular reason to prevent the user from using more than one tab?
Part 1 could be done using a singleton pattern that checks current sessionid for the user against a map of user-SID.
Part 2, which could be understood in transactional webapps where you need to ensure that the user reads the correct info (instead of having a one tab with old values and one tab with newer values- scenario)... it could use the same sessionid map, injecting it in the dom and validate it using javascript.
EDIT. Part 2 validation could be done better in a filter against the map of client-sessionid. And a correct definition of the object guarantees that a true unique singleton instance exists.

Managed-Beans and Scopes - how to handle it?

I want to do something like this: index.xhtml -> createPerson.xhtml -> addAddress.xhtml -> index.xhtml.
In Managed-Bean CreatePerson a new Person-Object will be created, filled and saved, in Managed-Bean AddAddress I need the Person-Object in order to add an address to this person and after this, it should navigate back to the starting point. I think, the Managed-Bean CreatePerson should be #SessionScoped, because I have to inject the Person-Object into AddAdress (here #ViewScoped).
I want to have a loop or rather the possibility to create more than one person, but how can I do this if I have a SessionScoped-Bean, that lives longer than I need it? Is there any command or annotation to destroy it? How do you handle such workflows related to the scopes?
I know about MyFaces Orchestra with conversation-scope, but I will, if possible, do it only with Eclipse/Tomcat (7.0.11)/Mojarra (2.0.3).
Use a single view and make use of the rendered attribute to show/hide included views with "subforms" depending on each other. This way you can go with a #ViewScoped bean.
Alternatively, just save the Person in the DB after create and pass its id as request parameter to the next view and let it load from the DB again.
If you only want (or can) use Tomcat and Mojarra then both solutions mentioned by BalusC work perfectly, although with the limitations that you have to stay on a single page or redo queries between page navigation. Your use case is exactly what the conversation scope in Java EE 6 (through CDI) is made for. You can add this too to Tomcat via the Weld reference implementation.
When using the method BalusC outlined for staying on a single page, to give the user a tiny bit the impression of dealing with separate pages, it might be an option to display the rendered parts of the page using 'dialogs' (floating, css, ...). If using a third party component library is an option for you, you could add RichFaces or PrimeFaces that both contain ready to use dialog components.

JSF/Seam - new component instance on submit?

And my confusion with JSF continues. This is a continuation of a question asked yesterday, but I feel it warrants a new question. I have a single seam component that expects a URL parameter to be injected for retrieving a List<String> from a method. This works perfectly on the first navigation to the page. The List is used to display many different selectOneRadio groups that populate a <h:form/>.
Now on the submit, I cannot get the URL parameter to be injected or otherwise set on the component! Adding <h:inputHidden/> causes FacesExceptions to be thrown.
Then I tried setting the List as an instance variable on the object, and when the subsequent call is made on the submit (which I also do not understand why that is done) I check to see if the variable is non-null: if it isn't, return it.
Now I found that a new instance of the component is created on submit!!!
getList() called
this.toString(): .BeanAction#5fd98420
#### This is when submit is clicked
getList() called
this.toString(): .BeanAction#22aacbce
The component has the following annotations:
Stateful
#Scope(ScopeType.CONVERSATION)
#Name("bean")
#Restrict("#{identity.loggedIn}")
Can someone explain why there is a new instance of the component created?
I'm really not quite sure how to go about handling this. I thought the hidden parameter would work, because that is how I would do it with straight HTML, and I'm a little surprised that its not working for JSF/Seam.
I hit upon the solution, but I still dont understand why it is required. By adding <S:conversationId/> to the <h:commandButton/> tag I am now getting the conversationId propagated across the form submit.
However, the seam documentation states:
If you don't do anything special, a non-faces request (a GET request for example)
will not propagate the conversation context and will be processed in a new
temporary conversation.
Which means Seam/JSF was treating my form submit as a "non-faces request". Why is that?
When you enter the page (or after the submit), do you see a conversation id in the url? I am concerned that perhaps the Seam Conversation is not being initialized correctly.

Model generation for manually entered page in Spring framework

I have to extend some Spring web application, but I'm not very familiar with the framework (however, I have some experience with few other frameworks). I can see that there is "ModelAndView" concept used by the framework. Controller returns both: a model and a view from onSubmit() method. But what to do if a model have to be generated for a page entered manually (user enters the page address to the browser address bar, instead of submitting a form). In such a case there is no onSubmit() call, so a model isn't prepared.
I thought of (ab)using formBackingObject() method of BaseFormController class, which prepares "command" object. But I don't know how to refer the object in the jsp code. Any hints would be appreciated.
You can configure the supported HTTP methods of the controller with the supportedMethods property. The default values are HEAD, GET and POST. If the same parameters are sent with a GET request (there are some restrictions on what can be transmitted) there should be no difference from the controller perspective.
It has to be noted that the HTTP methods have a semantic that should not be broken: get to retrieve (without changes), post to manipulate etc.
The proper method to override to provide model data for the "initial" view is referenceData(). As you can see in the Javadoc, there are two overloads of this method, depending on what you need to do.
Create a reference data map for the given request and command, consisting of bean name/bean instance pairs as expected by ModelAndView.
The default implementation delegates to referenceData(HttpServletRequest). Subclasses can override this to set reference data used in the view.

Categories

Resources