Visualizzazione post con etichetta Maven. Mostra tutti i post
Visualizzazione post con etichetta Maven. Mostra tutti i post

martedì 30 ottobre 2012

Maven, the better quickstart

http://slopjong.de/2011/03/04/maven-the-better-quickstart/


Posted on March 4, 2011



I read a lot of Maven documentation and at the end the most interesting question “How do I run an applicationwith its dependencies?” wasn’t answered. Instead I was flooded with many xml configuration sections without showing a simple and complete configuration file. That’s why I wrote this howto but first a little story.
I came across Ivy and Maven a couple of days ago, both of which make it very easy to add a list of libraries to your Java project and add them to the classpath.
Basically both look for a project configuration file including your dependency list and they download the libraries from the internet and install them in the local repository ~/.ivy2 for Ivy and ~/.m2/repository for Maven which are then shared with your Ivy/Maven projects.
While Ivy is only a dependency manager which is integrated with the most popular build management system for Java projects (Ant), Maven is more than just such a manager. With Maven you have a build system and a dependency manager in one tool.
I focused on Maven and it took me a while to find out that a feature I was looking for wasn’t there natively. I assumed it would have a similar behaviour than Ivy but it hasn’t and works completely different.
I was missing a clear Maven howto which shows in 5 minutes how your project is created, compiled, packaged and especially how your standard java application is run afterwards.
I assume that Maven is already installed and that you are familiar with using a shell as I won’t use m2eclipse, the Maven integration for Eclipse. Maybe I’ll update this post later and give you a little introduction but for now let’s concentrate on using it in a shell.
I don’t guarantee that everything is 100% correct because I don’t use Maven that long. Post a comment if something is wrong.

Creating a new project

First you should know that every single action in Maven is done by a plugin. Maven is shipped with the core plugin (1) by default but I didn’t figure out yet if this downloads the actual jar files the first time the actions are triggered. Maven actions are either goals or phases which groups multiple goals but I’m not going into details here just keep in mind that when you trigger a Maven action it has the following scheme:
mvn plugin:goal options
mvn phase
By entering the following line you create your project:
mvn archetype:generate -DgroupId=de.slopjong.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
Remember the scheme plugin:goal. archetype is the plugin here and generate the goal. What the options mean is listed next.
  1. groupId – this is your package name where your source is located into. In general this is a unique ID of your department or simply use your domain in reverse order.
  2. artifactId – this is the folder name of your project. This name will be used for your package name. In this case my-app would appear in the package name if you created a bundle of your compiled project.
  3. archetypeArtifactId – the archetype is a template of the directory structure. maven-archetype-quickstart is the standard template for simple Maven projects. If you were creating a webapp the archetype would have been maven-archetype-webapp.
  4. interactiveMode – by setting the interactive mode to true you can define a source package named other than your groupId and the version number can be specified by yourself instead of using the standard 1.0-SNAPSHOT
For the archetype maven-archetype-quickstart the resulting folder structure will be …
my-app
|-- pom.xml
`-- src
    |-- main
    |   `-- java
    |       `-- de
    |           `-- slopjong
    |               `-- app
    |                   `-- App.java
    `-- test
        `-- java
            `-- de
                `-- slopjong
                    `-- app
                        `-- AppTest.java
… and for maven-archetype-webapp:
my-app
|-- pom.xml
`-- src
    `-- main
        |-- resources
        `-- webapp
            |-- WEB-INF
            |   `-- web.xml
            `-- index.jsp
You can see that the project object model file pom.xml, src/main/java and src/test/java were created for the standard java application. Web applications need another structure, that’s why for the template maven-archetype-webapp something slightly different was created. Essentially the directory layout is …
my-app/
|-- pom.xml
|-- src
|   |-- main
|   |   |-- assembly
|   |   |-- config
|   |   |-- filters
|   |   |-- java
|   |   |-- resources
|   |   `-- webapp
|   |-- site
|   `-- test
|       |-- filters
|       |-- java
|       `-- resources
`-- target
    |-- classes
    |-- maven-archiver
    `-- test-classes
… for every Maven project. Of course not all these trees are also created by every archetype. Only those are created that are really needed. Having the same directory structure in every Maven project allows you to download projects from other developers while you already know its structure. This is called convention over configuration. In Ant you need to explicity configure it.
When you run the generate goal Maven outputs something like this (I removed all the download messages):
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] >>> maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom >>>
[INFO] 
[INFO] <<< maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom <<<
[INFO] 
[INFO] --- maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Batch mode
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-quickstart:1.0
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: de.slopjong.app
[INFO] Parameter: packageName, Value: de.slopjong.app
[INFO] Parameter: basedir, Value: /home/slopjong
[INFO] Parameter: package, Value: de.slopjong.app
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: artifactId, Value: my-app
[INFO] ********************* End of debug info from resources from generated POM ***********************
[INFO] project created from Old (1.x) Archetype in dir: /home/slopjong/my-app
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.958s
[INFO] Finished at: Wed Mar 02 18:01:44 CET 2011
[INFO] Final Memory: 7M/77M
[INFO] ------------------------------------------------------------------------

Compiling

The previous step created a hello world code example …
package de.slopjong.app;

public class App 
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
    }
}
… which is compiled by executing the compile phase
mvn compile
Now Maven compiled your source to target/classes in your project folder. To run the main method change intotarget and execute
java -cp classes de.slopjong.app.App
Because the package with your class file is located in classes and not in the current directory you have to add it to the classpath by setting the cp option

Adding dependencies

Now the project object model must be edited. Open pom.xml which contains information about the project and configuration details used to build the project. Some of those information were given to Maven at the beginning when you created the project. It also created a jUnit dependency by default.
<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>de.slopjong.app</groupId>
  <artifactId>my-app</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>my-app</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>
If we’d like to use log4j – a framework of the Apache Logging Services – we have to add it as a dependency which Maven will try to resolve next time the project is built. To find out the groupID, the artifactId and theversion of your dependencies I recommend to use a Maven browser like mvnrepository.com.
...
  <dependencies>
    ...
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.16</version>
    </dependency>
  </dependencies>
...
Change the java source …
package de.slopjong.app;

import org.apache.log4j.Logger;

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

    public static void main( String[] args )
    {
        logger.info( "Hello World!" );
    }
}
… and compile again. If you try now to run the main method again at this stage, you’ll get an exception.
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/log4j/Logger
This is because the logger library is not on your classpath. We could add the library from our local repository to the classpath but while this works for a very little amount of dependencies it shouldn’t be done like this. The reason is that the libraries are not flat organized in the repository. Each library itself is contained in a directory like groupId/artifactId/1.2.13/ so you would have to specify the full path to every single library. The disadvantage in adding directly libraries from the repository is that you can’t share your application with somebody else. You can’t just send the class file to a friend and hope he has a Maven environment or the required libraries installed. So now we are at the famous question.

How do I run an application with its dependencies?

When I started looking for an answer I had not yet understood the nitty-gritty of how the plugins integrate with Maven. The quickstarts Maven in 5 minutes and Maven Getting Started Guide don’t talk about this. Instead they have the section How do I build more than one project at once? but is this so important when you’re trying to compile a standard java application, seriously?
The keyword here is again plugin. What you are looking for is done by the assembly plugin which packs all your dependencies into a jar file by executing …
mvn assembly:single
… but please continue reading before execution.
Some older documentation refer to assembly goals other than single but these have been deprecated so don’t use them anymore. Before the product is assembled the first time the plugin must be configured first. Copy the build section so that your pom.xml looks like mine.
<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>de.slopjong.app</groupId>
  <artifactId>my-app</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>my-app</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.16</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.2.1</version>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
Now be sure that you are in the project root directory and assemble. The jar file is located in the target folder afterwards and it only contains the dependencies. Check the plugin site if you wish another plugin configuration .
Change again into target and execute this:
java -cp classes:my-app-1.0-SNAPSHOT-jar-with-dependencies.jar de.slopjong.app.App
The only difference to the previous run is only the newly created jar file on your classpath. And don’t wonder about the warnings …
log4j:WARN No appenders could be found for logger (de.slopjong.app.App).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
… you’ve got. There’s no appender configured but log4j actually is working.
You could also package your class files into a jar which makes it easier to distribute your application. This is done with the package phase.
mvn package
Also this jar file appears in the target folder which must be added to the classpath in place of classes.
java -cp my-app-1.0-SNAPSHOT.jar:my-app-1.0-SNAPSHOT-jar-with-dependencies.jar de.slopjong.app.App
You’ve reached the end of this howto but have a look at the ebooks Sonatype wrote.

Books

Sonatype.com offers Maven ebooks and if you want to avoid filling out a form with your name and email you can append the following lines one after the other to the domain:
  • /books/nexus-book/pdf/nxbook-pdf.pdf
  • /books/m2eclipse-book/pdf/m2ebook-pdf.pdf
  • /books/mvnex-book/pdf/mvnex-pdf.pdf
  • /books/mvnref-book/pdf/mvnref-pdf.pdf

Creare un progetto per Eclipse con Maven

Mi è capitato di scaricare un progetto opensource da source forge completo del suo file pom.xml, di compilarlo con Maven, ma di avere problemi a caricarlo su Eclipse.
Creando un nuovo progetto Java e importandoci dentro i sorgenti, non era ovviamente sufficiente a creare un progetto Eclipse adeguato, con i classpath e packages corretti.

Dopo un paio di ricerche con Google, ho proseguito così:

  • Da prompt dei comandi mi sono posizionato nella cartella a livello più alto del progetto, quella al cui interno si trova il folder src e le altre.
  • Da lì digito:    mvn clean eclipse:eclipse    che ha come effetto quello di creare un progetto per eclipse
  • A questo punto posso semplicemente andare in Eclipse e dal menù file seguo il wizard per importare un progetto già esistente.
  • Attenzione con questo sistema non viene creata la cartella "Lib" con dentro i realtivi jar. Quasta va copiata a mano, altrimenti non si può usare il designer.
Come alternativa a questa procedura è quella di usare     m2eclipse   . Si trattta di un plugin per Eclipse che va installato come gli altri plugin di Eclipse dal menù Help-Install new software- Available software site e si specifica: http://download.eclipse.org/m2e-wtp/releases/ (m2e-wtp releases repository)

QUesto strumento dovrebbe rendere più semplice importare, generare, manutenere progetti Maven con Eclipse.
In particolare dovrebbe mantenere allineato il classpath di Eclipse con il pom.xml di Maven semplicemente specificando dal menù Maven del progetto, la voce  Enable Dependency Management.
In realtà io nn ho trovato questa voce, e non l'housata.

Con m2eclipse dovrebbe essere semplice importare un progetto che fià dispone di un pom.xml, ma nel mio caso, forse per mia ignoranza, non sono riuscito a farlo (seguendo il wizard mi veniva chiesto quali moduli volessi importare ma nnosapevo cosa rispondere) e quindi non l'ho usato.

Informazioni interessanti si trovano in questo forum:

e in questa guida:
       

venerdì 21 settembre 2012

Compilare PMD 5.0.x

Con la 5.0.x del 1/5/2012 la compilazione non si fa più con Ant, ma con MAVEN.
Adesso la guida da seguire è:
http://pmd.sourceforge.net/snapshot/compiling.html

Maven l'avevo già installato.
Il file POM.xml si scarica insieme ai sorgenti, quindi si può passare direttamente a compilare, ma.. anche in questo caso FoxyProxy Video Utility crea problemi.
Una volta scaricato il sorgente da https://pmd.svn.sourceforge.net/svnroot/pmd/branches/pmd/5.0.x
in una cartella locale ( ad es. C:\Users\Duccio\workspace\pmd-5.0.x), da cmd ci si sposta nella cartella in questione e si esegue:


mvn package

Anche in questo caso, come per Selenium, ottengo l'errore:



#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000000180001b62, pid=5652, t
id=5936
#
# JRE version: 7.0_01-b08
# Java VM: Java HotSpot(TM) 64-Bit Server VM (21.1-b02 mixed mode windows-amd64
compressed oops)
# Problematic frame:
# C  [FPServiceProvider64.dll+0x1b62]
#
# Failed to write core dump. Minidumps are not enabled by default on client vers
ions of Windows
#
# An error report file with more information is saved as:
# C:\Users\Duccio\workspace\pmd-5.0.x\hs_err_pid5652.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.sun.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
C:\Users\Duccio\workspace\pmd-5.0.x>

Disinstallando  FoxyProxy Video Utility e lanciando nuovamente 
mvn clean package
 parte la compilazione

domenica 20 maggio 2012

Compilare Selenium Server

Occorre  scaricare e installare Maven dal sito:
http://maven.apache.org/download.html

Per configurare Maven fare riferimento alla guida sulla stessa pagina che indica:

Windows 2000/XP

  1. Unzip the distribution archive, i.e. apache-maven-3.0.4-bin.zip to the directory you wish to install Maven 3.0.4. These instructions assume you chose C:\Program Files\Apache Software Foundation. The subdirectory apache-maven-3.0.4 will be created from the archive.
  2. Add the M2_HOME environment variable by opening up the system properties (WinKey + Pause), selecting the "Advanced" tab, and the "Environment Variables" button, then adding the M2_HOME variable in the user variables with the value C:\Program Files\Apache Software Foundation\apache-maven-3.0.4. Be sure to omit any quotation marks around the path even if it contains spaces. Note: For Maven < 2.0.9, also be sure that the M2_HOME doesn't have a '\' as last character.
  3. In the same dialog, add the M2 environment variable in the user variables with the value %M2_HOME%\bin.
  4. Optional: In the same dialog, add the MAVEN_OPTS environment variable in the user variables to specify JVM properties, e.g. the value -Xms256m -Xmx512m. This environment variable can be used to supply extra options to Maven.
  5. In the same dialog, update/create the Path environment variable in the user variables and prepend the value %M2% to add Maven available in the command line.
  6. In the same dialog, make sure that JAVA_HOME exists in your user variables or in the system variables and it is set to the location of your JDK, e.g. C:\Program Files\Java\jdk1.5.0_02 and that %JAVA_HOME%\bin is in your Path environment variable.
  7. Open a new command prompt (Winkey + R then type cmd) and run mvn --version to verify that it is correctly installed.
attenzione:
nel mio caso ho docuto aggiungere la variabile di ambiente path, a quelle di sistema e non a quelle utente.

Una volta eseguita con successo la verifica con  mvn --version, ho provato a creare un nuovo file pom.xml, semplicemene copiando l'esempio proposto nella guida di selenium:

l'unica verifica che ho fatto è stata sulla versione di selenium da scaricare, per il resto ho copiato e basta.

Ho lanciato "mvn clean install" ed ho ricevuto un errore, sitrattava di FoxyProxy video Utility che già in passato mi aveva dato noie. L'ho disinstallata e ho creato il progetto.
Un paio di volte il processo di download e creazione del progrtto si è interrotto, ma riprovando alla fine ho ottenuto tutto quanto: compresa la cartella target con il jar.


Ho lanciato "mvn eclipse:eclipse" ed ho creato il progetto eclipse senza problemi.
Quando ho provato a caricarlo però ho ricevuto una serie di errori:

Unbound classpath variable: 'M2_REPO/cglib/cglib-nodep/2.1_3/cglib-nodep-2.1_3.jar' in project 'selenium-server-standalone-2.21.0'

A quanto pare basta seguire le indicazioni di:

e aggiungere una variabile di ambiente:

Define and add M2_REPO classpath variable manually into Eclipse IDE. Follow below steps :
  1. Eclipse IDE, menu bar
  2. Select Window > Preferences
  3. Select Java > Build Path > Classpath Variables
  4. Click on the new button > defined a new M2_REPO variable and point it to your local Maven repository
  5. Done.
ATTENZIONE! quale path devo associare ad M2_REPO?