Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [jetty-dev] Servlet-3.0 WebApp configuration

I've been fleshing out the new Configuration mechanism a little more.
This post is to report progress and see if anyone has anything they
want to contribute to the discussion.

Here's what I've got for the Configuration interface:

public interface Configuration
{
   //Called first
   public void preConfigure(WebAppContext);
//Called second
   public void configure(WebAppContext);

   //Called third
   public void postConfigure(WebAppContext);

   //Called when webapp is being stopped/destroyed
   public void deconfigure(WebAppContext);
}


The Configuration implementations need to be able to work in sequence and share data structures - that will be accomplished by setting context
attributes. But, we also need to make them independent enough so that
you can eliminate unneeded steps. For example, you might not want
to use annotations, so you can eliminate the annotation processing
step. Or you might not want to use JNDI, so you can eliminate that
step.

Here is the breakdown so far. These still need more work, but the general direction is there:



TmpDirConfiguration
-------------------
preConfigure:
* set up a tmp dir for the webapp
configure:
* adjust if work dir in unpacked webapp
postConfigure:
deconfigure:
* remove tmp dir if necessary


UnpackConfiguration
-------------------
preConfigure
* unpack war
configure: postConfigure:
deconfigure:
* clear list of jars


WebInfConfiguration
-------------------
preConfigure:
* save list of WEB-INF/lib/*.jar
configure:
* put WEB-INF/classes/* and WEB-INF/lib/*.jar onto webapp classloader
postConfigure:
deconfigure:
* destroy classloader?


WebXmlConfiguration
-------------------
preConfigure:
* read webdefault.xml, web.xml into memory
* compute ordering of web-fragments:
    * metadata-complete: no web-fragments
    * absolute ordering
* read override-web.xml into memory
* merge webdefault.xml, web.xml into effective web.xml
configure:
* merge override-web.xml into effective web.xml
* process the basic effective web.xml elements
postConfigure:
deconfigure:
* remove Servlets, Filters, ErrorPages etc

MetaInfConfiguration
----------------
preConfigure:
* scan WEB-INF/lib/*.jar for:
             * META-INF/resources
             * META-INF/web-fragment.xml
             * META-INF/*.tld
configuration:
postConfigure:
deconfigure:


FragmentConfiguration
---------------------
preConfigure:
* parse all web fragments for names and relative ordering
* order/exclude web fragments (& associated jars)
* merge web fragments into effective web.xml
configure:
postConfigure:
deconfigure:


JettyWebXmlConfiguration
------------------------
preConfigure:
* read & apply WEB-INF/jetty-web-pre.xml
configure:
* read & apply WEB-INF/jetty-web.xml
postConfigure:
* read & apply WEB-INF/jetty-web-post.xml
deconfigure:


JettyEnvXmlConfiguration
------------------------
preConfigure:
* read & apply WEB-INF/jetty-env.xml to declare resources in environment
* create java:comp/env namespace
configure:
* process resource-ref, injection, callbacks in effective web.xml (was plus.Configuration)
postConfigure:
* lock down java:comp/env
deconfigure:
* unlock java:comp/env
* destroy java:comp/env



TagLibConfiguration
-------------------
preConfigure:
* look for .tld files in effective web.xml
* look for .tld files in WEB-INF configure:
* add Listeners
postConfigure:
deconfigure:




AnnotationConfiguration
-----------------------
preConfigure:
configure:
* asm scan classes from each jar (using to ordering/exclusions) according to what annotations, class types to look for
* process resource annotations to create Injections
* process callback annotations to create LifecycleCallbacks
* process run-as to create RunAses
* process Servlet annotations to create ServletHolders
* process Filter annotations to create FilterHolders
* process Listener annotations to create Listeners
postConfigure:
 * set Injections on the Servlet/FilterHolders (pluggable customizer to ServletHandler instead)
* set Multipart on the Servlet/FilterHolders * set RunAses on Servlet/FilterHolders
 * set LifeCycleCallbacks on Servlet/FilterHolders
deconfigure:



ContainerInitializerConfiguration
---------------------------------
preConfigure:
* look for ServletContainerInitializer (jdk ServiceLoader)
* look for HandlesTypes annotation:
     if HandlesTypes value is an annotation, get all classes that have that annotation
     if HandlesTypes value is a classname, get all classes that extend or implement that classname
configure:
* instantiate ServletContainerInitializers, call doStart
postConfigure:
deconfigure:



LoadOnStartupConfiguration
--------------------------
preConfigure:
configure:
* instantiate all Servlets, Filters that are load-on-startup > 0 (possibly just Listeners)
* perform any Injections, RunAs, LifeCycleCallbacks on Servlets, Filters, Listeners
postConfigure:
deconfigure:
* call preDestroy LifeCycleCallbacks on Servlets, Filters, Listeners ?


I'll be starting to apply this new Configuration structure to jetty-7, leaving
out the Servlet Spec 3.0-isms such as the ServletContainerInitializer, which will
only go into jetty-8.


Comments etc welcome.

cheers
Jan



Jan Bartel wrote:
Greg,

maybe it's the classic "around" aop-y trilogy:

 interface WebAppConfiguration
 {
    void preConfigure(WebAppContext context);
    void configure(WebAppContext context);
    void postConfigure(WebAppContext context);
 }
?

Jan

Greg Wilkins wrote:
Jan Bartel wrote:
Greg,

Some comments. A bit stream-of-consciousness, sorry.
WebInfConfiguration:
--------------------

 discover WEB-INF/classes and add to class-path

 discover WEB-INF/lib/*.jar  and for each:
   a) add to class-path
   b) scan jar index for
      i)   META-INF/web-fragment.xml
           parse (not process) for name and partial orderings
      ii)  META-INF/*.tld   add to list of tlds
      iii) META-INF/resources add to resource base.

 set Thread context classloader
If we parse all the web-fragements at this stage, we might
do useless processing, as if metadata-complete is true in
web.xml we don't need to - and shouldn't - look at any
web fragments.
OK - so perhaps split this into
  WebInfConfiguration
  WebFragmentConfiguration (which is done after WebXmlConfiguration)


WebXmlConfiguration
-------------------

discover defaultweb.xml, WEB-INF/web.xml and override web.xml
   a) parse (but not process) to determine
      i)  if meta-data complete
      ii) if there is a web-fragment ordering

Apply orderings to list of WEB-INF/lib/*.jar
Store list of jars as attribute for later configurations.
Shouldn't we store the list of jars as an attribute back
in WebInfConfiguration when we load them onto the classpath?
yes


Use meta-data-complete and orderings to merge
   * defaultweb.xml
   * web.xml
   * web-fragment.xml s
   * override web.xml

to obtain an effective web.xml that respects
main merging rules.   Store resulting parse
tree as attribute for use by subsequent configuration
Good. I like having the effective web.xml. We can even
spit that out as a diagnostic.
yep


process effective web.xml standard configuration


EnvConfiguration
----------------
Process the effective web.xml looking for resources
and other JNDI type stuff.

Process jetty-env.xml
This would have to be done in the other order. jetty-env.xml
defines resources in the container's environment that you want
to be able to hook into the webapp via <resource> entries in
web.xml or annotations. So you need to process jetty-env.xml
first. Currently we're doing this as 2 separate configurations:

1. plus.EnvConfiguration: sets up the webapp's java:comp/env namespace and then loads resource definitions from jetty-env.xml

2. plus.Configuration: reads web.xml and hooks up resources
from the container's environment into the java:comp/env namespace, and also prepares any injections that are specified
   in web.xml (as opposed to injections specified by annotations
   which are handled by the annotation.Configuration class)
So we need to keep this split, maybe:

  EnvXmlConfiguration
  WebXmlResourceConfiguration

with the later working off the stored effective web.xml
with another pass over it.

the alternative is to have an extensible mechanism
that handles each element from a single pass through
the effective web.xml parse tree


AnnotationConfiguration
-----------------------

For each jar in ordered list scan classes for
   a) handled types for ServletContainerInitializers
   b) Servlets|Filters|Listeners instances with annotations
      i) Setup resource injection for newServlet and newFilter
We also need to have pre-scanned some jars that are in jetty's
container path (as opposed to the WEB-INF/lib jars) for @HandlesTypes
annotations. I say pre-scanned because we don't want to re-scan
for every webapp deployment.
Hmmm maybe.... could be done by a deployer and injected?

Also, the @HandlesTypes annotation could be handled a little differently
from the other annotations we scan for. The jdk6 java.util.ServiceLoader
api will give us back a list of instances of all classes that implement
the ServletContainerInitializer interface, so we could just use
reflection
to work out if it has a @HandlesTypes annotation as those classes are
already loaded, unlike in the scanning for the servlet/filter/listener
classes as we don't want to actually load those classes and therefore
we need to use asm to look at the byte code instead.
cool

Now, the actual value of @HandlesTypes annotation can be (quoting from
draft spec)   "The annotation will be applied on the implementation of
   ServletContainerInitializer to express interest in classes    that
are either annotated with the classes specified in    the value or if
a class extends / implements one of those classes."

So during our asm scanning of jars in WEB-INF/lib we need to look both
at annotations that are known a priori (ie hard coded from the spec) AND
at annotations that are dynamically discovered from the values of the
@HandlesTypes annotation on the ServletContainerInitializers classes.
So in fact, we have to have separately processed the @HandlesTypes
annotation BEFORE we commence our general jar scanning anyway, so the
reflection method outlined above seems most reasonable.
ok


Incidentally, our asm scanning needs to be extended, as currently we
just use it to look for annotations, but now we need to also look at
the class definition to find classes that extend or implement the
class names in @HandlesTypes.
or have annotations define in HandlerTypes


ContainerInitializerConfiguration
---------------------------------

user JVM service discovery to find ServletContainerInitializer classes
on container classpath.
   a) for each initialize use @HandlesTypes to discover interested
classes

For each ServletContainerInitializer
   i) scan ordered jar list for matching classes (or maybe all jars)
   i) call with list of discovered classes and allow to do programmatic
      configuration
See comments above. At this stage, we need to loop over the map
of ServletContainerInitializers, get their interested classes/annotations
and then get the matching class instances out of the results of our
asm parsing, then pass them into the onStartup() method of the
ServletContainerInitializer.
So I'm thinking this is a split pair of configurations as well.

hmmmmm

I'm wondering if this split configuration pairings really means that
we should have two methods on all the configuration.  Call all of their
first methods and then call all or their second methods?

I think this is better than endless pairings... need to think of
the appropriate names:

 prepareConfiguration
 performConfiguration



TagLibConfiguration
-------------------
Combine list of  META-INF/*.tld with
    * TLDs defined in effective web.xml
    * TLDs discovered in WEB-INF/*.tld (including
META-INF/resources/WEB-INF/*.tld)
    Parse TLDs for listeners - add to listener lists.
Don't forget the jars on the container's classpath that we have to
also scan for tlds. See the regexp in webdefault.xml that currently
determines which ones we scan.
Do we have to do this anymore?    I'm not so sure?
But we can have them added to the list I guess for old times!


What are you thinking of as far as a Configuration base class looks
like?
now I'm thinking of

interface WebAppConfiguration
{
   void prepareConfiguration(WebAppContext context);
   void performConfiguration(WebAppContext context);
}



cheers

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email







--
Jan Bartel, Webtide LLC | janb@xxxxxxxxxxx | http://www.webtide.com


Back to the top