enterprise flex pure mvc.v4

23
Flex Pure MVC архитектура для приложений enterprise уровня Описание: 1. Сначала мы вспомним основные составляющие микроахитектуры PureMVC, используя презентацию Samuel Asher Rivello. 2. Далее рассмотрим структуру и задачи, возникающие при использовании PureMVC в больших проектах. a. Разновидности и жизненный цикл элементов системы b. Необходимость синхронизации работы медиаторов с асинхронно создаваемыми видимыми элементами. 3. «Страничная» архитектура для PureMVC проекта: a. Управление View компонентами в «страничной» архитектуре: i. отложенное (deferred) создание, ii. расположение в иерархии Display Objects - слоты, медиаторы- слотхолдеры и их взаимодействие с медиаторами-клиентами. b. Жизненный цикл «страницы», дескриптор «страницы» c. Прелоадер страницы 4. Взаимодействие View Components и Mediators a. Шаблон «страницы» b. Интерфейс «страничного» View Component c. Обмен данными между медиатором и View компонентом. d. Состояние «редактирования» (Editing state) e. Обработка нажатий кнопок (Buttons) f. Обработка других команд (пример – Chevrons) 5. Использование модулей в «страничной» архитектуре. Требования к слушателям: знание AS3, жизненного цикла компонентов Flex, PureMVC http://puremvc.org Докладчик: Сергей Шичинов - Sergiy Shychynov (EPAM) [email protected]

Upload: sergiy-shychynov

Post on 01-Jul-2015

465 views

Category:

Documents


0 download

DESCRIPTION

Flex Pure MVC архитектура для приложений enterprise уровня. Черновик доклада для UA FPUG - встреча 35.

TRANSCRIPT

Page 1: Enterprise flex pure mvc.v4

Flex Pure MVC архитектура для enterprise приложений уровня

:Описание 1. Сначала мы вспомним основные составляющие микроахитектуры PureMVC, используя презентацию

Samuel Asher Rivello.2. Далее рассмотрим структуру и задачи, возникающие при использовании PureMVC в больших проектах.

a. Разновидности и жизненный цикл элементов системыb. Необходимость синхронизации работы медиаторов с асинхронно создаваемыми видимыми

элементами.3. «Страничная» архитектура для PureMVC проекта:

a. Управление View компонентами в «страничной» архитектуре:i. отложенное (deferred) создание,

ii. расположение в иерархии Display Objects - слоты, медиаторы-слотхолдеры и их взаимодействие с медиаторами-клиентами.

b. Жизненный цикл «страницы», дескриптор «страницы»c. Прелоадер страницы

4. Взаимодействие View Components и Mediatorsa. Шаблон «страницы» b. Интерфейс «страничного» View Componentc. Обмен данными между медиатором и View компонентом.d. Состояние «редактирования» (Editing state)e. Обработка нажатий кнопок (Buttons)f. Обработка других команд (пример – Chevrons)

5. Использование модулей в «страничной» архитектуре.

:Требования к слушателям знание AS3, жизненного цикла компонентов Flex, PureMVC http://puremvc.org

:ДокладчикСергей Шичинов - Sergiy Shychynov (EPAM) [email protected]

: Примечание пункт 4 был исключён из доклада для того чтобы длительность доклада соответствовала регламенту.

2012-03-24

Page 2: Enterprise flex pure mvc.v4

PureMVCОсновные составляющие (используя презентацию Samuel Asher Rivello)

http :// www . adobe . com / newsletters / inspire / december 2008/ articles / article 6/ index . html

MVC in PureMVC

Схема взаимодействия компонентов PureMVC для выполнения элементарной операции:

- Внешний вид компонента Hello Google – кнопка и текстовое поле для сообщения- Последовательность элементарных действий выполняемых при нажатии кнопки- Положение этих действий на диаграмме PureMVC

Page 3: Enterprise flex pure mvc.v4
Page 4: Enterprise flex pure mvc.v4

, PureMVC Основные задачи возникающиеприиспользовании в .больших проектах

Когда речь идет о приложение enterprise уровня, то это означает что они БОЛЬШИЕ. То есть имеется БОЛЬШОЕ количество РАЗНЫХ форм и компонентов, которые необходимо будет использовать в разных ситуациях и в разное время. И речи о том, что все элементы будут созданы одновременно или заранее быть не может. Более того – было бы неплохо, чтобы и грузить их все сразу не требовалось.

Рассмотрим несколько разных «видов» гипотетического большого приложения.

Page 5: Enterprise flex pure mvc.v4
Page 6: Enterprise flex pure mvc.v4

Среди всего UI большого приложения можно выделить элементы (подсистемы):

1. Которые постоянно находятся на экране и доступны для взаимодействия.2. Которые могут вызываться пользователем на экран по желанию и ведут себя относительно независимо

от других элементов UI.3. Которые имеют отношение к текущей операции, выполняемой пользователем, показываются на экране

когда он начинает выполнять эту операцию и будут убраны с экрана когда он эту операцию завершит. Причем таких циклов появления и исчезновения с экрана может быть много. Этот третий тип подсистем мы будем в дальнейшем называть страницами – Pages.

Page 7: Enterprise flex pure mvc.v4

( ) Иесли операции по обслуживаниюжизненного цикла описанные далее для компонетов1 2 ( и типа можно выполнить один раз например в StartupCommand), то выполнение всех

3- нижеперечисленных действий для компонентов подсистем его типа является рутинной .операцией и нуждается в автоматизации

Жизненныйцикл элементов системыКаждая подсистема 3 типа («страница») может состоять из одного или нескольких видимых элементов, функционирующих совместно в одном промежутке времени. И для функционирования любой отдельной подсистемы нашей большой системы нам будет необходимо:

1. Создать (инстанциировать) и разместить на экране (в иерархии DisplayObjects) необходимые компоненты - ViewComponents. (Здесь и дальше компонентом будет называться видимый элемент, занимающий место в иерархии DisplayObjects.)

2. создать и зарегистрировать необходимые медиаторы – Mediators.3. связать медиаторы с соответствующими компонентами

a. медиаторы должны иметь ссылки на свои компоненты, для того чтобы передавать в них данные и совершать действия

b. медиаторы прослушивают события – Events от компонентов для того чтобы узнать что нужно что-то делать

4. зарегистрировать необходимые для работы подсистемы комманды – Commands (связать их с Notifications),

5. создать и зарегистрировать необходимые для работы прокси – Proxy,6. отобразить в наших компонентах валидные данные и обеспечить взаимодействие

a. Как правило, эти данные загружаются извне (с сервера). Это может занять определенное время. Эти данные возможно не получится загрузить в результате ошибки. И возможно имеются некие политики безопасности, которые в зависимости от того какие именно данные хочет увидеть пользователь, могут не разрешить ему увидеть эти данные – и мы не узнаем о том разрешено это или нет, пока не получим ответ с сервера. Во всех этих случаях неразумно показывать на экране новые компоненты, еще не заполненные данными, до того как эти данные будут получены с сервера. Это процесс мы будем называть предзагрузка – preloader.

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

Page 8: Enterprise flex pure mvc.v4

c. Отдельный вопрос – это обработка ошибок (серверных) – в зависимости от типа ошибок мы может либо дальше продолжать оставаться на странице, либо потребуется обновить ее, либо придется покинуть ее.

7. После того как пользователь завершил операцию нам необходимо корректно освободить ресурсы системы от текущей «страницы» (очевидно перед тем как будет открыта следующая).

a. Удаление «актеров» PureMVC (медиаторов)i. «отписать» медиаторы от системы (unregister) чтобы они не прослушивали больше

нотификейшены.ii. Можно также удалять медиаторы, но можно сохранять их в «кэше» до следующего

использования.iii. Команды тоже можно «отписать» от системы, но это не обязательно.iv. Некоторые прокси можно было бы тоже отписывать от системы и удалять, но обычно этого

не нужно. И даже вредно.b. Отписывание медиаторов от events, которые они прослушивали от компонентов.c. Удаление видимых компонентов.

Вообще говоря, операция создания компонента и добавления его в DisplayList гораздо более ресурсоемкая, чем сделать невидимый компонент – видимым. Поэтому для увеличения перформанса и для того чтобы видимые элементы появлялись более плавно вместо удаления компонентов лучше делать их невидимыми.

d. Если в процессе выполнения операций были загружены какие-то большие данные и ссылки на них сохранились в компонентах или «актерах» PureMVC – то нужно их очистить, чтобы позволить Garbage Collector –у освободить память.

Необходимость синхронизации работымедиаторов с асинхронно создаваемыми .видимыми элементами

Как известно видимые элементы – компоненты флекса не создаются мгновенно по запросу. Как правил от момента создание экземпляра компонента, установки его свойств и добавления его в иерархию DisplayObjects проходит некоторое время и несколько этапов, прежде чем событие «creationComplete» дает нам знать, что компонент и все его подкомпоненты полностью созданы и готовы к работе.До этого момента медиатор, даже если и будет иметь ссылку на компонент, не сможет полноценно с ним работать.

DefferedMediator

Решает проблему асинхронного создания компонентов. Откладывает вызовы initialize и activate до момента, когда компонент будет создан и инициализирован. А потом еще откладывает update до момента, когда все медиаторы из списка будут активированы.

Constructor() – чистый конструктор (не выполняющий никаких действий)

* Override it to complete setup mediator properties and associate mediator* with the View Component. Use setupMediator function to do most of the tasks.function create():void

* The method is called after component <code>creationComplete</code> event.* Create it to add listeners and make additional view component initialization.function initialize():void;

* This method is called every time when you show and activate the view component.* Override it to add additional mediator's and view component's activation.function activate():void;

waitForMediatorsActivation ( mediatorNames );

* Override it to update view component in accordance with current viewParams.* You can process here both stateParams and viewParams.* Is called after initialize() (after creationComplete event) and

Page 9: Enterprise flex pure mvc.v4

* activate() methods.function update():void

* Deactivate mediator (remove from pureMVC workflow).* You can override it to make additional deactivation.function deactivate():void;

* Create it to remove listeners and make additional view component finalization.function finalize():void;

, .Кто когда и как создает видимые элементы, - Слоты медиаторы слотхолдерыиих взаимодействие с

- . компонентами клиентамиЗадача по созданию и связыванию вью компонентов с медиаторами возложена на медиатор.

Медиатору известен класс его компонента. При создании медиатора – в методе create() – медиатор создает экемпляр вью компонента и помещает его в DisplayList. Делается это с помощью концепции медиаторов-слотхолдеров, которые имеют в составе своего компонента slot – контейнер (обычно ViewStack ) в который можно поместить, найти и удалить комопнент.

SlotViewComponentDescription viewComponentName:String, viewComponentSlot:String, viewComponent:UIComponent

медиатор-клиент M1Mediator создает компонет и отправляет его слоту "SlotAMediator" - просит его хранить под именем "M1"

медиатор-слотхолдер SlotAMediator получает нотификейшен, адресованный ему и добавляет в свой слот (ViewStack или другой контейнер) новый компонет под именем "M1"

M1Mediator SlotAMediator

Page 10: Enterprise flex pure mvc.v4
Page 11: Enterprise flex pure mvc.v4

« » PureMVC Страничная архитектура для проектаМы ввели понятие страниц – Pages. «Страница» – это некоторое множество видимых элементов, функционирующих совместно в одном промежутке времени. Эти компоненты и обслуживающие их актеры PureMVC совместно создаются, работают и удаляются. Выполнением всех этих операций в PureMVC традиционно занимаются команды. Чтобы не писать отдельные команды для открытия каждой страницы, была создана единая команда открытия новой страницы ViewPageCommand. Эта команда выполняет все необходимые при открытии страницы действия в соответствии с переданным ей в качестве входного параметра дескриптором страницы.Она работает совместно с Pages Proxy, который и является хранителем информации обо всех доступных в системе «страницах» и «состояния» текущей открытой страницы.

Основные задачи PagesProxy: - хранение справочника всех страницах в системе

function getPageDescription(pageName:String):PageDescription

- хранение информации о текущей открытой странице (ее имя, дескриптор, стейт, состояние редактирование, helpContext и прочее)

Соответственно все страницы имеют уникальное имяpublic class Pages{ public static const ABOUT:String = "about"; public static const ADMIN_EMAIL_TEMPLATE_EDIT:String = "adminEmailTemplateEdit"; public static const DOCUMENT_TRANSLATION:String = "documentTranslation";…}и дескрипторы

PageDescriptionpageName:String,

preloader:Class, - наследник BasePagePreloader

mediators:Array, - список классов наследоников BaseMediatorproxies:Array = null,commands:Array = null, - список CommandDescription(name:String, commandClass:Class)

stateParams:Object = null, - редко встречающиеся дополнительные параметры pageTitle:String = null, } - часто встречающиеся дополнительные параметрыbreadcrumbs:Array = null. … }

:Пример дескриптора страницыnew PageDescription( Pages.QUESTIONNAIRE, QuestionnaireAnswerPreloader, [QuestionnaireSlotHolderMediator, QuestionnaireAnswerMediator], [QuestionnairesProxy, ProcessEditProxy, ProcessTypesListProxy, TimeScaleProxy], [ new CommandDescription(SPNotification.FIND_NEW_QUEST, LoadQuestiannairCommand), new CommandDescription(SPNotification.UPDATE_ASSET_QUEST, UpdateAssetForQuestCommand), ], { questionnaireComponentState: QuestionnaireComponentState.ANSWER }, "Questionnaire Registry")

PageNotificationParamsvar pageName:String;

Page 12: Enterprise flex pure mvc.v4

var pageState:String;var id:Number;var backPageName:String;var preloader : BasePreloaderMediator ; - создается и добавляется в процессе открытия страницы

ViewPageCommand1. Проверяет наличие дескриптора страницы и при необходимости подгружает модуль содержащий

страницу. Входными параметрами для открытия страницы являются:a. pageDescriptor – находится по имени страницыb. stateParams : {} – является дополнительным набором параметров страницы (которые не

вошли в сам дескрипотор – так как редко используются)c. viewParams : PageNotificationParams – дополнительные параметры страницы, заполняемые

при ее открытии2. Создает и регистрирует необходимые прокси (они могут быть нужны прелоадеру)3. Создает и запускает прелоадер

a. load()b. validate() + препроцессинг

4. Если прелоадер «дал добро», то закрывает текущую страницуa. отписывает от системы медиаторыb. подчищает «временные» данные (на вью компонентах и медиаторах!)c. отписывает медиатор от events компонентовd. добавляет ссылку на прелоадер с загруженными и подготовленными данными во viewParams

5. Регистрирует команды6. Создает (или достает из кеша) медиаторы, передает им значения stateParams и viewParams и

регистрирует их в системе.a. Если медиаторы создаются то это делается в следующем порядке

i. Конструкторii. Setup params (stateParams и viewParams)

iii. create()b. если достается из кеша, то просто Setup params (stateParams и viewParams)

7. Активирует медиаторы. В процессе активации медиаторы должны создать свои компоненты, разместить их в иерархии DisplayLists, сделать видимыми и подписаться на необходимые events.

8. После активации всех медиаторов вызывается update()

– Прелоадер PreloaderПрелоадер служит для того чтобы загрузить несколько «частей» данных (используя прокси или непосредственно делегаты). После полной загрузки всех частей возможна их валидация и дополнительная обработка. Прелоадер отрабатывает при попытке открыть новую «страницу» до того как она будет реально открыта. В случае если валидатор прелоадера выдает false, страница не будет открыта. Вместо этого будет выведено сообщение об ошибке.

Фрагмент кода вызова прелоадера при открытии страницыif(pageDesc.preloader != null) { setLoadingState(true); registerProxies(); // for preloadin purposes var preloaderMediator:BasePreloaderMediator = new (pageDesc.preloader)(); preloaderMediator.viewParams = params; preloaderMediator.stateParams = pageDescriptor.stateParam; preloaderMediator.callback = executeAfterPreload; preloaderMediator.load();

BasePreloaderMediator var stateParams:Object;

Page 13: Enterprise flex pure mvc.v4

var viewParams:PageNotificationParams;

* Override it to create more preloader parts. You can use viewParams and stateParams.function load():void { //... addDelegatePreloaderPart("YYYid", ResourceTypeDelegate.instance.getResourceTypeById(id)); //... addNotificationPreloaderPart("XXXid", XXXResultNotification, XXXFaultNotification); xxxProxy.load(blablabla); //... activate();}

* Override it to validate loaded data. If ERROR - you have to setup * preloader.errorKey before returning false value.function validate():Boolean { if(preloader.errorKey == null) { // достаем нужное нам данное и проверяем getPart("YYYid") – используем для проверки } return (preloader.errorKey == null);}

Пример прелоадера «детям до 16»public class ManageGroupMembershipPreloader extends BasePreloaderMediator{ override public function load():void { var id:Number = getID(true); if(!isNaN(id)) addDelegatePreloaderPart(ContactProxy.CONTACT, ContactDelegate.instance.getContactById(id) ); addNotificationPreloaderPart(LanguageProxy.PLAIN_LANGUAGE_LIST, SPNotification.PLAIN_LANGUAGE_LIST_LOADED, SPNotification.PLAIN_LANGUAGE_LIST_FAILED);

LanguageProxy(facade.retrieveProxy(LanguageProxy.NAME)).getPlainLanguageList();

super.load(); }

override public function validate():Boolean { if(super.validate()) { var contact:Contact = getPart(ContactProxy.CONTACT) as Contact; if(contact != null && contact.age < 16) setPreloaderError("Просмотр этой страницы не разрешен детям до 16"); return super.validate(); }}

МодульностьВ настоящее время система имеет: полторы сотни (150) основных страниц со связанными с ними rollover формами,

Page 14: Enterprise flex pure mvc.v4

несколько десятков popup-форм некоторое кол-во подсистем,

работающих постоянно на экране, вызываемых по требованию пользователя или работающий в качестве «демонов» – daemon (ping, system messages) и «сервисов» (messages, multiple operations, progress indication etc.)

Кодовая база клиентской части проекта включает более 2000 файлов. Из них более 1600 as файлов и около 400 mxml.

При этом с точки зрения заказчика это все разбито на 8 логических «модулей» и лицензия на использование каждого из них может покупаться отдельно.

Кроме того многие пользователи могут не иметь доступа к некоторым модулям (администрирование, отчеты) по соображениям секьюрности или в соответствии с их ролями.

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

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

RSL для этого использовать нельзя, так как для RSL приходилось бы вручную выбирать какие классы включать в эту библиотеку а какие - нет. Что неприемлемо при колве классов больше 2000. Флексовые модули для этого как бы не задумывались (это скорее неудачный способ монетизации флексовых приложений), но воспользоваться ими получилось.

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

И в разбиении системы на модули очень помогло то, что мы имели большинство функционала, организованного в виде «страниц». Страницы были использованы как ноды для дерева линковки всех классов, необходимых для работы текущего модуля.

Таким образом, модуль подгружает ViewPageCommand в момент когда впервые понадобиться страница содержащаяся в этом модуле. После загрузки модуля (и всех его классов) все PageDescriptors, содержавшиеся в этом модуле добаляются в список доступных страниц в PagesProxy.

Структура иерархиимодулей

Module – единица компиляции и линковкиModuleDescription – содержит полный набор всех Page Descriptors модуля PageDescriptionsXXX – логически сгруппированные наборы дескрипторов страницmoduleDescriptors.xml – справочник, содержащий информацию о том какая страница в каком модуле содержится

flex-include-vo.xml – список всех VO системы для включения в ядро системы (решение проблемы регистрации VO для ремотинга)

Соответствующие ANT скрипты. !!! НИКОГДА не включайте модули из среды Flash Builder!!!

.Проблема регистрации классов для римотинга[RemoteClass(alias="com.os.sp.domain.messaging.MessagesGroup")]public class MessagesGroup extends MessagesGroupBase implements IOSSPMessage {}

Не регистрирует класс, если VO линкуется через модуль!

Решение проблемы:

Page 15: Enterprise flex pure mvc.v4

1) в модуле делаем registerServerClass(MessagesGroup);

public static function registerServerClass(classRef:Class):void{ registerClassAlias(getClassServerName(classRef), classRef);}

2) линкуем все VO в ядро системы (flex-include-vo.xml <?xml version="1.0"?><flex-config><includes append="true"> <symbol>com.os.sp.domain.administration.authorization.ContactGroupIPRange</symbol> <symbol>com.os.sp.domain.messaging.MessagesGroup</symbol> <symbol>com.os.sp.domain.messaging.SmsCostConfig</symbol> <symbol>com.os.sp.domain.integrity.InvalidRecord</symbol> <symbol>com.os.sp.domain.reporting.monitoring.GenerationState</symbol></includes></flex-config>

public function ModuleMain(){ super();

_moduleDescription = new ModuleDescriptionMain();

//NameUtils.registerServerClass(ContactTask); //NameUtils.registerServerClass(ReportResponse);

initializeModule();}

public function ModuleDescriptionMain(){ super("ModuleMain", [], [] .concat(PageDescriptionsMain.pageDescriptions) .concat(PageDescriptionsMyShadowPlanner.pageDescriptions) .concat(PageDescriptionsContacts.pageDescriptions) .concat(PageDescriptionsResourcesAssets.pageDescriptions) .concat(PageDescriptionsReporting.pageDescriptions) );}

public class PageDescriptionsResourcesAssets

{public static const commonBreadcrumbs:Array = [Pages.R_A_VIEW_ROOT_RESOURCES];

public static const commonProxies:Array = [ResourceTypeProxy, ParentListProxy, SessionDataProxy,AssetProxy, ProcessEditProxy, ProcessesListProxy ];

public static const pageDescriptions:Array = [/////////////////////////////////////////////

new PageDescription(Pages.UPDATE_RESOURCE_TYPE, PageState.ADD_EDIT_VIEW, ResourceTypeEditPreloader, Pages.R_A_VIEW_ROOT_RESOURCES, [ResourcesSlotHolderMediator, ResourceTypeEditMediator], [SessionDataProxy, AssetProxy, ProcessEditProxy],

Page 16: Enterprise flex pure mvc.v4

[ new CommandDescription(SPNotification.FIND_ASSET_FOR_DETAILS, LoadAssetCommand), new CommandDescription(SPNotification.FIND_ASSET_FOR_EDIT, LoadAssetEditCommand), ], {accessArea: AccessArea.RESOURCE_TYPES}, commonBreadcrumbs.concat(), "page.updateResourceType.title", "page.updateResourceType.breadcrumbLabel", null).addAddPageState(null, "page.createResourceType.title", "page.createResourceType.breadcrumbLabel").addViewPageState(null, "page.updateResourceType.viewTitle", "page.updateResourceType.viewBreadcrumbLabel").addLibraryPageState( Pages.R_A_UPDATE_RESOURCE_TYPE_FOR_LIBRARY),

new PageDescription( Pages.QUESTIONNAIRE, PageState.EDIT_VIEW, QuestionnaireAnswerPreloader, null, [QuestionnaireAnswerMediator], [QuestionnairesProxy, ProcessEditProxy, ProcessTypesListProxy], null, {questionnaireComponentState:QuestionnaireComponentState.ANSWER}, [TreeNodeBase.NODE_BIA]).registerRollover(Rollovers.QUESTIANNAIRE_RECOVERY_SCHEDULE, PageState.ADD_EDIT_VIEW).registerRollover(Rollovers.QUESTIONNAIRE_ADD_PROCESS, PageState.ADD_EDIT_VIEW)

] /////////////////////////////////////////////}

moduleDescriptors.xml

<?xml version="1.0" encoding="UTF-8"?><Modules> <Module name="ModuleMain"> <Pages> <Page name="about"/> <Page name="myTasksPage"/> <Page name="myResponsibilitiesPage"/> <Page name="myPasswordPage"/> </Pages> <Dependencies/> </Module> <Module name="ModuleAdministration"> <Pages> <Page name="adminLogo"/> <Page name="adminLanguageEditor"/> <Page name="auditTrail"/> </Pages> <Dependencies/> </Module> <Module name="ModuleQuestionnaires"> <Pages> <Page name="questionnaires"/> <Page name="questionnaire"/> <Page name="questionnaireTemplates"/> </Pages> <Dependencies/> </Module></Modules>

Page 17: Enterprise flex pure mvc.v4

Фрагмент ant-task-а компиляции основного приложения (ядра системы)<property name="FLEX_INCLUDE_VO_CONFIGURATION" value="${MAIN_SOURCE_FOLDER}/flex-include-vo.xml" />

<mxmlc file="${MAIN_SOURCE_FOLDER}/${ROOT_APPLICATION}.mxml" output="@{output}.swf" link-report="${BUILD_FOLDER}/${ROOT_APPLICATION}.${FULL_LINK_REPORT_POSTFIX}" > <load-config filename="${FLEX_LOCAL_CONFIGURATION}"/></mxmlc>

Компиляция модулей<target name="compile-modules" if="flex.modular.exist"> <compile-module-simple moduleName="ModuleAdministration" /> <compile-module-simple moduleName="ModuleMessaging" /> <compile-module-simple moduleName="ModuleImportExport" /></target>

Фрагмент из макроопределения компиляции модуля<mxmlc file="${MODULE_SOURCE_FOLDER}/@{moduleName}.@{moduleType}" output="${BUILD_FOLDER}/@{moduleName}.swf" load-externs="${BUILD_FOLDER}/@{dependsOn}.${FULL_LINK_REPORT_POSTFIX}" ></mxmlc>

: Приложение особенности реализации SlotHolder медиаторовЗадача по созданию и связыванию вью компонентов с медиаторами возложена на медиатор.

Медиатору известен класс его компонента. При создании медиатора – в методе create() – медиатор создает инстанс класса вью компонента и отправляет его слот-холдер медиатору чтобы тот поместил его себе в DisplayList.

protected function setupMediator(…) mediatorName:String = null, // AUTO – такое же как имя класса – для регистрации в PureMVC

viewComponentReference:Object = null, // 1) null must be null, // 2) component class // 3) component instance (descendant of UIComponent)

viewComponentName:String = null, // viewComponent custom name // AUTO – по имени медиатора без постфикса Mediator // будет использовано как id и name в слотхолдере

viewComponentSlot:String = null, // specific slot for register/find viewComponent (if need) viewComponentInitAction:int = 0 // special init action (0 - no action)

INIT_NONE:int = 0; // no action

INIT_FIND_OR_WAITING_FOR_THE_VIEW_COMPONENT:int = 1;// find view component with appropriate name in appropriate slot or (in not

found)// listen for the BaseNotifications.SLOT_VIEW_COMPONENT_CREATION_COMPLETE

notification

INIT_FIND_VIEW_COMPONENT:int = 2;// find view component with appropriate name in appropriate slot

Page 18: Enterprise flex pure mvc.v4

INIT_ADD_TO_SLOT:int = 4;// add view component to appropriate slot using appropriate name

override public function listNotificationInterests():Array{ return (slots == null) ? super.listNotificationInterests() : super.listNotificationInterests().concat( BaseNotifications.SLOT_VIEW_COMPONENT_ADD, BaseNotifications.SLOT_VIEW_COMPONENT_REMOVE_BY_NAME, BaseNotifications.SLOT_VIEW_COMPONENT_SHOW, BaseNotifications.SLOT_VIEW_COMPONENT_HIDE, BaseNotifications.SLOT_VIEW_COMPONENT_FIND );}

override public function handleNotification(notification:INotification):void{ super.handleNotification(notification); …}

private function defaultSlotHolderNotificationHandler(notification:INotification):void{ if(slots && slots[notification.getType()]) { var desc:SlotViewComponentDescription = notification.getBody() as SVCD; var component:UIComponent; component = getViewComponentFromSlot(desc.viewComponentSlot, desc.viewComponentName); switch(notification.getName()) { case BaseNotifications.SLOT_VIEW_COMPONENT_SHOW: FlexUIComponentsUtils.showViewComponent(component, true); break; case BaseNotifications.SLOT_VIEW_COMPONENT_HIDE: component.visible = false; break; case BaseNotifications.SLOT_VIEW_COMPONENT_ADD: addViewComponentToInternalSlot(desc); desc.viewComponent = null; // mark viewComponent as added break; case BaseNotifications.SLOT_VIEW_COMPONENT_REMOVE_BY_NAME: removeViewComponentFromSlotByName(desc); break; case BaseNotifications.SLOT_VIEW_COMPONENT_FIND: desc.viewComponent = component; break;}}}

Далее описан антипаттерн, который используется для оптимизации взаимодействия слотхолдеров. Но мне не стыдно, потому что это, с одной стороны – служит оптимизации (можно было и не делать), с другой – можно было бы без этого обойтись просто воспользовавшись синглтоном-менеджером.

* Register handler for Notification - works just like addEventListebner.* It doesn't depend on registerMediator/removeMediator !BE AWARE!function addNotificationListener(notificationName:String, handler:Function):void{ org.puremvc.as3.core.View.getInstance().registerObserver( notificationName, new Observer(handler, this) );}

* Remove Notification handler - works just like removeEventListebner.

Page 19: Enterprise flex pure mvc.v4

* It doesn't depend on registerMediator/removeMediator !BE AWARE!function removeNotificationListener(notificationName:String):void{ org.puremvc.as3.core.View.getInstance().removeObserver( notificationName, this );}

Пример использования:* Try to add view component in appropriate external slot. If there isn't * appropriate slot then start waiting for SLOT_CREATION_COMPLETE.function addViewComponentToExternalSlot():void { var desc:SlotViewComponentDescription = new SlotViewComponentDescription viewComponentName, viewComponentSlot, viewComponent as UIComponent );

var addNotification:INotification = new Notification( BaseNotifications.SLOT_VIEW_COMPONENT_ADD, desc, viewComponentSlot);

facade.notifyObservers(addNotification);

if(desc.viewComponent != null) // его бы обнулили если бы он был найден { addNotificationListener(BaseNotifications.SLOT_CREATION_COMPLETE, handleSlotCreationCompleteNotificationToAddViewComponent); }}