Marzec
05
2010

Praca z API dla wtyczek Maven

Słowa kluczowe: , , | Kategorie: Java
No Gravatar

Gdy już wyrosłem z kompilacji programów z poziomu IDE (bez kontroli nad tym, co się tak naprawdę dzieje), bardzo pomocne okazały się skrypty makefile. Pozwalały one zdefiniować polecenia wykonywane do uzyskania kolejnych plików, niezbędnych do połączenia aplikacji bądź biblioteki w całość. Żegnając się z C++ (kto wie, może nie na zawsze) w celu rozpoczęcia przygody z językiem Java, poznałem prostotę i przejrzystość konfiguracji Apache Ant. W ostatnim czasie coraz większą popularnością cieszy się stosunkowo nowe narzędzie – Apache Maven.

Tak naprawdę, to obecnie funkcjonuje już wersja Maven 2.2, więc można powiedzieć, że jestem trochę opóźniony. Jednak wiele projektów ciągle korzysta z Apache Ant i stan ten raczej nie zmieni się w najbliższym czasie.

Jedną z wielu zalet Apache Maven jest możliwość rozbudowy o dodatkowe wtyczki, dzięki którym można przetwarzać przeróżne pliki źródłowe w oparciu o jeden schemat projektu. W ten sposób obok plików .java mogą znaleźć się także strony .jsp, źródła .cpp czy nawet zdjęcia, dla których tworzone będą miniatury.

Z powodu bieżących potrzeb, postanowiłem zająć się kompilacją dokumentów LATEX, a dokładniej generowaniem obrazków MetaPost z diagramów Dia. W ten sposób powstała wtyczka, o której pisałem ostatnio. Na jej przykładzie zamierzam omówić cały proces rozwoju wtyczek dla Apache Maven, wliczając testy, dokumentację i publikowanie.

pom.xml

Każda wtyczka do Maven2 musi być utworzona zgodnie z pewnym standardem. Na początek omówię podstawowe elementy pliku pom.xml:

<?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>pl.info.czerwinski</groupId>
  <artifactId>latex-metapost-maven-plugin</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>maven-plugin</packaging>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.0.2</version>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-plugin-api</artifactId>
      <version>2.0</version>
    </dependency>
  </dependencies>

  <repositories>
    <repository>
      <id>central</id>
      <name>Maven central repository</name>
      <url>http://repo1.maven.org/maven2</url>
    </repository>
  </repositories>

</project>
modelVersion (linia 7)

Wersja pliku pom.xml – dla Maven2 jest to 4.0.0.

groupId (linia 9)

Identyfikator grupy projektów – zazwyczaj określa producenta oprogramowania.

artifactId (linia 10)

Identyfikator konkretnego projektu, unikalny w ramach grupy.

Zgodnie ze standardem, wtyczki znajdujące się w centralnym repozytorium Maven2 noszą nazwy maven-name-plugin. Pozostałe wtyczki nazywają się name-maven-plugin.

version (linia 11)

Wersja projektu.

packaging (linia 12)

Sposób tworzenia archiwum projektu – np. jar, war, ear. Dla wtyczek jest to maven-plugin

build/plugins (linie 14–26)

Wtyczki użyte do zbudowania projektu ze źródeł.

Konfiguracja maven-compiler-plugin nie jest wymagana, ponieważ ta wtyczka wykorzystywana jest zawsze przy kompilacji źródeł Java (łącznie z testami). Jednak domyślne ustawienia przewidują wersję źródeł 1.3 oraz wersję docelową 1.1. W przypadku mojej wtyczki postanowiłem wykorzystać wersję Java 1.5 (linie 21, 22).

dependencies (linie 28–34)

Zależności, czyli biblioteki wykorzystywane przy tworzeniu projektu. Nie trzeba się już martwić o pobieranie każdej niezbędnej biblioteki, gdyż Maven robi to automatycznie.

Aby utworzyć wtyczkę Maven, będę potrzebował biblioteki maven-plugin-api, która dostarcza niezbędnego do tego celu interfejsu.

repositories (linie 36–42)

Repozytoria, które Maven ma przeszukać w celu odnalezienia wszystkich niezbędnych bibliotek i wtyczek.

Centralne repozytorium Maven2, znajdujące się pod adresem http://repo1.maven.org/maven2, jest domyślnym repozytorium i nie musi być dodatkowo definiowane.

Źródła wtyczki

Wykorzystując maven-plugin-api mogę zacząć prace nad główną klasą wtyczki. Wszelkie źródła Java powinny się znaleźć się w katalogu src/main/java, aby były dostępne dla maven-compiler-plugin.

Dla każdego zadania wtyczki wymagana jest osobna klasa, dziedzicząca po AbstractMojo. Na samym początku zdefiniuję klasę src/main/java/pl/info/czerwinski/latex/metapost/MetaPostCompilationMojo.java:

package pl.info.czerwinski.latex.metapost;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;

import java.io.File;

/**
 * MetaPost compilation goal.
 * @author Sławomir Czerwiński
 * @version 1
 * @goal compile
 */
public class MetaPostCompilationMojo extends AbstractMojo {
}

Nazwa zadania określona jest poprzez adnotację JavaDoc @goal (z uwagi na kompatybilność wsteczną, brak adnotacji Java). Użyta wraz z nazwą wtyczki (dla name-maven-plugin nazwą jest name) służy do wykonania danego zadania (w tym przypadku będzie to mvn latex-metapost:compile).

Wewnątrz klasy zadania brakuje jeszcze implementacji metody execute, która odpowiada za jego rzeczywistą realizację:

/**
 * Executes MetaPost compilation.
 * @throws MojoExecutionException if an unexpected problem occurs.
 * @throws MojoFailureException if an expected problem occurs.
 */
public void execute() throws MojoExecutionException, MojoFailureException {
    getLog().info("Compiling MetaPost for LaTeX.");
}

Metoda ta może zgłaszać dwa wyjątki. MojoExecutionException oznacza wystąpienie niespodziewanego błędu podczas realizacji zadania, podczas gdy MojoFailureException oznacza niepowodzenie operacji.

Tworzona wtyczka wymagać będzie określenia kilku parametrów konfiguracyjnych. Aby maksymalnie dostosować sposób wykonania zadania do indywidualnych potrzeb użytkowników, należy umożliwić przedefiniowanie katalogu źródłowego i docelowego, nazwy katalogu zawierającego dane wspólne dla wszystkich dokumentów czy ścieżki do plików wykonywalnych – mpost oraz dia.

Do klasy MetaPostCompilationMojo dodaję następujące pola:

/**
 * Common files directory inside the documents root.
 *

The directory will be attached to each other directory target.

 * @parameter expression="${latex-metapost.commonsDirName}" default-value="common"
 * @required
 */
private String commonsDirName;

/**
 * The documents root.
 * @parameter expression="${latex-metapost.docsRoot}" default-value="src/main/latex"
 * @required
 */
private File docsRoot;

/**
 * The LaTeX builds directory.
 * @parameter expression="${latex-metapost.latexBuildDir}" default-value="${project.build.directory}/latex"
 * @required
 */
private File latexBuildDir;

/**
 * Path to the MetaPost binaries installation.
 * @parameter expression="${latex-metapost.binariesPath}"
 */
private String binariesPath;

/**
 * Path to the Dia binaries installation.
 * @parameter expression="${latex-metapost.diaBinariesPath}"
 */
private String diaBinariesPath;

Parametry oznaczone są adnotacją JavaDoc @parameter. Atrybut expression definiuje wyrażenie, poprzez które będzie można ustawić wartość parametru z linii poleceń (np. -Dlatex-metapost.diaBinariesPath=/usr/bin). Wartość domyślna określana jest za pomocą atrybutu default-value.

Ustawienie wartości parametrów, dla których użyta została adnotacja @required, jest wymagane. Jednak w omawianym przypadku wszystkie takie parametry mają już ustawioną wartość domyślną.

Podsumowanie

W tej chwili wtyczka zawiera zadanie, które może zostać uruchomione, przy czym jej działanie ograniczy się do wyświetlenia komunikatu:

[info] Compiling MetaPost for LaTeX.

W kolejnej części zajmę się napisaniem testów, pozwalających określić poprawność działania wtyczki.

Napisz Komentarz

*