struts-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Martin Cooper <mart...@apache.org>
Subject Re: [shale] Overall requirements for "remoting" feature
Date Wed, 28 Dec 2005 05:26:35 GMT
On 12/27/05, Craig McClanahan <craigmcc@apache.org> wrote:
>
> On 12/27/05, Martin Cooper <martinc@apache.org> wrote:
> >
> > On 12/27/05, Craig McClanahan <craigmcc@apache.org> wrote:
> > >
> > > A recent RFE[1] in our issue tracking system, plus discussions with
> > > several
> > > folks at the recently completed ApacheCon US conference in San Diego,
> > has
> > > motivated me to attempt a distillation of where I think Shale's
> support
> > > for
> > > "remoting" should go.  For comparision (since there isn't any
> > > feature-related documentation to speak of), I'll start with a brief
> > > description of the current functionality, and then talk about what
> seems
> > > like a good idea for the future.
> > >
> > >
> > > CURRENT REMOTING FUNCTIONALITY:
> > >
> > > Shale's application level functionality is supplied by a Servlet
> filter
> > (
> > > org.apache.shale.faces.ShaleApplicationFilter).  One of the features
> of
> > > this
> > > filter is that it executes a standard Commons Chain[2] chain of
> commands
> > > for
> > > each request.  In turn, the default chain that is executed includes a
> > > command (org.apache.shale.remote.RemoteCommand) that is invoked if the
> > > request URL matches an extension mapping (default is "*.remote").  In
> > > turn,
> > > this command performs the following tasks:
> > >
> > > * Creates a ShaleWebContext instance (extension of Commons Chain
> > > ServletWebContext implementation)
> > >   to represent the "context" passed to each command.
> > >
> > > * Extracts the context relative path such as "/foo/bar.remote" from
> the
> > > servlet request path properties.
> > >
> > > * Looks for a corresponding Commons Chain command in a catalog named
> > > "remote".  If there is such a
> > >   command, invoke it (passing in the constructed
> ShaleWebContext).  This
> > > command is responsible for
> > >   constructing a response, which can be done by the usual
> > > RequestDispatcher.forward() call -- normally
> > >   to a JSP page that might use JSTL and EL expressions -- or
> > programmatic
> > > construction via an
> > >   instance of org.apache.shale.remote.ResponseWrapper that acts much
> > like
> > > a
> > > standard JSF ResponseWriter.
> > >
> > > * Several default command implementations are provided, including one
> > that
> > > invokes an arbitrary JSF
> > >   value binding expression and stores the result as a ShaleWebContext
> > > attribute.
> > >
> > > While this functionality does support achieving the original goal of
> > this
> > > portion of Shale (providing back-end support for AJAX enabled JSF
> > > components), it has several issues, including:
> > >
> > > * Bound to Servlet API objects, so not directly portable to a portlet
> > > environment.
> > >
> > > * As described in [1], requires quite a lot of work (plus an
> > understanding
> > > of
> > >   Commons Chain itself) simply to map an incoming URL to a piece of
> > > business
> > >   logic that produces the response.
> > >
> > > * Does not directly support serving of static resources (images,
> > > JavaScript
> > > files,
> > >   stylesheets) without mapping each individual resource as an
> individual
> > > command.
> > >
> > >
> > > PROPOSED REMOTING FUNCTIONALITY - GOALS:
> > >
> > > The remoting support in Shale should be focused on providing
> > > client-technology-agnostic mapping of incoming HTTP requests to server
> > > side
> > > dynamic logic for AJAX-enabled widgets (including AJAX-enabled
> > JavaServer
> > > Faces components), plus an easy way to serve static resources (from
> > either
> > > the web application itself or from class loader resources) that the
> > client
> > > side widgets might require.  This support must operate in either a
> > servlet
> > > or portlet environment, and require minimal (ideally none in the
> > simplest
> > > case) configuration at the application level.
> > >
> > >
> > > PROPOSED REMOTING FUNCTIONALITY - IMPLEMENTATION STRATEGY:
> > >
> > > Shale will provide a PhaseListener implementation that receives
> > > notification
> > > after the Restore View phase of the request processing lifecycle has
> > been
> > > completed.  At this point, a "view identifier" (a context-relative
> path
> > to
> > > the resource to be processed) will have been identified.  This view
> > > identiifer will be compared to one or more preregistered mapping
> > patterns
> > > --
> > > if the view identifier matches, this request will be processed by a
> > > corresponding processing logic module, instead of following the usual
> > JSF
> > > request processing lifecycle.
> > >
> > > Registering processing logic modules will be easy and extensible.  To
> > > minimize the effort required to assemble an application, however, the
> > > following standard processing logic modules will be provided:
> > >
> > > * Serve a static resource corresponding to this view identifier, from
> > the
> > > web application's
> > >   static resources (i.e. starting from the document root).  To be
> > > consistent
> > > with a servlet
> > >   container's standard behavior, no such resources will be served
> > directly
> > > from the "/WEB-INF"
> > >   or "/META-INF" paths.
> >
> >
> > I'm not sure I understand why I would want to use this. Requests for
> > static
> > content such as this would be processed more efficiently by letting the
> > container treat them as static content - or, even better for a high load
> > app, moving these files off the web container completely, and into a
> > fronting HTTP server.
>
>
> There are multiple perspectives on why this might actually be a good idea.
> Consider that, as an application deveoper, want to use some "widgets" in
> my
> application that require external JavaScript and/or stylesheet resources.
> Note that these widgets don't have to be JSF component libraries ... the
> issues are more generic than that.
>
> * From the widget developer's point of view, there is no standard
> mechanism
>   to publish static resources required by my widgets, such that they can
> be
>   served up as needed, without either reserving portions of the context
> relative
>   namespace and/or defining a special processing servlet for those
> resources
>   that can be mapped to some appropriate patterns.  Either technique is
> tedious
>   and error-prone.
>
> * Requiring the application developer to "reserve" parts of the context
> relative
>   namespace is unfriendly.  What happens if I want to include two
> different
>   widgets that have been hard coded to the same subdirectories?  Better if
> the
>   widget libraries have a way to programmatically determine the resource
> paths
>   for their dependent resources.


I understand what you're saying in the above two points. I'll just point out
that in the last several years of developing highly dynamic (i.e. boatloads
of JavaScript) web apps, I haven't encountered _any_ of the issues you
mention. We've simply reserved a subtree off the context, and configured
each widget library to point to the relevant location. It has been neither
tedious nor error-prone.

Furthermore, if a widget library has been hard-coded to a particular
location, it's clearly poorly designed, and you're likely to have much
bigger issues with it than just putting things in the right place... ;-)

* Even without name clashes, requiring the application developer to manually
>   copy resources into the output web application structure increases the
> compexity
>   of the Ant or Maven build script being used, versus simply dropping the
> widget
>   JAR into WEB-INF/lib that he or she will have to do anyway.  The same
> argument
>   applies to approaches that require the application deveoper to configure
> a
> special
>   servlet for serving such resources (to get around the hard coded names
> problem).


This is a one-off addition to your Ant or Maven build file, is usually at
the beginning of the project, and is typically a single copy command. If
you're changing the set of widget libraries along the way, then you may have
more work to do, but that wouldn't be such a great idea anyway, for a
variety of reasons.

I'm not arguing against embedding static resources inside of jar files,
since that is clearly a good way of providing a consolidated widget library.
In my experience, though, I've found that deploying as much of the
application as possible as a single compressed file (e.g. foo.js.gz)
provides the best performing app from a client perspective, and it is *very*
worthwhile doing some work up front in the build process to make that
happen. (If you want to see an example of the opposite of this, just take a
look at the Rialto demo. It's a nightmare.)

* Performance differences, compared to what you suggest (letting the
> container serve
>   static resources "in the usual way") will only occur if (a) you're not
> using a pure Java
>   servlet container -- the code that will implement this technique is
> doing
> essentially
>   what Tomcat's DefaultServlet does, for exampe, to serve static resource
> files, and
>   (b) the native implementation of serving static file resources is
> actually
> faster enough
>   to matter.  Historically, this has been a no brainer, but recent
> improvements the performance
>   of pure-Java containers, plus an increased emphasis on ease of
> development
> versus an
>   absolute focus on performance, makes this much more of a values-based
> decision versus
>   one that should be dictated primarily, or solely, by performance
> considerations.


If an app has a lot of static resources, as well as a lot of stuff that
needs to run in the web container, it can make a big difference to front the
web container with an HTTP server running on a separate box, so that
requests for static content never even reach the web container, leaving that
box to deal with only what it has to. That's what I was referring to.

--
Martin Cooper


* Serve a static resource corresponding to this view identifer, from the
> > > class loader resources
> > >   of this web application.  For example, this facilitates component
> > > libraries that wish to make
> > >   JavaScript files available to the client pages that utilize those
> > > components, without requiring
> > >   *any* specific configuration in web.xml, or manual assembly of
> > resources
> > > into a reserved
> > >   directory of the web application.
> >
> >
> > While I do understand how this would simplify the deployment of
> > components,
> > again performance will suffer if this is used extensively.
>
>
> That is a historically accurate assumption.  However, in *many* current
> scenarios it is either no longer true (due to improvements in the
> performance of pure Java servlet containers) or not relevant in the
> overall
> performance picture (because bottlenecks are dominated by the typical
> constraints on database performance and network traffic, not on CPU
> overhead
> on the container).
>
> That's not to say there are *no* circumstances in which the serving of
> static resource has critical impact on the overall performance of an
> application.  It's just to say that, IMHO, the 80% scenario says "it just
> doesn't matter".
>
> Perhaps there
> > could be some way to have components extract their static resources at
> > startup time, so that they could subsequently be treated as static by
> the
> > web container? Such resources would be harder to deploy to a fronting
> HTTP
> > server, but not impossible if a suitable extraction method can be
> defined.
> > But perhaps that would have to be dealt with in the JSF spec.
>
>
> It would indeed be nice to have a portable mechanism like that.  But it
> doesn't exist in current specs, and (in practical terms) could not exist
> until some Servlet spec after the Java EE 5 round (this is too generic a
> problem to restrict to only solving it in the JSF spec).
>
> And, if such a mechanism did come into being in some future spec, there's
> nothing that stops the remoting implementation support here from taking
> advantage of it, without impacting the APIs used by widgets to reference
> those resources :-).
>
> --
> > Martin Cooper
>
>
> Craig McClanahan
>
>
> * Map the view identifier (such as "/foo/bar.remote") to a method binding
> > > expression (such as
> > >   "#{foo.bar}"), identifying a public method that will be invoked to
> > > create
> > > the response for this
> > >   HTTP request.  The bean containing this method can be a managed
> bean,
> > > and
> > > thus created
> > >   on demand if needed.  The method itself can call
> > > FacesContext.getCurrentInstance() to retrieve
> > >   the per-request state information for this request (since we are, by
> > > defnition, performing a JSF
> > >   request at this point), and can use any desired JSF facilities
> > > (including
> > > the standard ResponseWriter)
> > >   to prepare the actual response.
> > >
> > > * (Optional) alternative dynamic execution mapping to execute a
> Commons
> > > Chain command
> > >   (essentially equivalent to the current functionality, and/or a
> tie-in
> > to
> > > Struts Action Framework 1.3.x
> > >   type processing logic).
> > >
> > > * (Optional) alternative dynamic execution mapping to execute an XWork
> > > action (essentially
> > >   equivalent to what WebWork currently does for mapping incoming URLs
> to
> > > business logic).
> > >
> > > In addition, the configuration information mapping incoming URL
> patterns
> > > to
> > > corresponding processing logic modules will be made available in a
> > simple
> > > JavaBean stored in application scope, so that dynamic code (such as
> the
> > > renderer for a JSF component wanting to utilize these facilities) will
> > > know
> > > what kind of context relative URL is required).
> > >
> > > Given these capabilities, and assuming some default mappings, one
> could
> > > have
> > > all of the following facilities with *zero* application level
> > > configuration,
> > > other than including the appropriate Shale library into /WEB-INF/lib:
> > >
> > > * For a context relative URL of the form "/web/foo/bar.js", serve the
> > > static
> > > resource at "/foo/bar.js"
> > >   with appropriate content type settings.
> > >
> > > * For a context relative URL of the form "/classpath/foo/bar.css",
> serve
> > > the
> > > resource "/foo/bar.css"
> > >   from the webapp classpath (typically, a resource file embedded in
> the
> > > JAR
> > > file containing the
> > >   component whose renderer requested this resource), with appropriate
> > > content type settings.
> > >
> > > * For a context relative URL of the form "/execute/foo/bar", execute
> the
> > > bar() method on the managed
> > >   bean named "foo".  This method will take total responsibility for
> > > producing the output, so it can do
> > >   whatever it needs.
> > >
> > >
> > > SUMMARY:
> > >
> > > Thoughts?
> > >
> > > Craig
> > >
> > > [1] http://issues.apache.org/bugzilla/show_bug.cgi?id=38050
> > > [2] http://jakarta.apache.org/commons/chain/
> > >
> > >
> >
> >
>
>

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message