[WARNING: Much rambling follows.]

Daniel Kulp <[EMAIL PROTECTED]> writes:

> Basically, in the servlet, we need to have some objects that the
> Servlet provides set into the bus that spring creates.  Those
> objects aren't created by any spring xml or anything like that.

A bus is first created by Spring, without these Servlet-related
objects wired in, but when the CXFServlet gets created, it needs to
add things to the bus already created and held by Spring. One of the
things that the CXFServlet adds is a special Resource resolver that
uses the ServletContext to find things. It also creates a child
ApplicationContext to hold objects loaded from the
"post-Servlet-initialization" configuration file. Is that correct?

> There may be some way to pre-initialize the context with those
> objects such that they could be built right into the bus
> immediately.  I really don't know.  If so, that could solve the
> problem and we could just do everything all at once and be done with
> it.

Well, why not ask Servlet users to specify a parameter to Spring's
ContextLoaderListener telling it which kind of ApplicationContext to
create? Right now, it defaults to XmlWebApplicationContext. However,
it will honor a "contextClass" parameter and load the specified class
instead. You could load BusApplicationContext right from the start.

Actually, that's probably not the right idea; the Spring
WebApplicationContext variants already take the hierarchy of a Web
application into account, with a root context and various per-Servlet
child contexts. It just looks to me like there's an extra context for
the CXFServlet: one BusApplicationContext, created by
SpringBusFactory.createBus(), and a GenericApplicationContext if the
Servlet-specific user-provided CXF configuration file is found.

Maybe the documentation has been too liberal with prescribing
Spring-based configuration for the CXFServlet. It looks like there
should be no CXFServlet-dependent configuration in the root
application context, as the Servlet hasn't been loaded yet when those
definitions are processed.

As endpoints depend upon the Servlet -- or maybe they only sometimes
depend upon the Servlet -- the example shown here looks wrong:

  Declaring your server beans
  http://cwiki.apache.org/CXF20DOC/writing-a-service-with-spring.html

The META-INF/cxf/cxf-servlet.xml file doesn't need to be loaded there,
or at least it shouldn't be necessary; it should be loaded by
CXFServlet no matter what, rather than conditionally as it is now in
loadSpringBus():

,----
| if (ctx == null) {
|    bus = new SpringBusFactory().createBus("/META-INF/cxf/cxf-servlet.xml");
| } else {
|    bus = new SpringBusFactory(ctx).createBus();
| }
`----

The jaxws:endpoint definition should be moved into a user-provided
cxf-servlet.xml file, or whatever is designated by the Servlet's
"config-location" parameter.

That would mimic Spring's existing setup: a root context for the whole
Web application, with "namespace"-specific contexts for individual
Servlets, or at least like Spring's DispatcherServlet.

Change BusApplicationContext to accept not just one configuration file
parameter, but an array of them. Then have CXFServlet pass its own
configuration file -- /META-INF/cxf/cxf-servlet.xml -- and the
user-provided file (if it exists) to a new
SpringBusFactory.createBus() overload that also takes an array of
configuration files. That would help get rid of the second-stage
configuration done by loadAdditionalConfig().

Well, maybe there's still too much work done in between when the Bus
is created and when the system is ready to process user-provided
Spring definitions such as jaxws:endpoint. Those ideas won't work.


Digging through the code, I see one point that looks like it should be
addressed: SpringBusFactory.createBus() should not be used as it is by
CXFServlet.

Three cases are possible: Either the user already initialized CXF in
some parent ApplicationContext before CXFServlet got loaded, or the
user has not, and there is no bean called "cxf" in the Servlet's
parent ApplicationContext. There's the third case that there is no
parent ApplicationContext at all, such as when the user has not
employed Spring's ContextLoaderListener.

If there is no existing parent ApplicaitonContext, call on
SpringBusFactory.createBus("/META-INF/cxf/cxf-servlet.xml"), as we do
now. Configure the Servlet-Bus interaction. Later proceed to check for
a user-provided Servlet-specific configuration file and create a child
GenericApplicationContext if such a file is present.

If there is no existing "cxf" bean in an existing parent
ApplicationContext, again, like above, call on
SpringBusFactory.createBus("/META-INF/cxf/cxf-servlet.xml"), as we do
now. Configure the Servlet-Bus interaction. Later proceed to check for
a user-provided Servlet-specific configuration file and create a child
GenericApplicationContext if such a file is present.

However, if there is an existing "cxf" bean,
SpringBusFactory.createBus() should /not/ be used, as it creates a new
BusApplicationContext each time, in this case unnecessarily. It does
avoid reloading the default configuration files, but it still creates
an extra ApplicationContext. Instead, call something like
SpringBusFactory.getBus(), which would just

  return (Bus)context.getBean(DEFAULT_BUS_ID);

Carry on setting up the Servlet-Bus interaction, then check if there's
a user-provided CXFServlet configuration file and create a child
GenericApplicationContext if such a file is present. That eliminates
creating an extra BusApplicationContext just to gain access to an
existing bus instance.

I see that SpringBusFactory just extends BusFactory, so its interface
wouldn't be as flexible as I thought. This has been a lot of rambling,
but the I do now agree that the Servlet-dependent Spring beans need to
be in a separate configuration file from the root ApplicationContext's
configuration files. It looks like the CXFServlet-SpringBusFactory
interaction could be cleaned up some to avoid spurious creation of
extra ApplicationContexts. Finally, the documentation should clarify
which CXF Spring configuration directives depend on CXFServlet and
hence need to live in a separate configuration file.

-- 
Steven E. Harris

Reply via email to