Мультимедиа-программирование вместе с Red 5 server. Часть 3

October 16, 2009

Я продолжаю рассказ о методиках создания веб-приложений совместно использующих возможности java, red5 и flash. Хотя конечной целью моих статей, в полном соответствии с вынесенным в заголовок названием, является организовать передачу мультимедиа информации с сервера flash-клиенту и обратно. Но следует понимать, что потоковое мультимедиа – это не самоцель, а всего лишь одна из составных частей хорошего приложения. В прошлой статье я начал построение универсального “каркаса” для веб-приложения выполняющегося в среде red5.

Создаваемый нами каркас пригодится и для разработки приложений, обменивающихся мультимедиа-информацией с сервером red, и для более “серьезных” бизнес-приложений. Сейчас перспективно создавать приложения, которые используют flash или flex как средство построения интерфейса пользователя, а всевозможные вычисления и расчеты выполняют на стороне сервера red5 и используют при этом все множество библиотек и framework-ов доступных для java-разработчиков. И действительно, не секрет, что подавляющее число разработок приложений, автоматизирующих работу больших предприятий и обслуживающих их бизнес-процессы, ведется, именно, на java. В прошлый раз я начал показывать то, как создать maven проект, состоящий из двух модулей: модуль пользовательского интерфейса в виде flash-приложения и модуль с бизнес-логикой. Сердце нашего maven-проекта это три pom.xml файла. Первый из них, содержащий перечисления сайтов с maven-репозиториями и ссылками на составляющие проект модули, я привел в прошлой статье. Теперь осталось разобраться с оставшимися двумя конфигурационными файлами и перейти к описанию, собственно, исходного кода примера. Итак, начнем с конфигурационного pom-файла модуля flashmodule:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3.   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  4.   <modelVersion>4.0.0</modelVersion>
  5.   <parent>
  6.     <groupId>test01</groupId>
  7.     <artifactId>red5demo</artifactId>
  8.     <version>1.0</version>
  9.   </parent>
  10.   <groupId>test01</groupId>
  11.   <artifactId>flashmodule</artifactId>
  12.   <version>1.0</version>
  13.   <packaging>swf</packaging>
  14.   <name>Rich Flash Client</name>
  15.   <build>
  16.    <sourceDirectory>src/main/flex</sourceDirectory>
  17.    <plugins>
  18.       <plugin>
  19.         <groupId>org.sonatype.flexmojos</groupId>
  20.         <artifactId>flexmojos-maven-plugin</artifactId>
  21.         <version>3.3.0</version>
  22.         <extensions>true</extensions>
  23.        <configuration> <debug>true</debug> </configuration>
  24.      </plugin>
  25.   </plugins>
  26.   </build>
  27.   <dependencies>
  28.    <dependency>
  29.      <groupId>com.adobe.flex.framework</groupId>
  30.     <artifactId>flex-framework</artifactId>
  31.    <version>3.2.0.3958</version>
  32.    <type>pom</type>
  33.    </dependency>
  34.   </dependencies>
  35. </project>
Содержимое pom-файла можно условно разделить на три части: общие сведения о модуле и указание на то, какую часть он занимает в общей структуре проекта. Затем идут настройки “жизненного цикла проекта”, и третья часть - это декларация нужных для работы модуля библиотек-зависимостей. Вначале я указываю то, что данный модуль существует не сам по себе, я является частью более сложного проекта. Для этого я указал внутри элемента “parent” координаты родительского проекта (test01:red5demo:1.0). Затем я задал координаты для самого модуля с помощью элементов groupId, artifactId, version. Обратите внимание на тип генерируемого в ходе сборки модуля артефакта (элемент packaging равен “swf”). Благодаря этому начинает работать “магия” maven. Во-первых, раз я в секции “build” добавил ссылку на плагин “flexmojos-maven-plugin”, то этот плагин будет вызваться при наступлении фазы “compile” и будет компилировать исходный код модуля в swf-ролик. Указание на то, в каком каталоге находятся actionscript и mxml-файлы, задается с помощью элемента “sourceDirectory”. Для того, чтобы flexmojos-maven-plugin мог выполнять свою работу, мне нужно подключить как зависимость для проекта ссылку на flex sdk (в состав этого sdk как раз и входит flash-компилятор). По правде говоря, раз я в конце прошлой статьи задекларировал, что буду использовать для набора кода такую среду разработки как intellij idea, то компиляцию проекта я мог бы выполнять и с ее помощью, но это не совсем правильно. Управление любым процессом требует единоначалия, и не важно в какой сфере эта работа выполняется. Так и в разработке программного обеспечения, мы должны создать единый скрипт (в виде maven, ant-сценария или чего-либо еще), который бы выполнял сборку абсолютно всего проекта: и веб-приложения с бизнес-логикой, а также интерфейса пользователя. Если такой согласованности не будет, то будет очень тяжело наладить работу отдела контроля качества (QA). Т.е. не важно из скольких частей состоит проект, но тестируется он всегда как единое целое. Возвращаясь к содержимому pom.xml файла, обратите внимание на опцию “debug” в настройке плагина flexmojos-maven-plugin. Это необходимо для того, чтобы созданный в ходе компиляции проекта, swf-файл содержал отладочную информацию. Если ее не будет, то мы не сможем из среды intellij idea подключиться к swf-файлу и выполнять пошаговую отладку его работы. Также, стоит напомнить о существовании двух разновидностей flashplayer-а: обычная версия и debug-версия. Если вы устанавливали у себя на компьютере adobe flex builder или flash ide, то наверняка, вместе с ними были установлены и отладочные версии flashplayer-а. Дело в том, что вы не можете выполнять пошаговую отладку flash-кода, если ваш flash-ролик будет исполняться на “обычной” версии flashplayer. В любом случае, на сайте adobe можно найти и загрузить debug-версии flashplayer для установки в internet explorer и для установки в firefox и иные браузеры. Теперь я приведу пример pom.xml файла для модуля с веб-интерфейсом.
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3.     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  4.   <modelVersion>4.0.0</modelVersion>
  5.   <parent>
  6.     <groupId>test01</groupId>
  7.     <artifactId>red5demo</artifactId>
  8.     <version>1.0</version>
  9.   </parent>
  10.   <name>Server Logic Module</name>
  11.   <groupId>test01</groupId>
  12.   <artifactId>warmodule</artifactId>
  13.   <version>1.0</version>
  14.   <packaging>war</packaging>
  15.   <build>
  16.    <finalName>warmodule</finalName>
  17.    <plugins>
  18.     <plugin>
  19.       <artifactId>maven-compiler-plugin</artifactId>
  20.       <configuration> 
  21.           < source >1.5< / source >  <!-- пробелы были добавлены специально для mediawiki -->
  22.           <target>1.5</target>  
  23.      </configuration>
  24.     </plugin>
  25.     <plugin>
  26.         <groupId>org.sonatype.flexmojos</groupId>
  27.         <artifactId>flexmojos-maven-plugin</artifactId>
  28.         <version>3.3.0</version>
  29.         <executions>
  30.             <execution>  
  31.               <goals> 
  32.                  <goal>copy-flex-resources</goal> 
  33.               </goals> 
  34.             </execution>
  35.        </executions>
  36.     </plugin>
  37.    </plugins>  
  38.   </build>
  39.  
  40.   <dependencies>
  41.     <dependency>
  42.       <groupId>javax.servlet</groupId>
  43.       <artifactId>servlet-api</artifactId>
  44.       <version>2.5</version>
  45.       <scope>provided</scope>
  46.    </dependency>
  47.    <dependency>
  48.      <groupId>test01</groupId>
  49.      <artifactId>flashmodule</artifactId>
  50.      <version>1.0</version>
  51.      <type>swf</type>
  52.     </dependency>
  53.    <dependency>
  54.      <groupId>eu.jakubiak</groupId>
  55.      <artifactId>jakubiak-red5-core</artifactId>
  56.      <version>0.8.0</version>
  57.      <scope>provided</scope>
  58.    </dependency>
  59.  </dependencies>
  60.  
  61. </project>
Начало pom-файла почти один в один совпадает с началом предыдущего pom-файла. Отличием будет только замена типа модуля с “swf” на “war”. Ведь сейчас я создаю модуль для последующего развертывания на веб-сервере, и по правилам содержимое модуля должно быть помещено внутрь архива war. Поскольку я хочу писать java-код для бизнес-логики с использованием всех современных возможностей java 1.5, то мне пришлось настроить плагин “maven-compiler-plugin”, который отвечает за компиляцию java-кода (элементы “source” и “target”). Также я внедрил в цикл сборки модуля вызов плагина flexmojos-maven-plugin. У этого плагина очень простая задача: скопировать внутрь формируемого war-архива swf-ролик, полученный в результате компиляции предыдущего модуля flashmodule. Осталось только прокомментировать список используемых модулем зависимостей. Во-первых, я сказал, что веб-модуль зависит от модуля flashmodule. С точки зрения здравого смысла это не совсем верно, поскольку интерфейсная часть (flash) обычно зависит от веб-части (бизнес-логика). Однако, здесь зависимость между модулями не прямая, а опосредованная; и фактически все, что мне нужно, так это скопировать внутрь war-архива swf-файл полученный как результат компиляции предыдущего модуля. Что касается второй зависимости, то все дело в том, что, создавая java-код, я активно использовал классы, являющиеся частью red5. Таким образом, для того, чтобы компиляция модуля завершилась удачно, мне нужно было подсказать компилятору путь к jar-файлам библиотек red5. Но нужны мне библиотеки red5 только на стадии компиляции проекта – я ни в коем случае не должен упаковывать библиотеки red5 внутрь war-архива. Созданное мною веб-приложение должно быть развернуто не на каком-либо произвольном java веб-сервере. А только на веб-сервере, идущем в составе дистрибутива red5, и априори содержащем внутри себя весь набор библиотек red5. После того как вы в прошлой статье скачали инсталлятор и установили у себя на компьютере red5 0.8, то вы получили в свое распоряжение полностью готовый к работе веб-сервер tomcat. И этот сервер уже настроен и адаптирован для хостинга, именно, java-приложений, использующих функционал red5. Возможно, вы захотите развернуть red5 приложение “с нуля” на каком-либо ином java сервере. Например, у вас в организации уже есть java-хостинг с jboss и вы решили добавить на него red5 приложение. То вот в этом случае, последовательность шагов создания веб-приложения сильно усложняется. Вам придется настраивать большое количество конфигурационных файлов, решать вопросы с безопасностью и внедрять библиотеки red5 внутрь war-файла с приложением. В большинстве своем это совершенно избыточная работа. Возможно, к концу этой серии статей я расскажу, как развернуть red5-приложение “с нуля”. Но пока я это делать не буду т.к. это и сложно и совершенно не нужно для урока знакомства. Как итог: я задекларировал зависимость веб-модуля от библиотеки jakubiak-red5-core. Но за счет того, что я пометил ее как “provided”, то она не будет скопирована в итоговый war-файл. Для небольшого удобства в работе я решил переименовать генерируемый war-файл с приложением и назвать его просто “warmodule” (элемент finalName). В оригинале имя конечного архива включало бы еще и номер версии приложения, т.е. warmodule-1.0, а это не совсем удобно.

Разобравшись с настройками maven-проекта, можно идти дальше и начать разбор конфигурационных файлов, составляющих веб-приложение. Напомню, что для java-приложений управляемых maven, существует правило, согласно которому должны быть организованы все составляющие веб-приложение файлы и каталоги. Так внутри каталога с веб-модулем warmodule, я создал два подкаталога src и target. Внутри каталога src будут находиться все файлы необходимые для создания веб-приложения, а внутрь каталога target будет скопирован созданный maven war-архив с веб-приложением. На рис. 1



я показал структуру каталога warmodule/src. Внутри каталога src я разместил три подкаталога java, resources (для нашего простого примера этот подкаталог будет пустым) и последним идет подкаталог webapp. К содержимому каталога java я вернусь чуть позже, а пока разберемся с содержимым каталога webapp. В корне модуля находится файл index.jsp и два подкаталога (js, WEB-INF). После того как maven-выполнит компиляцию всего проекта, в корень веб-архива помимо содержимого подкаталога webapp будет скопирован еще и файл flashmodule-1.0.swf. Поэтому давайте подумаем над тем как сделать так, чтобы автоматически при открытии нашего приложения в браузере посетитель увидел flash-файл. Согласно правилам java первый файл, который увидит посетитель нашего сайта, это index.jsp. Этот файл должен стать “заглушкой”, содержащей внутри себя ссылку на swf-файл с интерфейсом приложения. Поскольку я хочу сделать пример “красиво”, то решил не вставлять внутрь index.jsp файла код таких html-тегов как object и embed. А вместо этого я воспользуюсь известной javascript-библиотекой swfobject, предназначенной для внедрения в html-странички flash/flex приложения. Библиотечка эта представлена файлом swfobject.js, который я скачал с сайта http://blog.deconcept.com/swfobject/ и поместил внутрь подкаталога js. Для своего примера я использую “древнюю” версию swfobject равную 1.4.4, хотя вы можете воспользоваться и более свежими версиями swfobject. Итак, вот пример кода файла index.jsp:
  1. <html> 
  2.   <head>
  3.      <script src="js/swfobject.js"></script>
  4.   </head>
  5. <body>
  6.   <div id="swf_zone" style="padding: 3px;">
  7.     <b>FlashPlayer 9 is not available</b>
  8.   </div>
  9.   <script>
  10.         var so = new SWFObject("flashmodule-1.0.swf", "flashmodule_app", "640", "480", "9");
  11.          so.addVariable("contextName", "<%= application.getContextPath()%>");
  12.          so.write("swf_zone");
  13.       </script>
  14.   </body> 
  15. </html>
Устройство index.html файла тривиально: сначала внутри секции head я подключаю библиотеку “js/swfobject.js”. Затем внутри “тела” html-странички я создал блок div, играющий роль “заглушки”. Именно внутрь этого div-блока и будет загружен flash¬ролик. Внутри тега “script” я создаю объект SWFObject, указав в качестве параметров конструктора путь к swf-файлу, затем идет произвольный идентификатор, который будет назначен тому тегу embed или object, который сгенерирует swfobject. Третий и четвертый параметры конструктора SWFObject задают размер для внедряемого внутрь html-странички flash-ролика (640 на 480 пикселей). Последний параметр конструктора цифра “9” указывает на минимальную версию flashplayer, необходимую для того, чтобы корректно запустить swf-файл на выполнение. Некоторую сложность вызывает вызов функции addVariable с непонятным значением. Я уверен, что вы знаете о том, что в flash-ролики можно передавать произвольные переменные из родительского html-файла. Я воспользовался встроенной в swfobject функцией addVariable для того, чтобы передать внутрь flash-ролика переменную “contextName” с именем текущего контекста веб-приложения. Давайте вспомним, что такое контекст и зачем он нужен? Дело в том, что в терминологии java веб-приложений, контекст для веб-приложения это всего лишь имя каталога, в котором веб-приложение размещено. Например, если на веб-сервер скопировать war-файл, который называется “warmodule.war”. То для доступа к файлам внутри приложения нужно будет все пути предварять именем контекста, равным имени war-файла, т.е. http://localhost:8080/warmodule/index.jsp. Так вот, для того чтобы из flash-приложения установить соединение по протоколу RTMP, мне нужно знать то, как называется контекст, в котором размещено приложение (точнее говоря имя приложения, под которым оно зарегистрировано на red5 сервере, но пока я буду полагать эти понятия одинаковыми). Надеяться на то, что веб-приложение всегда будет называться warmodule не правильно. Дело в том, что решение о имени контекста веб-приложения должен принимать не разработчик веб-приложения, а его администратор в соответствии с политикой предприятия по использованию ПО. Так, что ваш war-архив может быть переименован, например, в “red5demo.war”. И если вы не будете динамически определять имя контекста, в который администратор сайта установил ваше приложение, и не будете это имя контекста передавать внутрь flash-ролика, то организовать общение между flash и java не получится. Последний шаг при работе с swfobject – это вызвать функцию write, передав ей как параметр идентификатор того div-блока, внутрь которого и будет внедрен swf файл. Если же на машине клиента не установлен flashplayer или он имеет недостаточный номер версии, то содержимое блока div останется без изменения, и мы увидим надпись “ FlashPlayer 9 is not available”.

Теперь перейдем к рассмотрению следующей составляющей warmodule – конфигурационных файлов. Размещены эти файлы внутри подкаталога webapp/WEB-INF и включают в себя red5-web.properties, red5-web.xml, web.xml. Главный конфигурационный файл для любого java веб-приложения – это web.xml. Так что его содержимое я рассмотрю первым:
  1. <?xml version="1.0" encoding="ISO-8859-1"?>
  2. <web-app
  3.   xmlns="http://java.sun.com/xml/ns/j2ee"
  4.   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5.   xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  6.   version="2.4">
  7.   <display-name>Red5 Demo application</display-name>
  8. </web-app>
Забавно, но внутри этого файла нет ни одной строки кода, кроме имени веб-приложения (display-name), да и то носящей декоративный характер. Вся “магия” в том, что нашему приложению не нужны какие-либо специальные конфигурационные директивы, поскольку оно предназначено для выполнения не на любом java веб-сервере, а только в среде веб-сервера tomcat, который был загружен и установлен с официального сайта red5. А вот если бы я создавал бы приложение, использующее функционал red5 и хотел бы создать приложение “с нуля” для его последующей установки на “чистый” java-сервер, то содержимое web.xml было бы очень-очень большое.

На сегодня все. В следующий раз я рассмотрю последние два конфигурационных файла веб-приложения (red5-web.properties и red5-web.xml), а затем мы можем перейти к созданию flash файла, который обменивается информацией с java сервером по протоколу RTMP.

Categories: Flash & Flex