mardi 7 mai 2013

Maven et paquet Debian

Il est possible de réaliser un paquet Debian avec Maven en s'aidant du plugin JDeb

Dans l'exemple qui suit, j'ai fait un programme Java qui va logguer un message toute les 5 secondes. J'utilise dans cette exemple Lombok , SLF4 et le @Scheduled de Spring . Il sera lancer comme service au lancement de l'OS.

Les sources de l'exemple sont sur github.


Fichier control

Pour la réalisation du paquet, il est nécessaire d'avoir un fichier control contenant les informations de votre paquet tel que son nom, sa version, ses dépendances...
Dans l'exemple, j'ai mis 2 dépendances pour illustrer cette utilisation : 
  • dos2unix interviendra dans le script de post-installation (postinst) pour s'assurer que le script de lancement est bien au format unix. 
  • sudo sera utilisé pour lancer le service avec l'utilisateur approprié

Scripts de pre et post-installation

L'installation d'un paquet peut aussi faire intervenir des scripts avant la phase d'installation de votre application et après installation de votre application. Vous pouvez faire intervenir les scripts :
  • preinst : avant installation
  • postinst : après installation
  • prerm : avant désinstallation
  • postrm : après désinstallation
Je met l'ensemble de ces fichiers dans le répertoire src/main/deb/control de mon projet :


Dans cet exemple, le script de pre-installation vérifie par exemple l'existence d'un utilisateur dédié au lancement du service. Il va aussi préparer l'arborescence pour le bon fonctionnement du service.

Le script de post-installation utilisera la commande update-rc.d pour inscrire le service et le démarrera.


Fichier init.d

Pour lancer et arrêter le service, j'utilise le fichier jdeb-tips.sh que j'ai mis dans le répertoire src/main/deb/init.d
J'ai utilisé et modifié un template provenant d'ici.


pom.xml


Step 1

Ayant utilisé des propriétés Maven dans les fichiers du répertoire src/main/deb, je les copies dans le répertoire 'target' en utilisant le filtragre :

            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.4.3</version>
                <executions>
                    <execution>
                        <id>copy-deb-package-resources</id>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${basedir}/target/deb</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>src/main/deb</directory>
                                    <filtering>true</filtering>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>



Step 2

Je récupère les dépendances pour permettre une exécution autonome du programme :

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/libs</outputDirectory>
                            <overWriteReleases>false</overWriteReleases>
                            <overWriteSnapshots>false</overWriteSnapshots>
                            <overWriteIfNewer>true</overWriteIfNewer>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

Step 3


J'utilise ensuite maven-jar-plugin pour réaliser mon Jar exécutable :

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>libs/</classpathPrefix>
                            <mainClass>fr.gunduz.tips.jdeb.Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>

Step 4


Enfin, l'utilisation du plugin JDeb. Ce qui est important de noter dans ce qui suit est comment indiquer au plugin où ce trouve les fichiers control grâce à la balise  <controlDir>. Etant donnée que j'ai copié les fichiers -afin qu'ils soient valués- dans le répertoire target, il faut absolument utiliser cette balise.
Le reste de la configuration indique uniquement les fichiers à inclure dans le paquet deb ainsi que les répertoires de destination et leurs propriétés.

            <plugin>
                    <artifactId>jdeb</artifactId>
                    <groupId>org.vafer</groupId>
                    <version>1.0</version>
                    <executions>
                        <execution>
                            <phase>package</phase>
                            <goals>
                                <goal>jdeb</goal>
                            </goals>
                            <configuration>

                                <verbose>true</verbose>
                                <controlDir>${basedir}/target/deb/control</controlDir>

                                <dataSet>
                                    
                                     <data>
                                        <src>${project.basedir}/target/libs</src>
                                        <type>directory</type>
                                        <mapper>
                                            <type>perm</type>
                                            <prefix>${debian.target.dir}/jdeb-tips/libs/</prefix>
                                            <user>jdeb-tips</user>
                                            <group>jdeb-tips</group>
                                            <filemode>644</filemode>
                                        </mapper>
                                    </data>
                                    
                                    <data>
                                        <src>${basedir}/target/${project.build.finalName}.jar</src>
                                        <dst>${debian.target.dir}/jdeb-tips/${project.build.finalName}.jar</dst>
                                        <type>file</type>
                                        <mapper>
                                            <type>perm</type>
                                            <user>jdeb-tips</user>
                                            <group>jdeb-tips</group>
                                            <filemode>644</filemode>
                                        </mapper>
                                    </data>
                                    <data>
                                        <src>${basedir}/target/deb/init.d/jdeb-tips.sh</src>
                                        <dst>/etc/init.d/jdeb-tips</dst>
                                        <type>file</type>
                                        <mapper>
                                            <type>perm</type>
                                            <user>root</user>
                                            <group>root</group>
                                            <filemode>755</filemode>
                                        </mapper>
                                    </data>
                                </dataSet>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>


Construction et installation

Il vous suffit de lancer la commande mvn clean install pour avoir votre paquet Debian. Pour l'installer sur le système hôte, il faudra utiliser la commande dpkg -i <votre paquet>. 

Attention, si vos dépendances ne sont pas installées au préalable à l'aide d'apt, la commande dpkg retournera une erreur.

samedi 24 novembre 2012

tomcat-maven-plugin, Tomcat 7, tomcat:deploy et un 403

Si vous vous retrouvez face à une erreur 403 en utilisant la commande mvn tomcat:deploy, c'est que l'URL permettant le déploiement a été modifié. Il faut changer la configuration du plugin pour avoir :

[...]

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<configuration>
<url>http://localhost:8080/manager/html</url>
[...]
</configuration>
</plugin>
[...]

lundi 5 mars 2012

Tomcat, Spring, JNDI & Oracle

Step 1:

Ajouter le JAR du driver Oracle dans le répertoire common/lib de Tomcat. S'assurer que dans le catalina.properties, la variable common.loader contient bien ${catalina.base}/common/lib/*.jar


Step 2:

Dans le fichier context.xml du répertoire conf de Tomcat, ajouter la ressource suivante :


<resource 
auth="Container" 
driverclassname="oracle.jdbc.driver.OracleDriver"
factory="oracle.jdbc.pool.OracleDataSourceFactory" 
maxactive="40" maxidle="3" 
maxopenpreparedstatements="100" maxwait="10000"
name="jdbc/oracleDataSource" password="password"
poolpreparedstatements="true" 
type="oracle.jdbc.pool.OracleDataSource"
url="jdbc:oracle:thin:@oracle_host:oracle_port:oracle_sid"
username="username" validationquery="SELECT SYSDATE FROM DUAL">
</resource>




Step 3:

Dans le fichier web.xml


<resource-ref>
<description>Connection Pool</description>
<res-ref-name>jdbc/oracleDataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>




Step 4:

Déclaration du data source dans le fichier de context Spring


<bean class="org.springframework.jndi.JndiObjectFactoryBean" id="dataSource">
<property name="jndiName" value="java:comp/env/jdbc/oracleDataSource"></property>
<property name="resourceRef" value="true"> </property>
<property name="proxyInterface" value="javax.sql.DataSource"></property>
<property name="lookupOnStartup" value="true"></property>
</bean>




Step 5:

Modifier les valeur maxActive, maxWait... pour qu'ils correspondent aux besoins.


...avec Maven et Cargo plugin

Ajouter la dépendance vers la librairie Oracle dans votre POM :


<dependency>
<groupid>com.oracle</groupid>
<artifactid>ojdbc5</artifactid>
<version>${oracle.version}</version>
<type>jar</type>
</dependency>



Dans la configuration du plugin cargo, dans la section 'container', ajouter la dépendance vers la librairie Oracle:


<pluginmanagement>
<plugins>
...
<plugin>
<groupid>org.codehaus.cargo</groupid>
<artifactid>cargo-maven2-plugin</artifactid>
<version>1.1.3</version>
<configuration>
<container>
<containerid>tomcat6x</containerid>
...
<dependencies>
<dependency>
<groupid>com.oracle</groupid>
<artifactid>ojdbc5</artifactid>
<classpath>extra</classpath>
</dependency>
</dependencies>
</container>
</configuration>
</plugin>
</plugins>
</pluginmanagement>


Réaliser un fichier tomcat-context.xml dans un répertoire de resource (par exemple, resource/conf/) avec pour contenu :


<context>
<resource 
auth="Container" 
driverclassname="oracle.jdbc.driver.OracleDriver"
factory="oracle.jdbc.pool.OracleDataSourceFactory" 
maxactive="40" maxidle="3" maxopenpreparedstatements="100"
maxwait="10000" name="jdbc/oracleDataSource" password="password"
poolpreparedstatements="true" type="oracle.jdbc.pool.OracleDataSource"
url="jdbc:oracle:thin:@oracle_host:oracle_port:oracle_sid"
username="username" validationquery="SELECT SYSDATE FROM DUAL">
</resource>



Finalement, modifier la configuration du plugin cargo :


<plugins>
<plugin>
<groupid>org.codehaus.cargo</groupid>
<artifactid>cargo-maven2-plugin</artifactid>
<executions>
<execution>
<id>start-cargo</id>
<phase>pre-integration-test</phase>
<goals>
<goal>${cargo.goal}</goal>
</goals>
<configuration>
<container>
<timeout>200</timeout>
</container>

<configuration>
<properties>
<cargo .servlet.port=".servlet.port">${servlet.port}</cargo>
</properties>
<deployables>
<deployable>
<groupid>application.group.id</groupid>
<artifactid>myapp</artifactid>
<type>war</type>
</deployable>
...
</deployables>
<configfiles>
<configfile>
<file>${project.build.directory}/test-classes/tomcat-context.xml</file>
<todir>conf/</todir>
<tofile>context.xml</tofile>
</configfile>
...
</configfiles></configuration></configuration></execution></executions></plugin>
</plugins>


mercredi 29 février 2012

Maven, attacher un artefact supplémentaire

Le projet génère plusieurs fichiers que j'aimerai rendre disponible sur notre Nexus (des WSDL).

Pour ajouter les fichiers supplémentaires, j'ai utilisé le plugin build-helper-maven-plugin


<plugin>
 <groupid>org.codehaus.mojo</groupid>
 <artifactid>build-helper-maven-plugin</artifactid>
 <version>1.7</version>
 <executions>
  <execution>
   <id>attach-artifacts</id>
   <phase>package</phase>
   <goals>
    <goal>attach-artifact</goal>
   </goals>
   <configuration>
    <artifacts>
     <artifact>
      <file>${project.build.directory}/generated/wsdl/Service1.wsdl</file>
      <type>wsdl</type>
      <classifier>Service1</classifier>
     </artifact>
     <artifact>
      
      <file>${project.build.directory}/generated/wsdl/Service2.wsdl</file>
      <type>wsdl</type>
      <classifier>Service2</classifier>
     </artifact>
     <artifact>
      
      <file>${project.build.directory}/generated/wsdl/Service3.wsdl</file>
      <type>wsdl</type>
      <classifier>Service3</classifier>
     </artifact>
    </artifacts>
   </configuration>
  </execution>
 </executions>
</plugin>




Ensuite, le module qui aurait besoin de ces fichiers n'aura plus qu'à ajouter les dépendances dans son POM.

mercredi 22 février 2012

Java, SLF4J, Logback & Maven

Petite recette pour une utilisation de SLF4J avec Logback dans un context Maven


Créez un projet maven avec l'arborescence classique. Le package de base que j'utilise dans le projet exemple est "fr.gunduz.logback".

Ajoutez dans le POM les dépendances suivantes :


<dependency>
   <groupid>org.slf4j</groupid>
   <artifactid>slf4j-api</artifactid>
   <version>1.6.4</version>
  </dependency>
  <dependency>
   <groupid>ch.qos.logback</groupid>
   <artifactid>logback-classic</artifactid>
   <scope>runtime</scope>
   <version>1.0.0</version>
</dependency>





Dans le répertoire 'resources', ajouter le fichier logback.xml avec le contenu suivant :


<configuration>
 <appender class="ch.qos.logback.core.ConsoleAppender" name="STDOUT">
  <layout class="ch.qos.logback.classic.PatternLayout">
   <pattern>
    %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
   </pattern>
  </layout>
 </appender>

 <logger level="DEBUG" name="fr.gunduz" />
 <root level="debug">
  <appender-ref ref="STDOUT" />
 </root>
</configuration>


On peut faire une classe pour tester logback :

package fr.gunduz.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class App 
{
  private static final Logger logger = LoggerFactory.getLogger(App.class);

  public static void main( String[] args )
  {
    String test = "with SLF4J and Logback";

    logger.debug("Hello wolrd, {}", test);
  }
}


On peut lancer l'execution :

mvn clean compile exec:java -Dexec.mainClass=fr.gunduz.logback.App



Et vous aurez le 'Hello world'!



Les sources sont disponible sur Google Code

lundi 13 février 2012

Maven, versions plugin

Assigner un nouveau numéro de version a un projet Maven et ses sous projets :
mvn versions:set -DnewVersion=<nouveau numéro de version>

Par exemple:
mvn versions:set -DnewVersion=1.12.1-SNAPSHOT

Il est possible de revenir en arrière si vous rencontrez un problème :
mvn versions:revert


Si tout est bon, on peut faire :
mvn versions:commit 

PS : les sous modules concernés sont uniquement ceux indiqués dans le POM parent. Si vous avez un répertoire de module dans votre projet mais qu'il n'apparait pas dans le POM parent pour diverses raisons, il ne sera pas touché par ces commandes.