Package organization
Организация кода в пакеты
Словарь
Рефакторинг - Классическая книга описывающая практики рефакторинга - http://www.ozon.ru/context/detail/id/1308678/
DSL - Domain-specific language
Введение
Пакеты это механизм для организации кода и разрешения конфликта уникальности наименования классов. Это техническое определение, но по какому принципу создавать наименования? Какими критериями руководствоваться? И зачем вообще об этом задумываться?
К сожалению этот вопрос слабо освещен в классической литературе. В данной статье я хочу поделиться своим опытом и некоторыми исследованиями по данному вопросу. Первая часть статьи это моя попытка выделить общие принципы. В частности много идей я подчеркнул из презентации Juergen Hoeller, http://www.infoq.com/presentations/code-organization-large-project. Вторая часть статьи - описание вымышленного flex проекта и пошаговое развитие его структуры на основе сформулированных принципов и моего личного опыта.
Общие принципы
Можно сформулировать следующие архитектурные принципы:
- Избегать циклических зависимостей;
- Избегать дублирования;
- Формировать модули;
- Стремиться создавать слабо связанные модули;
- Выбирать модули на основе логической, концептуальной организации (домена)
Далее о каждом их них более подробно:
Избегать циклических зависимостей между пакетами

Циклическая зависимость это когда два пакета ссылаются друг на друга. Обычно такая зависимость не планируется и появляется в последствии. Часто это может быть признаком ухудшения общего состояния кода. Создание пакетов - динамический процесс. Со временем приложение меняется, появляется новая функциональность, старая переосмысливается. Возможно вам придется разделить пакеты по разным приложениям(библиотекам) и компилировать по отдельности. Циклическая зависимость усложняет понимание и развитие кода. Не дает его повторно использовать.
Избегать дублирования
Часто альтернативой циклической зависимости является дублирование кода. Но такой код уже плохо пахнет. Дублирование загромождает код и затрудняет его модификацию. Попробуйте переосмыслить местоположение нового кода и не прятать его глубоко в иерархии.
Формировать модули
Модуль это концептуальная сущность содержащая один или несколько дочерних пакетов. Модуль определяет границы для используемых в нем пакетов.
Стремиться создавать слабо связанные модули

Слабая связность модулей также обеспечивает более понятный код и облегчает повторное использование.
Выбирать модули на основе логической, концептуальной организации (домена)
Часто модули разделяют на основе типов, например:

или на основе уровней:

Данная организация имеет право на существование, но она искусственная, то есть не следует из природы вещей. На мой взгляд, лучшим решением является разбиение на основе домена предметной области. Такое разделение ортогонально разбиению на основе типов или слоев, и развивается более естественно и имеет прозрачные границы.

Зачем об этом заботиться?
Правильная организация пакетов и модулей позволит:
- создать устойчивый внешний API для поддержки обратной совместимости;
- уменьшить время на понимание кода;
- упростить тестирование;
- облегчить повторное использование;
- уменьшить время компиляции, что немаловажно для большого приложения;
- привнести в работу программиста творчество.
Пример и несколько практических советов
В последнее время я часто встречаю в flex приложении структуру пакетов следуещего вида:
vo
view
model
control
commands
business
events
Такое разделение на пакеты пришло к нам из фреймворка Cairngorm, где, видимо его применение оправдано. Но оно встречается и в приложениях, где Cairngorm не используется. Как показывает моя практика, такое разделение плохо развивается при разрастании приложения, пакеты получаются сильно связанные и их практически невозможно использовать повторно в другом приложении.
Я использую разбиение по логике или функциональности. Попробую привести пример.
Рассмотрим приложение AdminPanel
Здесь будет показан сам принцип создания пакетов. Не надо воспринимать получившуюся структуру как эталон, в реальном приложение много дополнительных деталей и специфики.
Начальная структура
rootpackage = com.agakhov.examples.adminpanel
rootpackage.ApplicationView.mxml // определяется размещение всех компонентов приложения
rootpackage.MainDataModel.as // модель данных всего приложения
rootpackage.MainEventMap.xml // сущность из фреймворка mate, её можно заменить обычным классом контроллера
rootpackage.AdminApplucationEvent.as // событие уровня приложения, например ApplicationStart
defaultpackage.Main.xml //создает и инициализирует основные компоненты)
То, что я делал до сих пор, относилось ко всему приложению, поэтому я не выделял никаких специализированных пакетов. Приложение запускается показывает пустое окно и закрывается. Но уже работает.
Login
Допустим, что первая по приоритету задача это аутентификация, для неё я создаю пакет login, собирающий все что связано с этой задачей:
rootpackage.login.LoginView
rootpackage.login.LoginEvent
rootpackage.login.LoginLocalEventMap // содержит методы обращения к сервису
rootpackage.login.LoginModel
Теперь после загрузки наше приложение открывает форму авторизации LoginView и после её заполнения отправляет запрос на сервер. В случае успешной аутентификация и авторизации, посылается сообщение основному приложению и закрывается LoginView.
Registration
Возможно, данного пользователя нет в системе и он захочет зарегистрироваться. Для этого мы создаем пакет registration
rootpackage.registration.RegistrationView
rootpackage.registration.RegistrationEvent // события регистрации
rootpackage.registration.RegistrationlEventMap // содержит методы обращения к сервису регистрации
rootpackage.registration.RegistrationModel // данные о регистрации
Теперь пользователь может открыть окно регистрации, заполнить поля. Если все в порядке, информация отправляется на сервер.
В случае удовлетворительного ответа от сервера, RegistrationView закрывается, основное приложение получает соответствующее сообщение. Дальнейшее развитие этих пакетов зависит от сложности процесса регистрации и авторизации, например регистрация может использовать OpenId, капчу, автозаполнение и т.п. Если процессы многообразны, то возможно создать для их обработки отдельную EventMap. Некоторые функции попросятся в собственный модуль. Но сосредоточимся пока на доменах registration и login

Переход к высокоуровневому домену
Сейчас явно напрашивается желание собрать регистрацию и логи в общий пакет (модуль).
Я придумал наименование accessmanagment.
rootpackage.accessmanagment.AccessManagementModel.as
rootpackage.accessmanagment.AccessManagementLocalEventMap.xml
rootpackage.accessmanagment.AccessManagmentEvent
rootpackage.accessmanagment.login.LoginView
rootpackage.accessmanagment.login.LoginEvent
rootpackage.accessmanagment.login.LoginLocalEventMap // содержит методы обращения к сервису
rootpackage.accessmanagment.login.LoginModel
rootpackage.accessmanagment.registration
rootpackage.accessmanagment.registration.RegistrationView
rootpackage.accessmanagment.registration.RegistrationEvent
rootpackage.accessmanagment.registration.RegistrationlEventMap
rootpackage.accessmanagment.registration.RegistrationModel
Ортогональный домен
Думаю, идея создания пакетов на основании домена понятна, но напрашивается вопрос, что делать, если один и тот же класс необходимо использовать в нескольких модулях?
Для задач ортогональных домену предметной области я обычно завожу папку common на соответствующем уровне иерархии. Например мне необходимо выделить базовый класс для всех mate моделей или общего предка для всех модальных окон:
rootpackage.ApplicationView.mxml
rootpackage.MainDataModel.as
rootpackage.MainEventMap.xml
rootpackage.AdminApplucationEvent.as
defaultpackage.Main.xml
rootpackage.common
rootpackage.common.model.AbstractMateModel.as
rootpackage.common.view.ModalView.as
rootpackage.accessmanagment.*
rootpackage.accessmanagment.login.*
rootpackage.accessmanagment.registration.*
Для пакета common основным доменом будет именно ортогональная задача. Далее сommon может быть вынесен в самостоятельный проект используемый различными приложениями. Собственно, это и есть его продвижение по иерархии. Если мы выделим common на уровне accessmanagment, он будет использоваться задачами регистрация и аутентификация. Далее он может полностью или частично двигаться вверх в common для всего приложения и еще выше для нескольких приложений. Ну и наконец превратиться в публичный API.
Резюме
Основную идею которую я хотел передать - создание пакетов на основе домена предметной области. Такая техника оправдывает себя в моей практике. Хорошо работает в больших проектах. Для маленьких проектов я бы рекомендовал не создавать пакетов совсем. Зачем два события отделять в отдельный пакет? Как только приложение начнет расти, появятся пакеты предметной области это позволит всегда работать с маленьким приложением.
Ссылки
Всем заинтересовавшимся вопросом рекомендую к ознакомлению видео презентацию Juergen Hoeller, одного из основателей Spring Framework http://www.infoq.com/presentations/code-organization-large-projects и (или) её текстовые пересказы http://mikenereson.blogspot.com/2007/06/spring-on-code-organization-for-large.html,
http://www.kimchy.org/spring-one-code-organization/
Немного странный источник, но идеи примерно те же http://docstore.mik.ua/orelly/oracle/advprog/ch02_01.htm
Flex mojos 3.1 released
Релиз
Вышла новая версия Flex Mojos, теперь разработка flexmojos проходит под крышой
sonatype.org, и у алмаза появилась огранка)).
В извесную книгу о maven от sonatype добавленна глава про работу с flexmojos
Что изменилось?
Из полезных дополнений хочу обратить внимание на archetypes:
- flexmojos-archetypes-library проект swc библиотеки
- flexmojos-archetypes-application простой swf проект
- flexmojos-archetypes-modular-webapp многомодульный проект, состоит из swc, swf и war
archetypes - это maven комманда, которая создает проект с нуля. Для её запуска необходим установленный maven.
Выполните следующую комманду в командной строке (имя вашего пакета, верисю и артифакт id придется ввести в режиме диалога):
XML:
mvn archetype:generate \ | |
-DarchetypeRepository=http://repository.sonatype.org/content/groups/public \ | |
-DarchetypeGroupId=org.sonatype.flexmojos \ | |
-DarchetypeArtifactId=flexmojos-archetypes-library \ | |
-DarchetypeVersion=3.1.0 |
Комментарий
что бы проект собирался необходимо определить sonatype репозиторий в ~\.m2\settings.xml
XML:
<repositories> | |
<!−− ... −−> | |
| |
<repository> | |
<id>flex-mojos-repository</id> | |
<url>http://repository.sonatype.org/content/groups/public</url> | |
<releases> | |
<enabled>true</enabled> | |
</releases> | |
<snapshots> | |
<enabled>true</enabled> | |
</snapshots> | |
</repository> | |
| |
<pluginRepositories> | |
| |
<!−− ... −−> | |
| |
<pluginRepository> | |
<id>flex-mojos-repository</id> | |
<url>http://repository.sonatype.org/content/groups/public</url> | |
<releases> | |
<enabled>true</enabled> | |
</releases> | |
<snapshots> | |
<enabled>true</enabled> | |
</snapshots> | |
</pluginRepository> | |
| |
<!−− ... −−> | |
| |
</pluginRepositories> |
после этого можно запускать mvn install.
Для пользователей mac, что бы запускались тесты, необходимо добавить путь к flash player в PATH.
Code:
export PATH="set your path here/Adobe Flex Builder 3 Plug-in/Player/mac/10/mac/Flash Player.app/Contents/MacOS":$PATH |
и добавить в pom.xml следующие сторики:
XML:
... | |
<configuration> | |
<flashPlayerCommand>Flash Player</flashPlayerCommand> | |
</configuration> | |
... |
И на десерт, команда:
Code:
mvn flexmojos:flexbuilder |
создает flexbuilder проект. Единственно есть небольшой баг.
Придется поправить в FlexBuilder откройте
Project->Properties->Flex Compiler и исправьте в additional compiler arguments:
-localeen_US на -locale en_US
Тем кто переходит с версии flexmojos 2.x
Изменился репозиторий на http://repository.sonatype.org/content/groups/public
Изменился пакет и наименование flexmojos:
XML:
<groupId>info.flex-mojos</groupId> | |
<artifactId>flex-compiler-mojo</artifactId> |
теперь будет:
XML:
<groupId>org.sonatype.flexmojos</groupId> | |
<artifactId>flexmojos-maven-plugin</artifactId> |
вместо специализированных плагинов типа:
XML:
<groupId>info.flex-mojos</groupId> | |
<artifactId>html-wrapper-mojo</artifactId> |
теперь используются соответствующие goals, соответственно
mvn flexmojos:wrapper
Пакеты зависимостей для тестирования тоже поменялись:
XML:
<dependency> | |
<groupId>info.flex-mojos</groupId> | |
<artifactId>testing-support</artifactId> | |
<version>${flex-mojos.version}</version> | |
<type>swc</type> | |
<scope>test</scope> | |
</dependency> |
теперь:
XML:
<dependency> | |
<groupId>org.sonatype.flexmojos</groupId> | |
<artifactId>flexmojos-unittest-support</artifactId> | |
<version>${flex-mojos.version}</version> | |
<type>swc</type> | |
<scope>test</scope> | |
</dependency> |
Резюме
В целом изменения меня очень радуют, всё стало проще и логичней, в добавок sonatype обещают интеграцию с m2e в версии 0.9.8.
Первоисточники
flexmojos - blog
советы по переходу с flexmojos 2.x
страница проекта flexmojos
глава из книги о maven, по работе с flexmojos
p/s
Версия новая и интересная буду очень рад если поделитесь опытом и замечаниями по работе с ней.
Flex-Mojos. Пример сборки flex modules.
Предисловие
Flex модули на мой взгляд очень интересная и многообразная тема. Кроме разделения функциональности приложения, их можно использовать для загрузки внешних стилей и ресурсов. Если есть задача динамического изменения внешнего вида и языка или уменьшение размера основного приложения.
Введение
В данной статье я расскажу как собирать приложение которое использует flex modules.
Проект так же будет использовать библиотеки и уменьшать размер flex модулей. Для этого мы не будем включать в модуль код, который уже используется в основном приложении. Итак приступим.
Структура проекта
Данная структура соответствует принципу один maven модуль один артефакт. Следовательно flex модуль представлен ввиде отдельного maven модуля.
flexModulesProject/
flexModulesProject/pom.xml - основной pom, собирающий весь проект
//загрузчик модульного приложения.
flexModulesProject/flexClient/… - основное flex приложение
…
flexModulesProject/flexModuleRed/… - flex модуль
…
flexModulesProject/flex/pom.xml - корневой pom для flex приложение.
flexModulesProject/flexCoreLib/… - flex библиотека которая используется в проекте.
Разбор конфигурационных файлов проекта
на родительский pom проекта, pom библиотеки и корневой pom для flex проектов использование модуля ни как не повлияло. Более подробное описание их структуры можно посмотреть здесь.
pom для flexClient
XML:
<?xml version="1.0"?> | |
<project> | |
<parent> | |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>my-flex-super-pom</artifactId> | |
<version>1.0</version> | |
</parent> | |
| |
<modelVersion>4.0.0</modelVersion> | |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>flex-client</artifactId> | |
<packaging>swf</packaging> | |
<name>flex client</name> | |
<version>1.0</version> | |
| |
<build> | |
<plugins> | |
<plugin> | |
<groupId>info.rvin.mojo</groupId> | |
<artifactId>flex-compiler-mojo</artifactId> | |
<configuration> | |
<debug>true</debug> | |
<sourceFile>flexClient.mxml</sourceFile> | |
<linkReport>true</linkReport> | |
</configuration> | |
</plugin> | |
</plugins> | |
</build> | |
| |
| |
<dependencies> | |
<dependency> | |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>flex-core-library</artifactId> | |
<version>1.0</version> | |
<type>swc</type> | |
<scope>internal</scope> | |
</dependency> | |
</dependencies> | |
</project> |
Здесь существенна одна дирректива:
XML:
<linkReport>true</linkReport> |
данная строчка создает в maven репозитории xml файл с перечнем всех классов, которые включаются в данный swf. Этот перечень будет использоваться при копмиляции flex модуля.
pom для flexModuleRed
XML:
<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> | |
<parent> | |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>my-flex-super-pom</artifactId> | |
<version>1.0</version> | |
</parent> | |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>flexModuleRed</artifactId> | |
<packaging>swf</packaging> | |
<name>flex module red</name> | |
<version>1.0</version> | |
<build> | |
<plugins> | |
<plugin> | |
<groupId>info.rvin.mojo</groupId> | |
<artifactId>flex-compiler-mojo</artifactId> | |
<configuration> | |
<debug>true</debug> | |
<sourceFile>FlexModuleRed.mxml</sourceFile> | |
<loadExterns> | |
<MavenArtifact> | |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>flex-client</artifactId> | |
<version>1.0</version> | |
</MavenArtifact> | |
</loadExterns> | |
| |
| |
| |
</configuration> | |
</plugin> | |
</plugins> | |
</build> | |
<dependencies> | |
<dependency> | |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>flex-core-library</artifactId> | |
<version>1.0</version> | |
<type>swc</type> | |
<scope>external</scope> | |
</dependency> | |
</dependencies> | |
</project> |
следующий код:
Code:
<loadExterns> | |
<MavenArtifact> | |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>flex-client</artifactId> | |
<version>1.0</version> | |
</MavenArtifact> | |
</loadExterns> |
исключает классы которые включены в flex-client.
здесь:
Code:
<dependency> | |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>flex-core-library</artifactId> | |
<version>1.0</version> | |
<type>swc</type> | |
<scope>external</scope> | |
</dependency> |
важно включение библиотеки со scope external.
Еще одно замечание, имя flex модуля не должно использовать дефис, в моём проекте это вызвало необъяснимый глюк.
Сборока проекта.
Для сборки проекта необходимо в корневой библиотеке проекта запустить команду mvn install
Развертывание проекта.
Строго говоря, в обязанности maven эта задача не входит. После того как проект будет собран, нужно поместить flexModuleRed.swf в одну папку с flexClient.swf.
Исходники
Исходники можно взять отсюда
Flex-Mojos. Пример сборки модульного проекта.
Глоссарий
flex module - swf, которая может быть загружена или выгружена flex приложением. Она не может быть запущена независимо. Несколько приложений могут использовать один и тотже модуль.(как собирать flex модули я опишу в следующей статье)
maven module - логическая часть вашего проекта, например клиентские программы, библиотеки, серверные модули, модули конфигурации и т.п.
Введение
Рассмотрим сборку проекта состоящего их нескольких maven модулей. Для построения такого проекта нам потребуется, создать иерархическую структуру директорий, для каждого модуля своя директория, в каждой директории будет находиться исходный код модуля и роm.xml, который его собирает. В корневой директории будет находится родительский pom для всего проекта.
Структура проекта
Проект состоит из двух модулей:
корень проекта:
multyModulesProject/pom.xml - родительский роm.xml
flex библиотека:
multyModulesProject/flexCoreLibrary/pom.xml;
multyModulesProject/flexCoreLibrary/…;
flex приложение:
multyModulesProject/flexClient/pom.xml;
multyModulesProject/flexClient/…;
Наследование от flex-super-pom
Это достаточно тонкий момент. Возможны следующий решения:
- Унаследовать родительский pom от flex-super-pom. При данном решении возникает вопрос, что делать с модулями которые не имеют отношения к flex.
- Прописать все необходимые свойства непосредственно в дочерние модули. Приводит к излишнему дублированию кода.
- Создать ещё один уровень иерархии. С модулями flex и java например. В модуле flex будет находиться my-flex-super-pom. Наследуется от родительского pom всего проекта и включает все необходимые параметры из flex-super-pom. Все maven модули собирающие flex, наследуются от my-flex-super-pom и помещаются в директорию flex. Недостаток данного метода в появлении ещё одного уровня иерархии.
- И последний вариант, который я использую: Появляется модуль flex и my-flex-super-pom, как в предыдущем решении, но не создается иерархия. Все модули помещаются в корневую директорию. Модули собирающие flex артифакты наследуются от my-flex-super-pom. Сложность здесь в некоторой путанице с наследованием. Она не всегда совпадает с директориями, в которых находятся модули.
В итоге к нашему проекту добавился ешё один модуль flex.
multyModulesProject/flex/pom.xml; - по умолчанию полностью повторяет структуру flex-super-pom, но наследуется от родительского pom.
Родительский pom проекта
Родительский pom.xml нашего проекта может выглядеть следующим образом:
XML:
<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"> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>myProjectArtifactId</artifactId> | |
<name>myProjectName</name> | |
<packaging>pom</packaging> | |
<version>1.0</version> | |
<url>http://maven.apache.org</url> | |
<modules> | |
<module>flex</module> | |
<module>flexCoreLibrary</module> | |
<module>flexClient</module> | |
</modules> | |
<repositories> | |
<repository> | |
<id>flex-mojos-repository</id> | |
<url>http://svn.sonatype.org/flexmojos/repository/</url> | |
<releases> | |
<enabled>true</enabled> | |
</releases> | |
</repository> | |
</repositories> | |
| |
<pluginRepositories> | |
| |
<pluginRepository> | |
<id>flex-mojos-repository</id> | |
<url>http://svn.sonatype.org/flexmojos/repository/</url> | |
<releases> | |
<enabled>true</enabled> | |
</releases> | |
<snapshots> | |
<enabled>false</enabled> | |
</snapshots> | |
</pluginRepository> | |
</pluginRepositories> | |
</project> |
На что стоит обратить внимание:
XML:
<packaging>pom</packaging> |
определяет тип собираемого артефакта, в данном случае pom.xml, оперирует другими pom.xml. Тип родительского модуля логический, обозначается “pom".
XML:
... | |
<modules> | |
<module>flex</module> | |
<module>flexCoreLibrary</module> | |
<module>flexClient</module> | |
| |
</modules> | |
... |
здесь перечислены модули проекта, наименования должны совпадать с наименованием директорий.
XML:
... | |
<repositories> | |
... |
тег repositories, выноситься в родительский pom.xml, так как maven поддерживает наследование, то данное свойство будет доступно в дочерних модулях.
Замечу что если у вас несколько проектов, то лучше его вынести в файл конфигурации maven.
под winXP, он находиться в: “C:\Documents and Settings\username\.m2\settings.xml", в других OS в той-же по смыслу директории.
my-flex-super-pom
Находиться в дирректории: multyModulesProject/flex
Отличается от flex-super-pom, добавлением кода определяющего родителя:
XML:
... | |
<parent> | |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>myProjectArtifactId</artifactId> | |
<version>1.0</version> | |
</parent> | |
... |
и другим именем:
XML:
... | |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>my-flex-super-pom</artifactId> | |
<version>1.0</version> | |
<name>parent pom for building modules with flex</name> | |
<packaging>pom</packaging> | |
... |
flex-core-library
Находится в директории: multyModulesProject/flexCoreLibrary:
XML:
<?xml version="1.0"?> | |
<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 href="http://maven.apache.org/maven-v4_0_0.xsd">">http://maven.apache.org/maven-v4_0_0.xsd"> | |
<parent> | |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>my-flex-super-pom</artifactId> | |
<version>1.0</version> | |
</parent> | |
| |
<modelVersion>4.0.0</modelVersion> | |
| |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>flex-core-library</artifactId> | |
<packaging>swc</packaging> | |
<name>flex-core-library</name> | |
<version>1.0</version> | |
| |
</project> |
Тег parent
устанавливает родительский pom. Теперь всё что определено в my-flex-super-pom будет доступно в данном проекте.
flex-client
Находится в директории: multyModulesProject/flexClient
XML:
<?xml version="1.0"?> | |
<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 href="http://maven.apache.org/maven-v4_0_0.xsd">">http://maven.apache.org/maven-v4_0_0.xsd"> | |
<parent> | |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>my-flex-super-pom</artifactId> | |
<version>1.0</version> | |
</parent> | |
| |
<modelVersion>4.0.0</modelVersion> | |
| |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>flex-client</artifactId> | |
<packaging>swf</packaging> | |
<name>flex client</name> | |
<version>1.0</version> | |
| |
<dependencies> | |
<dependency> | |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>flex-core-library</artifactId> | |
<version>1.0</version> | |
<type>swc</type> | |
<scope>internal</scope> | |
</dependency> | |
</dependencies> | |
</project> |
Тег parent
устанавливает родительский pom. Теперь всё что определено в my-flex-super-pom будет доступно в данном проекте.
Тег dependency
определяет зависимость flex-client от flex-core-library
Исходники
Flex-Mojos, Управление зависимостями.
Введение
В данной статье будет рассмотрена тема управление зависимостями при сборки flex приложения с помощью maven.
содержание предыдущих серий:
Пара общих слов о maven
Сборка простого flex приложения с помощью Flex Mojos;
Генерация html wrapper c помощью flex-mojos;
Что такое maven зависимости?
Допустим мы хотим используем в своём проекте, внешнюю swc. В Flex Builder необходимо её подключить. В maven это решается с помощью указания зависимости от maven артефакта. Этот артефакт представляет собой ссылку на swc в репозитории maven.
Пример:
Code:
<project> | |
... | |
<dependencies> | |
<dependency> | |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>mylibrary</artifactId> | |
<version>1.0</version> | |
<type>swc</type> | |
<scope>external</scope> | |
</dependency> | |
... | |
<dependencies> | |
... | |
</project> |
Теги: groupId, artifactId, version, type - определяют путь к артефакту в maven repository,
Тег scope - определяет, как будет использоваться артефакт и может принимать следующие значения:
external - код swc, используется только для компиляции.
internal - код swc, полностью включается в итоговый проект.
merged - включается только та часть кода swc , которая используется в вашем проекте. Данное значение используется по умолчанию.
rsl - будет загружать swf, как rsl
caching - тоже что и rsl, но только для adobe библиотек swz, которые могут кэшироваться fp.
test - для компиляции тестов.
Я выделил жирным значения scope и тип артефакта с которым используется scope.
Как поместить артефакт в репозиторий?
Собственные библиотеки
Если вы собираете библиотеку с помощью maven, то она попадает в репозиторий после выполнения команды >mvn install.
После этого её можно использовать в любом вашем проекте указав зависимость.
Внешние библиотеки
В данный момент maven не слишком распространён в среде flex разработки. Поэтому общие библиотеки которые могут вам понадобиться(as3corelib, caingorm и т.д.) обычное не лежат в публичных репозиториях. Следовательно вам необходимо выложить их в свой локальный репозиторий. Для этого существует специальная команда maven:
Code:
mvn install:install-file -Dfile= -DgroupId= \ -DartifactId= -Dversion= -Dpackaging= |
Дополнения
Информациию о scopes и dependency можно также посмотреть на blog.flex-mojos;
Генерация html wrapper c помощью flex-mojos
Введение
Получить общее представление и посмотреть простой пример, c помощью flex mojos, можно здесь.
Также возможно ознакомиться с первоисточником Html Wrapper Mojo от Marvin Froeder’s, создателя flex mojos.
Знакомство с html-wrapper-mojo
Для того что бы сгенерить html wrapper для swf, достаточно в pom.xml
добавить mojo html-wrapper-mojo.
XML:
... | |
<plugins> | |
<plugin> | |
<groupId>info.flex-mojos</groupId> | |
<artifactId>html-wrapper-mojo</artifactId> | |
<executions> | |
<execution> | |
<goals> | |
<goal>wrapper</goal> | |
</goals> | |
</execution> | |
</executions> | |
<configuration> | |
<templateURI>embed:client-side-detection</templateURI> | |
<parameters> | |
<swf>${build.finalName}</swf> | |
<width>200</width> | |
<height>200</height> | |
</parameters> | |
</configuration> | |
</plugin> | |
</plugins> | |
... |
Конфигурация html-wrapper-mojo
тег templateURI
определяет один из варинтов шаблона от Adobe:
embed:client-side-detection
embed:client-side-detection-with-history (default)
embed:express-installation
embed:express-installation-with-history
embed:no-player-detection
embed:no-player-detection-with-history
или
URI на ваш собственный шаблон, например:"file:///etc/hosts". При этом файл с вашим шаблоном должен содержать index.template.html и быть в формате zip.
тег parameters
позволяет установить значения всем стандартным свойствам шаблона
title
version_major - требуемая версия fp, по умолчанию 9;
version_minor - требуемая минимальная версия fp, по умолчанию 0;
version_revision - требуемая ревизия, напрмер 115, по умолчанию 0;
swf - имя swf файла;
width
height
bgcolor
application - имя swf объекта внутри html.
Если вы используете свой собственный шаблон, то можете определить дополнительные параметры.
Дополнения
Для создания собственного шаблона можно использовать swfobject
Сборка простого flex приложения с помощью Flex Mojos
Начальные условия
установленная java jdk 5 или выше.
переменная окружения JAVA_HOME
установленный maven.
Стандартная для maven структура проекта
project-name/pom.xml………………. конфигурационный файл сборки проекта.
project-name/src
project-name/src/main/
project-name/src/main/flex…………. код flex приложения
project-name/src/test
project-name/src/test/flex…………. тесты flex приложения
project-name/src/main/flex/Main.mxml
Структура pom.xml
pom собирающий flex приложение:
XML:
<?xml version="1.0"?> | |
<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" > | |
| |
| |
<parent> | |
<groupId>info.rvin.mojo</groupId> | |
<artifactId>flex-super-pom</artifactId> | |
<version>1.0</version> | |
</parent> | |
| |
<modelVersion>4.0.0</modelVersion> | |
| |
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>myArtifactId</artifactId> | |
<packaging>swf</packaging> | |
<name>myArtifactName</name> | |
<version>1.0</version> | |
| |
| |
<repositories> | |
<repository> | |
<id>flex-mojos-repository</id> | |
<url>http://svn.sonatype.org/flexmojos/repository/</url> | |
<releases> | |
<enabled>true</enabled> | |
</releases> | |
</repository> | |
</repositories> | |
| |
<pluginRepositories> | |
<pluginRepository> | |
<id>flex-mojos-repository</id> | |
<url>http://svn.sonatype.org/flexmojos/repository/</url> | |
<releases> | |
<enabled>true</enabled> | |
</releases> | |
<snapshots> | |
<enabled>false</enabled> | |
</snapshots> | |
</pluginRepository> | |
</pluginRepositories> | |
| |
</project> |
Запуск сборки проекта с помощью maven
Для сборки приложения необходимо набрать в командной строке,
project-name> mvn install
Рассмортим pom.xml по частям
XML:
<parent> | |
<groupId>info.rvin.mojo</groupId> | |
<artifactId>flex-super-pom</artifactId> | |
<version>1.0</version> | |
</parent> |
тег parent определяет родительский pom, для текущего pom.
В maven, текущий проект наследует свойства родительского.
В качестве родительского pom, для flex проекта здесь выступает flex-super-pom, который является частью flex-mojos. В нём определены многие полезные параметры, которые можно использовать по умолчанию. В своём проекте вы можете использовать собственный parent, взяв из flex-super-pom только необходимое.
Следующие теги определяют ваш артефакт в репозитории maven. В дальнейшем вы сможете использовать данный артифакт в других проектах.
XML:
<groupId>com.mydomain.mypackage</groupId> | |
<artifactId>myArtifactId</artifactId> | |
<packaging>swf</packaging> | |
<name>myArtifactName</name> | |
<version>1.0</version> |
Стоит отметить
XML:
<packaging>swf</packaging> |
- определяет тип артифакта, для библиотеки это swc.
XML:
<repositories> | |
<repository> | |
<id>flex-mojos-repository</id> | |
<url>http://svn.sonatype.org/flexmojos/repository/</url> | |
<releases> | |
<enabled>true</enabled> | |
</releases> | |
</repository> | |
</repositories> |
тег repositories определяет перечень репозиториев, в которых можно осуществлять поиск артифактов.
XML:
<pluginRepositories> | |
<pluginRepository> | |
<id>flex-mojos-repository</id> | |
<url>http://svn.sonatype.org/flexmojos/repository/</url> | |
<releases> | |
<enabled>true</enabled> | |
</releases> | |
<snapshots> | |
<enabled>false</enabled> | |
</snapshots> | |
</pluginRepository> | |
</pluginRepositories> |
тег pluginRepositories определяет перечень репозиториев, в которых можно осуществлять поиск maven плагинов.
Полезные дополнения
Удаление артефактов осуществляется командой project-name>mvn clean
Генерация asdoc, осуществляется командой project-name>mvn asdoc:asdoc
Команды можно комбинировать, например project-name>mvn clean install
Что ещё может Flex mojos?
Компелить SWF, SWC, ASWF, ASWC.
Запускать тесты.
Поддерживать RSL.
Оптимизировать, шифровать swf.
Создавать html wrapper,
В итоге собирать сложные проекты, включающие библиотеки, стили, локализацию, flex модули.
Плюсы использования maven для flex сборки
По моему опыту плюсом является стандартизация структуры проекта. Для того что бы понять что откуда берёться, достаточно посмотреть pom.xml.
Flex Mojos - A Maven Flex Plugin
Недавно вышел новый Flex Mojos - A Maven Flex Plugin. Если вы собираетесь внедрять maven, рекомендую к нему присмотреться.
Сборка приложения использующего BlazeDS, Spring, Hibernate. очень хорошо описана в наборе статей (Flex, Spring and BlazeDS: the full stack! part 1, part2 , part3, part4)
Flex + Maven часть1
Для сборки flex c помощью maven необходимо произвести следующие действия:
- установить MAVEN
- установить flex sdk
- создать файл проекта pom.xml
- настроить среду
- создать структуру проекта и Main.mxml
- запустить maven
Создание файла проекта pom.xml
плагин для сборки swf/swc http://www.israfil.net
пример pom.xml для flex
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"> | |
| |
<name>test-flex-swf</name> | |
<groupid>test</groupid> | |
<artifactid>test-flex-swf</artifactid> | |
<version>1.0</version> | |
<modelversion>4.0.0</modelversion> | |
<description>test build flex with maven. | |
see: </description>">http://riapriority.com/blogs/agahov.php</description> | |
| |
<packaging>swf</packaging> | |
| |
<properties> | |
<flex .home>C:/FLEX_HOME/sdk/2.0.1</flex> | |
</properties> | |
<build> | |
<plugins> | |
<plugin> | |
<groupid>net.israfil.mojo</groupid> | |
<artifactid>maven-flex2-plugin</artifactid> | |
<extensions>true</extensions> | |
<configuration> | |
<flexhome>${flex.home}</flexhome> | |
<mainmxmlfile>Main.mxml</mainmxmlfile> | |
</configuration> | |
</plugin> | |
</plugins> | |
</build> | |
</project> |
Настройка среды
- flex.home в pom.xml должна ссылаться на flex sdk, которую вы хоти использовать для сборки
не забудте в файле $flex.home/frameworks/flex-config.xml отредактировать следующую строку:
winFonts.ser - для windows
macFonts.ser - для MAC
XML:
<flex -config> | |
<compiler> | |
<fonts> | |
<local -fonts-snapshot>---Fonts.ser</local> | |
</fonts> | |
</compiler> | |
</flex> |
Cтруктура проекта
project-name/pom.xml
project-name/src
project-name/src/main/
project-name/src/main/flex
project-name/src/test
project-name/src/main/flex/Main.mxml
Main.mxml может быть таким:
XML:
<?xml version="1.0" encoding="utf-8"?> | |
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> | |
<mx:Script> | |
<![CDATA[ | |
import mx.controls.Alert; | |
| |
private function start():void | |
{ | |
Alert.show("hi maven!"); | |
} | |
]]> | |
</mx:Script> | |
| |
<mx:Button click="start()"/> | |
</mx:Application> |
Сборка проекта с помощю maven
для сборки проекта зайдите в папку [project-name] и выполните команду: mvn pakage
Maven
Цели Maven
- Сделать процесс сборки лёгким
- Обеспечить унифицированную систему сборки
- Предоставить качественную информацию о проекте
- Дать руководство о лучших практиках разработки
- Обеспечить прозрачный переход к новым возможностям.