Okay, this is a bunch of inline responses, with a specific code &
procedure proposal at the very end:
On Sat, 4 Oct 2003, Jan Bartel wrote:
> I agree there may be common code that can be extracted for the
> deployment of various j2ee artifacts such as ears and wars. This will
> come out as development continues and matures. However, there will
> inevitably be differences between deploying say, a war, and a rar. It
> seems to me almost as if you are arguing for one big happy generic
> "application" deployer rather than specific deployers. If so, then I
> don't agree with that approach.
I'm arguing to split it up, so we do much of the common reusable
tasks in a central deployer and then dispatch to a specific deployer for
the truly custom details.
> 1. JSR88 deployment lifecycle vs geronimo hot deploy lifecycle
My feeling is that distribute can be done nearly entirely by the
common code, with 1 or 2 calls to the WebContainer. Let's look at the
case of an EAR. Something needs to set up a series of ClassLoaders,
create one MBean for the EAR and another per module, validate all the
modules, and generate container-specific classes. There are a number of
steps invokving Goals and Tasks and Plans. I think the application
deployer could do everything listed above, with calls to the WebContainer
to:
- get the AppModule MBean class name (to use for a createMBean task)
- validate the application (given URL, DD, etc.)
- generate container classes (which I think amounts to precompiling JSPs
in the case of a web container)
If there was other web-specific logic, it would presumably happen
in the postRegister event on the application MBean. I think these same 3
steps would work for implementing "distribute" for every container type.
Most of the container-specific work seems to be in "start", which is
implemented by the container-specific app module MBean anyway.
> 2. typed deployers
> the central deployment mechanism should only be responsible for
> detecting things to be deployed, and arranging for distribute(),
> start(), undeploy() or whatever to be called on the appropriate
> deployer. Typed deployers are necessary because the things that are
> being deployed are different. Sure, they might go through a certain
> amount of common steps, and these can be abstracted for re-use within
> each deployer, but it does not follow that therefore there should only
> be one deployer for everything. For example, the web deployer, and only
> the web deployer, should be responsible for determining such things as
> the context path of a web application. This is very webby specific and
> the natural place for this is in a web module. The information that is
> used to determine that path can come from many sources: the name of the
> directory or war, a tag in an application DD, or an override in a
> geronimo-web DD, but the algorithm for choosing is specific to web
> deployments only.
I agree with the spirit but potentially disagree with the example.
I do not believe that the application deployer should instruct the web
deployer on how to set up a servlet context or something like that. As
above, though, I think it can take most of the "distribute" work off your
hands, except for a couple container-specific callbacks. And startup is
in your court anyway, thanks to JSR-77.
As far as the context root is concerned, I don't want the web
container groping for content outside the web app -- the last things we
want is inadvertent dependencies where the web container penetrates its
interface to root around in the guts of the server or the application.
So I thought it would be easy enough for the common deployer to do that
calculation for you (after all, it has the EAR DD, the file name, etc.).
But it doesn't *have* to be done that way -- we could instead pass the EAR
DD POJOs to the web container along with the WAR DD POJOs and let you do
the calculation yourself.
Thinking back, I seem to have overlooked how the ObjectName will
be generated. Personally I would rather have standard application module
ObjectNames no matter what container is plugged in, so I'd rather see
"geronimo.deployment:role=WebApplication,instance=(unique ID)" instead of
"jetty:...". So I'd prefer to add a 4th method "getUniqueID" to the 3
listed above. But if you feel strongly it could just be "getObjectName"
and you can construct a Jetty name instead.
> 3. ear/war relationship
> wars can be deployed standalone, or bundled as part of an ear. In the
> latter case, then some of the deployment information for the war is
> contained in the deployment descriptor for the ear, and as you point
> out, the classloader hierarchy needs to be established. I think this
> should be handled as much as possible via the normal deployment mechanism.
>
> To that end, I suggest we augment the signature of the deploy,
> distribute, undeploy etc methods with another parameter:
> DeploymentContext. This context can contain deployment descriptor POJOs
> or xml, or classloader objects or perhaps state information. Anything
> that defines the context in which the deployment is taking place.
Well, I agree that we need to get more information to each
container.
Let me propose a revised base WebContainer and WebApplication, and
let me know what you think. I believe this should leave the bulk of the
"geronimo kernel"-specific logic in the central deployer, and the bulk of
the module-specific logic in the container, which seems to me like the
right split:
abstract class AbstractWebContainerMBean {
// returns i.e. JettyWebApplication
public abstract String getModuleMBeanClass()
// validates the deployment and returns an ObjectName if valid
public abstract ObjectName validateDeployment(URL, EAR-POJOs, WAR-POJOs)
}
abstract class AbstractWebApplicationMBean
public void setURL(URL)
public void setBaseClassLoader(ClassLoader/ClassSpace)
public void setEARDeploymentInfo(EAR-POJOs)
public void setWARDeploymentInfo(WAR-POJOs)
// will be called during distribution process; can precompile JSPs
public abstract void generateContainerClasses()
}
So now the sequence is something like this:
- common deployer identifies app and modules
- (something) validates EAR
- common deployer creates app MBean
- for each RAR in EAR:
- common deployer calls ConnectorContainer to validate a RAR, gets
ObjectName for valid ones
- common deployer gets connector MBean class from ConnectorContainer
- common deployer creates Connector MBean w/class & ObjectName provided
- common deployer sets properties on Connector MBean
- common deployer tells Connector MBean to generate custom code
- common deployer gets ClassSpace from Connector MBean
- for each EJB JAR in EAR:
- common deployer calls EJBContainer to validate a JAR, gets
ObjectName for valid ones
- common deployer gets EJB JAR MBean class from EJBContainer
- common deployer creates EJB JAR MBean w/class & ObjectName provided
- common deployer sets properties on EJB JAR MBean
- common deployer tells EJB JAR MBean to generate custom code
- common deployer gets ClassSpace from EJB JAR MBean
- for each web app in EAR:
- common deployer calls WebContainer to validate a web app, gets
ObjectName for valid ones
- common deployer gets web MBean class from WebContainer
- common deployer creates web app MBean w/class & ObjectName provided
- common deployer sets properties on web app MBean
- common deployer tells web app MBean to generate custom code
Note that all the deployment plans and goals and tasks are managed by
the common deployer -- when it says "creates web app MBean" and "sets
properties on web app MBean" it really means "registers a task in the
deployment plan to..." So the WebContainer is doing web stuff not
deployment plan stuff.
Then at start time, there are just a bunch of JSR-77 start() commands
executed, so the detailed startup logic is left to the module.
You seemed to be saying that there were web-specific steps that either the
common deployer would do inappropriately or the web container wouldn't be
given the opportunity to do -- would that still be the case?
Aaron