Java, SOA, Architecture & Methodes agiles par Thomas Recloux

Créer un packaging maven2

Publié le 7 juillet 2008 par Thomas Recloux

Maven 2 propose d’origine les types de packaging des différents composants java / j2ee : jar, war, ejb et ear.

Cependant, il faut parfois utiliser des types de packaging moins conventionnels qui nécessitent la création d’un packaging maven dédié.

Pour exemple, je vais créer un packaging nommé « custom », qui va créer des archives avec l’extension .cust et qui contient les classes et ressources du projet dans un répertoire « classes » et les dépendances du projet dans un répertoire lib.

  • Première étape : créer le plugin maven2 à l’aide de l’archetype plugin :
    mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-plugin -DgroupId=org.tartachuc.m2 -DartifactId=my-custom-packaging
  • Ajouter dans le descripteur de projet pom.xml le projet maven-archiver :
    
    <dependency>
    <groupId>org.apache.maven</groupId>
    <artifactId>maven-archiver</artifactId>
    <version>2.2</version>
    </dependency>
    
  • Modifier le MOJO généré par l’archetype pour qu’il prenne en charge le packaging.
    • Renommer la classe MyMojo en CustomPackageMojo
    • Changer le commentaire en entête de la classe pour préciser le goal : custom et la phase : package
      
      /**
      * Goal which creates a custom package
      * @goal custom
      * @phase package
      */
      
    • Ajouter au Mojo les attributs et leur documentation qui vont permettre de récupérer des informations sur le projet qui utilise le plugin :
      /**
      * The maven project.
      * @parameter expression="${project}"
      * @required
      * @readonly
      */
      private MavenProject project;
      
      /**
      * The directory containing generated classes.
      * @parameter expression="${project.build.outputDirectory}"
      * @required
      * @readonly
      */
      private File classesDirectory;
      
      /**
      * Build directory.
      * @parameter expression="${project.build.directory}"
      * @required
      */
      private File buildDirectory;
    • Ajouter au Mojo les attributs qui vont permettre de créer l’archive :
      /**
       * The Jar archiver needed for archiving.
       * @parameter expression="${component.org.codehaus.plexus.archiver.Archiver#jar}"
       * @required
       */
      private JarArchiver jarArchiver;
      
      /**
       * The maven archive configuration to use
       * @parameter
       */
      protected MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
    • Ce packaging maison nécessite d’archiver les dépendances du projet, dans un premier temps les dépendances vont être copiées dans un répertoire de travail. Pour pouvoir configurer ce répertoire de travail, ajouter un attribut au Mojo
      /**
       * Lib directory
       *
       * @parameter expression="${project.build.directory}/custom/libs"
       * @required
       */
      private File libDirectory;
    • Il faut maintenant implémenter la méthode « execute » qui est le point d’entrée du Mojo.
      /** {@inheritDoc} */
      public void execute() throws MojoExecutionException {
          // Compute archive name
          String archiveName = project.getBuild().getFinalName() + ".cust";
          File custFile = new File(buildDirectory, archiveName);
          // Configure archiver
          MavenArchiver archiver = new MavenArchiver();
          archiver.setArchiver(jarArchiver);
          archiver.setOutputFile(custFile);
      
          // copy runtime libs
          copyLibs();
          try {
              // archive classes
              archiver.getArchiver().addDirectory(classesDirectory, "classes/");
              // archive libs
              archiver.getArchiver().addDirectory(libDirectory, "lib/");
              // create archive
              archiver.createArchive(project, archive);
              // set archive as artifact
              project.getArtifact().setFile(custFile);
          } catch (ArchiverException e) {
              throw new MojoExecutionException("Exception while packaging", e);
          } catch (ManifestException e) {
              throw new MojoExecutionException("Exception while packaging", e);
          } catch (IOException e) {
              throw new MojoExecutionException("Exception while packaging", e);
          } catch (DependencyResolutionRequiredException e) {
              throw new MojoExecutionException("Exception while packaging", e);
          }
      }
      
      /**
       * Copy runtime libs
       * @throws MojoExecutionException
       */
      protected void copyLibs() throws MojoExecutionException {
          try {
              Set artifacts = project.getArtifacts();
              for (Iterator iter = artifacts.iterator(); iter.hasNext();) {
                  Artifact artifact = (Artifact) iter.next();
                  ScopeArtifactFilter filter = new ScopeArtifactFilter(
                          Artifact.SCOPE_RUNTIME);
                  if (!artifact.isOptional() && filter.include(artifact)
                          && "jar".equals(artifact.getType())) {
                      FileUtils.copyFileToDirectory(artifact.getFile(),
                              libDirectory);
                  }
              }
          } catch (IOException e) {
              throw new MojoExecutionException("Error copying libs", e);
          }
      }    
  • Il faut maintenant indiquer à maven quel MOJO exécuter lors du cycle de vie de notre nouveau packaging. Pour cela, le plugin doit inclure un descripteur plexus nommé components.xml à placer dans répertoire src/main/resources/META-INF/plexus.
    <?xml version="1.0" encoding="UTF-8"?>
    <component-set>
      <components>
        <component>
          <role>org.apache.maven.artifact.handler.ArtifactHandler</role>
          <role-hint>cust</role-hint>
          <implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
          <configuration>
            <type>cust</type>
            <extension>cust</extension>
            <language>java</language>
          </configuration>
        </component>
        <component>
          <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
          <role-hint>cust</role-hint>
          <implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>
          <configuration>
            <phases>
              <process-resources>org.apache.maven.plugins:maven-resources-plugin:resources</process-resources>
              <compile>org.apache.maven.plugins:maven-compiler-plugin:compile</compile>
              <process-test-resources>org.apache.maven.plugins:maven-resources-plugin:testResources</process-test-resources>
              <test-compile>org.apache.maven.plugins:maven-compiler-plugin:testCompile</test-compile>
              <test>org.apache.maven.plugins:maven-surefire-plugin:test</test>
              <package>org.tartachuc.m2:my-custom-packaging:custom</package>
              <install>org.apache.maven.plugins:maven-install-plugin:install</install>
              <deploy>org.apache.maven.plugins:maven-deploy-plugin:deploy</deploy>
            </phases>
          </configuration>
        </component>
      </components>
    </component-set>

    Nous avons inséré notre MOJO (org.tartachuc.m2:my-custom-packaging:custom) lors de la phase de packaging. les autres MOJO sont repris des plugins standards de maven.

  • Pour installer le plugin dans votre référentiel local, exécuter la commande
    mvn install
  • Pour utiliser le packaging nouvellement créé, il faut créer un nouveau projet et déclarer le packaging cust et le plugin créé ci-dessus comme extension du build.
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>org.tartachuc.m2</groupId>
      <artifactId>my-custom-project</artifactId>
      <packaging>cust</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>my-custom-project uses a custom packaging</name>
      <dependencies>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-orm</artifactId>
          <version>2.5.3</version>
        </dependency>
      </dependencies>
      <build>
        <extensions>
          <extension>
            <groupId>org.tartachuc.m2</groupId>
            <artifactId>my-custom-packaging</artifactId>
            <version>1.0-SNAPSHOT</version>
          </extension>
        </extensions>
      </build>
    </project>
  • Here it is :-)

Maven 1 et continuum

Publié le 24 mars 2008 par Thomas Recloux

Quelques astuces en vrac pour intégrer un projet maven1 (oui, il y en a encore :-) ) dans continuum.

  • Continuum ne supporte pas l’import de POM qui étendent un autre POM. la solution est de créer un POM minimal dédié à cet import et qui indique l’URL du SCM. Ensuite Continuum va déclencher un « checkout » à partir du SCM et récupérer le véritable POM.
  • Sous windows, le script bat de maven ne permet pas à continuum de récupérer le code de sortie et donc de savoir si le build est un succès. La solution est de récupérer la dernière version du script maven.bat et d’affecter la valeur « on » à la variable d’environnement « MAVEN_TERMINATE_CMD ». Il est possible d’affecter la variable d’environnement à l’aide des profils continuum.