DirectEvent.h

См. документацию.
00001 /*
00002  * CntmLib - Подсчет ссылок, потоки, синхронизация, асинхронные процедуры, события
00003  * Copyright (c) 2005, Овсеевич Роман, CntmLib@mail.ru
00004  * _______________________________________________________________________________
00005  * Разрешено свободное использование, копирование, распространение, изменение
00006  * (изменение сведений об авторских правах запрещено). Запрещена продажа и 
00007  * включение всей библиотеки или ее частей в другие библиотеки. В сведениях об
00008  * авторских правах на программу (или сведениях о программе, об авторах, 
00009  * использованных средствах разработки и т.д.) должна быть указана информация
00010  * о библиотеке CntmLib, ее авторе и, возможно, сайте или email'е.
00011  * Библиотека поставляется "как есть", без каких-либо гарантий со стороны автора.
00012  */ 
00013 
00014 #ifndef CNTM_DIRECTEVENT_H
00015 #define CNTM_DIRECTEVENT_H
00016 #include <Cntm/Utils/SignatureArgsCollector.h>
00017 #include <Cntm/Utils/SignatureInfo.h>
00018 #include <Cntm/Events/Internal/BasicDirectEvent.h>
00019 
00020 namespace Cntm
00021 {       
00022         
00023         /**
00024          * Шаблонный класс обычного (прямого) события. 
00025          * 
00026          * Под событием, в данном случае, понимается способ оповещения сервером заинтересованной стороны (клиентов) об изменении своего состояния. Для того, чтобы клиент мог обрабатывать событие, он должен создать связь между объектом события и обработчиком. В качестве обработчиков вуступают методы объектов, т.е. обработчик задается указателем на объект и указателем на метод. С одним событием м.б. связано несколько обработчиков. При генерации события указываются аргументы, которые получат обработчики события (т.е. методы). В процессе генерации события быдут вызваны все обработчики с указанными аргументами.
00027          * 
00028          * Класс Cntm::DirectEvent является шаблоном. В качестве параметра шаблона указывается сигнатура функции (т.е. без указания конкретного класса обработчика), которая будет использоваться при генерации события. Пример объвления события: 
00029          * DirectEvent<void (int,const string&,Class1*,const Class2::Ptr&)> ChangeEvent;
00030          * Методы обработчиков должны иметь такую же сигнатуру, как и событие. При попытке связать событие с собработчиком с другой сигнатурой будет выдана ошибка компиляции, т.е. обеспечивается жесткая проверка типов. Возвращаемое значение (если его тип не void) при вызове обработчиков игнорируется. Обычно объект события объявляется как public поле объекта, генерирующего событие.
00031          * 
00032          * Свзывание события с обработчиком осуществляется с помощью специального класса Cntm::EventLink (не является шаблоном). Что бы создать связь нужно создать объект этого класса и указать событие и обработчик (указатель на объект, указатель на метод). При уничтожении этого объекта связь будет автоматически разорвана. Также у этого класса есть метод Attach(), позволяющий изменить связь и имеющий такие же аргументы, что и конструктор (при этом старая связь разрывается и создается новая), а также метод Detach(), разрывающий текущую связь. Рассмотрим пример:
00033          * EventLink onChangeClass1(object1->ChangeEvent, this, &ThisClass::OnChangeClass1);
00034          * onChangeClass1.Attach(object2->ChangeEvent, this, &ThisClass::OnChangeClass2);
00035          * onChangeClass1.Detach();
00036          * 
00037          * Генерация события производится с помощью оператора operator() объекта события. В качестве аргументов этого оператора указываются аргументы, которые будут переданы обработчикам. Пример:
00038          * ChangeEvent(45, "Привет всем обработчикам", this, object2);
00039          * Вызов обработчиков прямого события происходит в момент генерации, т.е. в операторе operator() объекта события. 
00040          * 
00041          * Теперь подробнее о связях событий с обработчиками. Класс Cntm::EventLink имеет конструктор по умолчанию, который инициализирует пустую связь. Конструкторы связывания и методы Attach() имеют 3 параеметра. Рассмотрим их:
00042          * - 1 параметр Event - ссылка на объект события, т.е. должен передаваться объект события, с которым происходит связывание;
00043          * - 2 параметр Object - указатель на объект, который будет обрабатывать событие. Можно передвать либо ссылочный указатель либо обычный. Если указатель равен NULL, то генерируется исключение Cntm::NullArgException;
00044          * - 3 параметр Method - указатель на метод обработчика. Сигнатура метода должна полностью совпадать с сигнатурой события.
00045          * 
00046          * Некоторые особенности работы.
00047          * 
00048          * Время жизни объектов и подсчет ссылок. На объект, обрабатывающий событие (если это объект с подсчетом ссылок, наследующий Cntm::IRefObject) кол-во ссылок не увеличивается (что бы не препятствовать его удалению). Если после создания связи и до ее разрыва произойдет уничтожение объекта события, ничего страшного не случится, просто событие больше никогда не будет сгенерировано. Если во время существования связи произойдет уничтожение объкта обработчика, то это приведет к ошибкам выполнения, поэтому время жизни связи не должно превышать время жизни объекта обработчика.
00049          * 
00050          * Процесс генерации события. Вызываются только те обработчики, которые были добавлены до генерации события. Если обработчик добавлен после генерации события (например, в одном из обработчиков), то добавленный обработчик вызван не будет. Если обработчик был удален в момент генерации до его вызова, то гарантируется, что он не будет вызван. Для объектов обработчиков, являющихся объектами с подсчетом ссылок: если на момент вызова обработчика события на объект не осталось ссылок, но он еще существует (находится в удаляемом состоянии, см. Cntm::IRefObject), то вызов обработчика произведен не будет, если вызов обработчика произведен, то гарантируется наличие хотя бы одной ссылки на объект обработчика до выхода из метода обработки. Исключения, сгенерированные в обработчиках, ни как не влияют на вызов других обработчиков, они просто игнорируются. Относительно аргументов события:  1. изменения аргументов коснутся всех обработчиков, которые будут вызваны после изменившего; 2. если аргумент передан по ссылке, то нет гарантии, что если обработчик произведет изменение этого аргумента, то это изменение отразится на исходном значении аргумента, которое было передано при генерации.
00051          * 
00052          * Данный класс обеспечивает многопоточность.
00053          * @author Овсеевич Р.
00054          * \ingroup Events
00055          */
00056         template < typename SignatureT >
00057         class DirectEvent: public SpecUtils::BasicDirectEvent, public SignatureArgsCollector < DirectEvent < SignatureT >, void, SignatureInfo < SignatureT >, SignatureInfo < SignatureT > ::argsCount >
00058         {
00059         private:
00060         
00061                 friend class SignatureArgsCollector<DirectEvent<SignatureT>, void, SignatureInfo<SignatureT>, SignatureInfo<SignatureT>::argsCount>;
00062 
00063                 typedef SignatureArgsCollectObjectBase <typename SignatureInfo<SignatureT>::Args> SignatureArgsCollectObject;
00064                 typedef typename SignatureInfo<SignatureT>::template Method<HandlerType::Closure>::Pointer MethodPointer;
00065 
00066                 /**
00067                  * Создать объект вызова. Просто создает в куче объект типа SignatureArgsCollectObject. Вызывается из AignatureArgsCollector::operator(). 
00068                  */
00069                 SignatureArgsCollectObject* CreateCollectObject() { return new SignatureArgsCollectObject; }
00070                 
00071                 /**
00072                  * Обработать объект вызова. Вызывается из AignatureArgsCollector::operator(). 
00073                  */
00074                 void ProcessCollectObject(SignatureArgsCollectObject* Object)
00075                 {
00076                         HandlersRegisterEx::Enumerator en = HandlersRegister()->GetEnumerator(false); // Можно использовать без проверки на NULL, т.к. этот случай блокируется NoNeedCreateCollectObject() - вызова ProcessCollectObject() не будет, если NoNeedCreateCollectObject вернет true (это произойдет, если HandlersRegister равен NULL).
00077                         while (en.Next())
00078                         {
00079                                 if (en.Current()) // Если объект не в удаляемом состоянии - обрабатываем.
00080                                 {
00081                                         try
00082                                         {
00083                                                 SignatureInfo<SignatureT>::MethodCall(en.Current().Object(), 
00084                                                         reinterpret_cast<MethodPointer>(en.Current().Method()), Object->Args());
00085                                         }
00086                                         catch (...)
00087                                         {
00088                                         }
00089                                 }
00090                         }
00091                         delete Object;  
00092                 }
00093 
00094                 /**
00095                  * Проверяет, нужно ли обрабатывать вызов для генерации события. Если обработчиков нет, то никаких действий не выполняется. Вызывается из AignatureArgsCollector::operator(). 
00096                  */
00097                 bool NoNeedCreateCollectObject() { return NoNeedCall(); }
00098                 
00099                 /**
00100                  * Ничего не делает. Нужна для AignatureArgsCollector::operator(). 
00101                  */
00102                 void NoneProcessCollectObject() {}
00103         };
00104 
00105 }
00106 
00107 #endif //CNTM_DIRECTEVENT_H

SourceForge.net Logo
© Овсеевич Р.В. Документация по CntmLib 1.1.4 от 28 May 2008. Создано системой  doxygen 1.5.3