Ok, as discussed earlier, here goes:

The basic issue is that we don't want to include the continuation id
with the individual page as request data.  If you do, you can't cache
the form (server side).  For a forms heavy system like ours where 1000's
of forms can be viewed simultaneously by 100's of users but where
updates (form submits as POSTs) are rare this adds a lot of overhead.
The main issue is to uniquely identify each instance of a form.  There
are two main possibilities:

1) a unique instance of a form per page per user;

2) many unique instances of a form per page per user.

The solution I will discuss here only applies to the first use case, if
you have to support the 2nd I think you are stuck with putting the
continuation id in the form request.

As I've mentioned before, you can try to do continuation management
using cookies.  However, this gets complicated and by the time you are
done with it you are basically reinventing session management.  If
you're going to rely on cookies you might as well use sessions instead;
this solution relies on sessions, if you can't use sessions I think
you're back to request based continuations.  Using sessions means we can
uniquely identify users, part one of the requirement solved.
Identifying pages is easy; the page generation URL and the POST URL can
do that for you.  Thus, what we need is a way to map continuations to
URLs via session.  That's simply enough, any Map implementation put into
session will do that.  Thus the simple class:

public class ContinuationsData
{
    private Map continuationsMap = null;

    public ContinuationsData() {
        continuationsMap = new HashMap();
    }

    public void addContinuation( String page, String continuationId )  {
        continuationsMap.put( page, continuationId );
    }

    public String getContinuation( String page ) {
        return (String)continuationsMap.get( page );
    }

    public Map getContinuationsMap()  {
        return continuationsMap;
    }
}

Any generator can update this class at setup time:

                WebContinuation m_kont = FlowHelper.getWebContinuation(
objectModel );
                if ( m_kont != null )  {
                    String id = m_kont.getContinuation(0).getId();
                    if ( id != null )   {
                        Session session = request.getSession();
                        if ( session != null )  {
                            ContinuationsData contdata =
(ContinuationsData)session.getAttribute( CONTINUATIONS_DATA );
                            if ( contdata == null )   {
                                contdata = new ContinuationsData();
                                session.setAttribute(
CONTINUATIONS_DATA, contdata );
                            }
                            contdata.addContinuation(
request.getPathInfo(), id );
                        }
                    }
                }

You may want to use query string data in addition to path info or you
may want other ways to identify the page.  I would have liked to use the
source as passed to the generator to pick this up from the sitemap, but
then I have problems on the return side since I use an Input Module to
get the continuation id back for the POST response:

public class ContinuationsManagerModule extends AbstractInputModule
implements ThreadSafe {

    public Object getAttribute( String name, Configuration modeConf, Map
objectModel )
        throws ConfigurationException
    {
        Request request = ObjectModelHelper.getRequest(objectModel);
        Session session = request.getSession();
        if ( session != null )
        {
            ContinuationsData contdata =
(ContinuationsData)session.getAttribute( CONTINUATIONS_DATA );
            if ( contdata != null )
            {
                return contdata.getContinuation( request.getPathInfo()
);
            }
        }
        return null;
    }
        .
        .
        .

As I mentioned earlier I'd have liked to pick up the source form the
sitemap here using something like:

            <map:match pattern="*/**">
                <map:select type="request-method">
                    <map:when test="POST">
                        <map:call continuation="{continuations:2}"/>  

However, the 2nd parameter gets substituted after the input module gets
called and not before so I can't do that.  

Essentially, that's all there is to this solution.  I suspect there are
ways to use some of the existing Cocoon machinery to help this along
even further, but this is simple enough I haven't investigated them.
One other note, you've got to arrange for your session timeouts and
continuation timeouts to expire in the right order.  (Where do
continuation timeouts get configured?)

Not sure if any of this can get folded back into Cocoon, as I've got it
running so far it's probably pretty specific to our requirements.
However, if others have the same issues this may be of help?

Peter Hunsberger


Reply via email to