Maven plugins need to be environment-aware!

Let's imagine you wish to use Maven for J2EE development (quite a common
scenario). As you progress towards production you will notice that you
Maven projects will need to be environment-aware. Indeed, your artifacts
will not be the same whether you deploy them in the development
environment, the integration environment or in the production
environment. Let's take two example. A development environment may use
JBoss as its container whereas you wish to use WebSphere/WebLogic (pick
your preferred container) in production (Not that this is a good
strategy but it happens all the time). That requires to include a
jboss.xml file in META-INF/ for your EJB-JAR for JBoss and another one
for the other container. Even better, the jboss.xml will not be the same
for the different environment; the one for production might use a
cluster configuration whereas the one for development will usually not,
etc. The same applies for a lot of other artifacts: WAR, EAR, RAR,
configuration files for containers, start/stop scripts, etc.

More generally, there is a need to know what is the environment used
when building a project. The environment could also be things such as
the version of the JDK the project is built with, the OS (although this
doesn't affect much the java sources) or any other parameter related to
the building or target environment.

How do you deal with this in Maven?

One important thing to understand is that artifacts generated for a
given environment cannot be mixed with the artifacts generated for
another environment. There are 2 solutions to deal with this: one
involves 
adding the environment characteristic/name in the artifact name, such as
acme-registration-production-1.0.jar and
acme-registration-development-1.0.jar. Another solution is to have
separate Maven remote repositories 
(one per environment). The way to deal with this is easy: Have the
following in your build.properties/project.properties:

env.name=development
maven.repo.remote=http://ip:port/maven/repository/${env.name}

Then comes the more difficult question of how to make the project build
environment-aware. With the current Maven, the following solution works
(but is tiresome). First, start by creating environment-aware project
directory structures. For example, for an EJB-JAR project, you would
have something like:

myproject
  |_ src
    |_ ejb
      |_ development
        |_ META-INF
          |_ jboss.xml
      |_ integration
        |_ META-INF
          |_ jboss.xml
      |_ production
        |_ META-INF
          |_ jboss.xml
      |_ share
        |_ META-INF
          |_ ejb-jar.xml
  |_ [rest of the project]
  
Now, how do we deal with this? The current solution is to read the
plugin source code and find a way to intercept it before it includes the
META-INF files in the EJB-JAR. A post goal of ejb:init looks good. So
you need to write a maven.xml and write something like:

<postGoal name="ejb:init">
  <copy todir="${maven.build.dir}/src/ejb" overwrite="true"
filtering="on">
    <fileset dir="src/ejb/share"/>
  </copy>
  <copy todir="${maven.build.dir}/src/ejb" overwrite="true"
filtering="on">
    <fileset dir="src/ejb/${env.name}"/>
  </copy>
</postGoal>

And then write the following in the project.properties:

maven.ejb.src = ${maven.build.dir}/src/ejb

You would also add a env.name property in your build.properties (or on
the command line when you start maven)

env.name = development (for example)

Of course, you would have to do this for all your projects and for all
types of environment-aware projects. That's very tiresome. You could of
course improve that a little by creating a jelly
<copy-environment-resources> tag and using that in the maven.xml but
that wouldn't help much.

The real problem is that the current Maven plugins are not
environment-aware...

The solution is of course to make them environment-aware by building
this logic in them. For example, Maven could have the following
mechanism:

* An environment plugin which would contain the
<copy-environment-resources src="" dest=""/> tag. That plugin would also
define a variable called maven.environment.name which would default to
"" (empty string). In our example, we would override it to
"development", "integration", "production", "jdk12", "jdk13", "j2ee1.2",
"j2ee1.3", etc. This jelly tag would also standardize on a shared
environment config directory name. For example, by having a property:
maven.environment.share.dir=share. The tag logic would be the same as
shown above in our postGoal.
  
* Modify the existing plugins that should be environment aware so that
they become environment-aware. They would thus use the
<copy-environment-resources/> tag and copy/filter the config files in
the target directory and use that as the source of the config. In order
to boost performance a little, they could test if the
maven.environment.name property is an empty string or not, and if so,
bypass the copy step.

* Almost any plugin that uses config files would need to be environment
aware. The java plugin would need that. Same for the test plugin, etc.
  
What do you think?

Thanks
-Vincent


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to