30 mai, 2009

Introducere în Apache Maven 2, Partea 5 - Plugin-urile şi goal-urile Maven

Nucleul Maven este foarte puţin implicat în sarcinile legate de build-ul proiectului dvs. Singur, Maven nu ştie cum să compileze codul dvs. sau cum să creeze un fişier JAR. Maven deleagă tot acest lucru către plugin-urile Maven, cum ar fi plugin-ul Compiler pentru compilare, plugin-ul Jar pentru crearea fişierelor Jar, etc. Aceste plugin-uri sînt descărcate din repozitoriul central Maven la prima necesitate. Atunci cînd descărcaţi Maven, dvs. descărcaţi doar nucleul Maven, care constă dintr-un shell care ştie doar să analizeze comenzile din linia de comandă, să gestioneze classpath-ul, să analizeze fişierul POM şi să descarce plugin-uri Maven atunci cînd este necesar. Prin păstrarea plugin-ului Compiler separat de nucleul Maven şi asigurarea unui mecanism de actualizare, Maven face mai uşor pentru utilizatori de a avea acces la cele mai noi opţiuni în compilator. În Maven, noi nu definim sarcina de compilare într-un fişier de build, în schimb folosim plugin-ul Compiler care este împărtăşit de fiecare utilizator de Maven. Dacă apare o îmbunătăţire a plugin-ului Compiler, atunci fiecare proiect care utilizează Maven imediat poate beneficia de această îmbunătăţire fără a fi nevoie de careva schimbări.

Maven Plugin With Goals

Un Plugin Maven este o colecţie de unul sau mai multe goal-uri (scop, sarcină). Un goal este o sarcină specifică, care poate fi executat ca un goal de sine stătător sau împreună cu alte goal-uri ca parte a unui build mai mare. Un goal este o unitate de lucru în Maven. Exemple de goal-uri includ goal-ul compile din plugin-ul Compiler care compilează tot codul sursă al proiectului, sau goal-ul test din plugin-ul Surefire care execută unit testele. Goal-urile sînt configurate cu ajutorul proprietăţilor de configurare care pot fi utilizate pentru a personaliza comportamentul acestora. [Click mai jos pentru a citi articolul în întregime]

Maven prevede de asemenea posibilitatea de a defini plugin-uri personalizate. Un plug-in personalizat poate fi scris în Java sau în orice alt limbaj, inclusiv Ant, Groovy, Ruby, beanshell. Cînd scrieţi un plug-in propriu, dvs. pur şi simplu grupaţi un set de goal-uri într-un singur artifact de plugin. Fiecare goal în Maven corespunde unui MOJO (Maven Old Java Object). De exemplu goal-ul compiler:compile corespunde clasei CompilerMojo în Plugin-ul Maven Compiler şi goal-ul jar:jar corespunde clasei JarMojo în Plugin-ul Maven Jar.

Pentru a executa un singur goal al unui plug-in Maven vom folosi sintaxa mvn compiler:compile, unde compiler este prefixul plugin-ului şi compile este goal-ul. De asemenea putem transmite perechi -Dname=value ca argumente atunci cînd executăm un goal. Aceste argumente sînt sub forma de -D proprietăţi, similare cu acele opţiuni care pot fi transmise către Java Virtual Machine din linia de comandă.

Acum, să descriem mai detaliat ce înseamnă prefixul unui plugin. Deoarece fiecare plugin Maven este un artifact Maven, el ar trebui să fie referit folosind coordonatele Maven. Specificarea de fiecare dată a groupId, artifactId, version şi goal-ulului în linia de comandă este greoaie. Pentru a rezolva acest lucru, Maven atribuie cîte un prefix fiecărui plugin. Acum în loc să tastaţi:

mvn org.apache.maven.plugins:maven-compiler-plugin:2.0.2:compile
puteţi folosi prefix-ul de plugin compiler şi transforma linia de comandă de mai sus în mvn compiler:compile. Cum Maven transformă compiler:compile în org.apache.maven.plugins:maven-compiler-plugin:2.0.2? Maven se uită într-un fişier în repozitoriul Maven pentru a obţine lista de plugin-uri pentru un anumit groupId. În mod implicit, Maven este configurat să caute plugin-uri în două grupe: org.apache.maven.plugins şi org.codehaus.mojo. Cînd Maven caută plugin-uri pentru un anumit groupId, el preia un fişier XML din repozitoriul Maven care conţine metadate despre artifact-ele conţinute într-un grup. Acest fişier XML este specific pentru fiecare repozitoriu. Dvs. puteţi vedea metadatele Maven pentru grupul org.apache.maven.plugins în repozitoriul local Maven (<user_home>/.m2/repository) în fişierul org/apache/maven/plugins/maven-metadata-central.xml. Mai jos este arătat un fragment din fişierul maven-metadata-central.xml din grupul org.apache.maven.plugins.
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
  <plugins>
    ...
    <plugin>
      <name>Maven Clean Plugin</name>
      <prefix>clean</prefix>
      <artifactId>maven-clean-plugin</artifactId>
    </plugin>
    <plugin>
      <name>Maven Compiler Plugin</name>
      <prefix>compiler</prefix>
      <artifactId>maven-compiler-plugin</artifactId>
    </plugin>
    <plugin>
      <name>Maven Jar Plugin</name>
      <prefix>jar</prefix>
      <artifactId>maven-jar-plugin</artifactId>
    </plugin>
    ...
  </plugins>
</metadata>

După cum se poate vedea anume fişierul maven-metadata-central.xml în repozitoriul local este ceea ce face posibil ca dvs. să executaţi plugin-uri folosind doar prefixul plugin-ului.


Plugin-ul de Ajutor Maven

Plugin-ul de Ajutor Maven vă permite să aflaţi listă de atribute a unui plugin Maven, să afişaţi POM-ul efectiv, să vedeţi setările efective sau lista activă de profiluri Maven.

Plugin-ul de Ajutor Maven are patru goal-uri. Următoarele comenzi oferă cîteva informaţii generale despre cele patru goal-uri:

  • help:describe - descrie atributele unui plugin. Acest goal vă arată informaţii despre un plugin sau un goal al unul plugin. Cu ajutorul parametrului plugin puteţi specifica plugin-ul pe care doriţi să-l investigaţi. Ca valoare a acestui parametru poate fi atît prefixul plugin-ului (de exemplu compiler pentru maven-compiler-plugin) sau groupId:artifactId[:version] unde versiunea este opţională. De exemplu, următoarea comandă foloseşte goal-ul describe al plugin-ului de Ajutor pentru a afişa informaţii despre plugin-ul Maven Compiler:
    mvn help:describe -Dplugin=compiler
    ...
    [INFO] [help:describe]
    [INFO] org.apache.maven.plugins:maven-compiler-plugin:2.0.2

    Name: Maven Compiler Plugin
    Description: Maven Plugins
    Group Id: org.apache.maven.plugins
    Artifact Id: maven-compiler-plugin
    Version: 2.0.2
    Goal Prefix: compiler

    This plugin has 2 goals:

    compiler:compile
    Description: Compiles application sources
    Deprecated. No reason given

    compiler:testCompile
    Description: Compiles application test sources
    Deprecated. No reason given

    For more information, run 'mvn help:describe [...] -Ddetail'
    Puteţi obţine acelaşi lucru utilizînd sintaxa groupId:artifactId[:version]
    mvn help:describe -Dplugin=org.apache.maven.plugins:maven-compiler-plugin
    Dacă doriţi ca Plugin-ul de Ajutor să afişeze lista completă a goal-urilor cu parametri, executaţi goal-ul help:describe cu parametrul detail, după cum urmează:
    mvn help:describe -Dplugin=compiler –Ddetail
    Pentru a obţine informaţii despre un singur goal, setaţi parametrul mojo alături de parametrul plugin. Următoarea comandă afişează toată informaţia cu privire la goal-ul compile din plugin-ul Compiler:
    mvn help:describe -Dplugin=compiler -Dmojo=compile -Ddetail

    Celelalte trei goal-uri: active-profiles, effective-pom şi effective-settings trebuie să fie rulate în directorul de bază ale unui proiect.
  • help:active-profiles - afişează profilurile (proiect, utilizator, la nivel global) care sînt active pentru build.
  • help:effective-pom - afişează POM-ul efectiv pentru build-ul curent luînd în consideraţie profilurile active.
  • help:effective-settings - afişează setările calculate pentru acest proiect avînd în vedere orice profil de îmbunătăţire şi de moştenirea setărilor globale.

Aici încheiem acest post. În următorul post vom vorbi despre Ciclul de viaţă Maven.

24 mai, 2009

Introducere în Apache Maven 2, Partea 4 - Dependenţele proiectelor

Posibilitatea de a localiza uşor un artifact într-un repozitoriu pe baza coordonatelor Maven, ne oferă posibilitatea de a defini dependenţe către alte artifacte în POM-ul proiectului. Dacă veţi analiza POM-ul care a fost arătat în articolul precedent Introducere în Apache Maven 2, Partea 3 - Project Object Model (POM), în paragraful Coordonatele Maven, veţi vedea că există o secţiune care se ocupă de dependenţe, şi că în această secţiune se conţine o singură dependenţă către JUnit.

Maven poate gestiona atât dependenţe interne, cît şi externe. O dependenţă externă pentru un proiect Java ar putea fi o bibliotecă, cum ar fi Log4J sau Spring Framework. O dependenţă internă este reprezentată prin unul din proiectele dvs. care depinde de un alt proiect al dvs. De exemplu, un proiect cu o aplicaţie web, care depinde de un alt proiect care conţine service clasele sau logica de persistenţă.

Pentru a înţelege mai bine, mai jos sînt arătate câteva exemple de dependenţe:

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>org.apache.velocity</groupId>
      <artifactId>velocity</artifactId>
      <version>1.6.2</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.4</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>
  ...
</project>
[Click mai jos pentru a citi articolul în întregime]

Prima întrebare pe care o să vă o puneţi este: De unde am ştiut noi exact care sînt valorile pentru groupId şi artifactId pentru aceste artifacte? Puteţi localiza toate artifactele Maven folosind pagina web http://www.mvnrepository.com. Acest site oferă o interfaţă de căutare pentru repozitoriul Maven. Cu ajutorul lui puteţi căuta artifactele de care aveţi nevoie pentru a le adăuga ca dependenţe în proiectul dvs. Aveţi posibilitatea să căutaţi un artifact după groupId, artifactId sau chiar descriere. La căutare, o să vă fie afişat artifactul cu lista tuturor versiunilor cunoscute de repozitoriul central Maven. Făcînd click pe detaliile pentru o anumită versiune, veţi fi redirecţionat către o altă pagină care va conţine elementul <dependency> pe care îl puteţi copia şi insera în propriul pom.xml. Unele dintre aceste dependenţe sînt atât de des utilizate (de exemplu JUnit), încît le veţi memoriza foarte rapid groupId şi artifactId.

După cum se vede din fragmentul de POM de mai sus, o dependenţă se declară folosind groupId, artifactId şi version ale artifactului, şi scope (domeniul de aplicare) al acestei dependenţe.

Maven prevede diferite domenii de aplicare(scope) ale dependenţelor. Domeniul de aplicare dirijează care dependenţe sînt disponibile, şi în care classpath. Totodată el dirijează care dependenţe sînt incluse în distribuţie o dată cu aplicaţia. Să examinăm fiecare domeniu de aplicare în detaliu:

  • compile - este domeniul de aplicare implicit. Toate dependenţele au domeniul de aplicare compile în cazul în care domeniul de aplicare nu este specificat. Dependenţele cu domeniul de aplicare compile sînt disponibile în toate classpath-urile, de asemenea ele sînt ambalate(packaged) odată cu aplicaţia la distribuire.
  • provided - sînt folosite atunci când aşteptaţi ca JDK, container-ul sau server-ul să vă ofere aceste dependenţe. De exemplu, dacă dezvoltaţi o aplicaţie web, veţi avea nevoie de Servlet API disponibil în classpath-ul de compilare pentru a compila un servlet, dar nu doriţi să includeţi Servlet API la ambalare în WAR, deoarece jar-ul cu Servlet API este furnizat de server-ul sau servlet container-ul dvs. Dependenţele provided sînt disponibile doar în classpath-ul de compilare, nu runtime. De asemenea ele nu sînt ambalate odată cu aplicaţia la distribuire.
  • runtime - sînt necesare pentru executarea şi testare sistemului, dar nu sînt necesare pentru compilare. De exemplu, aţi putea avea nevoie de jar-ul cu JDBC API la momentul compilării şi de implementarea driver-ului JDBC numai la runtime.
  • test - nu sînt necesare în timpul funcţionării normale a aplicaţiei şi sînt disponibile numai în perioada de compilare şi execuţie a testelor.
  • system - este similar cu provided cu excepţia faptului că va trebui să oferiţi o cale explicită către fişierul jar în sistemul de fişiere local. Acest lucru este destinat pentru a permite compilarea cu folosirea bibliotecilor native. Dacă declaraţi domeniului de aplicare system, atunci trebuie să specificaţi de asemenea şi elementul systemPath.

Pe lîngă specificarea unei versiuni fixe, puteţi de asemenea specifica o serie de versiuni care ar putea satisface o anumită dependenţă. Puteţi face acest lucru prin plasarea unui sau mai multor numere de versiuni între următoarele caractere:

(, ) - Cuantificatori exclusivi

[, ] - Cuantificatori inclusivi

De exemplu, dacă doriţi să accesaţi orice versiune JUnit mai mare sau egală decît 3.8, dar mai mică decît 4.0, dependenţa dumneavoastră ar arăta aşa cum este arătat mai jos:

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>[3.8,4.0)</version>
  <scope>test</scope>
</dependency>

Dacă doriţi să depindeţi de orice versiune de JUnit nu mai mare decît 3.8.1, atunci trebuie să specificaţi doar o limită superioară inclusiv. Versiunea înainte de, sau după virgulă nu este necesară, şi înseamnă +/- infinit.

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>[,3.8.1]</version>
  <scope>test</scope>
</dependency>

Notă: Versiunea [1.2] înseamnă doar versiunea 1.2 şi nimic altceva. Când se declară o versiune normală, cum ar fi versiunea 3.8.1 de Junit, intern, aceasta este reprezentată ca: "permite orice, dar prefera 3.8.1". Acest lucru înseamnă că atunci când este detectat un conflict, Maven este autorizat să folosească algoritmi de conflict pentru a alege cea mai buna versiune. Dacă se specifică [3.8.1], aceasta înseamnă că doar 3.8.1 va fi folosit şi nimic altceva. Dacă în altă parte există o dependenţă care a specificat [3.8.2], atunci veţi obţine o eroare de conflict la build.


Dependenţe Tranzitive

O dependenţă tranzitivă este o dependenţă de către o altă dependenţă. Dacă un proiect A depinde de un alt proiect B, care la rîndul său depinde de proiectul C, atunci proiectul C este considerat o dependenţă tranzitivă a proiectului A. Dacă proiectul C depinde la rîndul său de proiectul D, atunci şi proiectul D de asemenea este considerat o dependenţă tranzitivă a proiectului A.

Maven Transitive Dependencies

Maven poate gestiona dependenţele tranzitive şi scuti developer-ul de necesitatea de a găsi toate dependenţele necesare pentru a compila şi rula o aplicaţie. Puteţi doar să declaraţi o dependenţă de vre-un framework sau bibliotecă fără să vă faceţi griji pentru depistarea tuturor dependenţelor pe care acestea le au.

Maven realizează acest lucru prin construirea unui graf de dependenţe şi rezolvarea tuturor conflictelor şi suprapunerilor care ar putea apărea. De exemplu, dacă Maven găseşte două proiecte care depind de aceleaşi groupId şi artifactId, acesta va selecta în mod automat care dependenţă să o folosească, întotdeauna favorizînd cea mai recentă versiune a dependenţei. Deşi sună convenabil, există unele cazuri în care dependenţele tranzitive pot cauza unele probleme de configurare. În astfel de scenarii, puteţi utiliza excluderea de dependenţe.

Mai jos este arătat un exemplu în care se adaugă o dependenţă de proiectul A, dar se exclude dependenţa tranzitivă de proiectul B şi se înlocuieşte cu o dependenţă de proiectul X:

<dependencies>
  <dependency>
    <groupId>com.company.project</groupId>
    <artifactId>project-a</artifactId>
    <version>1.0</version>
    <exclusions>
      <exclusion>
        <groupId>com.company.project</groupId>
        <artifactId>project-b</artifactId>
      </exclusion>
    </exclusions>
  </dependency>
  <dependency>
    <groupId>com.company.project</groupId>
    <artifactId>project-x</artifactId>
    <version>1.0</version>
  </dependency>
</dependencies>

După cum puteţi observa nu există nici un semn că dependenţa de proiectul X este o înlocuire. În cazul acesta proiectul X este o bibliotecă care asigură acelaşi API ca şi proiectul B. Pentru a înlocui o dependenţă tranzitivă cu o altă dependenţă, trebui să excludeţi dependenţa tranzitivă şi să declaraţi o altă dependenţă în loc.

De menţionat, că Maven nu descărca doar fişierul JAR al dependenţei, Maven descarcă de asemenea şi fişierul POM al dependenţei. Faptul că Maven descarcă fişierele POM adăugător faţă de artifacte îi permite să suporte dependenţele tranzitive, deoarece Maven consultă POM-urile dependenţelor pentru a găsi oricare alte dependenţe tranzitive. Aceste dependenţe tranzitive sînt apoi adaugate ca dependenţe a proiectului curent.


Dependenţe Opţionale

Dacă aveţi nevoie de câteva biblioteci pentru a compila proiectul dvs, dar nu doriţi ca toate bibliotecile să apară ca dependenţe tranzitive pentru proiectele care vor utiliza proiectul dvs ca dependenţă, atunci puteţi utiliza dependenţe opţionale aşa cum este arătat mai jos. De obicei aceasta situaţie poate apărea atunci cînd aplicaţia dvs suportă diferite implementări ale unui şi acelaşi API şi dvs lăsaţi utilizatorii să-şi aleagă singuri implementarea pe care o doresc.

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.company.project</groupId>
  <artifactId>my-project</artifactId>
  <version>1.0.0</version>
  <dependencies>
    <dependency>
      <groupId>org.othercompany</groupId>
      <artifactId>project-a</artifactId>
      <version>1.2.0</version>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>net.bigcompany</groupId>
      <artifactId>project-b</artifactId>
      <version>2</version>
      <optional>true</optional>
    </dependency>
  </dependencies>
</project>

Odată ce aţi declarat aceste dependenţe ca opţionale, sînteţi obligat să le includeţi în mod explicit în cadrul proiectului care depinde de my-project. De exemplu, dacă a-ţi scris o aplicaţie care depinde de my-project şi doriţi să folosiţi project-b ca implementare, atunci va trebui să adăugaţi următoarea configurare pentru proiectului dvs:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.company.project</groupId>
  <artifactId>my-application</artifactId>
  <version>1.0.0</version>
  <dependencies>
    <dependency>
      <groupId>com.company.project</groupId>
      <artifactId>my-project</artifactId>
      <version>1.0.0</version>
    </dependency>
    <dependency>
      <groupId>net.bigcompany</groupId>
      <artifactId>project-b</artifactId>
      <version>2</version>
    </dependency>
  </dependencies>
</project>


Referinţe către Proprietăţi

POM-ul poate include referinţe la proprietăţi precedate de semnul dolarului şi înconjurate de două acolade. Spre exemplu, priviţi la următorul POM:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.company.project</groupId>
  <artifactId>project-a</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
  <build>
    <finalName>${project.groupId}-${project.artifactId}</finalName>
  </build>
</project>

Când Maven citeşte POM-ul, el înlocuieşte referinţele la proprietăţi cu valorile acestora. În exemplul de mai sus finalName va fi evaluat în com.company.project-project-a. Aici noi am personalizat numele fişierului JAR generat prin adăugarea elementului finalName în configurarea de build a proiectului. Cu finalName egal cu com.company.project-proiect-a, build-ul va produce un fişier JAR în target/com.company.project-project-a.jar.

Maven pune la dispoziţie trei variabile implicite care pot fi folosite pentru a accesa variabilele de mediu şi sistem, informaţii din POM şi setările Maven:

  • env - expune variabile de mediu şi sistem care la rîndul lor sînt expuse de către sistemul de operare sau shell. De exemplu, o referinţă la ${env.PATH} într-un POM Maven va fi înlocuită cu valoarea variabilei de mediu $PATH (sau %PATH% în Windows).
  • project - expune POM-ul în întregime. Puteţi utiliza punctul (.) pentru a crea calea de referinţă către valoarea unui element din POM. De exemplu, în această secţiune am folosit groupId şi artifactId pentru a seta elementul finalName. Sintaxa pentru aceste referinţe a fost: ${project.groupId}-${project.artifactId}.
  • settings - expune informaţiile despre setările Maven. Puteţi utiliza punctul (.) pentru a crea calea de referinţă către valoarea unui element din fişierul settings.xml. De exemplu ${settings.offline} face referinţă la valoarea din elementul offline în <user_home>/.m2/settings.xml.

În plus faţă de cele trei variabile implicite, puteţi face referinţă la proprietăţile de sistem Java precum şi orice proprietăţi personalizate definite în POM sau într-un profil de build:

  • Proprietăţile de sistem Java - toate proprietăţile accesibile prin metoda getProperties() din java.lang.System sînt expuse ca POM proprietăţi. Câteva exemple de de proprietăţi sînt: ${user.name}, ${user.home}, ${java.home}, ${os.name}, etc. O listă completă a proprietăţilor de sistem Java pot fi găsite în Javadoc pentru clasa java.lang.System.
  • Proprietăţile personalizate - pot fi setate cu ajutorul elementului properties în pom.xml sau settings.xml, sau pot fi încărcate din fişiere externe. Dacă aţi stabilit o proprietate numită myproperty în pom.xml, atunci la această proprietate se poate face referinţă cu ${myproperty}. Mai jos este arătată sintaxa pentru definirea ${myproperty} = myvalue în POM:
    <project>
      ...
      <properties>
        <myproperty>myvalue</myproperty>
      </properties>
      ...
    </project>
    

Atît pentru astăzi. În următorul post vom descrie Plugin-urile şi Goal-urile Maven.

16 mai, 2009

Introducere în Apache Maven 2, Partea 3 - Project Object Model (POM)

Project Object Model (modelul obiect al proiectului) este un fişier XML, numit pom.xml, în care este definită structura proiectului, este configurat build-ul şi sînt definite relaţiile dintre proiecte. Un proiect Maven este caracterizat prin prezenţa fişierului pom.xml. Cînd Maven rulează, el consultă pom.xml pentru informaţii despre proiect. POM răspunde la astfel de întrebări ca: Ce fel de tip de proiect este acesta? Care este numele proiectului? Există careva personalizări pentru acest proiect?

Informaţia din POM este împărţită în 4 categorii:

  • Informaţia generală despre proiect - aceasta include numele proiectului, URL-ul proiectului, compania dezvoltatoare, lista de developeri şi colaboratori, licenţă proiectului.
  • Setările pentru build - În această secţiune se conţin toate personalizările proiectului. Se poate schimba locaţia fişierelor sursă, a testelor, se pot adăuga noi plugin-uri, se pot ataşa noi goal-uri (scopuri, obiective) ale plugin-urilor la ciclul de viaţă al proiectului, se pot personaliza parametrii pentru generarea paginii web a proiectului.
  • Mediul de build - constă din profiluri care pot fi activate pentru a fi utilizate în diferite medii (environment-uri). De exemplu, în timpul dezvoltării (development) se poate de ales de a face deploy pe un server de dezvoltare, iar în producţie de a face deploy pe un server de producţie.
  • Relaţiile POM-ului - Un proiect rareori este singur. De cele mai multe ori el depinde de alte proiecte, moşteneşte setări din POM-ul proiectului părinte, îşi defineşte propriile coordonate şi poate include şi sub-module.

Dacă dvs. doriţi să dezvoltaţi un proiect simplu, care produce un JAR, din sursele aflate în src/main/java, şi doriţi să rulaţi testele JUnit din src/test/java, atunci nu aveţi nevoie să personalizaţi nimic. Tot de ce aveţi nevoie în acest caz este cel mai simplu POM posibil, arătat mai jos:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.company.example</groupId>
    <artifactId>simple-project</artifactId>
    <version>1</version>
</project>

Dacă puneţi careva cod sursă în subdirectorul src/main/java şi rulaţi mvn install atunci în directorul target veţi avea generat fişierul simple-project-1.jar. [Click mai jos pentru a citi articolul în întregime]

Toate POM-urile proiectelor Maven extind acelaşi Super POM, care defineşte un set de valori şi setări implicite împărtăşite de toate proiectele. Super POM-ul este o parte din instalarea Maven, şi poate fi găsit în fişierul maven-2.1.0-uber.jar în ${M2_HOME}/lib. Dacă vă uitaţi în acest fişier JAR, veţi găsi un fişier numit pom-4.0.0.xml în pachetul org.apache.maven.project.

Deoarece POM-urile pot moşteni configurarea de la alte POM-uri, întotdeauna trebuie să ne gîndim la POM din punct de vedere al asocierii Super POM-ului cu POM-ul părinte şi în final cu POM-ul proiectului propriu zis. Maven începe cu Super POM şi apoi suprascrie configurarea implicită a acestuia cu unul sau mai multe POM-uri părinte. Apoi suprascrie configurarea primită cu POM-ul proiectului propriu zis. În final se ajunge la un POM efectiv, care este un amestec de diverse POM-uri. Dacă doriţi să vedeţi POM-ul efectiv al proiectului atunci puteţi să rulaţi goal-ul effective-pom al plugin-ului de ajutor Maven:

$ mvn help:effective-pom

După executarea acestei comenzi, ar trebui să vedeţi un POM mai mare, care expune pe lîngă ceea ce aţi definit dvs. explicit în POM, şi setările implicite de Maven (deoarece le va moşteni din Super POM). Plugin-urile şi goal-urile din Maven vor fi explicate în continuare într-un articol separat.


Coordonatele Maven

Cînd Maven execută un goal, fiecare goal are acces la informaţia definită în POM-ul proiectului. Cînd goal-ul jar:jar crează un fişier JAR, el accesează POM-ul pentru a găsi care trebuie sa fie numele fişierului JAR. Cînd goal-ul compiler:compile compilează sursele în byte-cod, el la fel accesează POM-ul pentru a vedea dacă nu sînt careva parametri definiţi pentru goal-ul compile. Toate goal-urile sînt executate în contextul POM-ului. Goal-urile nu sînt altceva decît nişte acţiuni pe care noi dorim să le aplicăm asupra unui proiect, iar proiectul este definit printr-un POM. POM-ul îi dă nume proiectului, îl înzestrează cu un set unic de identificatori (coordonate) şi stabileşte relaţii între acest proiect şi alte proiecte prin intermediul dependenţelor şi părinţilor.

Coordonatele Maven definesc un set de identificatori care pot fi folosiţi pentru a identifica un proiect, o dependenţă sau un plugin într-un POM Maven. Daţi să examinăm următorul POM simplu:

<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>com.company.project</groupId>
  <artifactId>simple</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>simple</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>

În POM-ul de mai sus am evidenţiat (rîndurile 6, 7, 8, 9) coordonatele Maven pentru acest proiect: groupId, artifactId, version şi packaging. Aceşti identificatori combinaţi împreună, plus încă unul classifier, care nu este menţionat în acest POM, reprezintă coordonatele unui un proiect în Maven. La fel ca şi în oricare alt sistem de coordonate, în Maven, coordonatele reprezintă o adresă pentru un anumit punct din "spaţiu". Maven face referinţă la un proiect prin coordonatele sale în cazul în care un proiect se referă la un alt proiect, fie ca dependenţă, plugin sau o referinţă către proiectul părinte. Coordonatele Maven sînt adesea scrise utilizând un 2 puncte(:) ca delimitator în următorul format: groupId:artifactId:packaging:version. În exemplul de POM de mai sus, coordonatele pentru proiect sînt org.company:simple:jar:1.0-SNAPSHOT.

Mai jos vom examina fiecare identificator în parte:

  • groupId - Grupul, compania, echipa, organizaţia, proiectul, sau un oricare alt grup. Convenţia pentru identificatoarele de grup este că ele încep cu numele invers al domen-ului organizaţiei care creează proiectului. De exemplu org.apache.maven este baza pentru toate groupId ale artifactelor produse de proiectul Apache Maven. Identificatoarele de grup, sînt transpuse în locaţii în repozitoriul Maven, de exemplu, org.apache.maven poate fi găsit în /org/apache/maven.
  • artifactId - este identificatorul principal al proiectului. Este un identificator unic în cadrul groupId care reprezintă un singur proiect. Nu pot exista două proiecte cu aceleaşi groupId şi artifactId. În timp ce "." (punct) este frecvent utilizat în groupId, aici ar trebui să se evite utilizarea lui. Acest lucru poate cauza probleme la analiza numelor.
  • version - versiunea proiectului. Proiectele care au fost puse în circulaţie deja (released), au o versiune fixă. În Maven versiunile sînt formate din următoarele părţi: versiunea majoră, versiunea minoră, versiunea incrementală şi calificativul. Într-o versiune, aceste părţi corespund următorului format:
    <major version>.<minor version>.<incremental version>-<qualifier>
    De exemplu, versiunea "1.3.5-beta-01" are o versiune majoră de 1, versiunea minoră 3, versiunea incrementală 5 şi un calificativ beta-01. Calificativul există pentru a reprezenta release-urile: alfa şi beta. Versiunile Maven pot de asemenea să conţină şi următorul şir de literali:
    • SNAPSHOT - ceea ce semnifică faptul că un proiect este în prezent în curs de dezvoltare activ. Există posibilitatea de a configura Maven pentru a descărca periodic cea mai recentă versiune snapshot din repozitoriu. În cazul în care o versiune conţine şirul de caractere SNAPSHOT, atunci Maven va înlocui acest şir cu valoarea datei şi orei convertite la UTC (Coordinated Universal Time) atunci cînd se instalează sau se pune în circulaţie acest component. De exemplu, 1.4-SNAPSHOT se va transforma în 1.4-20090501-112507-1 dacă i-ar fi fost făcut deploy la 11:25 la 1 mai 2009 UTC.
    • LATEST - se referă la cea mai recentă versiune snapshot sau la cea mai recentă versiune lansată (released) a unui anumit artifact din repozitoriu.
    • RELEASE - se referă la cea mai recentă versiune care nu este snapshot a unui anumit artifact din repozitoriu.

Packaging-ul (formatul de ambalare) proiectului este de asemenea o componentă importantă în sistemul de coordonate Maven, dar acesta nu face parte din sistemul unic de identificatori ale unui proiect Maven. Setul groupId:artifactId:version face proiectul unic; nu poate exista un proiect cu aceleaşi trei groupId, artifactId, şi version.

  • packaging - tipul proiectului, implicit este jar. Descrie ce format produce proiectul respectiv. Un proiect cu packaging jar, produce un fişier JAR. Un proiect cu packaging war, produce o aplicaţie web.

Şi al patrulea, mai puţin folosit identificator:

  • classifier - se foloseşte atunci cînd este necesar pentru acelaşi proiect de a produce două artifacte separate, din motive tehnice. De exemplu, dacă se doreşte două artifacte JAR, unul compilat cu compilator Java 1.4 şi altul compilat cu compilator Java 6. În acest caz se poate utiliza calificativul pentru a produce două artifacte JAR în aceeaşi combinaţie groupId:artifactId:version.

În cazul în care proiectul este instalat în repozitoriul local Maven, acesta devine imediat disponibil pe plan local pentru orice alt proiect care doreşte să-l folosească. Tot ce trebuie de făcut este de-al adăuga ca pe o dependenţă folosind setul unic de coordonate Maven.


Repozitoriile Maven

Maven vine cu o locaţie implicită a remote repozitoriului http://repo1.maven.org/maven2, care este folosită pentru a descărca plugin-urile Maven de bază şi dependenţele. Maven descarcă plugin-urile şi dependenţele din repozitoriul remote la dvs. pe computer, într-un repozitoriu local. Odată ce Maven a descărcat un artifact din repozitoriul remote, el niciodată nu va mai avea nevoie să-l descarce încă o dată, deoarece Maven se uită întotdeaună mai întîi în repozitoriul local. În Windows XP repozitoriul local este situat în C:\Documents and Settings\USERNAME\.m2\repository, în sistemele din familia Unix el se afla în ~/.m2/repository.

Ce face un repozitoriu să fie un Maven repozitoriu? Un Maven repozitoriu este definit prin structura sa, un repozitoriu este o colecţie de artifacte ale proiectelor, stocate într-o structură şi un format care poate fi uşor înţeles de către Maven. Într-un repozitoriu Maven totul este stocat într-o structură de directoare, care se aseamănă foarte mult cu sistemul de coordonate Maven al unui proiect. Puteţi vedea această structură prin accesarea paginii repozitoriului central Maven http://repo1.maven.org/maven2/. Veţi vedea că un artifact cu coordonatele org.apache.velocity:velocity:1.6.2 este disponibil în sub-directoriul /org/apache/velocity/velocity/1.6.2/ într-un fişier numit velocity-1.6.2.jar. Standardul pentru un repozitoriu Maven este de a stoca un artifact în următoarea locaţie relativ cu directorul rădăcină al repozitoriului:

/<groupId>/<artifactId>/<version>/<artifactId>-<version>.<packaging>

Repozitoriul Maven este atît un cache local pentru artifactele descărcate din repozitoriul remote, cît şi un mecanism care permite proiectelor de a depinde unul de celălalt. Dacă aveţi 2 proiecte, A şi B, unde proiectul B depinde de artifactele produse de proiectul A, atunci Maven va prelua artifactele proiectului A din repozitoriul local atunci cînd va face build proiectului B.

Aici încheiem acest articol. În următorul post vom vorbi despre dependenţele proiectelor în Maven.

13 mai, 2009

Introducere în Apache Maven 2, Partea 2 - Instalarea Maven

În acest articol se va descrie cum de instalat Apache Maven pe computer-ul dvs. Mai jos sînt enumerate instrucţiunile care trebuiesc urmate:

  1. Verificaţi instalarea Java - Încredinţaţi-vă că aveţi instalată cel puţin Java 5. Atît Java 5 cît şi Java 6 se potrivesc, dar cel mai bine e să aveţi ultima versiune disponibilă. Pentru a verifica ce versiune de Java aveţi instalată puteţi rula următoarea comandă:
    C:\>java -version
    java version "1.5.0_18"
    Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_18-b02)
    Java HotSpot(TM) Client VM (build 1.5.0_18-b02, mixed mode, sharing)
  2. Descărcaţi Maven - Puteţi descărca Maven de pe pagina oficiala a proiectului Apache Maven http://maven.apache.org/download.html. Aveţi grijă să alegeţi ultima versiune disponibilă.
  3. Instalaţi Maven - După ce l-aţi descărcat, alegeţi o locaţie şi despachetaţi fişierul arhivat descărcat. Apoi veţi avea nevoie să definiţi 2 variabile de sistem: PATH şi M2_HOME. Dacă lucraţi pe Windows, o puteţi face cu următoarele comenzi:
    set M2_HOME=c:\apache-maven-2.1.0
    set PATH=%PATH%;%M2_HOME%\bin
    Rularea acestor comenzi în linia de comandă vă va permite să rulaţi Maven doar în sesiunea curentă, pentru a evita setarea lor de fiecare dată, le puteţi seta în Control Panel ca Environment Variables.

    Dacă lucraţi pe un sistem de operare din familia Unix, atunci puteţi folosi următoarele comenzi:
    export M2_HOME=/usr/local/apache-maven-2.1.0
    export PATH=${M2_HOME}/bin:${PATH}
  4. Testaţi instalarea - După ce aţi instalat Maven, îl puteţi testa rulînd mvn -version din linia de comandă pentru a vedea versiunea acestuia. Dacă instalarea a fost OK, atunci va trebui să vedeţi ceva de genul acesta:
    C:\>mvn -version
    Apache Maven 2.1.0 (r755702; 2009-03-18 21:10:27+0200)
    Java version: 1.5.0_18
    Java home: C:\Program Files\Java\jdk1.5.0_18\jre
    Default locale: ro_RO, platform encoding: Cp1250
    OS name: "windows xp" version: "5.1" arch: "x86" Family: "windows"
    Dacă nu puteţi vizualiza acest mesaj sau sistemul de operare nu poate găsi comanda mvn atunci ar trebui să verificaţi încă o dată dacă variabilele PATH şi M2_HOME sînt setate corect. [Click mai jos pentru a citi articolul în întregime]
  5. Setarea de Proxy - Dacă aveţi acces direct la internet puteţi omite acest pas. Doar cei care folosesc un proxy pentru ieşirea în internet au nevoie să urmeze instrucţiunile de mai jos. Deoarece Maven are nevoie de Internet atunci cînd lucrează în modul cel mai optim, este nevoie de a-l configura pentru a şti ce proxy aveţi dvs. Pentru aceasta creaţi (sau dacă există deja modificaţi) fişierul <user_home>/.m2/settings.xml cu următorul conţinut:
    <settings 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/settings-1.0.0.xsd">
      <proxies>
        <proxy>
          <id>myproxy</id>
          <active>true</active>
          <protocol>http</protocol>
          <host>proxy.somewhere.com</host>
          <port>8080</port>
          <username>proxyuser</username>
          <password>somepassword</password>
        </proxy>
      </proxies>
    </settings>
    
    Fişierul <user_home>/.m2/settings.xml conţine setările specifice utilizatorului respectiv pentru autentificare, repositorii (repositories) şi alte lucruri care pot modifica comportamentul Maven.

    Notă: Vom utiliză syntaxa <user_home> pentru a ne referi la directorul de pornire al utilizatorului. În sistemele de operare din familia Unix, directorul de pornire a utilizatorului este /home/USERNAME sau ~. În Windows XP directorul de pornire al utilizatorului este C:\Documents and Settings\USERNAME. De acum înainte dvs. trebuie să interpretaţi locaţiile de genul <user_home>/.m2/settings.xml în dependenţă de sistemul dvs. de operare.
  6. Ştergerea (uninstall) Maven - Dacă doriţi să ştergeţi Maven de pe computer-ul dvs, atunci va trebui să ştergeţi directorul unde a-ţi instalat Maven şi să eliminaţi variabilele de sistem. De asemenea va fi nevoie să ştergeţi şi directorul <user_home>/.m2 care reprezintă repositorul local Maven.

    Aici încheiem acest articol. În următorul post vom descrie Project Object Model (POM).

12 mai, 2009

Introducere în Apache Maven 2, Partea 1 - Ce este Maven?

Apache Maven Logo Acesta este primul articol dintr-o serie dedicată Apache Maven 2. Menirea acestora este de a face o introducere în privinţa acestui tool open source (instrument cu codul sursă deschis) care este pe larg utilizat atît de majoritatea proiectelor Java Open Source, cît şi de celelalte. Vreau să menţionez că se va vorbi doar despre Apache Maven 2, şi chiar dacă în context cifra 2 nu este specificată, se are în vedere anume Maven 2. Versiunea Maven 1 nu este în scopul acestei introduceri.

Deci, ce este Maven? Cea mai mare parte a utilizatorilor Maven vor spune că Maven este un instrument pentru build, în timp ce definiţia de pe pagina oficială a proiectului Apache Maven http://maven.apache.org spune că Maven este un instrument pentru management al proiectelor. Deci, care este diferenţa? Un instrument pentru build se axează în principal pe preprocesare, compilare, ambalare (packaging), testare şi distribuţie. Un instrument pentru management, cum ar fi Maven, în plus faţă de capacităţile de build pe care le are, şi care sunt cu mult mai simple şi uşoare în folosire, mai prevede de asemenea şi un ciclu de viaţă al proiectului, un sistem de management al dependenţelor, poate rula rapoarte, genera o pagină web a proiectului, facilitează comunicarea între membrii echipei de lucru prin oferirea unei interfeţe comune, şi multe alte facilităţi.

Mai jos sînt enumerate principiile de bază pe care le prevede Maven: [Click mai jos pentru a citi articolul în întregime]

  • Convenţia în favoarea Configuraţiei (Convention over Configuration) - Convenţia în favoarea Configuraţiei este un concept foarte simplu. Sistemele, bibliotecile şi framework-urile trebuie să definească valori implicite rezonabile. Fără a necesita configurare inutilă, sistemele ar trebui simplu să lucreze. Maven include acest concept prin furnizarea unor setări implicite pentru proiecte. Fără nici o personalizare şi configurare, codul sursă se presupune a fi în: src/main/java şi a resurselor în: src/main/resources. Testele se presupun a fi în: src/test şi proiectul se asumă să producă un fişier JAR. Maven presupune că se doreşte ca byte-codul să fie compilat în target/classes şi apoi să se creeze un fişier JAR repartizabil (distributable) în target. Maven aplică un set comun de convenţii pentru compilarea codului sursă, ambalarea fişierelor pentru repartizare, generarea de pagini web, şi multe alte procese. Dacă se urmează convenţiile, Maven va necesita un efort minim, aproape de zero - doar plasaţi sursele în directoarele corecte şi Maven va avea grijă de restul.
  • O interfaţă comună - Înainte ca Maven să propună o interfaţă unică pentru a face build la produsele software, fiecare proiect avea sistemul său propriu de build. Fiecare developer care dorea să facă build la proiect trebuia să se întrebe un şir de întrebări. Ce va produce build-ul? De ce biblioteci şi librării am nevoie? De unde să le descarc? Unde trebuie să le pun? Ce comandă sau goal (scop) trebuie să rulez? Developerii aveau nevoie de ceva timp ca să înveţe cum să facă build la un proiect sau altul. În prezent însă, atunci cînd vedem că un proiect foloseşte Maven, putem presupune că vom putea fară mari probleme să descarcăm sursele şi să-i facem build cu mvn install.
  • Abordare declarativă - Totul în Maven se face într-un mod declarativ folosind Project Object Model (POM) (modelul obiect al proiectului). Noi nu doar compilăm codul sursă, ci creăm o descriere a proiectului şi atributelor acestuia, în acelaşi timp alocîndu-i proiectului un set unic de coordonate. Care este licenţa proiectului? Cine dezvoltă şi contribuie la acest proiect? Care sînt proiectele de care depinde acest proiect? Tot ce trebuie de făcut este de creat fişierul pom.xml cu descrierea proiectului şi de pus sursele în directoarele predefinite. Maven va avea grijă de restul.
  • Refolosirea logicii de build - Maven a abstractizat sarcinile comune de build în plugin-uri, care sînt menţinute centralizat şi share-uite (împărţite, împărtăşite) universal către toţi. Nucleul Maven este destul de simplu şi limitat. El nu ştie altceva decît să parse-ze (analizeze) cîteva documente XML şi să menţină cîteva cicluri de viaţă a proiectului şi cîteva plugin-uri. Maven a fost creat astfel încît să delege marea responsabilitate către un set de plugin-uri Maven. Cea mai mare parte a acţiunilor în Maven se întâmplă în plugin-uri, care se ocupă de lucruri ca compilarea codului sursă, ambalarea bytecode-ului, publicarea paginilor web, precum şi orice altă activitate de care este nevoie într-un build.

Deci, pentru a răspunde la întrebarea iniţială: Maven este multe lucruri pentru multe persoane. Este un set de standarde şi o abordare specifică în dezvoltarea proiectelor software. Maven este un instrument foarte capabil, care poate fi în acelaşi timp simplu sau complex, în dependenţă de ce este nevoie. Din acest motiv, de cele mai multe ori există mai multe moduri pentru a realiza aceeaşi sarcină.

Aici încheiem acest articol. În următorul post va fi descris cum se poate de instalat Apache Maven.

Notă: Imaginea de la începutul articolului a fost luată de pe http://commons.wikimedia.org/wiki/File:Maven_logo.gif şi este licenţiată sub licenţa Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.

Recent pe Blog

Ultimele comentarii

  Blogger template adapted from The Professional Template by Ourblogtemplates.com 2008

Header image adapted from Free Web Page Headers