Petit focus sur 2 plugins Maven

- Olivier Lamy (http://olamy.blogspot.com/), qui est architecte open source et commiteur actif de moultes projets (je ne les citerai pas, il y en a trop… 😉 ) et qui travaille chez Talend,
- et Olivier Bazoud (http://blog.bazoud.com/) qui est architecte chez Ekino et également co-auteur du livre Spring Batch In Action aux éditions Manning.
Application Assembler Maven Plugin
Description
- *Nix,
- Windows NT
- Java Service Wrapper
Cas d’utilisation
- appassembler:assemble qui permet de créer une arborescence de fichiers comprenant des scripts de lancement de l’application ainsi que de toutes les dépendances nécessaires à son exécution.
- appassembler:create-repository qui permet de créer le répertoire contenant toutes les librairies nécessaires au bon fonctionnement de l’application.
- appassembler:generate-daemons qui permet de créer une arborescence de fichiers comprenant des scripts et des librairies à utiliser pour wrapper l’application dans un service via Java Service Wrapper.
Exemple
package fr.soat.maven.sample; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FooClass { private static final Logger LOGGER = LoggerFactory.getLogger(FooClass.class); public static void main(String[] args) { LOGGER.info("this is FooClass sample"); } }
Cet exemple a pour objectif de montrer, dans un premier temps, ce que génère le goal assemble puis, dans un second temps, le goal generate-daemons.
Pour ce faire, le pom.xml suivant sera utilisé :
<?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>fr.soat.maven.sample</groupId> <artifactId>sample-assembler-plugin</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <projectBaseUri>${project.baseUri}</projectBaseUri> <java.version>1.6</java.version> <slf4j.version>1.6.4</slf4j.version> <logback.version>1.0.0</logback.version> </properties> <dependencies> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> <scope>runtime</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>appassembler-maven-plugin</artifactId> <version>1.2</version> <configuration> <daemons> <daemon> <id>mainService</id> <mainClass>fr.soat.maven.sample.FooClass</mainClass> <commandLineArguments> <commandLineArgument>start</commandLineArgument> </commandLineArguments> <platforms> <platform>jsw</platform> </platforms> <generatorConfigurations> <generatorConfiguration> <generator>jsw</generator> <includes> <include>linux-x86-32</include> <include>linux-x86-64</include> </includes> </generatorConfiguration> </generatorConfigurations> </daemon> </daemons> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>appassembler-maven-plugin</artifactId> <version>1.2</version> <executions> <execution> <goals> <goal>assemble</goal> </goals> </execution> </executions> <configuration> <programs> <program> <mainClass>fr.soat.maven.sample.FooClass</mainClass> <name>main</name> </program> </programs> <binFileExtensions> <unix>.sh</unix> </binFileExtensions> </configuration> </plugin> </plugins> </build> </project>
mvn package
On obtient :
Où le main.sh est le suivant :
#!/bin/sh
# —————————————————————————-
# Copyright 2001-2006 The Apache Software Foundation.
#
# Licensed under the Apache License, Version 2.0 (the “License”);
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an “AS IS” BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# —————————————————————————-
#
# Copyright (c) 2001-2006 The Apache Software Foundation. All rights
# reserved.
BASEDIR=`dirname $0`/..
BASEDIR=`(cd “$BASEDIR”; pwd)`
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
case “`uname`” in
CYGWIN*) cygwin=true ;;
Darwin*) darwin=true
if [ -z “$JAVA_VERSION” ] ; then
JAVA_VERSION=”CurrentJDK”
else
echo “Using Java version: $JAVA_VERSION”
fi
if [ -z “$JAVA_HOME” ] ; then
JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Home
fi
;;
esac
if [ -z “$JAVA_HOME” ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config –jre-home`
fi
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n “$JAVA_HOME” ]
JAVA_HOME=`cygpath –unix “$JAVA_HOME”`
[ -n “$CLASSPATH” ]
CLASSPATH=`cygpath –path –unix “$CLASSPATH”`
fi
# If a specific java binary isn’t specified search for the standard ‘java’ binary
if [ -z “$JAVACMD” ] ; then
if [ -n “$JAVA_HOME” ] ; then
if [ -x “$JAVA_HOME/jre/sh/java” ] ; then
# IBM’s JDK on AIX uses strange locations for the executables
JAVACMD=”$JAVA_HOME/jre/sh/java”
else
JAVACMD=”$JAVA_HOME/bin/java”
fi
else
JAVACMD=`which java`
fi
fi
if [ ! -x “$JAVACMD” ] ; then
echo “Error: JAVA_HOME is not defined correctly.”
echo ” We cannot execute $JAVACMD”
exit 1
fi
if [ -z “$REPO” ]
then
REPO=”$BASEDIR”/repo
fi
CLASSPATH=$CLASSPATH_PREFIX:”$BASEDIR”/etc:”$REPO”/org/slf4j/slf4j-api/1.6.4/slf4j-api-1.6.4.jar:”$REPO”/ch/qos/logback/logback-classic/1.0.0/logback-classic-1.0.0.jar:”$REPO”/ch/qos/logback/logback-core/1.0.0/logback-core-1.0.0.jar:”$REPO”/fr/soat/maven/sample/sample-assembler-plugin/1.0-SNAPSHOT/sample-assembler-plugin-1.0-SNAPSHOT.jar
EXTRA_JVM_ARGUMENTS=””
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n “$CLASSPATH” ]
CLASSPATH=`cygpath –path –windows “$CLASSPATH”
[ -n “$JAVA_HOME” ]
JAVA_HOME=`cygpath –path –windows “$JAVA_HOME”
[ -n “$HOME” ]
HOME=`cygpath –path –windows “$HOME”`
[ -n “$BASEDIR” ]
BASEDIR=`cygpath –path –windows “$BASEDIR”`
[ -n “$REPO” ]
REPO=`cygpath –path –windows “$REPO”`
fi
exec “$JAVACMD” $JAVA_OPTS \
$EXTRA_JVM_ARGUMENTS \
-classpath “$CLASSPATH” \
-Dapp.name=”main” \
-Dapp.pid=”$$” \
-Dapp.repo=”$REPO” \
-Dbasedir=”$BASEDIR” \
fr.soat.maven.sample.FooClass \
“$@”
Après un rapide :
chmod +x target/appassembler/bin/main.sh
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>appassembler-maven-plugin</artifactId> <version>1.2</version> <configuration> <daemons> <daemon> <id>mainService</id> <mainClass>fr.soat.maven.sample.FooClass</mainClass> <commandLineArguments> <commandLineArgument>start</commandLineArgument> </commandLineArguments> <platforms> <platform>jsw</platform> </platforms> <generatorConfigurations> <generatorConfiguration> <generator>jsw</generator> <includes> <include>linux-x86-32</include> <include>linux-x86-64</include> </includes> </generatorConfiguration> </generatorConfigurations> </daemon> </daemons> </configuration> </plugin>
Ainsi, après l’exécution de la commande :
mvn appassembler:generate-daemons
on obtient :
chmod +x target/generated-resources/appassembler/jsw/mainService/bin/mainService
chmod +x target/generated-resources/appassembler/jsw/mainService/bin/wrapper-linux-x86-64
./target/generated-resources/appassembler/jsw/mainService/bin/mainService start
Qu’à cela ne tienne, si il manque le répertoire logs, il suffit de le créer…
wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp
set.default.REPO_DIR=repo
set.default.APP_BASE=.
# Java Classpath (include wrapper.jar) Add class path elements as
# needed starting from 1
wrapper.java.classpath.1=lib/wrapper.jar
wrapper.java.classpath.2=%REPO_DIR%/fr/soat/maven/sample/sample-assembler-plugin/1.0-SNAPSHOT/sample-assembler-plugin-1.0-SNAPSHOT.jar
wrapper.java.classpath.3=%REPO_DIR%/org/slf4j/slf4j-api/1.6.4/slf4j-api-1.6.4.jar
wrapper.java.classpath.4=%REPO_DIR%/ch/qos/logback/logback-classic/1.0.0/logback-classic-1.0.0.jar
wrapper.java.classpath.5=%REPO_DIR%/ch/qos/logback/logback-core/1.0.0/logback-core-1.0.0.jar
Il semble donc qu’il manque le répertoire repo où les librairies sont recherchées…
Qu’a cela ne tienne, la commande suivante :
mvn appassembler:appassembler:create-repository
Conclusion
Tomcat 7 Maven Plugin
Description
Cas d’utilisation
- tomcat7:deploy
- tomcat7:deploy-only
- tomcat7:exec-war
- tomcat7:exec-war-only
- tomcat7:run
- tomcat7:run-war
- tomcat7:run-war-only
- tomcat7:shutdown
Exemple
Maven Tomcat 7 Plugin
package fr.soat.maven.tomcat.sample; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.Writer; public class FooServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Writer out = resp.getWriter(); out.append("GET FooServlet successfully called..."); out.flush(); out.close(); } }
pour le web.xml :
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <servlet> <servlet-name>FooServlet</servlet-name> <servlet-class>fr.soat.maven.tomcat.sample.FooServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FooServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
<?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>fr.soat.maven.tomcat.sample</groupId> <artifactId>sample-tomcat-plugin</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <projectBaseUri>${project.baseUri}</projectBaseUri> <java.version>1.6</java.version> <servlet-api.version>3.0-alpha-1</servlet-api.version> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>${servlet-api.version}</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.0-SNAPSHOT</version> <executions> <execution> <id>tomcat-war-exec</id> <goals> <goal>exec-war</goal> </goals> <phase>package</phase> <configuration> <warRunDependencies> <warRunDependency> <dependency> <groupId>fr.soat.maven.tomcat.sample</groupId> <artifactId>sample-tomcat-plugin</artifactId> <version>${project.version}</version> <type>war</type> </dependency> </warRunDependency> </warRunDependencies> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
On constate que le goal exec-war est associé à la phase package.
De ce fait, en exécutant la commande suivante :
mvn package
on obtient :
Ainsi, avec la commande suivante :
cd target
java -jar sample-tomcat-plugin-1.0-SNAPSHOT-war-exec.jar
il devient alors possible via notre navigateur préféré (à l’url suivante : http://localhost:8080/sample-tomcat-plugin/) d’obtenir la page suivante :
Maven Tomcat 7 Archetype
Ainsi, la commande :
mvn archetype:generate \
-DarchetypeGroupId=org.apache.tomcat.maven \
-DarchetypeArtifactId=tomcat-maven-archetype \
-DarchetypeVersion=2.0-SNAPSHOT \
-DarchetypeRepository=https://repository.apache.org/content/repositories/snapshots/
donne le résultat suivant :
- le module basic-api contient les interfaces pour le webservice REST
- le module basic-api-impl contient l’implémentation des webservices REST
- le module basic-webapp contient l’application web
- le module basic-webapp-exec permet de générer un jar exécutable embarquant l’application web ainsi que le nécessaire de tomcat pour le démarrer en standalone
- le module basic-webapp-it permet de lancer des tests Selenium sur l’application web démarrée au sein d’un Tomcat7
mvn install -Pchrome
Conclusion
Conclusion
Pour aller plus loin…
- Site officiel de l’archetype Maven Tomcat7 : http://tomcat.apache.org/maven-plugin-2.0-beta-1/archetype.html
- Site officiel du plugin Maven Tomcat7 : http://tomcat.apache.org/maven-plugin-2.0-SNAPSHOT/tomcat7-maven-plugin/
- Site officiel du plugin Maven AppAssembler : http://mojo.codehaus.org/appassembler/appassembler-maven-plugin/
- Blog d’Olivier Lamy : http://olamy.blogspot.com/
Nombre de vue : 303
Merci pour ce focus, j’ai découvert le plugin appassembler, il va prochainement prendre la place du plugin assembly dans plusieurs projets !
Cool! Par contre, gare au fait qu’il n’est pas monté dans le Repository Manager…
Gare aussi au chmod 😉
Enfin, en tout cas, ça changera des .bat et .sh maintenus à la main (cf. ici) 😉
Sympa ces deux plugins!
A quand un plugin/archetype permettant de demarrer un conteneur OSGI + ESB + serveur web permettant le choix de chaque plateforme avec Selenium et consorts? Un bon pari non?
hum… c’est vrai que c’est tentant… faudrait juste faire le choix de quelles technos choisir…
Concernant OSGi j’aurais bien envie de choisir l’extension Weld-OSGi pour la couche d’abstraction et Apache Karaf qui offre de bonnes killer features.
Pour les ESB… hum… c’est plus compliqué… ESB light ou ESB “normal” basé sur feu-JBI mais dans ce cas, quid de la configuration multi-noeud… 🙁
Allez, pour le fun, ouvrons le débat 😉