You can find the full source code for this website in the Seam package in the directory /examples/wiki. It is licensed under the LGPL.
| Online: | 17 Members of 4546 |
| Forum: Seam Users |
22. Mar 2008, 09:39 CET | Link |
Hello,
I'm not able to access properties of a conversation scoped component. Here is my component:
@Stateful
@Name("blogEntryList")
@Scope(ScopeType.CONVERSATION)
@Restrict("#{identity.loggedIn}")
public class BlogEntryListBean implements LocalBlogEntryList {
...
@In(required = false)
@Out(required = false)
private BlogEntry currentBlogEntry;
@DataModel
private List<BlogEntry> blogEntries;
public BlogEntry getCurrentBlogEntry() {
return currentBlogEntry;
}
public void setCurrentBlogEntry(BlogEntry blogEntry) {
log.info("got blogEntry= #0", blogEntry);
this.currentBlogEntry = blogEntry;
}
public List<BlogEntry> getBlogEntries() {
return blogEntries;
}
public void setBlogEntries(List<BlogEntry> blogEntries) {
this.blogEntries = blogEntries;
}
...
}
The setter setCurrentBlogEntry() is called from the blogEntryList.xhtml page:
<h:dataTable id="blogEtriesDataTable" value="#{blogEntries}" var="blogEntry" rendered="#{blogEntryList.resultListSize > 0}">
<h:column>
<f:facet name="header">ID</f:facet>
#{blogEntry.id}
</h:column>
<h:column>
<f:facet name="header">Title</f:facet>
#{blogEntry.title}
</h:column>
<h:column>
<f:facet name="header">Actions</f:facet>
<s:link id="blogEntryTest"
value="Test"
action="#{blogEntryList.setCurrentBlogEntry(blogEntry)}"
view="/xcms/blog/blogEntryList.xhtml" /> 
</h:column>
</h:dataTable>
When i click on the link, the setCurrentBlogEntry() method is called, but the output reports null value assigned:
10:19:00,015 INFO [BlogEntryListBean] got blogEntry= null
I guess this has something to do with the life-cycle of the conversation scoped components, but since I am very new to seam and to the notion of conversation, I wasn't able to understand what should I do to keep the component alive
within several page calls.
I even tried to promote my conversation to a long-running one by marking one @Create method of this component with @Begin(join=true), with no success.
On the other hand, if I try to scope the component to SESSION, things are working OK and the blogEntry variable is caught correctly.
Where am I going wrong?
Thank you for any hint. Bogdan.
I'm pretty sure it will work just fine if you choose to use <h:commandLink> instead of <s:link>.
But I can't answer why it doesn't work with the <s:link> !
http://docs.jboss.com/seam/2.0.1.GA/reference/en/html_single/#d0e22695
Thank you Kenneth for the reply!
As I read through the docs you pointed at, I have found this:
and this:
Well, as far as you can see in my backing bean (BlogEntryListBean), my data (blogEntries) is exposed as a DataModel and is rendered inside an <h:dataTable>. Still with no success in using <s:link/>.
Anyway, I tried using <h:commandLink /> as you suggested, and the method is called as expected, and the data is caught properly (not null). The only problem is that it refreshes the current page, but I guess that with some simple pageflow in pages.xml I can solve this.
But I want to benefit of the many advantages that s:link offers.
Any other opinions or suggestions?
Anyway, as far as I see on the booking example, even Gavin decided to hold his listBeans scoped to session, so for the moment I will put this workaround to work.
@Stateful @Scope(SESSION) @Name("bookingList") @Restrict("#{identity.loggedIn}") @TransactionAttribute(REQUIRES_NEW) public class BookingListAction implements BookingList, Serializable { ... @DataModel private List<Booking> bookings; @DataModelSelection private Booking booking; ... }Thank you again for the reply,
Bogdan.
Hi,
as Kenneth mentioned, the problem is
<s:link action="#{blogEntryList.setCurrentBlogEntry(blogEntry)}"/>I had same problem in past.
The result is, that h:commandLink support action method parameters in EL but the s:link does NOT.
The workaround is simple: use f:param
<s:link action="#{blogEntryList.setCurrentBlogEntry}"> <f:param name="id" value="#{blogEntry.id}"> </s:link>Thanks for the reply Martin.
I got the picture with the difference between s:link and h:commandLink. Your workaround is quite nice and I bet it solves the cases where one can't expose components to session.
As far as I understood, the problem is not that s:link doesn't support parameters inside JBoss EL (because it does: <s:link id="viewHotel" value="View Hotel" action="#{hotelBooking.selectHotel(hot)}"/>), but that objects passed in there are not properly kept alive in the conversation. My workaround for this was to keep lists in SESSION, and start conversations only after selecting one. This approach was suggested by this:
(From the link provided by Kenneth)
So now, my link looks like this:
<h:dataTable id="blogEtriesDataTable" value="#{blogEntries}" var="blogEntry"> <s:link id="blogEntryEdit" value="Edit" action="#{blogEntryView.editBlogEntry(blogEntry)}" view="/xcms/blog/blogEntryEdit.xhtml" /> </h:dataTable>blogEntries is scoped to SESSION and blogEntryView.editBlogEntry(blogEntry) starts a new CONVERSATION. This way, data is available both when the page is rendered and when the data is submitted. I haven't lost the advantage of conversations because several tabs can edit a different blogEntry, since blogEntryView.editBlogEntry(blogEntry) starts a new CONVERSATION.
Since I am very new to Seam I will be very grateful if someone would be kind enough to tell his opinion about my approach.
Thank you,
Bogdan.
Martin,
I encountered the case where I need your workaround with <f:param>. And I did something like this:
<s:link action="#{blogEntryList.setBlogEntryById}"> <f:param name="id" value="#{blogEntry.id}"> </s:link>which is backed by this method from the bean:
... @RaiseEvent("com.brit.xcms.cms.Page.pageListModified") public void setBlogEntryById(Long blogEntryId) { this.blogEntry = blogEntryDAO.findBlogEntryById(blogEntryId); find(); } ...The link comes out right, but clicking it generates this exception:
javax.el.MethodNotFoundException: Method not found: CategoryListBean:a002r-j4glz4-fe78zera-1-fe7ap87m-34.setParentById() at org.jboss.el.util.ReflectionUtil.getMethod(ReflectionUtil.java:252) at org.jboss.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:341) ...which I kind of understand, because I think EL needs to build through reflection the actual bean method that needs to be called. As far as I know reflection need the full method prototype, including parameter types. From my EL: blogEntryList.setBlogEntryById, the parameters are void, so it expects the setBlogEntry() method, and not setBlogEntry(Long) as I need.
How can I specify the actual method that I need to call?
Thanks, Bogdan.