My implementation erroneously did not have the "fix" applied to the
html:rewrite tag, so here it is for those interested:
http://users.erols.com/sukachevin/struts/MultiRewriteTag.java
-- Stoehr
-----Original Message-----
From: Sukachevin, Stoehr
Sent: Wednesday, February 28, 2001 09:43 PM
To: '[EMAIL PROTECTED]'
Subject: RE: Multiple ActionServlet instances in a web app
I completed the implementation of what I said I was going to do (see email
below), so if anyone is interested in seeing the code, get
"http://users.erols.com/sukachevin/struts/multi-struts-src.zip" (the
javadocs that were generated from the source are in
"http://users.erols.com/sukachevin/struts/multi-struts-javadocs.zip").
Please note that the "fix" tries to be as hands-off as possible w.r.t. the
original classes that are subclassed so that the "fixed" subclasses can
remain valid as the original classes evolve. Keep in mind that the original
intent of these subclasses are to put into place a "patch" to support
multiple action servlet instances in the same web application. While the
ideas behind this code as an ultimate fix to Struts remain valid, what you
see implemented here would not make sense to be used as-is for an ultimate
fix because of the hands-off approach that I took. (Assuming that one liked
the ideas of the fix, then there would be better ways of implementing it by
modifying and enhancing the base classes of the various custom tags, for
example, rather than simply extending particular tags in a more hands-off
approach.)
The following is a summary of the ideas for the fix:
[1] We assume that as a default, only one action servlet instance will be
used in a web application. Only if you want to deploy more than one
instance in a web app do you need to specify a little more information in
the web.xml file and your JSP files.
[2] To support multiple servlet instances, each instance needs to be
reference-able by a name. For my implementation, I simply use the servlet
instance name that is specified in the web.xml file (a different
implementation could define a new servlet init parameter instead).
[3] For the Struts custom tags, a new attribute can be specified with a name
(see [2]) that tells which servlet instance the tag is related to. If this
attribute is not specified for a given Struts tag, then the attribute value
of a Struts ancestor tag would be used as a default. For my implementation,
the new attribute is called "context", and I actually do not make every
single Struts custom tag aware of this new attribute -- only the ones where
it is currently applicable and makes sense. For example, the
<struts-html:form>, <struts-html:link>, or <struts-html:html> tag.
[4] One servlet instance can be marked as the default one so that tags only
need to specify the new attribute (see [3]) if they are related to a
different servlet instance than the default one. For my implementation,
first of all, the action servlet you would deploy is
org.apache.struts.action.MultiActionServlet; second of all, you specify
"false" for the new "default" servlet init parameter of the servlet instance
(the parameter defaults to "true" if not specified because of [1]). So if
you have a servlet instance that is the default one, then [3] is not
necessary for a JSP page that is related to the servlet since it is the
default one.
Using my "fix", you could do the following as an example:
[a] Deploy two action servlets in the web.xml file. Use
"org.apache.struts.action.MultiActionServlet" as the servlet class and
specify "false" for the "default" init params of each servlet (we are not
going to use this feature of having a default for this example). Remember
the servlet names you use for the two servlets -- for the sake of this
example, say you named the servlets "SubsystemOne" and "SubsystemTwo". (See
[1], [2], and [4].)
[b] I've included in the "multi-struts-src.zip" file modified
"struts-bean.tld", "struts-html.tld", and "struts-logic.tld" files in the
"lib" directory -- they are actually called "struts-*-multi.tld" in the ZIP
file. Use these "struts-*-multi.tld" tag libraries instead of the original
ones so that the subclasses I created will be used for the appropriate tags
instead of the original classes. (Note is not a file for
"struts-template.tld" since my implementation of the fix did not have to
modify any of the tags in that library.)
[c] In a JSP file, assume that you are going to use some Struts tags that
are related to the second servlet called "SubsystemTwo". Simply use the
<struts-html:html> tag and include the "context" attribute with the
"SubsystemTwo" value: <struts-html:html context="SubsystemTwo"> . All
Struts tags in the HTML tag will now be related to the "SubsystemTwo"
servlet.
[d] In another JSP file (this example is a little bit contrived), assume
that you are going to use two <struts-html:form> tags, but the first one is
related to the first servlet, and the second tag is related to the second
servlet. In that case, you can include the appropriate "context" attributes
for the two <struts-html:form> tags individually: <struts-html:form
name="x" context="SubsystemOne"> and <struts-html:form name="y"
context="SubsystemTwo"> . (Alternatively, you could have <struts-html:html
context="SubsystemTwo">, <struts-html:form name="x" context="SubsystemOne">,
and <struts-html:form name="y">. This would be equivalent to the first
case.)
-- Stoehr
-----Original Message-----
From: Sukachevin, Stoehr
Sent: Monday, February 26, 2001 10:31 AM
To: '[EMAIL PROTECTED]'
Subject: RE: Multiple ActionServlet instances in a web app
"Craig McClanahan" wrote:
> Because this question comes up occasionally, I would be interested
> in understanding more about what might motivate a desire to have
> more than one instance of the controller servlet. Do you have some
> particular use cases in mind where this would be helpful?
(First of all, I agree with Elod Horvath's comments below.)
The main motivation behind why I want to have more than one
instance of the controller servlet is for "configuration
management" reasons in a large-scale web application (being
implemented by many developers) which Elod alluded to.
Irrespective of whether Struts as a framework should support
multiple controller servlets or not (my vote is yes), I would like
at the very least to subclass various components of the framework to
support multiple controller servlets. (I am interested in doing so
without too much deviation from the main code because of time
constraints and less maintenance of the subclasses as the main
classes of Struts evolves.)
The main issue I see that is preventing multiple controllers is that
the keys used by the ActionServlet for the object attributes stored
in the servlet context remain constant for each instance of the
servlet (e.g., as you all know, Action.MAPPINGS_KEY,
Action.SERVLET_KEY, Action.FORM_BEANS_KEY, etc.).
I would like to extend the ActionServlet with a subclass that
uses the servlet instance name as part of another set of attributes
in the servlet context that correspond to the already existing
attributes. For example, when the servlet sets the action mappings
object, not only will it set an attribute in the servlet context
with the key Action.MAPPINGS_KEY, but it will also set an
additional attribute for the same mappings object with the key:
Action.MAPPINGS_KEY + '.' + getServletName()
With these additional attributes in the servlet context, all the
various Struts custom tags that use these "application scope"
objects set by the servlet could be subclassed to accept an optional
"context" property (that the JSP developer can assign the servlet
name to) which, when specified, will be used by the subclasses to
formulate the correct key. If the optional "context" property is
not specified, then the subclasses can revert to the usual behavior
of using the original keys.
The intent of the above changes is to remain compatible with the
normal use of Struts when there is only one controller servlet,
yet allow one to use Struts with multiple controller servlets as
well with the only penalty being that your JSP code that uses
certain Struts custom tags would need to specify the additional
"context" property (definitely not ideal, but I could live with
it).
So I was wondering if I could get some feedback/confirmation from
you all about the following steps that I will be doing to implement
the above:
[1] For the subclass of ActionServlet, where ever the following
keys are used to set an attribute in the servlet context,
set another attribute for the same object with the key
"Action.MAPPINGS_KEY + '.' + getServletName()":
Action.DATA_SOURCE_KEY
Action.FORM_BEANS_KEY
Action.FORWARDS_KEY
Action.MAPPINGS_KEY
Action.MESSAGES_KEY
Action.SERVLET_KEY
[2] For the following Struts custom tags, create subclasses
that accept a "context" property (not sure if "context" is the
best name for the property) so that if specified, the
appropriate keys for the "application scope" objects placed
in the servlet context by the servlet in [1] will be used
to retrieve the objects (I've omitted the "org.apache.struts."
prefix, and have not included the v0.5 "struts-form" tags):
taglib.bean.IncludeTag
taglib.bean.MessageTag*
taglib.bean.StrutsTag
taglib.html.ErrorsTag*
taglib.html.FormTag
taglib.html.ImageTag*
taglib.html.ImgTag*
taglib.html.LinkTag
taglib.html.OptionTag*
taglib.logic.ForwardTag
taglib.logic.RedirectTag
Note that additional logic will be implemented in the tags
marked with asterisks (*) since they use the Action.MESSAGES_KEY
key indirectly via the default value for the "bundle" property
[which is used as a parameter for the util.RequestUtils#message(...)
methods].
Additional enhancements could be:
[A] Specify an additional servlet init parameter for the
ActionServlet subclass called something like "default" which
defaults to "true". If this parameter is "false", then
for item [1] above, the servlet will not store the objects
in the servlet context with the original keys. This allows
the original keys to be the "default" keys for the particular
servlet whose "default" parameter is "true" **and** allows that
servlet to not have to be the last one to be loaded (if you
recall that for the original implementation of the
ActionServlet, the last instance loaded by the web container
will have its objects be the ones ultimately in the
servlet context simply because all instances used the same
keys during initialization).
[B] Apply item [2] above to the appropriate v0.5 "struts-form" tags:
taglib.ErrorsTag
taglib.ForwardTag
taglib.IncludeTag
taglib.Link1Tag
taglib.LinkTag
taglib.MessageTag
-- Stoehr
-----Original Message-----
From: Elod Horvath [mailto:[EMAIL PROTECTED]]
Sent: Monday, February 26, 2001 08:35 AM
To: [EMAIL PROTECTED]
Subject: Re: Multiple ActionServlet instances in a web app
"Craig R. McClanahan" wrote:
>
> "Sukachevin, Stoehr" wrote:
>
> > In looking at some of the more recent source code for v1.0, it appears
that
> > since the ActionServlet caches a lot of objects in the servlet context,
like
> > action mappings, app resources, etc., the ActionServlet was not designed
to
> > allow multiple instances of the servlet to be deployed in a single web
> > application.
> >
> > In other words, if for whatever reason, one wanted to deploy multiple
> > ActionServlets in a single web application so that each servlet can deal
> > with its own set of action mappings, etc., this would not work with the
> > current implementation of the ActionServlet.
> >
> > Is my understanding correct?
> >
>
> That is correct. Within the context of a single web application, the
design
> assumption is (and, at least as far as intent goes) always has been, that
there
> will be exactly one instance of the controller servlet. Separate web
apps, of
> course, are completely independent of each other, and will have their own
custom
> configured instances.
>
> Because this question comes up occasionally, I would be interested in
> understanding more about what might motivate a desire to have more than
one
> instance of the controller servlet. Do you have some particular use cases
in
> mind where this would be helpful?
>
I'll take a stab at this...I've been meaning to for a while but
have been too busy to sit down and write up my issues.
First off, I'll mention that this single controller issue
is actually a stopper in my current struts based project. My day
job is for a financial institution. We're currently prototyping the
move of our web based commercial cash management suite
offering from ASP to JSP [hopefully] based on struts.
The site is a portal like collection of sub-applications
which share a common integrated signon, environment,
and "shell" framework. Currently, we have around 7
production sub-applications providing a range of services with
several more in active development.
Each sub-app is logically independent from the others and is usually
developed/maintained by different groups. They must work and play
well together but cannot be developed, configured, or deployed in
a monolithic fashion.
(Reference a prior mailing on the struts user list that I wrote up
in early January detailing my site's macro structure:
<
http://www.mail-archive.com/struts-user@jakarta.apache.org/msg01823.html
>
)
Because the sub-apps must cooperate and share certain common
components including sign-on in the application and session contexts,
they _cannot_ be deployed as different webapps. Because of the
number and size of the logically and functionally independent sub-apps,
they should be developed/deployed as separate controllers (which may
have
unique customizations required to support the peculiarities of the
particular sub-app).
As an application framework, struts should strive to minimize the
amount and type of restrictions placed on the apps using it. Forcing
deployment assumptions such as one controller servlet per webapp
oversteps the bounds of what the framework should do. Yes, some
application designs are not really affected by the one controller
restriction, but, some apps are not all apps.
(I've pasted quotes from previous emails on this subject below so
that I can respond in context.)
> The reasoning is that some resources are truly application wide,
> and there is zero benefit in duplicating them.
> For example,
> because servlets run in a multithreaded environment, having more
> instances of them would not make it run any faster.
This point I don't dispute (except for the 'zero benefit' part :).
Speed isn't necessarily the issue -- the issue is logical
organization for development, maintenance, and production support.
I don't really dispute the above statements, but
I also don't think that having multiple controllers contradicts them
either. Multiple controllers should be able to coexist non-
destructively.
>
> Also, a single controller servlet gives you a central point of
> control where you can guarantee that functions you want
> performed happen on every single request.
Regardless of whether you're running a single controller or
multiple ones, they're running off the same code base so these
"certain" functions will happen anyway -- just not in one specific
monolithic object.
> If you have more than one instance of ActionServlet (even if it is
subclassed)
> in the same webapp, you will run into problems if you depend on any of the
> [below] -- which is almost impossible to avoid in a Struts based
application.
> For example, the only mappings that will be visible are those loaded from
the
> last struts-config.xml file that was processed, because the ActionMappings
> collection is a global variable per webapp.
>
I realize that it may actually be somewhat difficult at this point
to abstract struts to allow multiple controllers in a webapp --
quite a few custom tags rely on it and already developed struts
applications may be making making use of and depend on the
keys and structures used to store the global servlet context
resources. Maybe if these servlet context attributes are managed
more cooperatively (with the assumption that multiple controllers
can access/initialize them)...Perhaps giving each controller a
unique app ID which it can use in accessing/identifying its own
resources (this is actually what I did in my prototype for my custom
resources)
> The controller servlet initializes the following servlet context
attributes,
> under the keys identified in square brackets:
>
> * The generic DataSource object if you have initialized one
> under the default key. [org.apache.struts.action.DATA_SOURCE]
I cannot, unfortunately, provide any commentary (besides this dodge :)
on the generic DataSource since I have in no way used it or needed
it in my development work.
>
> * The ActionFormBeans collection that is the lookup table for everything
> configured in the <form-beans> section of your struts-config.xml file.
> [org.apache.struts.action.FORM_BEANS]
I see no reason why this collection can't be shared among multiple
controllers. The first one [controller] to initialize creates the
collection -- the remaining controllers perhaps just add to it. The
real problem at this point is sub-application namespace collisions
with respect to the names given to the form beans. This namespace
conflict can be resolved by using some variety of the controller unique
app ID mentioned above to qualify the names.
>
> * The ActionForwards collection that is the lookup table for everything
> configured in the <global-forwards> section of your struts-config.xml
file.
> [org.apache.struts.action.FORWARDS]
Ditto for this collection. Since they are "global forwards", maybe no
special care needs to be taken related to namespace collisions. They
should be, as you say, global and accessible to all controllers. Then
again, some sort of namespace qualification may be needed anyway.
>
> * The ActionMappings collection that is the lookup table for everything
> configured in the <action-mappings> section of your struts-config.xml
file.
> [org.apache.struts.action.MAPPINGS]
And now we come to marrow of the problem -- the action mappings.
I do think that multiple controllers can cooperate here by
qualifying their mappings through the app ID concept described above.
This is certainly a solvable problem.
>
> * The MessageResources implementation for your application
> resources object. [org.apache.struts.action.MESSAGE]
And again here. I can see where having a central message resources
repository may be convenient for some, but what if that repository
actually spans 10 very different sub-applications and becomes so
large as such that it is unwieldy to maintain. Not to mention the
configuration nightmare of keeping it up to date in production with
changes coming from all angles. Best to split it apart along sub-app
lines. Let the developers/maintainers of the individual sub-apps
be responsible for their messages and their messages alone -- no
cross talk, no conflict.
-------------
I hope I've been able to present my concerns and arguments in
at least a partially understandable way. I am open to discussion
on this, but unfortunately, I feel at this time that the end result
should be that struts not impose the ONE controller solution on us.
Although others may disagree, I cannot say that struts 1.0 is
ready for final release until the single-controller limitation is
removed. Removing the limitation *may* require some changes that
are not backward compatible and therefore should be made sooner
rather than later.
e
--
_______________________________________________________________________
Elod Horvath ('e') / ITFAIS Records (http://www.itfais.com/)