struts-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Michael Jouravlev" <jmi...@gmail.com>
Subject Re: Private Actions Mappings?
Date Thu, 07 Sep 2006 17:49:07 GMT
Martin, I am really interested in those gnarly bits of including a
Struts action, because I use this approach a lot. Maybe what I do
helps me to somehow avoid the reefs, but for the sake of broader
education I would really be interested in possible issues.

I will try to reconstruct what happens with including a Struts action.
Please correct me if/when I get wrong.

(1) First, the JSP dynamic include mechanism is a legitimate way of
building composite pages. It should work properly with no regards to
what is included, whether a Struts action or a JSP file. Tomcat's
Jasper compiler uses RequestDispatcher.include for <jsp:include>
action:

  if(flush && !(out instanceof BodyContent))
      out.flush();
  String resourcePath = getContextRelativePath(request, relativePath);
  RequestDispatcher rd = request.getRequestDispatcher(resourcePath);
  rd.include(request, new ServletResponseWrapperInclude(response, out));

Such straightforward usage of RequestDispatcher.include does not work
well with Struts actions because a Struts action usually performs a
forward to JSP. Forwarding from an included resource does not work
because servlet spec states explicitly that container should flush the
output stream after forwarding. Therefore the content of a composite
page that follows the included Struts action is not rendered.

This is not that bad actually. Resin renders such a composite page
successfully, apparently they went a little bit farther than SRV spec.
Tomcat, on the other hand, renders a partial page, cutting out the
content that follows an included action, exactly by the book. So using
standard <jsp:include> tag does not work well for Struts actions. Oh
well, but <c:import> works!

In Tomcat a resource imported with JSTL <c:import> results in:

  ImportResponseWrapper irw =
    new ImportResponseWrapper((HttpServletResponse)pageContext.getResponse());
  rd.include(pageContext.getRequest(), irw);
  pageContext.getOut().print(irw.getString());

Instead of writing directly to original response and flushing it,
ImportSupport tag uses a separate response wrapper and adds the output
of included resource to original stream. This allows using forwarding
in an included resource and makes including of a Struts action
possible.

The verdict on dynamic inclusion: Apache implementation of JSTL spec
allows to include a resource that forwards to another resource, like a
Struts action forwarding to JSP page. Will this work with non-Apache
JSTL implementation? I don't know, frankly I haven't read JSTL spec.
This may be a potential issue. But it seems that Apache implementation
is the industry standard, Sun's website links to Apache when one wants
to download JSTL implementation. So I am pretty confident about
including a Struts action with a <c:import> tag.

(2) Repeating the request processing sequence, by container. This
should work on all containers for all types of resources, so I don't
see how including a Struts action is worse than including a JSP file.
If a container behaves differently, by executing or not executing
filters for included resources, it should behave the same way for JSP
file or for a Struts action.

(3) Repeating the request processing sequence, by Struts. Struts will
repeat the whole command chain for an included request. Aside from
extra processing time, how bad is it? Right off the bat I can see the
only major problem with instantiating and populating ActionForms.

First problem is having the same ActionForm referred to in a composite
page as well as in included action. If the ActionForm is defined in
different scopes, it will be recreated. Long ago I experimented with
chained actions having ActionForms in different scopes and I agree
that the result did not exactly turn as I predicted. So one should use
the same scope for the same-named actionform to avoid "gnarly issues".
If an ActionForm is in the same scope for both actions, it will be
repopulated. So what? This seems normal to me, at least for the way
how Struts works, and this is documented.

On the other hand, composing a page out of actions is not exactly the
same thing as chaining. I doubt that one would use the same actionform
for composite page itself and for an included action. I see included
actions as standalone components, they should not share their parts.

Another issue is messages. Currently messages are bound to scope, not
to an action. This is just wrong. Messages should be bound to an
ActionForm, messages should be *stored* in an ActionForm. This makes
things simple. ActionForm is an UI object that represents business
data. ActionForm also contains messages related to this data. I think
this is logical. I am not going to change how messages are handled
now, but I would like to add new messages object, that is a property
of an ActionForm.

Wrote a lot... What did I miss or get wrong?

On 9/7/06, Martin Cooper <martinc@apache.org> wrote:
> On 9/6/06, Michael Jouravlev <jmikus@gmail.com> wrote:
> >
> > On 9/6/06, Martin Cooper <martinc@apache.org> wrote:
> > > The action is (intended to be) the class that handles the entire
> > > request, whether that involves parcelling out the work to other classes
> > or
> > > not. An action was designed to be the end point of the request, not one
> > of a
> > > set that handles the request in collaboration with each other.
> >
> > The SS-18 ballistic missile was created to deliver a dozen of nuclear
> > warheads to another continent. Now it is used to launch satellites
> > into orbit. I don't see a problem in using something in a way it was
> > not intended to be used.
> >
> > > It is the nested invocation of
> > > the request dispatcher that causes all of the issues with (traditional)
> > > action chaining. It's the request dispatcher that may or may not execute
> > > filters, depending on the container and J2EE version you are running. It
> > is
> > > the request dispatcher that will combine request parameters from the
> > > original request with those of the include or forward, possibly
> > occluding
> > > what you want to see. Those are where the gnarly bits lie.
> >
> > These are all good arguments against composing a page out of
> > action-based components. Still I don't see a *really* serious problem
> > here. Yes, parameters will be combined. Yes, request dispatcher will
> > do the same work several times for one request, so what? Filters,
> > well, I haven't thought about them... Still, I don't want to dismiss
> > the composition idea just because of "gnarly bits" of implementation
> > ;)
>
>
> For six years or so, I've watched people repeatedly shoot themselves in the
> foot becuse they think they want to chain actions and they _don't know_ the
> consequences or their - uh - actions. The serious problem is that many -
> perhaps most - developers have no idea what is going on under the covers,
> and they _will_ get into problems with chaining actions, and will have no
> idea _why_ they are getting into problems. There's no way I want to see us
> encouraging the use of an anti-pattern that is an anti-pattern for very good
> reasons. Just because it _can_ be done doesn't mean it _should_ be done. We
> are here to help users to build their applications as simply as possible.
> Using techniques that have traps and pitfalls that are easily stumbled upon
> is not a good way to do that.
>
> --
> Martin Cooper

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


Mime
View raw message