Введение в Spring Roo: Часть 3. Разработка дополнений Spring Roo

Spring Roo – это RAD-инструмент, упрощающий и ускоряющий разработку приложений (главным образом Web-приложений). Архитектура Spring Roo основана на OSGI-модулях, что позволяет наращивать его возможности путем добавления дополнений (add-ons). Spring Roo предоставляет команды для создания дополнений, которые легко можно сделать доступными сообществу пользователей Spring Roo. В данной статье мы сначала рассмотрим архитектуру Spring Roo, проанализируем использование Spring Roo преимуществ такой архитектуры для предоставления различных функциональных возможностей, а затем создадим дополнения, используя Roo Shell, и изменим их в соответствии с нашими требованиями.

Шекхар Гулати, старший консультант, Xebia

Шекхар Гулати (Shekhar Gulati) работает Java-консультантом в Xebia India. Более шести лет он занимается корпоративными Java-приложениями. Имеет обширный опыт работы со Spring-проектами, такими как Spring, Spring-WS и Spring Roo. В сферу его интересов входят Spring, базы данных NoSQL, Hadoop, RAD-среды (такие как Spring Roo), облачные вычисления (в основном PaaS-сервисы, такие как Google App Engine, CloudFoundry, OpenShift). Является активным автором статей для JavaLobby, Developer.com, IBM developerWorks и своего собственного блога http://whyjava.wordpress.com/. Связаться с ним можно в Твиттере (@ http://twitter.com/#!/shekhargulati).



20.02.2012

Начало работы

В первой и второй частях серии статей "Введение в Spring Roo" мы создали с нуля полноценное корпоративное приложение при помощи Spring Roo. Первые две статьи были посвящены созданию Web-приложений с использованием среды быстрой разработки приложений Spring Roo. Мы рассмотрели много функциональных возможностей, таких как JPA, Selenium-тестирование, Spring Security, интеграция электронной почты, функции социализации, реверсивное проектирование баз данных и др. Теперь мы рассмотрим архитектуру дополнений Spring Roo. Затем мы напишем дополнения Spring Roo, используя команду addon create. После прочтения статьи вы сможете быстро и просто создавать свои собственные дополнения для Spring Roo.


Архитектура дополнений Spring Roo

Простейшее дополнение представляет собой программный компонент, добавляющий в приложение специфические возможности. Например, в большинстве Web-браузеров поддержка видеоданных осуществляется при помощи дополнений. Другим примером является Eclipse – интегрированная среда разработки с открытыми исходными кодами, которую используют или как минимум знают многие Java™-разработчики. Большинство возможностей предоставляется посредством дополнений, например поддержка JUnit, SVN и т.д. Я использую понятие "дополнение" в качестве общего термина для плагинов и расширений.

Идея дополнений Spring Roo состоит в том, чтобы:

  1. Позволить сторонним разработчикам создавать возможности, расширяющие Spring Roo.
  2. Помочь Spring Roo легко добавлять новые функции.
  3. Сделать так, чтобы Spring Roo оставался маленьким джином (т.е. уменьшить размер Spring Roo).

Логические компоненты Spring Roo

Spring Roo состоит из двух логических частей.

Базовые компоненты Spring Roo. Для поддержки разработки дополнений Spring Roo предоставляет ряд базовых компонентов, формирующих среду исполнения для различных дополнений. К этим компонентам относится Classpath, который поддерживает Process Manager (менеджер процессов) и Shell (командный процессор). В свою очередь, Process Manager поддерживает Project (проект) и File Undo (откат файла). Project поддерживает Model (модель), Metadata (метаданные) и File Monitor (мониторинг файла). Наконец, имеется компонент Support (поддержка), используемый всеми компонентами. На рисунке 1 представлена графическая схема этих взаимосвязей.

Рисунок 1. Базовые компоненты Spring Roo
Рисунок 1. Базовые компоненты Spring Roo

Рассмотрим некоторые из базовых модулей:

  • Support – модуль org.springframework.roo.support предоставляет общие вспомогательные классы, используемые всеми базовыми модулями и дополнениями. Вот некоторые вспомогательные классы: Assert, FileCopyUtils, XmlUtils, StringUtils, FileUtils и т.д. Например, для копирования содержимого одного файла в другой можно использовать FileCopyUtils.
  • Metadata – модуль org.springframework.roo.metadata предоставляет реализацию и интерфейс поставщика сервиса метаданных, включая кэширование и регистрацию зависимостей.
  • File Monitor – модуль org.springframework.roo.file.monitor публикует события изменений в файловой системе (реализация по умолчанию использует автоматически масштабируемый опрос дисков).
  • File Undo – модуль org.springframework.roo.file.undo предоставляет возможность отката файлов для использования менеджером процессов.
  • Project – модуль org.springframework.roo.project абстрагирует системы сборки типовых пользовательских проектов, такие как Apache Maven и Apache Ant.
  • Process Manager – модуль org.springframework.roo.process.manager предлагает ACID-абстракцию файловой системы, включающую в себя откат дисковой подсистемы и синхронизацию процессов.
  • Classpath – модуль org.springframework.roo.classpath выполняет синтаксический анализ абстрактного синтаксического дерева и связывание типов модулей компиляции Java и AspectJ.

Базовые дополнения Spring Roo. Spring Roo предоставляет всю функциональность посредством дополнений. Базовые дополнения, поставляемые с Roo V1.1.3:

  • Add-On Creator – дополнение org.springframework.roo.addon.creator позволяет легко создавать пользовательские дополнения Roo.
  • Backup – дополнение org.springframework.roo.addon.backup позволяет выполнять резервное копирование в ZIP-файл при помощи команды backup.
  • Cloud Foundry – дополнение org.springframework.roo.addon.cloud.foundry обеспечивает поддержку VMware Cloud Foundry.
  • Configurable – дополнение org.springframework.roo.addon.configurable обеспечивает поддержку представления аннотаций Spring @Configurable посредством ITD-объявлений AspectJ.
  • Database reverse engineering – дополнение org.springframework.roo.addon.dbre обеспечивает поддержку инкрементного реверсивного проектирования существующих баз данных.
  • Data on Demand – дополнение org.springframework.roo.addon.dod обеспечивает поддержку автоматического создания примеров данных, используемых для тестов интеграции.
  • Email – дополнение org.springframework.roo.addon.email обеспечивает поддержку интеграции и настройки Spring-системы обмена сообщениями в целевом проекте.
  • Entity – дополнение org.springframework.roo.addon.entity обеспечивает расширенную поддержку автоматической обработки классов Java Persistence API @Entity.
  • Dynamic Finder – дополнение org.springframework.roo.addon.finder создает типизированные, совместимые с системой автоматического завершения кода методы поиска на языке JPA-запросов.
  • Git – дополнение org.springframework.roo.addon.git обеспечивает поддержку интеграции GIT в проекте. Каждая успешно выполненная команда будет автоматически фиксироваться в локальном GIT-репозитории.
  • GWT – дополнение org.springframework.roo.addon.gwt обеспечивает поддержку построения пользовательского интерфейса с использованием Google Web Toolkit.
  • JavaBean – дополнение org.springframework.roo.addon.javabean автоматически обрабатывает JavaBean getter- и setter-методы для классов с аннотацией @RooJavaBean.
  • JDBC – дополнение org.springframework.roo.addon.jdbc инкапсулирует OSGi-доступ к JDBC-драйверам, поставляемым в различных пакетах (используется главным образом другими дополнениями).
  • JMS – дополнение org.springframework.roo.addon.jms обеспечивает поддержку настройки параметров Java Messaging System в целевом проекте.
  • JPA – дополнение org.springframework.roo.addon.jpa устанавливает указанного JPA-поставщика и соответствующим образом настраивает JDBC.
  • JSON – дополнение org.springframework.roo.addon.json добавляет в POJO-объекты связанные с JSON методы сериализации и десериализации.
  • Logging – дополнение org.springframework.roo.addon.logging устанавливает Log4j, включая управляемую командами конфигурацию log-уровня.
  • Pluralization – дополнение org.springframework.roo.addon.plural обеспечивает перевод существительных во множественное число (используется главным образом другими дополнениями).
  • Property Editor – дополнение org.springframework.roo.addon.property.editor управляет редакторами свойств согласно требованиям Spring MVC.
  • Property File – дополнение org.springframework.roo.addon.propfiles обеспечивает поддержку управления файлами свойств в целевом проекте.
  • RooBot Client – дополнение org.springframework.roo.addon.roobot.client обеспечивает поддержку управления дополнениями посредством сервера RooBot.
  • Security – дополнение org.springframework.roo.addon.security устанавливает Spring Security, включая страницы входа, фильтры и зависимости.
  • Serializable – дополнение org.springframework.roo.addon.serializable добавляет поддержку java.io.Serializable (например, обработку UID-идентификаторов) для запрошенных Java-типов.
  • Solr – дополнение org.springframework.roo.addon.solr обеспечивает поддержку настройки и интеграции функций Apache Solr в целевой проект.
  • Integration Test – дополнение org.springframework.roo.addon.test создает тесты интеграции JUnit для логических объектов проекта.
  • ToString – дополнение org.springframework.roo.addon.tostring создает корректный метод toString() для любого класса с аннотацией @RooToString.
  • WebFlow – дополнение org.springframework.roo.addon.web.flow обеспечивает поддержку настройки и интеграции функций Spring Web Flow в целевой проект.
  • Web MVC Controller – дополнение org.springframework.roo.addon.web.mvc.controller обеспечивает поддержку настройки и интеграции контроллеров Spring MVC в целевой проект.
  • Web MVC Embedded – дополнение org.springframework.roo.addon.web.mvc.embedded расширяет дополнение MVC, что позволяет добавлять на Web-страницы такие встроенные возможности как карты, видео и т.д.
  • Web MVC JSP – дополнение org.springframework.roo.addon.web.mvc.jsp настраивает и интегрирует возможности Spring MVC JSP в целевой проект.
  • Selenium – дополнение org.springframework.roo.addon.web.selenium настраивает и интегрирует Web-тесты Selenium в целевой проект.

Теперь, познакомившись с базовыми компонентами и дополнениями Spring Roo, приступим к написанию собственных дополнений.


Среда времени исполнения OSGi

Spring Roo основана на OSGi, идеально подходящей для архитектуры дополнений Roo. OSGi предоставляет отличную инфраструктуру для разработки модульных, встраиваемых, сервис-ориентированных приложений.

Roo Shell использует Apache Felix в качестве среды времени исполнения OSGi вместе с Service Component Runtime (SCR) для управления компонентами и репозиторием OSGi Bundle Repository (OBR). В Roo Shell доступны различные OSGi-команды, которые можно увидеть, выполнив команду help osgi (см. листинг 1).

Листинг 1. Справочная информация Roo для OSGi
roo> help osgi 
* osgi find - Finds bundles by name 
* osgi framework command - Passes a command directly 
through to the Felix shell infrastructure 
* osgi headers - Display headers for a specific bundle 
* osgi install - Installs a bundle JAR from a given URL 
* osgi log - Displays the OSGi log information 
* osgi obr deploy - Deploys a specific OSGi Bundle Repository (OBR) bundle 
* osgi obr info - Displays information on a specific OSGi Bundle Repository (OBR) bundle 
* osgi obr list - Lists all available bundles from the 
OSGi Bundle Repository (OBR) system 
* osgi obr start - Starts a specific OSGi Bundle Repository (OBR) bundle 
* osgi obr url add - Adds a new OSGi Bundle Repository (OBR) repository file URL 
* osgi obr url list - Lists the currently-configured 
OSGi Bundle Repository (OBR) repository file URLs 
* osgi obr url refresh - Refreshes an existing 
OSGi Bundle Repository (OBR) repository file URL 
* osgi obr url remove - Removes an existing 
OSGi Bundle Repository (OBR) repository file URL 
* osgi ps - Displays OSGi bundle information 
* osgi resolve - Resolves a specific bundle ID 
* osgi scr config - Lists the current SCR configuration 
* osgi scr disable - Disables a specific SCR-defined component 
* osgi scr enable - Enables a specific SCR-defined component 
* osgi scr info - Lists information about a specific SCR-defined component 
* osgi scr list - Lists all SCR-defined components 
* osgi start - Starts a bundle JAR from a given URL 
* osgi uninstall - Uninstalls a specific bundle 
* osgi update - Updates a specific bundle 
* osgi version - Displays OSGi framework version

Команда создания дополнения Spring Roo

Spring Roo поставляется с командами, предназначенными для создания дополнений различных типов. Add-on Creator, предоставляющий команды addon create, тоже является дополнением Roo. В настоящее время Roo поддерживает четыре типа дополнений:

  1. Internationalization Add-on (дополнение интернационализации) – это дополнение поддерживает добавление переводов на другие языки построенных на основе Roo приложений Spring MVC (например, добавление перевода на хинди).
  2. Simple Add-on (простое дополнение) – эти дополнения поддерживают небольшие добавления к конфигурации и (или) зависимостям проекта, выполняя некоторые изменения в maven pom.xml (например, добавляя определенные JAR-файлы или плагины Maven).
  3. Advanced Add-on (расширенное дополнение) – это дополнение выполняет тяжелую работу и используется для построения полноценных дополнений Spring Roo, требующих создания Java-кода (например, дополнения, которое может писать методы equals и hashcode для вашего доменного объекта). Для этих функций уже существует дополнение сообщества.
  4. Wrapper Add-on – это дополнение-обертка для артефактов Maven, которое предназначено для создания пакета, совместимого с OSGi. Оно используется в случае, когда полную функциональность дополнения обеспечивает зависимость. Например, дополнению реверсивного проектирования базы данных для выполнения своих задач необходим JDBC-драйвер Postgres, поэтому нужно упаковать этот драйвер в дополнение-обертку.

Эти дополнения создают команды для облегчения разработки дополнений Roo путем создания новых дополнений, которые:

httppgp://

В версии Spring Roo V1.1 появился механизм Pretty Good Privacy (PGP), позволяющий пользователям указывать, каким разработчикам доверено подписание цифровой подписью программного обеспечения, которое будет загружаться и активизироваться в Roo Shell. Фактически каждая версия самого Roo теперь подписана PGP-подписью. В Roo была представлена новая схема реализации протокола httppgp:// для указания, что в URL содержится PGP-подпись. Это обеспечивает открытую форму системы безопасности, помогающую защитить пользователей от подозрительных загрузок. Эти стандарты позволяют также использовать автономные PHP-средства для независимой проверки Roo-операций.

  • Интегрированы с системой управления исходными кодами Google Code SVN.
  • Размещены в открытом репозитории Maven, входящем в состав проекта Google Code.
  • Совместимы с RooBot – предоставляемым VMware сервисом, индексирующим важное содержимое в открытых Roo OBR-файлах. OBR-файл – это XML-представление метаданных пакета. Для совместимости с RooBot дополнения должны быть:
    1. Совместимы с OSGi.
    2. Подписаны PGP-подписью с открытыми ключами.
    3. Зарегистрированы посредством протокола httppgp://.

При использовании команды Roo addon create мы получаем все вышеперечисленные возможности, автоматически настроенные для наших дополнений. Это безусловно уменьшает время создания и публикации дополнений.

Перед написанием дополнений проверьте работоспособность среды Spring Roo. Инструкции по установке Spring Roo приведены в первой части серии.


Реализация поддержки языка хинди (создание дополнения интернационализации)

При создании основанного на Spring MVC Web-приложения при помощи Spring Roo можно добавить поддержку различных языков, используя команду web mvc language. В Spring Roo встроена поддержка английского, немецкого, испанского, итальянского, голландского и шведского языков. Поддержка интернационализации осуществляется дополнением Web MVC JSP и становится возможной только после записи JSPX-файлов в каталог webapp. JSPX-файлы генерируются командой контроллера, преобразующей простое JAR-приложение в Spring MVC Web-приложение.

Будучи индийцем, я захотел добавить поддержку языка хинди в мое Web-приложение. Spring Roo предоставляет команду addon create i18n, являющуюся расширением команды web mvc install language для добавления нового языка (хинди). Ей нужен только перевод файла messages.properties на соответствующий язык.

При создании Spring MVC Web-приложения Spring Roo создает два файла свойств: application.properties и messages.properties. Файл application.properties содержит специфичные для приложения свойства, например его название. Файл messages.properties содержит свойства, не являющиеся специфичными для какого-либо приложения, например, сообщение "Вы действительно хотите удалить этот элемент?", появляющееся при нажатии кнопки "Удалить", либо сообщения при входе или выходе из приложения и т.д. Поэтому при написании дополнения интернационализации необходимо предоставить перевод файла messages.properties.

Теперь, когда мы узнали о поддержке интернационализации в Spring Roo по умолчанию, давайте напишем дополнение интернационализации, которое добавит поддержку языка хинди. Я покажу, как настроить проект в Google Code, написать дополнение с использованием команды, опубликовать и выпустить его в свет, а также зарегистрировать в сервисе RooBot. Регистрация в сервисе RooBot очень важна, поскольку она позволит RooBot проиндексировать ваше дополнение и покажет его в результатах поиска, когда другие разработчики будут искать дополнения при помощи команды addon search.

Настройка проекта

В документации по Spring Roo подробно объясняется процесс настройки проекта и Maven-репозитория в Google Code, поэтому я не буду повторяться. Просто отмечу, что в качестве имени проекта буду использовать roo-hind-addon.

Создание дополнения интернационализации

После установки проекта у нас будет пустой каталог roo-hindi-addon. Перейдите в этот каталог и введите команду roo. В командном процессоре выполните команду addon create i18n. Нажав клавишу Tab, вы увидите, что эта команда принимает семь атрибутов. Три из них обязательны: topLevelPackage (пакет верхнего уровня для нового дополнения), locale (языковая аббревиатура, например "it" для итальянского) и messageBundle (полный путь к файлу message_xx.properties, где xx – это имя локали). Остальные четыре атрибута не обязательны: language (полное название языка), flagGraphic (полный путь к файлу xx.png, где xx – имя флага), description (описание дополнения) и projectName (название проекта; если не указывается, используется название пакета верхнего уровня). Я рекомендую использовать атрибут projectName и присвоить ему название проекта, размещаемого в Google Code. Поэтому в нашем примере это будет roo-hindi-addon.

Из вышеупомянутых атрибутов самым важным является messageBundle, ссылающийся на переведенный файл messages.properties. Самым простым способом перевода файла messages.properties на хинди является использование сервиса Google Translate; каждое свойство переводится по очереди и записывается в файл messages_hi.properties. Однако в нашем случае это не работает, поскольку Java-файлы свойств используют кодировку ISO-8859-1, не поддерживающую символы языка хинди. Для решения этой проблемы я использовал плагин Eclipse под названием Eclipse ResourceBundle Editor, который позволяет преобразовывать и создавать пакеты ресурсов для различных языков. Его можно установить, используя сайт обновлений http://www.nightlabs.de/updatesites/development/. Преобразование файла messages.properties в messages_hi.properties не является предметом рассмотрения данной статьи. Плагин ResourceBundle Editor использовать легко. Отмечу, что если бы символы языка поддерживались, не было бы необходимости использовать ResourceBundle Editor. Файл messages_hi.properties приведен в листинге 2.

Листинг 2. Пример файла messages_hi.properties
button_cancel = \u0930\u0926\u094D\u0926 
button_end = \u0905\u0902\u0924
button_find = \u0916\u094B\u091C\u0947\u0902
button_home = \u0918\u0930 
...

Просмотрите файл полностью. После перевода файла messages_hi.properties на хинди для создания дополнения достаточно выполнить всего одну команду. Дополнение Hindi можно создать при помощи Roo Shell команды, приведенной в листинге 3.

Листинг 3. Команда для создания дополнения Hindi
addon create i18n --locale hi --topLevelPackage org.xebia.roo.addon.i18n.hindi 
  --messageBundle <location to messages_hi.properties> \
--language hindi --projectName roo-hindi-addon 
  --flagGraphic <full path to flag hi.png>

В листинге 4 приведены артефакты, созданные командой addon create i18n.

Листинг 4. Созданные артефакты
Created ROOT/pom.xml 
Created ROOT/readme.txt 
Created ROOT/legal 
Created ROOT/legal/LICENSE.TXT 
Created SRC_MAIN_JAVA 
Created SRC_MAIN_RESOURCES 
Created SRC_TEST_JAVA 
Created SRC_TEST_RESOURCES 
Created SRC_MAIN_WEBAPP 
Created SRC_MAIN_RESOURCES/META-INF/spring 
Created ROOT/src/main/assembly 
Created ROOT/src/main/assembly/assembly.xml 
Created SRC_MAIN_RESOURCES/org/xebia/roo/addon/i18n/hindi 
Created SRC_MAIN_RESOURCES/org/xebia/roo/addon/i18n/hindi/messages_hi.properties 
Created SRC_MAIN_RESOURCES/org/xebia/roo/addon/i18n/hindi/hi.png 
Created SRC_MAIN_JAVA/org/xebia/roo/addon/i18n/hindi 
Created SRC_MAIN_JAVA/org/xebia/roo/addon/i18n/hindi/HindiLanguage.java

Команда сгенерировала Maven-проект, который можно импортировать в Eclipse (при помощи m2eclipse) или в SpringSource Tool Suite, выбрав в меню File > Import > Maven > Existing Maven projects. Нам не нужно импортировать этот проект, поскольку нам не нужно модифицировать дополнение.

Теперь можно установить дополнение, использовать его в наших проектах и опубликовать. Но сначала рассмотрим некоторые артефакты, чтобы лучше понимать сгенерированный код:

  • pom.xml – это конфигурация стандартного Maven-проекта. Сгенерированный pom.xml имеет различные заранее настроенные плагины, выполняющие работу, связанную с подписанием артефактов PGP-подписью, выпуском дополнения при помощи плагина Maven release и созданием OSGi-пакетов при помощи плагина Maven bundle. Также он добавляет в проект зависимости OSGi и Felix, необходимые для работы дополнения в Roo Shell.
  • assembly.xml – определяет конфигурации, используемые плагином Maven assembly для упаковки дополнения.
  • messages_hi.properties – это файл пакета сообщений, предоставляемый нами при создании дополнения, который копируется в папку ресурсов.
  • hi.png – это PNG-файл с изображением флага, предоставляемый нами при создании дополнения, который копируется в папку ресурсов.
  • HindiLanguage.java – это единственный Java-файл, создаваемый дополнением и используемый для получения информации о соответствующем языке. Например, он предоставляет имя локали, файл ресурсов пакета сообщений и т.д.

Добавление поддержки языка хинди в наше приложение

Сейчас я покажу, как можно добавить в приложение поддержку языка хинди, используя только что созданное дополнение:

  1. Выйдите из Roo Shell и выполните команду mvn clean install. Во время процесса сборки отобразится запрос на ввод идентификационной фразы GPG.
  2. После сборки дополнения Roo откройте новое окно командной строки и создайте каталог i18n-hindi-client. Мы создадим простой клиент для нашего дополнения.
  3. Войдите в каталог i18n-hindi-client и выполните команду roo.
  4. Выполните приведенные ниже команды в Roo Shell. Эти команды создадут простое Web-приложение Spring MVC.
    Листинг 5. Roo-команды для создания Web-приложения MVC
    project --topLevelPackage com.shekhar.roo.i18n.client \
    --projectName i18n-hindi-client  
    persistence setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY  
    entity --class ~.domain.MyUser  
    field string --fieldName name --notNull  
    controller all --package ~.web
  5. Введите команду web mvc language --code de en es it nl sv и нажмите кнопку Tab.

    Поддержка языка хинди отсутствует. Причина в том, что мы еще не установили дополнение Hindi.

  6. Для установки этого дополнения выполните следующую команду:
    osgi start --url file:///<location to addon target 
       folder>/org.xebia.roo.addon.i18n.hindi-0.1.0.BUILD-SNAPSHOT.jar

    Она должна установить и активировать наше дополнение Spring Roo Hindi. Можно просмотреть состояние дополнения, используя команду osgi ps, отображающую информацию о OSGi-пакете и о его состоянии, например:

    [ 95] [Active ] [ 1] roo-hindi-addon (0.1.0.BUILD-SNAPSHOT)
  7. Повторно введите команду web mvc language –code и нажмите кнопку Tab. На этот раз вы увидите код для языка хинди. Выберите код hi, и в ваше приложение будет добавлена поддержка языка хинди.
  8. Выйдите из Roo Shell и выполните команду mvn tomcat:run. В папке появится флаг Индии. Щелкните на флаге левой кнопкой мыши, и ваше приложение отобразится на Хинди, как показано на рисунке 2.
    Рисунок 2. Поддержка языка хинди
    Рисунок 2. Поддержка языка хинди

После тестирования работы дополнения в среде разработки можно поместить его в созданный нами проект Google Code.

Что внутри

Теперь, когда созданное дополнение работает, давайте рассмотрим, как язык хинди стал доступен для приложения:

  1. Дополнение roo-hindi-addon было запущено при помощи команды osgi start.
  2. После запуска дополнения созданный командой addon create i18n класс HindiLanguage регистрируется с помощью i18nComponent, который является прослушивателем OSGi-сервиса для регистрации и отмены регистрации дополнений интернационализации. Класс HindiLanguage отмечается аннотациями @Component и @Service, которые предоставляет Apache Felix. Эти аннотации гарантируют, что компоненты и сервисы зарегистрированы в Roo Shell и доступны для использования.
  3. После ввода команды web mvc install language –code и нажатия клавиши Tab сервис завершения кода вызывает метод getSupportedLanguages() класса i18nComponent, возвращающий java.util.Set дополнений интернационализации. Поскольку HindiLanguage уже зарегистрирован с помощью i18nComponent, он тоже возвращается.

Публикация дополнений

Опубликовать дополнения не трудно, поскольку команда Roo create выполняет основную часть работы за нас, устанавливая все необходимые плагины Maven. Перейдите в корневой каталог проекта и выполните команды, приведенные в листинге 6.

Листинг 6. Публикация проекта Roo
svn add pom.xml src/ legal/ readme.txt 
svn commit -m "Roo Hindi Addon first version" 
mvn release:prepare release:perform

Плагин Maven release запросит версию выпуска, имя тега и версию разработки. Можно просто выбрать значения по умолчанию и продолжить работу. Выпуск и публикация артефактов в проекте Google Code займет несколько минут. После этого можно будет просмотреть артефакты дополнения в вашем проекте Google Code.

Регистрация дополнения в RooBot

После выпуска дополнения можно отправить его по электронной почте по адресу s2-roobot@vmware.com для регистрации вашего репозитория дополнений. Письмо должно содержать файл repository.xml. Например, для только что созданного нами дополнения этим файлом является http://code.google.com/p/roo-hindi-addon/source/browse/repo/repository.xml. Дополнительная информация по регистрации в RooBot приведена в документации Spring Roo.


Мониторинг Java-приложения (создание простого дополнения)

Обычным требованием для многих корпоративных приложений является возможность мониторинга Java-приложения для определения узких мест в производительности. У нас тоже есть такое требование, поэтому давайте рассмотрим некоторые доступные решения с открытым исходным кодом. Java Application Monitor (JAMon) – это бесплатный высокопроизводительный потокобезопасный программный интерфейс Java, позволяющий выполнять мониторинг работающих приложений.

Для добавления поддержки JAMon в Web-приложение:

  1. Необходимо добавить JAR-файл jamon в ваш pom.xml.
  2. Необходимо определить bean-компонент JamonPerformanceMonitorInterceptor в файле контекста приложения. Пример определения bean-компонента приведен в листинге 7.
Листинг 7. Код JamonPerformanceMonitorInterceptor
	<bean id="jamonPerformanceMonitorInterceptor" 
		class=\
"org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor"> 
		<property name="trackAllInvocations" value="true"></property> 
		<property name="useDynamicLogger" value="true"></property> 
	</bean> 

	<bean id="autoProxyCreator" 
		class=\
"org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> 
		<property name="interceptorNames"> 
			<list> 
				<idref bean="jamonPerformanceMonitorInterceptor" /> 
			</list> 
		</property> 
		<property name="beanNames"> 
			<list> 
				<value>speakerController</value> 
				<value>talkController</value> 
			</list> 
		</property> 
	</bean>

Это непростое определение bean-компонента будет не легко запомнить любому разработчику, и я подумал, что было бы здорово автоматизировать эту шаблонную настройку. Поэтому я решил написать дополнение для автоматизации процесса добавления JAMon-зависимости и присоединения bean-компонента перехватчика (interceptor bean). Какое необходимо дополнение, простое или расширенное?

  1. Используйте простое дополнение, если хотите добавить в свой проект Maven-зависимости и (или) артефакты конфигурации.
  2. Используйте расширенное дополнение, если нужно написать полноценное дополнение, расширяющее существующие Java-типы и (или) представляющее новые Java-типы и ITD-объявления AspectJ.

Наше требование – добавить jamon.jar в classpath и написать файл контекста приложения, который будет содержать определение нашего bean-компонента. Лучше написать новый файл контекста приложения Spring, чем использовать существующий, поскольку это помогает применить модульный подход к контексту приложения. Эти требования показывают, что нам нужно написать простое дополнение, которое сможет добавлять поддержку JAMon в любое Web-приложение.

Настройка проекта

Необходимо настроить проект так же, как мы делали это для дополнения интернационализации. Я назову этот проект spring-roo-addon-jamon.

Создание простого дополнения

После установки проекта у нас будет каталог spring-roo-addon-jamon с единственной папкой .svn. Перейдите в каталог spring-roo-addon-jamon и запустите Spring Roo Shell. Затем выполните следующую команду:

addon create simple --topLevelPackage org.xebia.roo.addon.jamon \
--projectName spring-roo-addon-jamon

Это все! Дополнение создано.

Установка сгенерированных дополнений

Установить дополнение можно при помощи следующей команды:

osgi start --url file://<Location to addon
    target folder>/org.xebia.roo.addon.jamon-0.1.0.BUILD-SNAPSHOT.jar

После установки дополнения создайте простого клиента, как делали это для тестирования модуля интернационализации. Сгенерированное дополнение предоставляет две команды:

  1. Команда say hello выводит приветствие в Roo Shell. Эта команда доступна всегда, и ее можно выполнить в любое время при условии, что запущен командный процессор Roo Shell.
  2. Команда web mvc install tags замещает MVC-теги по умолчанию, сгенерированные при сборке Web-приложения. Эта команда доступна только после создания Web-приложения.

Анализ сгенерированного кода

Теперь, после тестирования дополнения, рассмотрим файлы, сгенерированные этим дополнением и перечисленные в листинге 8.

Листинг 8. Файлы, сгенерированные для spring-roo-addon-jamon
Created ROOT/pom.xml 
Created ROOT/readme.txt 
Created ROOT/legal 
Created ROOT/legal/LICENSE.TXT 
Created SRC_MAIN_JAVA 
Created SRC_MAIN_RESOURCES 
Created SRC_TEST_JAVA 
Created SRC_TEST_RESOURCES 
Created SRC_MAIN_WEBAPP 
Created SRC_MAIN_RESOURCES/META-INF/spring 
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon 
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon/JamonCommands.java 
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon/JamonOperations.java 
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon/JamonOperationsImpl.java 
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon/JamonPropertyName.java 
Created ROOT/src/main/assembly 
Created ROOT/src/main/assembly/assembly.xml 
Created SRC_MAIN_RESOURCES/com/shekhar/roo/addon/jamon 
Created SRC_MAIN_RESOURCES/com/shekhar/roo/addon/jamon/info.tagx 
Created SRC_MAIN_RESOURCES/com/shekhar/roo/addon/jamon/show.tagx

Артефакты pom.xml, assembly.xml, LICENSE.TXT и readme.txt аналогичны сгенерированным для модуля интернационализации. Мы обсудили их ранее, поэтому я не буду повторяться. Более интересны артефакты JamonCommands, JamonOperations, JamonOperationsImpl и JamonPropertyName. Рассмотрим их по очереди, чтобы лучше понимать код, сгенерированный командой simple add-on.

  1. JamonCommands.java:JamonCommands – это класс, реализующий интерфейс маркера CommandMarker и предоставляющий две команды, say hello и web mvc install tags, как показано в листинге 9.
    Листинг 9. Сгенерированный код из JamonCommands.java:JamonCommands
    @Component 
    @Service 
    public class JamonCommands implements CommandMarker { 
            
           @Reference private JamonOperations operations; 
            
           @Reference private StaticFieldConverter staticFieldConverter; 
    
    
           protected void activate(ComponentContext context) { 
               staticFieldConverter.add(JamonPropertyName.class); 
               } 
    
    
           protected void deactivate(ComponentContext context) { 
                   staticFieldConverter.remove(JamonPropertyName.class); 
           } 
            
           @CliAvailabilityIndicator("say hello") 
           public boolean isSayHelloAvailable() { 
                   return true; 
           } 
            
           @CliCommand(value = "say hello", 
    help = "Prints welcome message to the Roo shell") 
           public void sayHello( 
                   @CliOption(key = "name", mandatory = true, 
    help = "State your name") String name, 
                   @CliOption(key = "contryOfOrigin", mandatory = false, 
           help = "Country of origin") JamonPropertyName country) { 
                    
                   log.info("Welcome " + name + "!"); 
                   log.warning("Country of origin: " + (country == null ? \
    JamonPropertyName.NOT_SPECIFIED.getPropertyName() : country.getPropertyName())); 
                   
                   log.severe("It seems you are a running JDK " 
    + operations.getProperty("java.version")); 
                   log.info("You can use the default JDK logger anywhere in your" 
    + " add-on to send messages to the Roo shell"); 
           } 
            
           @CliAvailabilityIndicator("web mvc install tags") 
           public boolean isInstallTagsCommandAvailable() { 
                   return operations.isInstallTagsCommandAvailable(); 
           } 
            
           @CliCommand(value = "web mvc install tags", 
    help="Replace default Roo MVC tags used for scaffolding") 
           public void installTags() { 
                   operations.installTags(); 
           } 
    }

    Чтобы сократить код, я удалил все комментарии генератора кода. Давайте познакомимся с важными членами этого класса:

    1. CommandMarker. Чтобы все классы command были зарегистрированы (а их команды доступны в Roo Shell), они должны реализовывать интерфейс CommandMarker и иметь аннотации @Component и @Service. Поля, аннотированные @Reference, являются зависимостями класса JamonCommands и внедряются используемым Roo OSGi-контейнером. Все классы, имеющие аннотации @Component и @Service, могут быть внедрены в другие дополнения.
    2. Методы Activate и Deactivate. Методы activate и deactivate вызываются при установке дополнения при помощи команды addon install или удаления дополнения при помощи команды addon remove. Эти методы позволяют встроиться в цикл жизни дополнения, управляемого OSGi-контейнером.
    3. Методы, аннотированные @CliAvailabilityIndicator. Методы, аннотированные @CliAvailabilityIndicator, помогают скрыть команды, когда они недоступны. Например, команда security setup, устанавливающая Spring Security в проект, невидима для проектов, не являющихся Web-приложениями. Эти методы необязательны, но они полезны, поскольку не позволяют пользователю активизировать команды, не имеющие смысла в данный момент. Например, выполнение команды security setup при отсутствии Web-приложения не имеет никакого смысла.
    4. Методы, аннотированные @CliCommand. Методы, аннотированные @CliCommand, регистрируют команду в Roo Shell. Аннотация @CliCommand имеет два атрибута: value, определяющий имя команды, и help, определяющий подсказку, отображаемую командой help. Каждая команда может определять обязательные и необязательные атрибуты, используя аннотацию @CliOption в составе команды. Например, команда say hello имеет обязательный атрибут name и необязательный – country.
  2. JamonOperationsImpl.java. Классы команд, необходимые для выполнения некоторых операций во время работы команды. Эти операции выполняются классами операций. JamonOperationsImpl – это класс операций, отвечающий за выполнение необходимой работы, такой как добавление зависимости в pom.xml или копирование ресурсов в нужное место. Класс JamonOperationsImpl выполняет свои операции, используя базовые сервисы, предоставляемые средой Spring Roo. Например, для добавления зависимости он использует интерфейс ProjectOperations. Для копирования файлов он использует интерфейс FileManager. Рассмотрим исходный код класса JamonOperationsImpl (см. листинг 10), чтобы лучше понять работу дополнения Roo.
    Листинг 10. JamonOpertionsImpl
    	@Component 
    	@Service 
    	public class JamonOperationsImpl implements JamonOperations { 
    		private static final char SEPARATOR = File.separatorChar; 
    	 
    		@Reference private FileManager fileManager; 
    		@Reference private ProjectOperations projectOperations; 
    
    		public boolean isInstallTagsCommandAvailable() { 
    			return projectOperations.isProjectAvailable() &&
                fileManager.exists(projectOperations.getProjectMetadata().
    			getPathResolver().getIdentifier(Path.SRC_MAIN_WEBAPP,
                    "WEB-INF" + SEPARATOR + "tags")); 
    	} 
    
    		public String getProperty(String propertyName) { 
    			Assert.hasText(propertyName, "Property name required"); 
    			return System.getProperty(propertyName); 
    		} 
    
    		public void installTags() { 
    			PathResolver pathResolver =
                projectOperations.getProjectMetadata().getPathResolver(); 
    			createOrReplaceFile(pathResolver.getIdentifier(
    			    Path.SRC_MAIN_WEBAPP, "WEB-INF" + SEPARATOR +
                        "tags" + SEPARATOR + "util"), "info.tagx"); 
    
    		createOrReplaceFile(pathResolver.getIdentifier(
    			Path.SRC_MAIN_WEBAPP, "WEB-INF" + SEPARATOR +
                    "tags" + SEPARATOR + "form"), "show.tagx"); 
    		} 
    	 
    		private void createOrReplaceFile(String path, String fileName) { 
    			String targetFile = path + SEPARATOR + fileName; 
    			MutableFile mutableFile = fileManager.exists(targetFile) ?
                    fileManager.updateFile(targetFile) :
                    fileManager.createFile(targetFile); 
    			    try { 
    			    	FileCopyUtils.copy(TemplateUtils.getTemplate(getClass(),
                            fileName), mutableFile.getOutputStream()); 
    			    } catch (IOException e) { 
    				throw new IllegalStateException(e); 
    			} 
    		} 
    	}

    Класс JamonOperationsImpl имеет два важных метода: isInstallTagsCommandAvailable проверяет доступность команды, а installTags устанавливает теги в целевой проект. Для выполнения этих операций класс JamonOperationsImpl использует некоторые базовые сервисы и вспомогательные программы Spring Roo:

    1. Класс ProjectOperations : JamonOperationsImpl использует сервис ProjectOperations для проверки доступности проекта и для получения пути к папке тегов.
    2. Класс FileManager : JamonOperationsImpl использует сервис FileManager для проверки существования файла в определенном месте и для обновления или создания MutableFile. MutableFile – это еще один специальный класс Roo, представляющий указатель файла, который может быть изменен.
    3. Вспомогательный класс TemplateUtils : TemplateUtils используется для получения InputStream в файлы шаблонов (info.tagx и show.tagx) в нашем пакете дополнений.
    4. Вспомогательный класс FileCopyUtils : FileCopyUtils используется для копирования шаблонов (из TemplateUtils) в MutableFile (из FileManager).

Изменение дополнения в соответствии с нашими требованиями

В разделе о простом дополнении мы рассмотрели два требования, которые нужно реализовать, чтобы наше дополнение могло настраивать JAMon в любом Spring MVC Web-приложении. Вот эти требования:

  1. Добавить JAMon JAR в файл pom.xml.
  2. Определить bean-комопнент JamonPerformanceMonitorInterceptor в файле контекста приложения.

Для реализации этих требований мы изменим класс JamonCommands, чтобы он поддерживал команду jamon setup. Затем мы добавим одну операцию, соответствующую команде jamon setup и выполняющую необходимую работу для удовлетворения наших требований.

JamonCommands. Класс JamonCommands теперь будет иметь всего два метода: isInstallJamon для проверки доступности команды jamon setup и installJamon для установки JAMon при активизации команды jamon setup (см. листинг 11).

Листинг 11. Код для JamonCommands
@Component 
@Service 
public class JamonCommands implements CommandMarker { 
	 
	private Logger log = Logger.getLogger(getClass().getName()); 

	@Reference private JamonOperations operations; 
	 
	@CliAvailabilityIndicator("jamon setup") 
	public boolean isInstallJamon() { 
		return operations.isInstallJamonAvailable(); 
	} 
	 
	@CliCommand(value = "jamon setup", help = "Setup Jamon into your project") 
	public void installJamon() { 
		operations.installJamon(); 
	} 
}

Это все, что нам нужно в классе JamonCommands. Требуется только предоставить команду jamon setup, а остальная работа делегируется классу JamonOperationsImpl (см. листинг 12).

Листинг 12. Код для JamonOperationsImpl
JamonOperationsImpl

JamonOperationsImpl need to implement two methods – \
isInstallJamonAvailable() and installJamon(). 

Метод isinstallJamonAvailable() возвращает булево значение, определяющее
доступность команды в данном месте. Я хочу разрешить JAMon только для
Web-приложений, поэтому нужно проверить, является проект таковым или нет.
Для этого пишется следующий код

	public boolean isInstallJamonAvailable() { 
		return projectOperations.isProjectAvailable() &&
        fileManager.exists(projectOperations.getPathResolver()
			.getIdentifier(Path.SRC_MAIN_WEBAPP, "/WEB-INF/web.xml")); 
	}

Код, приведенный в листинге 12, использует сервис ProjectOperations для проверки доступности проекта в этом месте и для получения пути к файлу web.xml (файл web.xml существует только для Web-приложений). Сервис FileManager используется для проверки существования файла web.xml в месте, указанном ProjectOperations.

Второй метод, который необходимо реализовать, – это installJamon(), который должен добавлять JAMon-зависимость в pom.xml и определение bean-компонента в webmvc-config.xml. Перед написанием кода для этого метода необходимо создать XML-файл configuration.xml в папке src/main/resources/org/xebia/roo/addon/jamon. Структура папки org/xebia/roo/addon/jamon аналогична структуре пакета вашего дополнения Roo. Файл configuration.xml определяет версию JAMon и зависимость JAMon JAR, как показано в листинге 13.

Листинг 13. Содержимое файла configuration.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?> 
<configuration> 
    <jamon> 
        <properties> 
            <jamon.version>2.4</jamon.version> 
        </properties> 
        <dependencies> 
            <dependency> 
            <groupId>com.jamonapi</groupId> 
            <artifactId>jamon</artifactId> 
            <version>${jamon.version}</version> 
        </dependency> 
        </dependencies> 
    </jamon> 
</configuration>

Давайте напишем код для добавления зависимости в pom.xml, как показано в листинге 14.

Листинг 14. Содержимое pom.xml
	public void installJamon() { 
		Element configuration = XmlUtils.getConfiguration(getClass()); 
		updatePomProperties(configuration); 
		updateDependencies(configuration); 
	} 

	private void updatePomProperties(Element configuration) { 
		List<Element> properties = \
XmlUtils.findElements("/configuration/jamon/properties/*"
		, configuration); 
		for (Element property : properties) { 
			projectOperations.addProperty(new Property(property)); 
		} 
	} 

	private void updateDependencies(Element configuration) { 

		List<Dependency> dependencies = new ArrayList<Dependency>(); 
		List<Element> jamonDependencies = XmlUtils.findElements(
			"/configuration/jamon/dependencies/dependency", configuration); 
		for (Element dependencyElement : jamonDependencies) { 
			dependencies.add(new Dependency(dependencyElement)); 
		} 
		projectOperations.addDependencies(dependencies); 
	}

Это стандартный механизм добавления зависимости в pom.xml, который можно обнаружить в большинстве дополнений Roo. Код, приведенный в листинге 14, понятен без объяснений – в нем используется вспомогательный класс XmlUtils для чтения содержимого из configuration.xml, а затем сервис ProjectOperations для обновления файла pom.xml.

После добавления зависимости pom.xml необходимо создать отдельную конфигурацию Spring, web-jamon-config.xml, которая будет содержать определение bean-компонента для JamonPerformanceMonitorInterceptor.

Листинг 15. Содержимое web-jamon-config.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
	xmlns:context="http://www.springframework.org/schema/context" 
	xmlns:mvc="http://www.springframework.org/schema/mvc" \
xmlns:p="http://www.springframework.org/schema/p" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation=\
"http://www.springframework.org/schema/beans \
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     
	http://www.springframework.org/schema/context \
http://www.springframework.org/schema/context/spring-context-3.0.xsd     
	http://www.springframework.org/schema/mvc \
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> 


	<bean id="jamonPerformanceMonitorInterceptor" 
		class=\
"org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor"> 
		<property name="trackAllInvocations" value="true"></property> 
		<property name="useDynamicLogger" value="true"></property> 
	</bean> 

	<bean id="autoProxyCreator" 
		class=\
"org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> 
		<property name="interceptorNames"> 
			<list> 
				<idref bean="jamonPerformanceMonitorInterceptor" /> 
			</list> 
		</property> 
		<property name="beanNames"> 
			<list> 
				<value></value> 
			</list> 
		</property> 
	</bean> 

</beans>

В файле web-jamon-config.xml, приведенном в листинге 15, настроено все необходимое для JAMon в Spring-приложении. Я не указал только имена bean-компонентов для мониторинга. Генератор кода не может это предвидеть, поэтому их имена должен указывать разработчик дополнения.

Теперь нам нужно написать код для копирования файла web-jamon-config.xml в папку web_INF/spring (где расположен webmvc-config.xml) и код для выражения add import в webmvc-config.xml для импорта web-jamon-config.xml (см. листинг 16).

Листинг 16. Код для управления pom.xml
public void installJamon() { 
		 
	// обновить код pom.xml 
	PathResolver pathResolver =
        projectOperations.getProjectMetadata().getPathResolver(); 
	String resolvedSpringConfigPath = pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP,
        "/WEB-INF/spring"); 
	if (fileManager.exists(resolvedSpringConfigPath + "/web-jamon-config.xml")) { 
			return; 
	} 
	copyTemplate("web-jamon-config.xml", resolvedSpringConfigPath); 
		 
	String webMvcConfigPath = resolvedSpringConfigPath + "/webmvc-config.xml"; 

	new XmlTemplate(fileManager).update(webMvcConfigPath, new DomElementCallback() { 
		public boolean doWithElement(Document document, Element root) { 
			if (null ==
               XmlUtils.findFirstElement\
("/beans/import[@resource='web-jamon-config.xml']",
                   root)) { 
                   Element element = document.createElement("import"); 
		        element.setAttribute("resource", "web-jamon-config.xml"); 
				root.appendChild(element); 
		        return true; 
		    } 
		    return false; 
		   } 
	}); 
		 
} 
	 
private void copyTemplate(String templateFileName, String resolvedTargetDirectoryPath) { 
	
    try { 
	    FileCopyUtils.copy(TemplateUtils.getTemplate(getClass(),
               templateFileName), fileManager.createFile(
	            resolvedTargetDirectoryPath + "/" +
                   templateFileName).getOutputStream()); 
	} catch (IOException e) { 
           throw new IllegalStateException(
               "Encountered an error during copying of resources for Jamon addon.", e); 
    } 
}

Класс XmlTemplate, использованный выше, взят из дополнения Spring web flow. Поэтому в наше дополнение нужно добавить зависимость для модуля web flow (см. листинг 17).

Листинг 17. Добавление зависимости для дополнения web flow
	<dependency> 
		<groupId>org.springframework.roo</groupId> 
		<artifactId>org.springframework.roo.addon.web.flow</artifactId> 
		<version>${roo.version}</version> 
      		<type>bundle</type> 
	</dependency>

В листинге 17 roo.version – это версия используемого Roo.

Последнее, что необходимо сделать в этом дополнении, – настроить журналирование и установить log-уровень для трассировки. Для этого используется LoggingOperations – класс операций для дополнения log4j. Чтобы использовать этот класс, необходимо сначала добавить зависимость для дополнения журналирования в файле pom.xml, как показано в листинге 18.

Листинг 18. XML-код добавления зависимости для дополнения журналирования
	<dependency> 
		<groupId>org.springframework.roo</groupId> 
		<artifactId>org.springframework.roo.addon.logging</artifactId> 
		<version>${roo.version}</version> 
      		<type>bundle</type> 
	</dependency>

После добавления зависимости в pom.xml добавьте LoggingOperation в класс JamonOperationsImpl, используя следующую строку:

@Reference private LoggingOperations loggingOperations;

Затем в метод installJamon добавьте следующую строку:

loggingOperations.configureLogging(LogLevel.TRACE, LoggerPackage.PROJECT);

Это весь код, который нужно написать для данного дополнения. Полностью код класса JamonOperationsImpl приведен в листинге 19.

Листинг 19. Полный код класса JamonOperationsImpl
@Component 
@Service 
public class JamonOperationsImpl implements JamonOperations { 
       @Reference private FileManager fileManager; 
       @Reference private ProjectOperations projectOperations; 
       @Reference private LoggingOperations loggingOperations; 


       public boolean isInstallJamonAvailable() { 
               return projectOperations.isProjectAvailable() && 
fileManager.exists(projectOperations.getPathResolver()
.getIdentifier(Path.SRC_MAIN_WEBAPP,"/WEB-INF/web.xml")); 
       } 


       public void installJamon() { 
               Element configuration = XmlUtils.getConfiguration(getClass()); 
               updatePomProperties(configuration); 
               updateDependencies(configuration); 
               PathResolver pathResolver = 
projectOperations.getProjectMetadata().getPathResolver(); 
               String resolvedSpringConfigPath = 
pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP, 
            "/WEB-INF/spring"); 
               if (fileManager.exists(resolvedSpringConfigPath 
+ "/web-jamon-config.xml")) { 
                       return; 
               } 


               copyTemplate("web-jamon-config.xml", resolvedSpringConfigPath); 
                
               String webMvcConfigPath = resolvedSpringConfigPath 
+ "/webmvc-config.xml";


               new XmlTemplate(fileManager).update(webMvcConfigPath, 
new DomElementCallback() { 
                       public boolean doWithElement(Document document, Element root) {
                            if (null == XmlUtils.findFirstElement(
"/beans/import[@resource='web-jamon-config.xml']",
root)) { 
                                 
Element element = document.createElement("import"); 
                                element.setAttribute("resource", "web-jamon-config.xml"); 
                                root.appendChild(element); 
                                return true; 
                             } 
                             return false; 
                       } 
               });
               loggingOperations.configureLogging(LogLevel.TRACE, 
LoggerPackage.PROJECT); 
       } 
        
       private void copyTemplate(String templateFileName, 
String resolvedTargetDirectoryPath) { 
               try { 
FileCopyUtils.copy(
      TemplateUtils.getTemplate(getClass(), templateFileName),
              fileManager.createFile(resolvedTargetDirectoryPath + "/" + 
              templateFileName).getOutputStream()); 
               } catch (IOException e) { 
                       throw new IllegalStateException(
               "Encountered an error during copying of resources for Jamon addon.", e);
               } 
       } 
        
       private void updatePomProperties(Element configuration) { 
               List<Element> properties = XmlUtils
     .findElements("/configuration/jamon/properties/*",configuration);
               for (Element property : properties) { 
                       projectOperations.addProperty(new Property(property));
               } 
       } 


       private void updateDependencies(Element configuration) { 
               List<Dependency> dependencies = new ArrayList<Dependency>(); 
               List<Element> jamonDependencies = XmlUtils.findElements(
           "/configuration/jamon/dependencies/dependency", configuration); 
               for (Element dependencyElement : jamonDependencies) { 
                       dependencies.add(new Dependency(dependencyElement)); 
               } 
               projectOperations.addDependencies(dependencies); 
       } 
        
}

Весь исходный код этого дополнения можно загрузить из репозитория Google Code. Теперь давайте добавим в наше приложение поддержку JAMon, используя только что созданное дополнение:

  1. Закройте Roo Shell и выполните команду mvn clean install. Во время сборки отобразится запрос на ввод идентификационной фразы GPG.
  2. После завершения сборки дополнения откройте новое окно командной строки и создайте каталог jamon-client. Мы создадим простой клиент для нашего дополнения.
  3. Перейдите в каталог jamon-client и выполните команду roo, чтобы запустить Roo Shell.
  4. В Roo Shell выполните команды, приведенные в листинге 20. Эти команды создадут простое Web-приложение Spring MVC.
    Листинг 20. Создание простого MVC Web-приложения
    project --topLevelPackage com.shekhar.roo.jamon.client --projectName jamon-client 
    persistence setup --provider HIBERNATE --database
    HYPERSONIC_IN_MEMORY
    entity --class ~.domain.MyUser
    field string --fieldName name --notNull
    controller all --package ~.web
  5. Для установки этого дополнения выполните следующую команду:
    osgi start --url <a
    href="../../../../">file:///</a><location \
    to addon target folder >
    /org.xebia.roo.addon.jamon-0.1.0.BUILD-SNAPSHOT.jar

    Эта команда установит и активизирует наше дополнение JAMon. Состояние модуля можно просмотреть при помощи команды osgi ps.

  6. Выполните команду jamon setup и увидите, что в нашем приложении был сконфигурирован JAMon. Если теперь запустить приложение при помощи команды mvn tomcat:run, в окне консоли не будет никаких log-сообщений, потому что еще ни один bean-компонент не был настроен для мониторинга. Давайте настроим наш bean-компонент myUserController в web-jamon-config.xml, используя код, приведенный в листинге 21.
    Листинг 21. Конфигурация myUserController в web-jamon-config.xml
    	<bean id="autoProxyCreator" 
    		class=\
    "org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> 
    		<property name="interceptorNames"> 
    			<list> 
    				<idref bean="jamonPerformanceMonitorInterceptor" /> 
    			</list> 
    		</property> 
    		<property name="beanNames"> 
    			<list> 
    				<value>myUserController</value> 
    			</list> 
    		</property> 
    	</bean>
  7. Теперь запустите приложение, используя команду mvn tomcat:run, и увидите log-сообщения JAMon в консоли maven. Пример приведен в листинге 22.
    Листинг 22. Пример log-сообщения JAMon
    TRACE MyUserController - JAMon performance statistics for method 
    [MyUserController.populateMyUsers]: 
    JAMon Label=MyUserController.populateMyUsers, Units=ms.: (LastValue=187.0, 
    Hits=1.0, Avg=187.0, Total=187.0, Min=187.0, Max=187.0, Active=0.0, Avg 
    Active=1.0, Max Active=1.0, First Access=Wed May 18 15:33:41 IST 2011, Last 
    Access=Wed May 18 15:33:41 IST 2011)

После тестирования работы нашего дополнения в среде разработки можно разместить его в созданном нами проекте Google Code. Для публикации дополнения выполните действия, которые использовались при публикации модуля интернационализации. Аналогичным образом зарегистрируйте дополнение в RooBot, следуя процедуре регистрации интернационализации.


Заключение

Мы рассмотрели архитектуру дополнений Spring Roo и примеры создания дополнения интернационализации и простого дополнения. Архитектура дополнений важна для Roo, поскольку она обеспечивает гибкость для быстрого добавления новых функциональных возможностей. Для разработчиков эта архитектура важна потому, что она позволяет реализовывать необходимую им функциональность, не дожидаясь ее глобальной реализации. Позже, когда функциональность будет интегрирована в Roo, можно относительно легко изменить реализацию, удалив пользовательское решение.

В четвертой части серии я покажу, как писать расширенные дополнения и дополнения-обертки.

Ресурсы

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Open source
ArticleID=858631
ArticleTitle=Введение в Spring Roo: Часть 3. Разработка дополнений Spring Roo
publish-date=02202012