00001 /*************************************************************************** 00002 * * 00003 * (c) Art Tevs, MPI Informatik Saarbruecken * 00004 * mailto: <tevs@mpi-sb.mpg.de> * 00005 * * 00006 * This program is free software; you can redistribute it and/or modify * 00007 * it under the terms of the GNU General Public License as published by * 00008 * the Free Software Foundation; either version 2 of the License, or * 00009 * (at your option) any later version. * 00010 * * 00011 ***************************************************************************/ 00012 00013 00014 #ifndef _NR_EVENT_CHANNEL_H_ 00015 #define _NR_EVENT_CHANNEL_H_ 00016 00017 //---------------------------------------------------------------------------------- 00018 // Includes 00019 //---------------------------------------------------------------------------------- 00020 #include "Prerequisities.h" 00021 #include "EventActor.h" 00022 #include <queue> 00023 00024 namespace nrEngine{ 00025 00026 //! Event channel used for communication between application/engine's components 00027 /** 00028 * \par 00029 * EventChannel represents a message bus for the communication between 00030 * system components. Events/messages could be send through this channel 00031 * to all listeners connected to this channel. 00032 * 00033 * \par 00034 * In our engine we mix the concept of event messaging and state machines. 00035 * So we do not have only events but also states. The states are stored in 00036 * communication channels, so each listener of a channel could also be noticed 00037 * if any state changes. This is also how we handle it in the nrEngine. 00038 * 00039 * \par 00040 * The communication actors are connected to the channel by its name. Also 00041 * the lifetime of each actor is tracked. So if an actor is removed from the 00042 * memory, so it will be automaticaly disconnected from the database. 00043 * We do not use smart pointers for this purpose, because it will cause in 00044 * undefined working flow. i.e. if you think the actor is removed from the memory 00045 * because you have deleted it, it still get noticed about the things going on 00046 * the channel. So this will ends up in undefined state.In our implementation 00047 * the destructor of EventActor does simply say all channels it connected to, 00048 * that the object does not exists anymore, so it can be disconnected. 00049 * 00050 * \ingroup event 00051 **/ 00052 class _NRExport EventChannel { 00053 public: 00054 00055 //! Create a new instance of the communication channel 00056 EventChannel(EventManager* manager, const std::string& name); 00057 00058 //! Releas eused memory and destroy hte instance. 00059 virtual ~EventChannel(); 00060 00061 /** 00062 * Connect a new actor to the channel. The actor will be connected 00063 * so it get noticed about any communication on the channel. 00064 * 00065 * The actor has to implement default event reactions needed for 00066 * our channel communication system. Compilation error will occur 00067 * if the reactions to the default events are not implemented. 00068 * 00069 * @param actor An actor to connect to the channel 00070 * @param notice Should channel let notice the actor that he is connected now (default YES) 00071 **/ 00072 Result add(EventActor* actor, bool notice = true); 00073 00074 /** 00075 * Disconnect an actor from the channel. It is a good coding style 00076 * if you call this function, when you do not need the connection anymore. 00077 * However our engine does provide you the possibility to 00078 * forget about disconnecting the actors from the channel, because the lifetime 00079 * of an actor will be tracked. If the object does not exists anymore, so 00080 * it will be automaticaly disconnected. 00081 * 00082 * If you want to be performant, so remove actors from the channels, if they do not 00083 * need the connection anymore. 00084 * 00085 * @param actor An actor already connected to the channel 00086 * @param notice Should channel notice the actor, about disconnection (default YES) 00087 **/ 00088 Result del(EventActor* actor, bool notice = true); 00089 00090 /** 00091 * Get the name of the channel 00092 **/ 00093 NR_FORCEINLINE const std::string& getName () const { return mName; } 00094 00095 /** 00096 * Emit a certain event to a channel. This will send this event 00097 * to all connected actors, so they get noticed about new event. 00098 * 00099 * @param event Smart pointer to an event object 00100 **/ 00101 void emit (SharedPtr<Event> event); 00102 00103 /** 00104 * Instead of emit() this will not send the message directly to 00105 * the channel listeners, but it store the message first in 00106 * a queue based on priority numbers of the events. When 00107 * you call deliver(), then all messages are getting delivered 00108 * to the channel listeners 00109 * 00110 * @param event Smart pointer to the event message 00111 * 00112 * NOTE: If event priority is immediately so the message will 00113 * be emitted immediately without be stored in the queue 00114 **/ 00115 void push(SharedPtr<Event> event); 00116 00117 /** 00118 * Deliver all stored event messages from the queue 00119 * to the actors connected to the channel. 00120 **/ 00121 void deliver(); 00122 00123 protected: 00124 //! The event manager system is a friend to this class 00125 friend class EventManager; 00126 00127 //! Store here the mapping between actor names and their connections 00128 typedef std::map<std::string, EventActor*> ActorDatabase; 00129 00130 //! Unique name of the communication channel 00131 std::string mName; 00132 00133 //! We always does store a pointer to the event manager where this channel belongs to 00134 EventManager* mParentManager; 00135 00136 //! Connected actor database 00137 ActorDatabase mActorDb; 00138 00139 /** 00140 * This structure is used as a wrapper to define a way 00141 * how to distinguish between priority numbers of events. 00142 **/ 00143 template <class ClassT> 00144 struct GreatEvent : public std::binary_function<ClassT, ClassT, bool> 00145 { 00146 bool operator()(ClassT x, ClassT y) const 00147 { 00148 return x->getPriority() > y->getPriority(); 00149 } 00150 }; 00151 00152 //! We store our event messages in a priority queue 00153 typedef std::priority_queue<SharedPtr<Event>, std::vector<SharedPtr<Event> >, GreatEvent<SharedPtr<Event> > > EventQueue; 00154 00155 //! Store the event messages in this variable 00156 EventQueue mEventQueue; 00157 00158 //! Check whenever a given actor is already connected 00159 bool isConnected(const std::string& name); 00160 00161 //! Disconnect all actors from the channel 00162 void _disconnectAll(); 00163 00164 }; 00165 00166 }; // end namespace 00167 00168 #endif