Currently, I'm just running everything in session scope, and attached
some convenience methods to an Action superclass, along the lines of the
saveErrors() convenience method. The cache is instantiated when the
actor logs in, and the convenience methods access it through a constant
key, just as Struts components access resources from the application
context under a known key.

Of course, you could also put one of these in application scope if
needed, and use it the way Struts uses the ActionMappings. 

For a sub-application, or "package" scope, you could name the keys with
a dotted syntax (thisPakage.token or thatPackage.token), or add a
wrapper to place the objects in a bean with a "scope" property, and
define a hierachry (page/request/workflow/package/application). So, you
might request eiher (scope,token) or (token) if you just wanted the
lowest instance in the hierarchy. 

In practice, the signature I'm using now includes the httpRequest, which
can be used to obtain the session.

In the action, the calls resolve to things like 

// -- Check cache for form in progress
cacheRemoveForm(mapping,form,request,errors);

and

// -- Notify cache of latest key value
cacheSetString(request,"donor",thisForm.getDonor());


The cacheRemoveForm method uses BeanUtil.populate(), and so needs the
errors collection to report the exception if something shoudl go wrong
there. 


Here's the Action code:

    /**
     * Store an ActionForm in the cache under it's mapping form name.
     *
     * @param mapping The ActionMapping used to select this instance
     * @param actionForm The ActionForm bean for this request
     * @param request The HTTP request we are processing
     */
    protected void cachePutForm(ActionMapping mapping,
             ActionForm form,
             HttpServletRequest request) {
        // Acquire cache
        HttpSession session = request.getSession();
        ResourceCache cache = (ResourceCache)
                session.getAttribute(Constants.RESOURCE_CACHE_KEY);
        if (cache!=null) {
            // Store form under mapping name
            servlet.log("cache: Saving Form",2);
            // Tempted to clone this first, but shouldn't be necessary.
            cache.put(mapping.getName(),form);
        }
    }

    /**
     * Remove a cached ActionForm, if it exists, and populate the given
     * form.
     *
     * Reports an "unexpected" error if BeanUtil generates an exception.
     *
     * @param mapping The ActionMapping used to select this instance
     * @param actionForm The ActionForm bean for this request
     * @param request The HTTP request we are processing
     * @param errors The ActionErrors resource
     */
    protected void cacheRemoveForm(ActionMapping mapping,
                     ActionForm form,
                     HttpServletRequest request,
             ActionErrors errors) {
        // Acquire cache
        HttpSession session = request.getSession();
        ResourceCache cache = (ResourceCache)
                session.getAttribute(Constants.RESOURCE_CACHE_KEY);
        if (cache!=null) {
            // Check for form
            String formName = mapping.getName();
            if (cache.containsKey(formName)) {
                servlet.log("reg: Restoring Form from Registry",2);
                ActionFormCache cachedForm = (ActionFormCache)
cache.remove(formName);
                try {
                    BeanUtils.populate(form,cachedForm.getMap());
                }
                catch (IllegalAccessException iae) {
                    errors.add(ActionErrors.GLOBAL_ERROR,
                        new ActionError("action.error.unexpected"));
                }
                catch (InvocationTargetException ite) {
                    errors.add(ActionErrors.GLOBAL_ERROR,
                        new ActionError("action.error.unexpected"));
                }
            }
            ActionFormCache thisForm = (ActionFormCache) form;
            thisForm.resetKeys(mapping,request);
        }
    }

    protected void cacheRemove(HttpServletRequest request, String key) {
        // Acquire cache
        HttpSession session = request.getSession();
        ResourceCache cache = (ResourceCache)
                session.getAttribute(Constants.RESOURCE_CACHE_KEY);
         if (cache!=null) cache.remove(key);
    }

    protected void cacheSetString(HttpServletRequest request, String
key,
            String value) {
        if ((key!=null) && (value!=null)) {
            // Acquire cache
            HttpSession session = request.getSession();
            ResourceCache cache = (ResourceCache)
                    session.getAttribute(Constants.RESOURCE_CACHE_KEY);
             if (cache!=null) cache.put(new String(key),new
String(value));
        }
    }


Right now, the ResourceCache class is just a wrapper around a hashtable.

The ActionFormCache is an interface:

/**
 * Define methods required to put and remove an
 * Action Form to a hashtable or other resource.
 *
 * @author Ted Husted
 * @version $Revision: 1.1 $ $Date: 2001/06/13 $
 */

public interface ActionFormCache {

    // --------------------------------------------------- Instance
Variables
    // -----------------------------------------------------------
Properties
    // --------------------------------------------------------- Public
Methods

    /**
     * Reset only selected (key) fields in ActionForm, for use after
     * removing ActionForm from a resource.
     */
    public void resetKeys(ActionMapping mapping,
        HttpServletRequest request);

    /**
     * Return map of properties, for use with BeanUtil.populate().
     *
     * @return map of properties, for use with BeanUtil.populate().
     */
    public Map getMap();
}




Jonathan Asbell wrote:
> 
> How are you dealing with scope.
> 
> Do you use an adaptor to Session or ServletContext to hide the scope's
> implementation from the
> developer, or do you outright use a Session etc.

Reply via email to