Aaron,

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.
I am definitely in favour of a central controller, but not a central deployer. The DeploymentController that we have now is the only central entity that is necessary. In other words, something whose only task is to notice that there are things that need to be deployed, undeployed or redeployed. The DeploymentController needs to be able to support both the geronimo hot deploy directory and also deployments coming from a JSR88 tool.



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.
In my reply to Gianny's email, I've said what I think is the biggest weakness with the central deployer approach: that is the lack of flexibility. To add support for a new deployable type, we'd have to modify the central deployer code, adding yet more "if then else" clauses each time. By keeping individual deployers (but that reuse common deployment code perhaps from a baseclass) we gain a lot of flexibility. For example, with individual deployers, we are able to hot deploy a new deployer and introduce support for a brand new deployment type into a running geronimo instance.


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.
I'd much prefer that the interface contract to the deployers contained the DD pojos (preferably as part of a DeploymentContext, but that is covered in other threads), so that the individual deployer can extract whatever information it requires. That allows for maximum flexibility.


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.
As Gianny has pointed out, JSR77 seems to have something to say about acceptable names, so we'll stick to those. I just blindly followed the naming precedent that had been set in the "hack" Jetty integration. Now I know better :-)


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

As I mentioned above, one of the major problems with this approach
is the tight coupling between the EARDeployer and every other deployer
in the system. A looser coupling, whereby the EARDeployer, WARDeployer,
RARDeployer, ServiceDeployer and XYZDeployer all re-use common Deployer
code (maybe as a base class or maybe as a delegate), but all communicate through a standard set of JSR77/JSR88 style methods (JSR77: start/stop etc, JSR88: distribute, undeploy etc) mediated by the DeploymentController, gives us:


 - maximum flexibility to easily introduce support for new deployment
   types

 - uniformity of control flows

 - uses existing mechanisms for co-ordinating deployment, eg checking if
   a deployment task can proceed based on the outcome of other tasks,
   suspending deployments for which no appropriate deployer can be
   found, retrying failed deployments etc etc



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?


cheers,
Jan



Reply via email to