Import maven plugin configuration by composition rather than inheritance. Can it be done with build extensions?

Tony Lâmpada picture Tony Lâmpada · Jul 31, 2012 · Viewed 8.3k times · Source

Import maven plugin configuration by composition rather than inheritance. Can it be done with build extensions?

I have used maven for more than 3 years and there's one shortcoming that has always bugged me. It's time to find a solution for that already.

The problem:

I have a "daddy" maven module with 3 children: "boy", "girl", and "kid". Each of these children must have its own distinct set of plugin configurations for a default "clean install" build. I don't want to put that configuration on the children's poms. I'd rather put it somewhere that I can reuse later.

I have tried using profiles for that, and it doesn't work - please see my comment and attached project on MNG-5127

I have found a better solution by making the following changes on the daddy.zip project:

1) On daddy's pom, Replaced the [profiles] with plugin executions having [phase]none[/phase]

<build>
    ...
    <plugins>
        <plugin>
            <artifactId>maven-antrun-plugin</artifactId>
            <executions>
                <execution>
                    <id>printboy</id>
                    <phase>none</phase>
                    <configuration>
                        <target>
                            <echo message="@@@@@@@@@@@@ HELLO! Iam a BOY project"/>
                        </target>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
                <execution>
                    <id>printkid</id>
                    <phase>none</phase>
                    <configuration>
                        <target>
                            <echo message="@@@@@@@@@@@@ HELLO! Iam a KID project"/>
                        </target>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
                <execution>
                    <id>printgirl</id>
                    <phase>none</phase>
                    <configuration>
                        <target>
                            <echo message="@@@@@@@@@@@@ HELLO! Iam a GIRL project"/>
                        </target>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
    ...
</build>

2) On the same pom, added a custom build extension

<build>
    <extensions>
        <extension>
            <groupId>br.com.touchtec.maven.plugins</groupId>
            <artifactId>execution-enabler-extension</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </extension>
    </extensions>
    ...
</build>

3) The extension will change the plugin execution phases based on the project's property values. Java code below.

@Component(role = AbstractMavenLifecycleParticipant.class, hint = "enableif")
public class EnableIfExtension extends AbstractMavenLifecycleParticipant {

    @Override
    public void afterProjectsRead(MavenSession session)
            throws MavenExecutionException {
        String phase = "validate";
        for(MavenProject project : session.getProjects()){
            Properties properties = project.getProperties();
            if(properties != null){
                if("boy".equals(properties.getProperty("project_type"))){
                    setExecutionPhase(project, "printboy", phase);
                    setExecutionPhase(project, "printkid", phase);
                }
                if("girl".equals(properties.getProperty("project_type"))){
                    setExecutionPhase(project, "printgirl", phase);
                    setExecutionPhase(project, "printkid", phase);
                }
                if("kid".equals(properties.getProperty("project_type"))){
                    setExecutionPhase(project, "printkid", phase);
                }
            }
        }
    }

    private void setExecutionPhase(MavenProject project, String executionId, String phase) {
        for(Plugin plugin : project.getBuild().getPlugins()){
            if(plugin.getExecutions() != null){
                for(PluginExecution execution : plugin.getExecutions()){
                    if(executionId.equals(execution.getId())){
                        execution.setPhase(phase);
                    }
                }
            }
        }
    }
}

4) The child module poms only need to define a property that will tell the build extension what to do, for example, the boy project:

<project>
    <properties>
        <project_type>boy</project_type>
    </properties>

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.family</groupId>
    <artifactId>boy</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <parent>
        <groupId>com.family</groupId>
        <artifactId>daddy</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <!-- No "build" section. Beautifull. -->
</project>

Invoking mvn clean install on the daddy project like thiss, will output the desired result: boys will be boys, girls will be girls and both will be kids.

The question is: can we do better?

In theory, a build extension could import the build configuration definitions for boy, girl, and kid from different poms... right? That would be the a clever and elegant way of importing [build] configuration into a pom.

There are a lot of available maven plugins, but I don't see a lot (actually any) of available build extensions that one can plug into a build. Does anyone know of a build extension that helps with this?


Update

This is not an actual answer, but it's an actual solution to my problem, so here goes.

Import maven plugin configuration by composition rather than inheritance. Can it be done with build extensions?

Probably

Does anyone know of a build extension that helps with this?

I'm pretty sure there isn't one

However, there is a solution using profiles.

The trick is that file-based profile activation is actually inherited (it only works with maven3 though)

Please see the daddy2.zip attached to MNG-5127

This is way better than using the build extension strategy, because using a profile provides more flexibility than just changing a few plugin execution phases.


Update 2

Does anyone know of a build extension that helps with this?

I'm pretty sure there isn't one

Actually there is something!

It's attached as project in MNG-5102 (by Maurizio Pillitu) I haven't tested it, but it seems it does something very close to the proposed build extension.

Answer

maoo picture maoo · Aug 6, 2012

I think that Maven Tiles can help you with your specific use-case. It is still work in progress, but it currently accomplishes what you're describing, I managed to "decompose" the wicket-quickstart and run Jetty successfully, even adding a multi-module structure.

Any comment or hint is more than welcome. Thanks, Maurizio