You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@struts.apache.org by Cody Sherr <cs...@covalent.net> on 2003/05/01 20:03:17 UTC

Re: [Long] Re: Page Context Stack - a general solution to the problem of returning to your start page

I've implemented something similar. However, I took a different approach
for item 1). Instead of generating a return path on all the pages that
might be the origin, I set it in my controllers. Each controller has the
responsibility of generating a return url that represents it's current
state and saving it in the session. If a user enters a workflow, that
returnPath is taken from the session and is pushed onto the workflow as
it's origin.

-Cody Sherr



On Wed, 2003-04-16 at 14:51, Jeff Smith wrote:
> Jefficus said: Would that be useful to anybody?
> Laird said: Very much so.
> 
> So here ya go.
> 
> There are three steps to the problem:
> 1) Determining what page you came from.
> 2) Storing that page info when you start an action sequence
> 3) Returning to that page when you complete (or abort) an action sequence.
> 
> 1) At first I was going to use request.getHeader("referer"). But then I read
> a couple of postings about how it is not reliably provided by some client
> browsers. So I decided to do it differently. At the top of every JSP in my
> app, I have placed the following code:
> <c:set var="waiURL">
>   <c:out  value="${pageContext.request.requestURL}" escapeXml="false"/>
>     <c:if test="${pageContext.request.queryString != null}">
>       ?<c:out  value="${pageContext.request.queryString}"
> escapeXml="false"/>
>     </c:if>
> </c:set>
> <bean:define id="PageStackCurrentLocation" toScope="session">
>   <c:out value="${waiURL}" escapeXml="false"/>
> </bean:define>
> 
> (Improvements to this gobbledy-gook would be most welcome. :-)
> 
> There are probably more elegant ways to accomplish this - I am no JSP taglib
> genius. But essentially this fragment constructs the full URL path of the
> page that is being rendered and places that URL (including request params)
> into a session bean called PageStackCurrentLocation.
> 
> If you have a bunch of disjoint JSP files, you'll probably want to put this
> fragment in a separate file and include it into each of your JSPs.
> Fortunately for me, I use a single Tiles template to control the layout of
> all my pages, so I just had to stick it in the template.
> 
> 
> 2) Now my user invokes a "floating action chain", say the Edit User Profile
> sequence which in my app can be accessed from every single page. The link
> forwards to the first action in the sequence. In my app, most sequences
> (even simple editors) have a prepAction that I go to first so that I can do
> some logging and any pre-display processing. (This prepAction is required
> for now, but down below I'll explain how I've removed this requirement.)
> 
> When I get to my prepAction, the first thing I do is call
> PageStack.pushPage( ). Since I have not yet forwarded to the JSP for this
> action, my session PageStackCurrentLocation bean is still pointing to the
> JSP I just left. (Neat, huh?) I simply grab this from the session scope and
> put it into another session bean called PageStackMemory.
> 
> In my world, I implemented PageStackMemory as a simple String array of size
> 8. I'm never going to nest 8 action chains. But you can be as fancy as you
> like with dynamic array lists and whatever turns your crank. I just place my
> URL in the first empty cell of the array and move on. Now the prepAction can
> do its other processing and jump to its associated JSP or go wherever it
> likes.
> 
> 
> 3) Sooner or later, the action sequence will either terminate or the user
> will abort. In either case, I now want to go back to my starting point. So
> instead of looking for an action forward (I'll explain that part later) I
> call PageStack.popPage( ) which goes to my PageStackMemory array in the
> session and grabs the first non-empty cell (starting at the end of the
> array) and set that cell to empty. PageStack.popPage( ) then calls
> response.Redirect(myURL) and I jump back to where I started.
> 
> At any point between step 2 and 3,  I can allow the user to start another
> floating sequence, pushing the URL of the current page and then popping back
> to it when that sub-sequence is  done. In my case, I can only allow 8 of
> these nested sequences, but you get the idea.
> 
> 
> 
> Eliminate Requirement for PrepAction
> The next trick is to eliminate the requirement for a prepAction at the
> beginning of each action chain. The class I referred to above, PageStack, is
> actually an Action class. (More specifically, its a DispatchAction, but who
> wants to quibble?)
> 
> Suppose I want the user to be able to logon from any page he might be on in
> the app, and then return to that page after logon. If you're a normal
> person, you don't have a prepAction for your logon sequence. So how do you
> grab the current page before displaying your logon form?
> 
> Here's how it works - create a global forward that looks like this:
> <forward name="startLogon"
> path="/PageStack.do?operation=pushPage&NextAction=logon/>
> 
> And then set your logon link like this: <html:link forward="startLogon"/>
> 
> When the user clicks on the logon link, it will forward to the
> PageStack.pushPage method, which, as you may recall, is where I grab the
> current page and put it into the PageStackMemory bean. After doing so, it
> looks in the request params for the name of the NextAction and forwards
> there.  In our example, that would be your traditional "logon" action.
> Voila!. You've reached your form page and you've saved the URL of the start
> location along the way.
> 
> 
> 
> Eliminate Direct call to PageStack.popPage
> When I was in there setting up the global forward for startLogon, I also set
> one up called popPage, like this:
> <forward name="popPage" path="/PageStack.do?operation=popPage/>.
> 
> Now any action chain that wants to return to its starting place can just
> forward to "popPage" and it will work, as long as it went through pushPage
> at the outset.
> 
> 
> Support More Complex First Actions
> There were two special cases that I encountered while setting this up, that
> we still haven't covered.
> 
> A) What if the first page of my sequence takes request params to control its
> function?
> 
> Simple.  Just create another global forward like this:
> <forward name="paramInfestedActionStep"
> path="/MyAction.jsp?someparam=foo&otherparam=bar"/>
> Now your startLogon declaration can set NextAction=paramInfestedActionStep
> and everything will be peachy.
> 
> B) Even worse, my first step not only takes params, but they are determined
> dynamically, so I can't create a statically declared global action to get me
> there.
> 
> Again, no problem. My implementation of pushPage is smart - it takes all of
> its incoming params and relays them to whoever it forwards to. (except the
> operation and NextAction params which are consumed locally). So if your call
> to "startLogon" includes params, they will be passed to
> paramInfestedActionStep and the world should proceed apace. (Unless you are
> unlucky enough to have params called NextAction or operation. But I'll leave
> fixing that as an exercise for the reader.)
> 
> So now we have a page stack system that allows recursive action sequences to
> declare both their start and end using the struts-config action forwards,
> but the definitions are not rooted to specific URLs. It's a little
> complicated when you first look at it, but once you understand it, its
> pretty simple to work with. (Sounds like most of struts. :-) And best of
> all, it doesn't require changes to the struts code itself, so it should work
> on (most? many? some?) struts revs out there.
> 
> Hope some of you find that useful,
> Jefficus
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: struts-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: struts-user-help@jakarta.apache.org
> 
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: struts-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: struts-user-help@jakarta.apache.org