Title: RE: [Wicket-develop] RequestCycle/Redirect fix..

I think the approach that Martijn/Johan/Eeelco have come up with is a good one for solving the redirect problems when using a SINGLE SERVER installation. However, I don't think it is necessarily a good approach when working with a MULTI-SERVER CLUSTER because it adds an extra stage of replication - and a large page could be a number of KB in size.

Having thought it through, I don't think there is a 'one size fits all' solution to this. In fact, there are two distinct problems that we are trying to solve that are both related to exactly the same issue:

1) Martijn/Johan/Eelco are trying to solve the problem of not wanting to create a hibernate session and load business objects twice for each page (once when the main request for the page is received and again when the page is rendered).

2) Chris/Jon are trying to solve the problem of minimising the number of times objects are added/changed in the session in order to minimise cluster replication.

There appears to be quite a lot of overlap between these two problems and also a large amount of mutual exclusivity in the possible solutions!


For Martijn/Johan/Eelco's problem there are three potential solutions...

1.1) Hold the hibernate session (or similar object) for a scope that is longer than the one request. Allocate it on start of the main request and then close it at the end of the redirect request.

        Advantages:
        + Solves the problem of allocating hibernate sessions multiple times
        + Allows the use of the redirect pattern
        Disadvantages:
        - Doesn't work in a cluster as the redirect might be handled by a different server (in a cluster we generally accept the extra overhead of re-establishing objects multiple times as a necessity to achieve scalability)

1.2) Handle all of the page processing and rendering in the main request and store the rendered HTML content in the session so that the redirect just has to write out the page and doesn't do any processing work

        Advantages:
        + Solves the problem because hibernate sessions and business objects only need the scope of one request
        + Allows the use of the redirect pattern
        Disadvantages:
        - Doesn't scale well in a clustered environment as we synchronize not only the page objects but also the generated HTML content for each page - which may be too large to achieve scalability

1.3) Don't use the redirect pattern and do all processing in one request and return the response. However, a way would need to be provided to detect the same submission happening again (e.g. a page refresh) and this should result in a re-render only.

        Advantages:
        + Eliminates the redirect problem entirely
        + Works perfectly in a clustered environment
        Disadvantages:
        - We would still need to support the redirect pattern when people wish to avoid their users seeing the 'resubmit POST data' message.


For Chris/Jon's problem there are two potential solutions...

2.1) Make sure that rendering is immutable so that the redirect never changes the components or the underlying models (requires changes to ListView and the code that auto resolves things based on the markup (e.g. autolink)).

        Advantages:
        + Solves the need to update the session multiple times per page (once for main request and again for redirect)
        + Solves the need for multiple hibernate sessions unless using detached models
        Disadvantages:
        - Requires changes to existing working solutions (e.g. ListView and autolinks)
        - Still requires multiple hibernate sessions if detached models are being used

2.2) Don't use the redirect pattern and do all processing in one request and return the response. However, a way should be provided to detect the same submission happening again (e.g. a page refresh) and this should result in a re-render only.

        Advantages:
        + Eliminates the redirect problem entirely
        + Works perfectly in a clustered environment
        Disadvantages:
        - We would still need to support the redirect pattern when people wish to avoid their users seeing the 'resubmit POST data' message.



Solutions 1.3 and 2.2 are identical and solve both the problems of multiple hibernate sessions and of multiple cluster updates. This is my preferred solution for a large system where scalability is key. However, we still need to support the redirect pattern because a) People might want cases where the user doesn't get a 'resubmit form data' popup message AND b) because people expect this functionality to be available even if they don't use it.

Solution 2.1 solves the other clustering issues, but doesn't solve the multiple hibernate session problem (unless you use non-detached model objects - but this will overload the cluster replication)

Solutions 1.1 and 1.2 solve the multiple hibernate session problem but don't work well in a cluster.


I would therefore propose the following solution:

1) We implement good (default?) support for working without the redirect pattern as this seems to solve both problems to a reasonably degree.

2) We make the changes so that the render phase of a request is ALWAYS immutable - never changes the component hierarchy or the model objects - as this allows the redirect pattern to be used within a clustered environment. In a cluster you would generally take the hit of creating a second hibernate session in order to reload any detached models.

3) We provide support for either multiple request scope objects AND/OR pre-rendered pages (I don't have a preference on either). However we make it VERY clear that this approach should not be used if a Wicket application is deployed in a clustered environment.

Does this sound like a sensible approach?
Regards,
Chris





>
>
>
> right right... so the Page that's being rendered on the redirect is
> already in the session and it's already being replicated.
>
> which brings me back to my earlier thought... if the page you're
> redirecting to is already replicated and in the session, then the
> request could occur on server A and the response could come
> from server
> B simply because the Page was constructed (and therefore is in the
> session).  so if this is the case, i've flipped my opinion back
> around... why can't the hibernate session just be opened on
> begin(A) and
> be closed on end(B) ??
>
> sorry i've been free associating tonight i really only have like 15
> minutes to respond to all this tonight...  i'm still a little lost on
> this, but i'm unsure about the solution still.  can someone follow
> through my thoughts and questions and set me straight?  thanks!
>
> best,
>
>        jon
>
> Jonathan Locke wrote:
>
> >
> > okay, so if we do decide to do it this way, a couple questions...
> >
> > - why a map?  isn't there only one redirect at a time for a session?
> > couldn't this be a single attribute
> >
> > - shouldn't you remove the attribute at the end of the redirect?
> >
> > - why use this low-level way of getting the session attribute?
> > shouldn't you just say
> getSession().getAttribute("wicket-redirect") ?
> >
> > Johan Compagner wrote:
> >
> >> We always do clientside redirects. So developer don't always take
> >> this into account.
> >> Like setResponsePage(new Page(myHibernateObject))
> >> then myHibernateObject uses a wrong HibernateSession.
> >>
> >> ClientSide redirect do fix a number of problems so we like to keep
> >> this.
> >>
> >> Now i made a hybrid  solution.
> >> We do use a clientside redirect put the responsepage is rendered as
> >> it was a serverside redirect...
> >>
> >> Changed 2 classes/methods:
> >>
> >> WebRequestCycle.redirectTo(final Page page)
> >>    {
> >>        String redirectUrl = page.urlFor(page,
> IRedirectListener.class);
> >>        // create the redirect response.
> >>        Response previous = getResponse();
> >>        RedirectResponse rr = new RedirectResponse(redirectUrl);
> >>        setResponse(rr);
> >>        page.request();
> >>        setResponse(previous);
> >>        Map map =
> >>
> (Map)getWebRequest().getHttpServletRequest().getSession(true).
> getAttribute("wicket-redirect");
> >>
> >>        if(map == null)
> >>        {
> >>            map = new HashMap(3);
> >>           
> >>
> getWebRequest().getHttpServletRequest().getSession(true).setAt
> tribute("wicket-redirect",map);   
> >>
> >>        }
> >>        map.put(redirectUrl,rr);
> >>        // Redirect to the url for the page
> >>        response.redirect(redirectUrl);
> >>    }
> >>
> >> So when we redirect the page is first rendered
> (page.request())  in a
> >> buffered response object.
> >> this object is stored in the httpsession.
> >> Then the redirect is done.
> >>
> >> in:
> >>
> >> WicketServlet.doGet(final HttpServletRequest servletRequest,
> >>            final HttpServletResponse servletResponse) throws
> >> ServletException, IOException
> >>    {
> >>        // try to see if this is a redirect that is already
> stored in
> >> the wicket-redirect map of its session.
> >>        Map redirectMap =
> >>
> (Map)servletRequest.getSession(true).getAttribute("wicket-redirect");
> >>        if(redirectMap != null)
> >>        {
> >>            RedirectResponse rr =
> >>
> (RedirectResponse)redirectMap.remove(servletRequest.getRequestURI() +
> >> "?" + servletRequest.getQueryString());
> >>            if(rr != null)
> >>            {
> >>                PrintWriter pw = servletResponse.getWriter();
> >>               
> servletResponse.setContentLength(rr.getContentLength());
> >>                servletResponse.setContentType(rr.getContentType());
> >>                pw.write(rr.toString());
> >>                pw.close();
> >>                return;
> >>            }
> >>        }
> >>        // Get session for request
> >>        final WebSession session =
> >> webApplication.getSession(servletRequest);
> >>
> >> I first test if there is a redirect response item in the redirect
> >> map. If this is the case then that redirect object is removed from
> >> the map and the redirect is written to the directly written to the
> >> response.
> >>
> >> the drawback:
> >> There is a complete page in mem of the server for a very
> short time.
> >>
> >> plus:
> >> the redirect is very very fast. And doesn't take almost no
> memory, no
> >> hibernate session need to be created nothing needs to be loaded.
> >>
> >>
> >> Any objections for this approach?
> >> We could make it optional or something
> >>
> >> johan
> >>
> >>
> >> -------------------------------------------------------
> >> SF.Net email is sponsored by: Tell us your software development
> >> plans! Take this survey and enter to win a one-year sub to
> >> SourceForge.net Plus IDC's 2005 look-ahead and a copy of
> this survey
> >> Click here to start! 
> http://www.idcswdc.com/cgi-bin/survey?id=> 105hix
> >>
> _______________________________________________
> >>
> Wicket-develop mailing list [email protected]
> >> https://lists.sourceforge.net/lists/listinfo/wicket-develop
> >>
> >
> >
> > -------------------------------------------------------
> > SF.Net email is sponsored by: Tell us your software
> development plans!
> > Take this survey and enter to win a one-year sub to SourceForge.net
> > Plus IDC's 2005 look-ahead and a copy of this survey Click here to
> > start!  http://www.idcswdc.com/cgi-bin/survey?id=105hix
> > _______________________________________________
> > Wicket-develop mailing list [email protected]
> > https://lists.sourceforge.net/lists/listinfo/wicket-develop
> >
>
>
> -------------------------------------------------------
> SF.Net email is sponsored by: Tell us your software
> development plans! Take this survey and enter to win a
> one-year sub to SourceForge.net Plus IDC's 2005 look-ahead
> and a copy of this survey Click here to start! 
> http://www.idcswdc.com/cgi-bin/survey?id=> 105hix
>
> _______________________________________________
>
> Wicket-develop mailing list [email protected]
> https://lists.sourceforge.net/lists/listinfo/wicket-develop
>

Reply via email to