Ok everyone, I have preliminary work done for these proposals and would
like your comments on it. If it looks like something you think belongs
in the commons, I'll go ahead and submit a patch. Currently all of the
work I've done is for J2SE5 and JSF1.2. I personally would question
backporting these utilities to 1.1, but most of them can be done with
little effort.
As for what project these would go into, IMO all of these should be in
the utilities jar. I don't really see the need to have separate
projects for the context and the configurator packages, but others can
chime in if they want. Maybe a single configurator project for BOTH the
context and config classes since both of those packages support the
configurator mechanism?
Here is the synopsis:
1.org.apache.myfaces.common.util.ClassLoaderUtils: This is a series of
utilities dealing with class loaders. It ensures the correct
classloader is used when loading classes or resources in order to avoid
issues in dealing with complex classloader environments. The "key"
piece of functionality with this class is the "getServices" method which
allows reading of the META-INF/services directory to retrieve a list of
services. This method also allows of a certain degree of influence of
the "ordering" of loaded classes though the use of the OrderedService
interface.
2. org.apache.myfaces.common.util.OrderedService: This is an optional
interface that may be implemented by services loaded by the classloader
utils. This interface allows a service to return an integer based
"priority". By default all services have a priority of "0", but
implementing this interface allows services to be loaded before or after
this default. The "list" returned from the getServices method will be
in descending order according to this priority.
3. org.apache.myfaces.common.util.ExternalContextUtils: This is a
utility class which make it easier to work with the external context,
especially in portal environments. This utility has methods to get the
content length as well as the request input stream (both of which are
missing on the ExternalContext). It also has a series of utilities to
inform the application of the type of request being use and even has
some pieces in place to handle JSR-286 although these are experimental
ATM.... This utility will work regardless of whether the portlet
classes are in the runtime classpath or not and it should automatically
handle both JSR-168 and JSR-286 containers. :)
4. org.apache.myfaces.common.context.FacesContextFactory: This class
provides a faces context that enables the configurator sub-system (see
below). It's a decorator so other FacesContextFactories could be used
in conjunction with this one. Applications or renderkits wishing to use
configurators should add this FacesContextFactory to their faces-config.xml.
5. org.apache.myfaces.common.context.FacesServletContextListener: A
simple context listener that is needed to properly execute the "destroy"
method of the configurators in portlet environments. Applications or
renderkits wishing to use this framework, at this time, should add this
to their web.xml or a tld file in the META-INF directory. Because this
logic is extremely low impact if configurators are not used, I could
possibly add this filter as part of the utilities package being
installed, but for now it must be explicitly invoked.
6. org.apache.myfaces.common.context.ExternalContextWrapper: A wrapper
for the external context that will be used heavily in the configurators.
7. org.apache.myfaces.common.config.Configurator: This is the interface
that all configurators must implement. It consists of the following
methods: init(ExternalContext), beginRequest(ExternalContext),
getExternalContext(ExternalContext), endRequest(ExternalContext), and
destroy(). These methods have a very strict contract on when they are
called and work consistently in a servlet as well as in a portlet.
Implementing configurator services can replace much of the
"ServletFilter" logic in JSF applications so that this logic will also
work in Portal environments that don't support filters.
8. org.apache.myfaces.common.config.AbstractConfigurator: An
implementation of the Configurator and the OrderedService interfaces.
It provides default functionality for all methods, making it easier to
implement a configurator by simply overriding the methods you need to.
9. org.apache.myfaces.common.config.GlobalConfigurator: This is the
master configurator and allows renderkits or applications the ability to
manually invoke all configurator services, temporarily disable those
services, and a number of other functions. It is responsible for
loading all the Configurator services and executing them at the
appropriate time according to the contract. Generally this class will
be invoked and handled automatically by the FacesContextFactory in item
#4, but making this public allows invoking the configurator subsystem to
be invoked from legacy filter code in order to maintain backward
compatibility.
Scott O'Bryan wrote:
Ok, I'm assuming at this point that we are going to have a 1.1 AND a
1.2 branch for the commons. If this is not the case some of the
following may be impossible. But I would like people's input on this
to see if it's something they would be interested in.
1. org.apache.myfaces.jsfcommons.services - A set of utilities for
loading "service" files from the META-INF/services directory in the
class path. Service files are a recommendation from J2EE as a design
pattern for supporting extendable frameworks. Essentially a services
file contains the names of all classes which must be instantiated and
returned for a particular service. Many of these files can exist for
any given service. For example, let say we have the following files
in the classpath:
jar1.jar/META-INF/service/org.apache.MyService
org.apache.myservice.impl1
jar2.jar/META-INF/services/org.apache.MyService
org.apache.myservice.impl2
Loading these services would return a list of the impl1 and impl2
objects. The cool thing about this framework is that dropping in
extra functionality is as simple as dropping a new jar in the
classpath. While this is not a JSF specific piece of functionality,
something like it is needed by the Configurators (see item #2) and I
thought it might be handy to have as a public API rather then wrapping
it up in the Configurator mechanism itself. Trinidad makes extensive
use out of services and is the "key" component to allowing us to build
the RichClient Framework off of the Trinidad core. Simply copying the
RichClient jars into the classpath gives you the extra functionality.
This would give all renderkits the ability to have this type of
"extensible" behavior.
This package could be in both JSF 1.1 and 1.2 compatible branches.
Only the 1.2 compatible branch (using J2SE5) would be able to support
generics which would increase the performance and ease of use of this
package.
2. org.apache.myfaces.jsfcommons.config - These are, essentially, and
expanded version of the Trinidad "configurators". Essentially
"configurators" allow a renderkit to do most of the tasks that are
typically done in filter (like multi-part form handling and the like)
without using a filter. Much like Tobago's implementation, the
configurator system leverages a special "FacesContext" that someone
could enable in their own jars. The configurator provides hooks that
allow execution of initialization logic to happen at various points
during an application (and request) lifetime. It even provides a
mechanism (based off of ExternalContext Wrapping) that allows
modification of the Request and Response objects. There are two real
benefits to using Configurator's as opposed to filters. The first is
that the Configurators are "configuration free". This means that a
renderkit can enable the configurator framework by simply including
the appropriate FacesContext object in their jar's faces-config.xml.
The second is that this framework will work within a portlet
environment which does not support filters in all cases and it makes a
great fit to JSR-301. One of the cornerstones of Trinidad's portlet
compatibility is the Configurator system and other renderkits should
find it easy to provide container agnostic functionality on their own
as well. How this solution differs from the one in Tobago, I believe,
is that it is generic and services based. This means that multi-part
form handling is simply one configurator service while a renderkit (or
multiple renderkits) can feel free to define their own.
Although I am not yet proposing Multi-part form handling
implementation at this time, we could use this mechanism to leverage
such a solution as Trinidad has done. The solution works great on
both local and remote portals as well as servlet environments.
This package could be used in both JSF 1.1 and 1.2 compatible branches
with the appropriate modifications.
3. org.apache.myfaces.jsfcommons.utils.ExternalContextUtils - Back
when we first started taking seriously about this project, some people
expressed interest in having Trinidad's externalContextUtils in the
commons package. This class is very simple and self contained and
handles some issues that renderkit developers may have in dealing with
a portal environment. In JSF the ExternalContext abstracts users from
having to drop down to the native request/response objects. But there
are some functions missing on the ExternalContext which require you to
load and cast the underlying request and response objects. The
problem is that with 2 different portlet request and response objects
and the servlet request and response objects, this can be cumbersome.
This utility provides some of this missing functionality as well as
has the ability to determine whether an ExternalContext contains
Portlet objects or not. The real benifit to this class, however, is
that it doesn't require the portal objects or the bridge to be in the
classpath at runtime. This means that you can develop a portlet
compatible renderkit which uses these methods, but don't need to have
the portlet-api or bridge classes present during runtime. It
currently works independantly of any bridge implementation so it
should also work in both JSF 1.1 and 1.2 and will work with in servlet
containers as well portlet containers using any bridge.
Please let me know what you guys think of these proposals and if the
"idea's" sound good I can try to flush some things out and post some
of the API's and post some more specifics to the list. If people are
NOT interrested, I won't waste the time. :)
Scott