The complaint about SEAM's attempt at navigation has been going on for a long time now. The SEAM devs don't seem to think its a problem, but obviously in any application bigger then the booking example it is a problem.
I think the problem with what is being asked in this thread is that it doesn't tie into the SEAM conversation lifecycle. You are ending a conversation and beginning a new one in a completely different spot then normal.
And I'm pretty sure they could argue that this isn't supported thus hasn't been implemented in the SEAM core.
However, the concept of ending a conversation and going to a brand new one in one action is obviously something that should be offered out of the box. Any there is no navigation logic reasoning for not wanting that. Technical reasons asside, SEAM should support this.
Now, with regards to how you can do this.
The most simple way is to create your own redirect method. So you would change your s:link to a h:commandLink with an action that calls your redirect method.
Then its simple.
Your steps are basically.
- End the current conversation
- Leave the current conversation
- Begin a new conversation long running conversation
Conversation.instance().end(); //Flag this conversation for ending Conversation.instance().leave(); //Leave this conversation (forces new temporary converation to start Conversation.instance().begin(); //Make our new temporary conversation long running String newConversationId = Conversation.instance().getId(); //get the new conversation's id Manager.instance().redirect(viewId, newConversationId ); //redirect to our new view using our new conversation
I've been using this tecnique heavily on the application I'm working on (a medium sized app) although I have got a lot of stuff wrapped around these steps. But, the steps are the general idea.
In my opinion doing it this way is slightly better then the way suggested earlier with calls made to
Lifecycle.destroyConversationContext(getSessionMap(), convID); ConversationEntries.instance().removeConversationEntry(convID);
There are risks involved in fiddeling with Lifecycle.destroy and ConversationEntries.remove.
But whatever works for you :)
I have tried the code you prefered, end->leave->begin, if you go to debug page you will see the old one still there and the destroy didn't occured after you leave the new one, same thing with leave->end-begin, that's why I explict call destroy and remove methods.
I have gone through the conversation section in the REF. seems the way you and me did is trying to term and begin the new Conv. before redirect, what Pete said was try to end the old one before redirect and start new one after redirect. the create new conv. just happened in different place.
Yes, I think seam should really support this feature in the next release, back year ago, I used Spring web flow to do a relatively simple project, and I found that it nevigation model doesn't fit the big app.
in any bigger web app, there must be some spot user will jump into the "conversation"/"wizard pages" or jump out the "conversation"/"wizard pages", with ajax, most likely you won't be able to refresh the whole page. and force the app to redirect sometime is not doable.
The problem is that even you end previous long run conversation, when you call @Begin or conversation.begin(), seam will default reuse previous ended long run conversation and prompt that one to a
newlong run conversation, so whatever objects that stored in the previous conversation won't be released or cleanup.
I tried to do a woodoo magic to make the @Begin method release previous conv, and recreate new one.
And there are 2 way that you can do this for now (I mean with the 2.1.2 release):
either create that method I posted to do the dirty job or you can do a redirect to the same page and in you page.xml do the magic.
I still think seam should provide a easy way to do this.
anyway I'll continue my journey with Seam and see how far I can go.
Hey Wang Liyu,
I must apologise. I was looking at my navigation code and completely missed a very important line. (I wrote this code a few months ago so I'll use that as my excuse hehe :P)
The really important line was of course
So really the steps SHOULD be:
String oldConversationId = Conversation.instance().getId(); Conversation.instance().end(); //Flag this conversation for ending Conversation.instance().leave(); //Leave this conversation (forces new temporary converation to start ConversationEntries.instance().removeConversationEntry(oldConversationId); //Remove this conversation completely from the system Conversation.instance().begin(); //Make our new temporary conversation long running String newConversationId = Conversation.instance().getId(); //get the new conversation's id Manager.instance().redirect(viewId, newConversationId ); //redirect to our new view using our new conversation
But this got me thinking as to why the Conversation.instance().end() doesn't work. And I'm assuming that because we don't finish the actual conversation lifecycle the
end()doesn't really happen.
But anyways... Sorry for the slightly missleading information :)
The code looks good, except I call leave() first, then call end(), the end() really is just set the flag to temp.
Pete's solution also works fine in the
normalway, I found it has problem with a4j:include tag, see my new post:
I think Seam really should support this feature in the next release, otherwise there are always some bumpers.
Anyway, thanks for the clarification.
Hey Wang Liyu,
I don't really have a lot of experience with pages.xml. None of the guys on my team (including myself) like xml very much. So we've opted to do our own navigation with code. (Built a NavigationManager to handle this and so far it is working rather well :) )
So, havn't tried to do what you are explaining there, but I'll keep my eye on the post so I can see the outcome :)
George Wu wrote on Jul 09, 2009 00:03:
Liyu and Tim,
Should you end the root conversation? What if the current conversation is a nested child conversation? Ending current conversation seems not enough.
There should be a way in the API to programmatically end (demote to temp conv) the child and/or parent/root LRC. I would imagine that if you explicitly end the root LRC, all others
below itwill end as well.
Here are the key id's to consider:
id String A value that identifies this conversation. This value is typically numeric, though business key identifiers are also supported.
parentId String The conversation id of the parent conversation of this nested conversation.
rootId String The conversation id of the primary (top-level) conversation of this nested conversation.
so perhaps something like this:
@End or conversation.end() doesn't really do anything, it just set the LRC flag to false, and you call begin() after end(), will just set the flag back to true, you have to do something to destroy the object in the previous LRC and the conversation as well, then create a new temp conversation, prompt that to LRC, that's the idea. but seems SEAM team doesn't want to give you that, it cause a lot headache.
THe redirect works for the normal cases, but with <a4j:include> tag, i can't use <redirect> in the pages.xml, instead, I have to use render tag, which doesn't trigger the redirect, in this case, how to terminate the previous LRC & begin a new LRC?
BTW, I still think Seam should support begin brand new and close before LRC out of box, that will save us a lot.
Yes I agree Wang, they should support it. Why don't you create a JIRA and propose them making it? Or in Pete's case, why don't you contribute in creating that @ReBegin or something similar.
I mean, seam is open source, you can try to contribute to make that annotation, or a new component that does that.
Seems like a very good idea.