23 марта 2013 г.

Работа с модулями JBoss 7 на примере log4j

Используются: Maven 3, JBoss 7.1, EJB 3.1, IntelliJ Idea 12 Ultimate, log4j 1.2.17.

В JBoss 6 достаточно было кинуть jar-файл в папку deploy или lib соответствующей конфигурации и вы уже могли использовать содержащиеся в архиве классы в своих компонентах.

В JBoss 7 значительно изменилась архитектура сервера приложений в целом. Теперь любой jar-файл библиотеки называется модулем. Он лежит в строго отведённом месте и снабжён конфигурационным файлом.

Давайте разберёмся, как можно использовать модули JBoss 7 в своих приложениях. Ранее мы уже создали при помощи maven простой EJB, которое что-то возвращает клиенту а также добавили к нему дополнительные maven-плагины. Теперь добавим к нему функционал библиотеки log4j.

Эта библиотека логирования уже доступна по умолчанию в JBoss 7.1 в виде модуля. Он находится в папке $JBOSS_HOME/modules/org/apache/log4j/main. В этой папке лежит jar-файл библиотеки и конфигурационный файл module.xml. Откроем его.
<module xmlns="urn:jboss:module:1.1" name="org.apache.log4j">
    <properties>
        <property name="jboss.api" value="private"/>
    </properties>
    <resources>
        <resource-root path="log4j-1.2.16.jar"/>
        <!-- Insert resources here -->
    </resources>
    <dependencies>
        <module name="org.dom4j" optional="true"/>
        <module name="javax.api"/>
    </dependencies>
</module>
Как видите, этот файл содержит информацию об имени модуля (атрибут name в секции module), информацию о jar-файле, а также зависимости этого модуля от других.

Добавим в наш pom-файл, в конфигурацию плагина maven-ejb-plugin секцию archive-manifestEntries-Dependencies. Там через запятую следует перечислять имена нужных нам модулей. В данном случае это один модуль с именем org.apache.log4j.
<archive>
<manifestEntries>
<Dependencies>
org.apache.log4j
</Dependencies>
</manifestEntries>
</archive>
Теперь после компиляции проекта в файле META-INF/MANIFEST.MF внутри собранного архива появится строка:
Dependencies: org.apache.log4j
JBoss 7 автоматически загрузит этот модуль при деплое нашего компонента. Модуль подключен, осталось его настроить и задействовать.

Положите в папку src/main/resources нашего maven-проекта конфигурационный файл log4j.xml. В эту папку нужно складывать любые файлы, которые могут потребоваться во время выполнения вашего приложения. Они будут автоматически добавлены в корень jar-архива.


Пример содержимого файла:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration debug="false" xmlns:log4j="http://jakarta.apache.org/log4j/">

    <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">
        <param name="Encoding" value="utf-8"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d{ISO8601} [%-5p][%-16.16t][%32.32c] - %m%n" />
        </layout>
    </appender>

    <root>
        <priority value="INFO"/>
        <appender-ref ref="ConsoleAppender" />
    </root>

</log4j:configuration>

Здесь все сообщения с уровнем INFO и выше будут выводиться на консоль. Подробнее о настройках этой библиотеки и уровнях логирования я уже писал ранее.

В pom-файл в секцию dependencies нужно добавить зависимость этой библиотеки (не забудьте добавить в секцию properties актуальный номер версии библиотеки):
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>${version.log4j}</version>
</dependency>
Теперь осталось добавить пару строчек кода в наш класс SimpleBean. Объявим логгер как член класса.
private static final Logger logger = Logger.getLogger(SimpleBean.class);
Вызовем его из метода getMessage:
logger.info("SimpleBean invoked");
Полный текст класса SimpleBean:
package com.blogspot.developer.remarks;
import org.apache.log4j.Logger;
import javax.ejb.Stateless;
@Stateless
public class SimpleBean implements SimpleBeanRemote {
    private static final Logger logger = Logger.getLogger(SimpleBean.class);
    @Override
    public String getMessage() {
        logger.info("SimpleBean invoked");
        return "This message was generated by simple ejb";
    }
}
Таким образом, при вызове клиентом этого метода EJB, в консоли сервера появится соответствующее сообщение с уровнем INFO.

21 марта 2013 г.

Плагины maven для работы с EJB

Используются: Maven 3, JBoss 7.1, EJB 3.1, IntelliJ Idea 12 Ultimate.

Ранее мы при помощи maven собрали ejb-jar и успешно развернули его на сервере JBoss. Теперь приступим к конфигурированию его pom.xml. Для начала автоматизируем процесс разворачивания на сервере.

Deploy на JBoss

Добавим в секцию plugins элемент jboss-as-maven-plugin. Он позволяет разворачивать на сервере компоненты, обновлять их и удалять с сервера.

<plugin>
<groupId>org.jboss.as.plugins</groupId>
<artifactId>jboss-as-maven-plugin</artifactId>
<version>${version.org.jboss.as.plugins.maven.plugin}</version>
<configuration>
    <filename>another-yet-project-1.0-SNAPSHOT.jar</filename>
</configuration>
<executions>
   <execution>
<id>deploy</id>
<phase>install</phase>
<goals>
   <goal>deploy</goal>
</goals>
   </execution>
</executions>
</plugin>

Не забудьте в секцию properties добавить свойство с номером версии плагина:

<version.org.jboss.as.plugins.maven.plugin>7.4.Final</version.org.jboss.as.plugins.maven.plugin>

configuration - filename задаёт имя файла, который получится в результате сборки и который требуется развернуть на сервере. Чтобы при изменении версии проекта не редактировать конфиг плагина, воспользуемся свойством project.build.finalName. Если посмотреть его определение, то можно обнаружить, что это свойство комбинирует два других: project.artifactId и project.version. Именно такой формат по умолчанию даётся сборкам в maven. Нам же в конце остаётся добавить только расширение файла. Конфигурация плагина примет вид:
<filename>${project.build.finalName}.jar</filename>
Секция execution указывает, что цель deploy плагина будет запущена в фазе install проекта. То есть специально запускать плагин не требуется, он автоматически отработает, когда вы запустите фазу install или более позднюю. Но если вам потребуется развернуть ранее собранный файл без запуска всего процесса сборки проекта, то достаточно дважды кликнуть на цели jboss-as:deploy.


Также будет полезной цель jboss-as:undeploy для удаления компонента с сервера.

Сборка архива с интерфейсами EJB

Для работы с EJB клиенту требуется его интерфейс. Мы могли бы положить клиенту целиком EJB, но ему не нужны файлы с реализацией этих интерфейсов. Тогда нам нужно собрать отдельный архив с такими интерфейсами. Можно сделать это вручную, а можно автоматически, добавив всего пару строк к конфигурации maven-ejb-plugin. Привожу его обновлённую конфигурацию:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ejb-plugin</artifactId>
<version>2.3</version>
<configuration>
   <ejbVersion>3.1</ejbVersion>
   <generateClient>true</generateClient>
   <clientExcludes>
<clientExclude>com/blogspot/developer/remarks/SimpleBean.class</clientExclude>
   </clientExcludes>
</configuration>
</plugin>

generate-client - true, создаёт рядом с основным архивом специальный клиентский архив. В нашем случае он будет называться another-yet-project-1.0-SNAPSHOT-client.jar. Для того, чтобы исключить файлы реализации воспользуемся секцией clientExcludes. В ней мы задаём список уже скомпилированных class-файлов с указанием полного пути до него, начиная от корня jar-архива. Обратите внимание, что путь не должен начинаться со слеша. Исключать можно как отдельные class-файлы, так и целые папки.

После сборки проекта вы можете сравнить два полученных архива. Клиентский будет иметь меньший размер.

Для того, чтобы на клиенте использовать именно клиентскую версию, а не полную, следует добавить элемент classifier со значением client. Зависимость будет выглядеть так:
<dependency>
    <groupId>com.blogspot.developer.remarks</groupId>
    <artifactId>another-yet-project</artifactId>
    <version>1.0-SNAPSHOT</version>
    <classifier>client</classifier>
</dependency>

Сборка архива с исходниками

Подключив клиентскую версию нашего EJB на вызывающей стороне, вы не увидите javadoc и имена параметров методов. Эта информация нужна только разработчикам и она хранится в исходниках. Формировать исходники в отдельный архив вручную было бы утомительно, поэтому мы воспользуемся плагином maven-source-plugin. Добавим его в секцию build/plugins нашего pom.xml.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
Здесь ничего настраивать не требуется, архив с исходниками автоматически появится рядом с основным jar-файлом в фазе package. Он будет называться another-yet-project-1.0-SNAPSHOT-sources.jar. Подключить на клиентской стороне его можно следующим образом:
<dependency>
  <groupId>com.blogspot.developer.remarks</groupId>
  <artifactId>another-yet-project</artifactId>
  <version>1.0-SNAPSHOT</version>
  <classifier>sources</classifier>
</dependency>

Области видимости в maven

Области видимости (scope) зависимостей (dependency) в maven. Может быть указана в секкции dependency файла pom.xml.

  • compile - область видимости по умолчанию. Используется, когда область видимости явно не указана. Компилирует зависимости, доступные во всех classpath проекта.
  • provided - эта область видимости очень похожа на compile, но показывает, что JDK или среда исполнения должна предоставить эти зависимости во время выполнения.
  • runtime - показывает, что зависимость не нужна для компиляции, но нужна во время выполнения.
  • test - показывает, что эти зависимости не нужны для работы приложения и используются только в фазе тестирования.
  • system - очень похожа на provided за исключением того, что вы предоставите архив, который содержит эту зависимость. Артефакт всегда доступен, поэтому его поиск в репозитории не производится.
  • import (Maven версии 2.0.9 или выше) - эта область видимости используется только в зависимости типа pom в секции <dependencyManagement>. Она показывает, что указанный pom должен быть заменён зависимостями из pom'a, который указан в dependencyManagement.

20 марта 2013 г.

Создание EJB при помощи maven и Idea

Используются: maven 3, IntelliJ Idea 12 Ultimate, Enterprise Java Bean 3.1, JBoss 7.1

Давайте создадим EJB в виде maven-проекта при помощи Idea. Выберите File - New Project. В открывшемся окне выберите Maven Module.


В поле Project name укажите имя проекта. В имени проекта принятно использовать только строчные буквы. Если в названии присутствует несколько слов, вместо пробелов ставятся дефисы. Например: another-yet-project. Затем жмём кнопку Next.

Обратите внимание, что в открывшемся окне в первых двух строках (Add as module to и Parent) сняты галочки и ничего не указано. Это связано с тем, что мы создаём самостоятельный maven-проект. Если бы создавали его как модуль другого проекта, эти две строки содержали бы информацию о родительском maven-проекте.

ArtifactId - имя вашего проекта в maven. Соглашения об именах такие же, как и на предыдущем шаге. Можно оставить то, что будет указано по умолчанию.

GroupId - имя группы для нескольких взаимосвязанных проектов. Принято также писать строчными буквами, пробелы заменяя точками. В качестве имени группы можно выбрать общий для проектов java-пакет. Например, com.blogspot.developer.remarks.


Затем отмечаем галочку Create from archetype. Архетип - это структура конфигурационных файлов и каталогов в maven, принятая для данного типа компонентов. Свои архетипы есть для EJB, EAR, WAR, SAR и т.п. Нам же нужно выбрать в списке ejb-javaee6.

Скорее всего, у вас может не оказаться в списке этого архетипа. Тогда вам нужно его добавить. Нажмите кнопку Add archetype. В появившемся окне укажите в соответствующих полях следующие значения:
<dependency>
<groupId>org.codehaus.mojo.archetypes</groupId>
<artifactId>ejb-javaee6</artifactId>
<version>1.5</version>
</dependency>
Эти значения можно взять с search.maven.org, выполнив поиск по имени необходимого архетипа. Нажмите ОК.


Затем жмём Next.

В третьем окне менять ничего не нужно. Только проконтролируйте, что в поле Maven home directory указан правильный путь до maven. Впрочем, эту настройку можно будет изменить и потом. Жмём Finish.

В результате будет создана необходимая структура проекта, а также ключевой файл для maven - pom.xml. В этом файле уже будет указана достаточная для сборки информация.


Рассмотрим файл pom.xml поподробнее.
    <groupId>com.blogspot.developer.remarks</groupId>
    <artifactId>another-yet-project</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>ejb</packaging>
    <name>another-yet-project</name>
groupId, artifactId - это ровно то, что мы указывали ранее. version имеет значение SNAPSHOT - т.е. временная версия ПО, находящегося в разработке. packaging - ejb говорит maven о том, что на выходе требуется jar-файл с ejb.
    <properties>
        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
Секция, которая содержит свойства проекта. Вы можете добавить туда любые свойства, которые вам нужны (аналог property-файлов). Чаще всего там указывают различные номера версий. Имя свойства записывается строчными буквами. Пробелы заменяются точками.
    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
Секция dependencies содержит зависимости (библиотеки кода) для данного проекта. Здесь указана только одна зависиомость - API Java версии Enterprise Edition. Scope - provided свидетельствует о том, что данная зависимость будет предоставлена средой исполнения (сервером приложений JBoss), поэтому не нужно включать её в jar-файл. Вы можете добавлять любые зависимости, которые вам необходимы. Множество зависимостей можно найти на search.maven.org.

Далее идёт секция build, которая содержит плагины, используемые при сборке.

maven-ejb-plugin - плагин, который позволяет настроить сборку ejb.

Давайте добавим в наш проект простейший EJB. Создадим клиентский интерфейс SimpleBeanRemote, а затем и реализацию SimpleBean.

Интерфейс:
import javax.ejb.Remote;
@Remote
public interface SimpleBeanRemote {
    String getMessage();
}
Реализация:

import javax.ejb.Stateless;
@Stateless
public class SimpleBean implements SimpleBeanRemote {
@Override
public String getMessage() {
return "This message was generated by simple ejb";
}
}

Наш EJB не делает ничего особенного. У него есть единственный метод, который возвращает одну и ту же строку. Аннотацией @Remote помечается интерфейс, который будет использоваться клиентом. Аннотация @Stateless указывает на то, что данный EJB не сохраняет своё состояние между вызовами его методов. Поведение EJB с такой аннотацией аналогично созданию нового экземпляра класса при каждом вызове любого из его методов.

Настало время собрать jar-файл. Для этого перейдём на вкладку Maven Projects.


С точки зрения maven сборка нашего приложения имеет несколько фаз, которые указаны в списке Lifecycle. Они выполняются последовательно друг за другом, начиная от фазы validate (clean сюда не входит, его нужно вызывать отдельно) и до выбранного этапа.

Основные фазы жизненного цикла сборки приложений в maven:
  1. clean - удалить все ранее сгенерированные maven'ом файлы; используется, как правило, только при серьёзных изменениях в исходниках
  2. validate - проверка проекта и доступности всей необходимой информации
  3. compile - компиляция исходников
  4. test - на этом шаге вызываются unit-тесты, если они есть; эти тесты исключаются из самой сборки
  5. package - упаковка скомпилированного кода в необходимый формат дистрибутива
  6. install - публикация дистрибутива в локальном репозитории; проект становится доступным для других локальных проектов
  7. deploy - публикация дистрибутива в удалённом репозитории; проект становится доступным для других разработчиков в вашей команде
Дважды щёлкните на фазе install - если всё было сделано правильно, в папке target в корне проекта вы получите готовый файл another-yet-project-1.0-SNAPSHOT.jar, который можно разместить на сервере приложений.

Если вы используете jboss 7.1, то вам нужно скопировать этот файл в папку $JBOSS_HOME/standalone/deployments и запустить сервер из папки $JBOSS_HOME/bin командой
./standalone.sh
В логах сервера вы увидите следующие строки:

java:global/another-yet-project-1.0-SNAPSHOT/SimpleBean!com.blogspot.developer.remarks.SimpleBeanRemote
java:app/another-yet-project-1.0-SNAPSHOT/SimpleBean!com.blogspot.developer.remarks.SimpleBeanRemote
java:module/SimpleBean!com.blogspot.developer.remarks.SimpleBeanRemote
java:jboss/exported/another-yet-project-1.0-SNAPSHOT/SimpleBean!com.blogspot.developer.remarks.SimpleBeanRemote
java:global/another-yet-project-1.0-SNAPSHOT/SimpleBean
java:app/another-yet-project-1.0-SNAPSHOT/SimpleBean
java:module/SimpleBean

Данные строки свидетельствуют о том, что компонент был успешно развёрнут на сервере.