-
1. Re: Passing Instance To Home Class
damianharvey.damianharvey.gmail.com Mar 5, 2008 3:22 PM (in response to leesy)You can drop the @DataModelSelection (which is confusing IMO) and as you're using @DataModel you can pass your
i
as a parameter
<s:link action="#{browseItems.remove(i)}">Note sure if you can pass it to the ItemHome like that though as the ItemHome doesn't know about the @DataModel. You can always have a method in your BrowseItems that calls a delete method in ItemHome. Try both. It would be interesting to see if you can get the first way working.
Cheers,
Damian.
-
2. Re: Passing Instance To Home Class
keithnaas Mar 5, 2008 3:27 PM (in response to leesy)Lee,
There are a variety of ways to accomplish this. If you are using @DataModel, a @DataModelSelection can be applied to a field that identifies the row the user was on when they click the remove link.
@DataModel List<T> results; // T is the type of object in the list @DataModelSelection T selectedResult
Another way, is to use f:param's as children of the link.
And last, but not least, Seam has extensions to EL which allow for parameters to be passed to method expressions.
So if the remove method looks like
public String remove(T selectedResult) // can be a void method too! { // remove it return "success"; }
Then the xhtml can be coded like this:
<rich:dataTable id="itemTable" var="i" value="#{browseItems.results}" rendered="#{browseItems.rowCount >0}"> ... <h:column> <s:link action="#{itemHome.remove(i)}">Delete</s:link> </h:column> </rich:dataTable>
The last one is the approach that we normally take.
Good Luck!
-
3. Re: Passing Instance To Home Class
christian.bauer Mar 5, 2008 3:38 PM (in response to leesy)<s:link action="#{itemHome.remove(i)}">Delete</s:link>
Remember that this is the most evil way possible how you can abuse s:link action. Yes, some examples might even do this, we need to document it better.
This is a GET request that is neither safe nor idempotent. Would you like it if the Googlebot
clicks
on it?The correct way is to use DELETE requests, but since browsers don't support that, we all should use overloaded POST. In other words, h:commandButton/Link with a no-argument remove() action, in a POST form that wraps the datatable, with @DataModel/@DataModelSelection on the backend.
Finally, what you have shown is not really
parameters passed to method expressions
, that would be:<s:link action="#{itemHome.remove(i.id)}">Delete</s:link>
Because i.getId().toString() is evaluated at render-time. What you have shown is called
s:link can do special magic tricks with the datamodel selection if you put it inside an h:datatable, just look at the generated URL with lots of magic parameters
. There is an open JIRA issues that discusses removing this particular mis-feature. -
4. Re: Passing Instance To Home Class
damianharvey.damianharvey.gmail.com Mar 5, 2008 3:58 PM (in response to leesy)It's useful for hiding the ids of your entities though.
-
5. Re: Passing Instance To Home Class
leesy Mar 5, 2008 4:00 PM (in response to leesy)Well thanks for the responses all. I didn't realise I could pass variables to my methods now. As that's evil, I'll leave that as the backup plan :)
Although I've got the @DataModel and @DataModelSelection set, those are set in the ItemBrowserclass and not in the ItemHome class (where I am trying to call remove) I don't think that's going to work.
So I'll take a stab at the child parameter. I gave that a quick once over earlier but never tried it. If that fails, guess I'll be taking the evil route till I figure it out.
-
6. Re: Passing Instance To Home Class
keithnaas Mar 5, 2008 4:42 PM (in response to leesy)Christian,
We used h:commandLinks which are POSTS so the GET issue wasn't really an issue.
As far as the magic tricks part - this was on Seam1.2.1.GA so it may no longer apply - the whole reason we did it was because when we used DataModels we had numerous other issues that resulted:
- DataModelSelection not always being set correctly (oftentimes it would reset to the first item in the list).
- Trying to reuse the same code and templated xhtml in many places resulted in naming conflicts on the DataModel when it was evaluated by Seam. Seam does it for a valid reason, but it can be difficult to workaround.
- and a few others issues that currently escape me.
So...since we had a deadline, we took the lazy approach, gave up, and did the workaround :)
Thanks, Christian!
-
7. Re: Passing Instance To Home Class
sleroux Mar 7, 2008 6:44 PM (in response to leesy)
Christian Bauer wrote on Mar 05, 2008 03:38 PM:<s:link action="#{itemHome.remove(i)}">Delete</s:link>
[...]
This is a GET request that is neither safe nor idempotent. Would you like it if the Googlebotclicks
on it?
[...]<s:link action="#{itemHome.remove(i.id)}">Delete</s:link>
Because i.getId().toString() is evaluated at render-time. What you have shown is calleds:link can do special magic tricks with the datamodel selection if you put it inside an h:datatable, just look at the generated URL with lots of magic parameters
. There is an open JIRA issues that discusses removing this particular mis-feature.Sorry to come back on this, but could you please explain what's is wrong with the code
<s:link action="#{itemHome.remove(i)}">Delete</s:link>
- is it the fact that's inside a non-idempotent action in a s:link
- or that's generally a bad thing to use the
datatable loop variable
(don't know the real name of this) as parameter in an EL expression?
This is definitively an intuitive way of doing things - and it's very useful! So if it's inherently wrong, what's the best way of passing a table entry as parameter? By systematically using the Id of the object (in the case of an entity bean) as you suggest?
Thanks in advance for making things clearer,
Sylvain. -
8. Re: Passing Instance To Home Class
keithnaas Mar 7, 2008 7:03 PM (in response to leesy)Use a commandLink and then instead of passing in i, pass in the primary key or ID of i.
After looking at our code again, we passed in the key, not the actual JPA object.
-
9. Re: Passing Instance To Home Class
christian.bauer Mar 7, 2008 7:21 PM (in response to leesy)
Sylvain Leroux wrote on Mar 07, 2008 06:44 PM:- is it the fact that's inside a non-idempotent action in a s:link
- or that's generally a bad thing to use the
datatable loop variable
(don't know the real name of this) as parameter in an EL expression?
Both. It should be clear why GET is supposed to be safe and idempotent. As for the loop variable, think about it like this:
The loop variable is a temporary variable, it's only available during RENDER RESPONSE when your datatable is rendered. If you trigger another request, be it GET or POST, it's not going to be there. So there are several tricks how you can transport the
row
you clicked on into this subsequent request.One is with @DataModelSelection and a POST request. The selection index will be part of the POST request body as a parameter (you can see that if you look at the rendered table HTML and the h:commandLink that triggers the POST with Javascript). On the server during request processing, Seam/JSF pull the item at this index out of the datamodel. (Which needs to be in a scope that lasts longer than a single request! PAGE or CONVERSATION are common choices.) It then injects it into your @DataModelSelection property. That's the clean solution because it uses overloaded POST for actions that might not be idempotent nor safe (which is what clients expect from POST).
The second option is s:link with an action that looks like it is passing the loop variable
into
the next GET request. Now, that is of course not what is happening. It's the same trick as before, just with a GET. Seam attaches a magic request parameter onto your s:link URL that sayspull that index out of the datamodel and pass it into the action method as an argument
. It's just a convenient shortcut. But it's conceptually wrong to use GET for that, so that is why we are discussing removing it.In my experience, people have trouble with this because they are not fully aware of the JSF lifecycle and don't realize the scope of variables, especially variables that are only available during response rendering. There is no way how you can pass
objects
between requeston the client
. You can pass identifiers or keys (or whatever you like to call them) between requests as parameters and you need to make sure that the subsequent request can pull the stuff out of some data store that is in the right scope (data model, list, whatever) when that key needs to be resolved. -
10. Re: Passing Instance To Home Class
sleroux Mar 7, 2008 11:50 PM (in response to leesy)
In my experience, people have trouble with this because they are not fully aware of the JSF lifecycleI must admit this is my case...
Of course, it was surprising to be able to pass loop variables as an argument to EL expression. But since things were working like that... I thought that was some JSF/Seam white magic. So half by laziness, half by lack of time, I didn't look into the details! I think many people are just like me...
Now, I know that's not the good way of doing things!
So, thank you for your answers,
Sylvain. -
11. Re: Passing Instance To Home Class
luke.maurer Mar 8, 2008 3:00 AM (in response to leesy)
There is no way how you can passobjects
between requeston the client
. You can pass identifiers or keys (or whatever you like to call them) between requests as parameters and you need to make sure that the subsequent request can pull the stuff out of some data store that is in the right scope (data model, list, whatever) when that key needs to be resolved.I tend to cringe at the idea of passing identifiers around explicitly; should I reconsider this position? Or is using an EL method parameter just not the right way to hide the identifiers (as opposed to @DataModel and friends)?
Christian Bauer wrote on Mar 05, 2008 03:38 PM:
Because i.getId().toString() is evaluated at render-time. What you have shown is calleds:link can do special magic tricks with the datamodel selection if you put it inside an h:datatable, just look at the generated URL with lots of magic parameters
. There is an open JIRA issues that discusses removing this particular mis-feature.Which issue is this? I found jbseam://1734 and jbseam://2391, but they're closed.
-
12. Re: Passing Instance To Home Class
gavin.king Mar 8, 2008 4:09 AM (in response to leesy)
I tend to cringe at the idea of passing identifiers around explicitlyHonestly, I think that URLs with primary keys in them is just about the only truly semantically correct way to use HTTP.
-
13. Re: Passing Instance To Home Class
gavin.king Mar 8, 2008 4:11 AM (in response to leesy)I'm speaking approximately, of course: it doesn't have to be the primary key, just some stable unique key of the entity.
-
14. Re: Passing Instance To Home Class
sleroux Mar 8, 2008 4:04 PM (in response to leesy)
Gavin King wrote on Mar 08, 2008 04:09 AM:
Honestly, I think that URLs with primary keys in them is just about the only truly semantically correct way to use HTTP.Am I wrong, or that's the RESTful way of doing things? Or at least it enforce a resource oriented architecture (ROA). Does this advice apply to all POST requests as well as GET requests?
From the user point of view, it could be of great benefits to have URLs with primary keys: they will have an unique identifier (the URL) for any operation on that resource. But that require a browser supporting http methods like PUT or DELETE. That's currently not the case.
I tend to cringe at the idea of passing identifiers around explicitlyMaybe your problem with
passing identifiers
is related to security concerns. What if someone change the URL in such way that give him access to an other resource?Since the solution based on @DataModelSelection use index on the list, as far as I understand, there's no way for the user to access resources other than those present in the corresponding @DataModel. This is a
stateful
way of doing things.In the other hand, using identifiers in the URL requires to check if the user should really have access to the given resource before processing each request. This is a more
stateless
way of doing things. The good news is in that case you now have bookmarkable URL.Restful architectures are stateless. And Seam is a stateful framework. So by re-reading this post again and again, I came to the conclusion that, in order to have the best of both worlds, we should:
- use stateless/restful/bookmarkable URL using resources identifiers for idempotent operations (GET requests). Not forgetting to check user rights on the resource before processing.
- use framework stateful capabilities (like @DataModel/@DataModelSelection) and a POST request for non-idempotent operations: in that case you don't need to check user rights before processing.
Even more: I feel like if any Seam conversation should begin with a GET request on a
restful URI
. In other words, that anyentry point
in an application should be a resource. I'm not sure I'm clear here (it's still a little bit confuse in my mind;). But I'm sure there's something to dig there...Sylvain.