В первой части статьи мы рассмотрели комбинацию Caché + Java. Здесь будет показана структура проекта непосредственно реализующего комбинацию Caché + Java + Flex, а также основные инструменты и их настройки, используемые для её реализации. Стоит отметить, что здесь будет приведен лишь общий вид взаимодействия, в то время как, конкретные примеры будут рассмотрены в заключительной части. Начнем с описания модулей, входящих в состав проекта, и постепенно перейдем к особенностям их взаимодействия.
Структура проекта
Проект состоит из трёх основных модулей:
- flex – здесь располагаются mxml-классы, описывающие структуру web-интерфейса, дополнительные библиотеки на ActionScript, а также сгенерированные ActionScript-проекции java-классов;
- biz-logic – включает java -c и -m классы (подробнее о данных классах было рассказано в первой части статьи), класс контроллер, а так же классы-интерфейсы, отвечающие за логику приложения;
- web-application – генерируемый модуль, хранящий сформированные jar-файлы из модуля biz-logic и swf из модуля flex. Кроме этого, данный модуль отвечает за генерацию WAR (Web application ARchive), который позже размещается на web-сервере.
Далее стоит сказать несколько слов о применяемых инструментах. В качестве web-сервера был использован Apache Tomcat версии 6.0.35. Как было отмечено в первой части, в качестве основного инструмента для связи Java и ActionScript используется фреймворк Granite DS, представляющий комплексное решение для разработки и интеграции flex + javaEE RIA приложений. Его необходимо подключать как в настройках для flex, так и biz-logic модулей (как это сделать, будет рассказано дальше). Для автоматизации сборки проекта выбран Maven – универсальный инструмент для сборки Java проектов (компиляции, создания jar, создания дистрибутива программы, генерации документации). Maven, по умолчанию, создает по отдельному POM (Project Object Model) файлу для каждого из модулей, а также один общий для всего проекта. POM файлы используются для настройки конфигурации, а также для подключения библиотек из репозиториев (подробнее о работе с Maven можно прочитать здесь, а также работа с Maven подробно рассматривалась на Хабре). Приведем примеры некоторых настроек, использованных нами.
Содержание POM-файлов
Рассмотрим подробнее особенности POM-файлов для каждого из модулей проекта. В POM-файл модуля flex прописываются настройки Granite DS и пути к java-классам, проекции которых необходимо создать. Кроме этого здесь же привязываются используемые библиотеки. К примеру, данный код служит для указания файлов для проецирования, а так же содержит ряд настроек для GraniteDS.
<execution> <goals> <goal>generate</goal> <!—цель генерация--> </goals> <configuration> <generatorToUse>graniteds21</generatorToUse> <!—используемый генератор--> <baseOutputDirectory>${project.build.directory}/generated- sources</baseOutputDirectory> <!—выходная директория для проекций--> <outputDirectory>${project.build.directory}/../src/main/flex </outputDirectory> <!—выходная директория для классов наследующих от проекций--> <extraOptions> <tide>true</tide> <uid>uid</uid> <entityFactory>org.granite.generator.as3.BVEntityFactory </entityFactory> <outputEnumToBaseOutputDirectory>false </outputEnumToBaseOutputDirectory> </extraOptions> <includeJavaClasses> <include>edu.samples.sample.domain.**</include> <!—путь к классам, проекции которых необходимо сгенерировать--> <include>edu.samples.sample.services.I*Service</include> <!—путь к интерфейсам, проекции которых необходимо сгенерировать --> </includeJavaClasses> </configuration> </execution>
Следующий код так же располагается в POM-файле модуля flex и демонстрирует подключение библиотек Granite из репозитория:
<dependency> <!—основные координаты библиотеки--> <groupId>org.graniteds</groupId> <artifactId>granite-core</artifactId> <!—версия файла библиотеки--> <version>${graniteds.version}</version> </dependency>
В POM-файле для модуля biz-logic указываются параметры для генерации jar-файлов.
Кроме этого, необходимо подключить библиотеки cachedb и cachejdbc для работы с Caché (данные библиотеки в виде jar-файлов предоставляются вместе с продуктами Ensemble и Caché. По умолчанию располагаются в “dev\java\lib\JDK16\”).
В нашем случае файлы библиотек указаны локально:
<dependency> <!—зависимости (библиотеки) используемые для сборки--> <groupId>cache.cachedb</groupId><!—основные координаты библиотеки--> <artifactId>cachedb</artifactId> <type>jar</type> <!—тип файла библиотеке--> <version>${cachedb.version}</version> <!—версия файла библиотеки--> <scope>system</scope> <!—назначение библиотеки--> <systemPath>C:/soft/javalibs/cachedb.jar</systemPath> <!—путь к файлу-библиотеке--> </dependency> <dependency> <groupId>cache.cachejdbc</groupId> <artifactId>cachejdbc</artifactId> <version>${cachejdbc.version}</version> <type>jar</type> <scope>system</scope> <systemPath>C:/soft/javalibs/cachejdbc.jar</systemPath> </dependency>
В POM-файле для модуля web-application прописываются привязка сгенерированных ранее в модуле biz-logic jar-файлов и опции для генерации WAR-файла такие как: output-директория для сгенерированного файла, подключение библиотек war-компилятора (maven-compiler-plugin, maven-war-plugin, maven-dependency-plugin). Так же должны быть прописаны опции для генерации swf-файла.
Настройка модуля web-application
<plugin> <!—основные координаты плагина в репозитории--> <groupId>org.sonatype.flexmojos</groupId> <artifactId>flexmojos-maven-plugin</artifactId> <version>${flexmojos.version}</version> <configuration> <stripVersion>true</stripVersion> </configuration> <executions> <execution> <goals> <goal>copy-flex-resources</goal> <!—цель копирование флекс ресурсов--> </goals> <configuration> <artifactItems> <artifactItem> <!—основные координаты файлов для копирования в swf--> <groupId>edu.sample</groupId> <artifactId>flex</artifactId> <type>swf</type> <!—тип генерируемого файла swf--> <overWrite>true</overWrite> <!—перезаписать существующий--> <destFileName>sample.swf</destFileName><!— имя сгенерированного файла--> </artifactItem> </artifactItems> </configuration> </execution> </executions> </plugin>
Порядок сборки проекта следующий: компилируются java-классы из модуля biz-logic, затем на их основе с помощью GraniteDS генерируются ActionScript-проекции, которые помещаются в модуль flex. После этого компилируется модуль flex и с помощью плагина org.sonatype.flexmojos (предоставляется Flex) генерируется .swf файл. Он вместе с используемыми библиотеками помещается на сервер по прописанному в конфигурационном файле пути. На основе сгенерированных .swf и .jar файлов, а также используемых библиотек формируется .war файл.
Настройка .war файла
<properties> <!—опции для генерации--> <war.name>sample</war.name><!—имя сгенерированного war-файла--> <catalina.home>C:\Program Files\Apache Software Foundation\Tomcat 6.0</catalina.home> <!--путь к серверу, на котором будет размещен war--> <skipTests>true</skipTests> </properties> <build> <finalName>sample</finalName> <testSourceDirectory>src/test/java</testSourceDirectory> <plugins> <!--подключение плагина для компиляции--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <sourсe>1.6</sourсe> <target>1.6</target> </configuration> </plugin> <!—подключения плагина для генерации war--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <configuration> <warName>${war.name}</warName> </configuration> </plugin> <!—подключение плагина определяющего зависимости--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.1</version> <executions> <execution> <id>copy</id> <phase>install</phase> <goals> <goal>copy</goal> </goals> <configuration> <artifactItems> <artifactItem> <groupId>edu.sample</groupId> <artifactId>web-application</artifactId> <version>1.0</version> <type>war</type> <overWrite>true</overWrite> <destFileName>${war.name}.war</destFileName> <outputDirectory>${catalina.home}\webapps\ </outputDirectory> </artifactItem> </artifactItems> </configuration> </execution> </executions> </plugin> </plugins> </build>
После того, как все настройки выполнены, можно приступать к непосредственному рассмотрению механизма взаимодействия Flex + Java + Caché.
Общий вид механизма взаимодействия Flex + Java + Caché
Начнём с того, что всё взаимодействие Flex + Java проходит через ActionScript-проекции, среди которых, кроме проекций хранимых классов (Java-m классы), есть и классы-проекции интерфейсов сервера, отвечающие за логику приложения. В момент запуска web-приложения в браузере (на стороне клиента) при инициализации создается объект, реализующий интерфейс сервисов сервера (в нашем случае это объект userService). Через него и будет в дальнейшем происходить связка flex + java. Для выполнения какой-либо операции над хранимыми объектами вызывается соответствующий метод в userService. В случае удачного прохождения определенных условий на сервере изменения также будут выполнены в БД Caché.
Кроме того, для реализации описанной связки через Granite DS необходимо, чтобы выполнялись следующие условия.
- Класс должен реализовывать интерфейс Serializable.
- В проецируемых классах должен использоваться специальный синтаксис Granite DS. Например, для методов get() и set() проецируемых свойств нужно использовать теги @ExternalizedProperty, а для самого проецируемого класса – @ExternalizedBean, как показано в примере ниже.
@ExternalizedBean(type=DefaultExternalizer.class) public class mCicl implements Serializable { … @ExternalizedProperty public List<mDiscipline> getListOfDisc() { return listOfDisc; } public void setListOfDisc(List<mDiscipline> listOfDisc) { this.listOfDisc = listOfDisc; } … }
Не стоит также забывать о java-нотации. Так, к примеру, при именовании свойства с заглавной буквы в проекции, данное свойство будет иметь модификатор доступа private без get и set методов.
Как уже говорилось выше, в модуле flex используется интерфейс (@RemoteDestination) сервисов (@Serviсe) сервера, поэтому в модуле biz-logic должна быть соответствующая реализация данного интерфейса. Например, для проецируемого класса-интерфейса
@RemoteDestination public interface IUserService { … void delOneDisc(Integer i); … }
должна быть прописана реализация
@Service public class UserService implements IUserService { … @Override public void delOneDisc(Integer i) { objT.deleteOneDisc(i); } … }
Подводя итоги данной части, можно сказать, что здесь мы описали лишь общий механизм взаимодействия Caché + Java + Flex через интерфейсы и проекции, а также необходимые для них настройки, не заостряя внимания на конкретных примерах. Поэтому в следующей части статьи мы уделим больше внимания конкретным практическим примерам. В частности рассмотрим преобразования коллекций на протяжении всей связки, а также примеры передачи объектов от БД до браузера и обратно.
было б не плохо целиком исходник проекта увидеть, а то некоторые примеры с мавеном не понятны….