Thanks to Craig and Slava for your well thought out and explained opinions.
This stuff is gold, I hope others are benefitting as much as I am. Some of
your sample code looks so much like what we have written it's freaky, except
that it shouldn't be, because the design I am using is completely based on
what I have learned participating in this list.
For a little restrospective clarification, Slava was correct when he
suspected I was passing an identical list of additional parameters to the
web action perform( ) methods for the application services (reflected in the
perform( ) method signature in thw WebAction interface they implement).
Also that that the proposed Hashtable of services would be cached at the
application scope, not rebuilt for each call.
I actually delegate the building of the web action hash table and req
dispatching to a separate WebActionManager class, which as with Craig's
design, keeps the controlling servlet quite small. The WebActionManager
would also appear to be a good place to invoke any security functionality,
eg. is the current user allowed to access this action. I am yet to finalise
this part of the system, so another design review is probably pending...
It's strange, but with a single controlling servlet, an issue arises whether
to store shared resources in the ServletContext (application scope) or as
members of the servlet itself. I have been using the ServletContext for all
of this stuff, but the lack application lifecycle events in Servlet 2.2 API
makes it a little hard to ensure it is all cleaned up properly with the
application goes down. As Slava mentioned, the controlling servlet could be
unloaded/reloaded at any time, so the init & destory methods do not
neccesarily correspond to the application starting and stopping.
Thanks for giving me plenty to think about guys.
Regards
Drew Cox
> -----Original Message-----
> From: Craig R. McClanahan [SMTP:[EMAIL PROTECTED]]
> Sent: Monday, January 17, 2000 6:42 AM
> To: [EMAIL PROTECTED]
> Subject: Re: Providing application resources to action classes in
> single-servlet delegation model
>
> Slava Kozlov wrote:
>
> > > -----Original Message-----
> > > From: A mailing list about Java Server Pages specification and
> reference
> > > [mailto:[EMAIL PROTECTED]]On Behalf Of Craig R. McClanahan
> > > Sent: Sunday, January 16, 2000 11:09 AM
> > > To: [EMAIL PROTECTED]
> > > Subject: Re: Providing application resources to action classes in
> > > single-servlet delegation model
> > >
> >
> > ....
> >
> > >
> > >
> > > As you can see, I'm passing a reference to the calling servlet
> > > (passed as "this"),
> > > along with the specific request and response I am dealing with.
> > > (Alternatively, I
> > > suppose you could make the servlet a JavaBeans property of the
> > > action class, and
> > > have the controller servlet set it the first time that the action
> > > instance is
> > > loaded).
> >
> > Firstly, I believe the alternative is dangerous - I don't believe the
> > Servlet API guarantees the longevity of individual servlet objects.
> Servlet
> > engines can kill off servlet objects and restart them as they see fit
> > (including during development). Please correct me if I'm wrong. This
> would
> > mean that the servlet reference that a WebAction was initialized with
> could
> > grow stale and revert to null, crashing the WebAction when it tries to
> > dereference it.
> >
>
> It's not dangerous when you remember that 'killing off" the servlet means
> killing off all the WebAction instances as well. They are simply a set of
> processing methods that is split out of what would otherwise be a bunch of
> methods in the controller servlet -- accessed by an "if .. else if" chain.
> The
> action instances have no life outside of the servlet that created them.
> (In
> fact, in my implementation they are referenced nowhere but inside the
> cache
> collection of the controller servlet, so they are garbage collected at the
> same
> time that the servlet itself is.)
>
> The code in my controller servlet that actually does this is something
> like the
> following (plus appropriate error checking and exception catching):
>
> // Key = path info selector, value = WebAction instance
> Hashtable actions = new Hashtable();
>
> // Key = path info selector, value = WebAction class name
> Hashtable mappings = new Hashtable();
>
> public void init() {
> ...
> ... Initialize mappings table from init parameters ...
> ...
> }
>
> public void doGet(...) {
>
> // Extract the selector
> String pathInfo = request.getPathInfo();
>
> // Retrieve or create a WebAction instance for this request
> WebAction action = (WebAction) actions.get(pathInfo);
> if (action == null) {
> ActionClass actionClass = Class.forName(pathInfo);
> action = actionClass.newInstance();
> actions.put(pathInfo, action);
> }
> // Note - single shared instance for any given path info value
> // is created the first time it is requested, and then reused
> // from then on for the lifetime of the controller servlet.
>
> // Call the perform method for the selected action
> action.perform(this, request, response);
>
> }
>
> Inside the web action instance itself, the reference to the servlet lasts
> as
> long as the call does.
>
>
>
> >
> > > Passing the servlet reference lets me access any resources that
> > > the underlying
> > > servlet can get.
> >
> > ...
> >
> > > If the controller servlet itself had methods you wanted to treat as
> shared
> > > functionality for your action procedures, you could pass a
> > > reference to your
> > > servlet class instead of HttpServlet if you wanted. I've got a
> > > generic controller
> > > servlet that does all the common stuff (request parsing, loading
> > > and caching the
> > > action class instances, calling the correct one), which I can
> > > subclass to provide
> > > additional shared functionality that is unique to a particular
> > > web application.
> > >
> >
> > Judgement call. The more stuff the controller does itself the more
> Godlike
> > it becomes. At some point it may makes sense to decompose it and its
> > functionality. Again, judgement call. :-)
> >
>
> That's why my generic controller servlet is only 100 lines or so of acual
> code
> -- most of that is initialization, configuration, and error checking. The
> ten
> or so lines showed above are the only meat. It can be used as the
> controller
> for any number of different web apps with zero changes.
>
> For extended functionality, it is up to the designer for a particular web
> app
> -- they can choose to subclass the controller servlet and implement
> functionality there, or stick with the generic one and add things in
> servlet
> context attributes (or share them in some other manner). Each app makes
> that
> choice totally independently.
>
>
> >
> > > >
> > > > Currently I am just having the controlling servlet extract
> references to
> > > > these beans from the application scope and passing them as
> > > parameters to the
> > > > action class perform( ) method.
> > > >
> > >
> > > Doesn't that mean that the method signature for perform() changes for
> each
> > > action? That would seem to require changes to the controlling
> > > servlet as you add
> > > new actions that require different signatures. In my model, the
> > > call to perform()
> > > is the same for all actions.
> > >
> >
> > I think Drew meant that each perform() method has the same signature,
> where
> > the parameter list includes all the various services.
> >
> > ...
> >
> > > There is also a non-zero
> > > amount of work
> > > allocating a new Java object for the collection, and then filling
> > > it in -- and you
> > > are paying this cost on every single request.
> > >
> >
> > I think Drew meant that there is but one services Hashtable which gets
> > initiated at some point in the beginning and gets passed around to every
> > invocation of perform(). Thus no additional per-request object creation.
> >
>
> Even if that's the case, then every time you add a new global service you
> have
> to go modify your controller servlet to put one more thing into the
> hashtable.
> You should not have to do something like that.
>
> In the design I suggested, a new service object can be added to the
> servlet
> context attributes, say, and a new (or enhanced) WebAction instance can
> refer
> to it, with zero changes to the controller servlet itself.
>
> >
> > > From a design viewpoint, there's an additional question. Let's
> > > say you've built a
> > > particular web action, and you want to enhance it. But now, it needs
> an
> > > additional resource out of the servlet context attributes that
> > > was not required
> > > before. Do you need to go back to your controller servlet and
> > > add an additional
> > > services object to the collection?
> >
> > Unless you make up a mechanism to add services at runtime (either during
> > startup in a config file or dynamically somehow), I don't see how one
> gets
> > around the problem that: for every application-wide service that you
> add,
> > you need to change some core code somewhere (define "core code" as
> > non-WebAction). Either by adding a name/value pair to a Hashtable
> (either a
> > self-defined one or ServletContext's) or changing a factory method.
> >
>
> The mechanism I use is to put shared stuff in servlet context attributes.
> As
> described above, I can add a new service simply by doing that, and it
> becomes
> available to all web actions -- having to change the controller servlet as
> well
> (to add it to a services collection) is the kind of thing that will be
> forgotten and cause bugs.
>
> This approach also works well for shared objects that are added after
> initialization of the app -- they become available, instantly, as soon as
> they
> are created. I don't have to go back on every request and make sure I've
> copied all of the servlet context attribute objects into my Hashtable.
>
> >
> > -s
> >
>
> Craig
>
> ==========================================================================
> =
> To unsubscribe: mailto [EMAIL PROTECTED] with body: "signoff
> JSP-INTEREST".
> FAQs on JSP can be found at:
> http://java.sun.com/products/jsp/faq.html
> http://www.esperanto.org.nz/jsp/jspfaq.html
===========================================================================
To unsubscribe: mailto [EMAIL PROTECTED] with body: "signoff JSP-INTEREST".
FAQs on JSP can be found at:
http://java.sun.com/products/jsp/faq.html
http://www.esperanto.org.nz/jsp/jspfaq.html