xref: /haiku/src/apps/cortex/support/observe.h (revision 89755088d790ff4fe36f8aa77dacb2bd15507108)
1 // Observe.h (cortex)
2 // * PURPOSE
3 //   Messages used for implementation of the Observer pattern.
4 //
5 // * HISTORY
6 //   e.moon		19aug99		Begun
7 
8 #ifndef __Observe_H__
9 #define __Observe_H__
10 
11 #include <Messenger.h>
12 #include <Debug.h>
13 #include <string.h>
14 
15 #include "cortex_defs.h"
16 __BEGIN_CORTEX_NAMESPACE
17 
18 // -------------------------------------------------------- //
19 // *** MESSAGES ***
20 // -------------------------------------------------------- //
21 
22 // messages sent to the Observable (source)
23 enum observer_message_t {
24 	// Requests that an observer be added to a given
25 	// observable (target).
26 	// - "observer" (BMessenger)
27 	M_ADD_OBSERVER							= Observer_message_base,
28 
29 	// Requests that a given observable (target) stop
30 	// sending notifications to a given observer.
31 	// Should be sent in response to M_RELEASE_OBSERVABLE
32 	// in order to allow the observable object to be deleted.
33 	// - "observer" (BMessenger)
34 	M_REMOVE_OBSERVER,
35 
36 	// Requests that an observable quit immediately without
37 	// waiting for its observers to acknowledge that they're done.
38 	// This should only be posted to an Observable in an
39 	// emergency
40 	M_KILL_OBSERVABLE
41 };
42 
43 
44 // messages sent by the Observable (target)
45 enum target_message_t {
46 	// sent when the target is no longer needed; the
47 	// observer should reply with M_REMOVE_OBSERVER in order
48 	// to release (allow the deletion of) the target
49 	// - "target" (BMessenger)
50 	M_RELEASE_OBSERVABLE				= Observable_message_base,
51 
52 	// SUGGESTED BUT NOT REQUIRED FOR IObservable IMPLEMENTATION:
53 	// *** IObservables are encouraged to send other replies!
54 	// sent upon successful receipt of M_ADD_OBSERVER
55 	// - "target" (BMessenger)
56 	M_OBSERVER_ADDED,
57 
58 	// SUGGESTED BUT NOT REQUIRED FOR IObservable IMPLEMENTATION:
59 	// *** IObservables are encouraged to send other replies!
60 	// sent upon successful receipt of M_REMOVE_OBSERVER
61 	// - "target" (BMessenger)
62 	M_OBSERVER_REMOVED,
63 
64 	// sent when no matching observer was found for an
65 	// M_REMOVE_OBSERVER message, or if the observer specified
66 	// in an M_ADD_OBSERVER message was previously added.
67 	// - "target" (BMessenger)
68 	// - "observer" (BMessenger)
69 	M_BAD_OBSERVER,
70 
71 	// sent when the target receiving an M_ADD_OBSERVER
72 	// or M_REMOVE_OBSERVER didn't match the target described
73 	// in the message.  also sent if the target is currently
74 	// in the process of quitting (it's already sent M_RELEASE_OBSERVABLE
75 	// to its current observers, and is waiting for them to acknowledge
76 	// with M_REMOVE_OBSERVER so that it can delete itself.)
77 	// - "target" (BMessenger)
78 	// - "observer" (BMessenger)
79 	M_BAD_TARGET
80 };
81 
82 // -------------------------------------------------------- //
83 // *** FUNCTIONS ***
84 // -------------------------------------------------------- //
85 
86 // * Asynchronous
87 
88 status_t add_observer(
89 	const BMessenger&				observer,
90 	const BMessenger&				target);
91 
92 status_t remove_observer(
93 	const BMessenger&				observer,
94 	const BMessenger&				target);
95 
96 // * Synchronous
97 
98 status_t add_observer(
99 	const BMessenger&				observer,
100 	const BMessenger&				target,
101 	BMessage&								reply,
102 	bigtime_t								timeout =B_INFINITE_TIMEOUT);
103 
104 status_t remove_observer(
105 	const BMessenger&				observer,
106 	const BMessenger&				target,
107 	BMessage&								reply,
108 	bigtime_t								timeout =B_INFINITE_TIMEOUT);
109 
110 // -------------------------------------------------------- //
111 // *** TOOL CLASSES ***
112 // -------------------------------------------------------- //
113 
114 template <class _observable_t>
115 class observer_handle {
116 
117 public:										// ctor/dtor
118 
119 	virtual ~observer_handle() {}
120 
121 	observer_handle(
122 		const BMessenger&			observer,
123 		_observable_t*				target,
124 		bigtime_t							timeout =B_INFINITE_TIMEOUT) :
125 
126 		_observer_messenger(observer),
127 		_target_messenger(target),
128 		_target_cache(target),
129 		_timeout(timeout),
130 		_valid(false) {
131 
132 		BMessage reply;
133 		status_t err = add_observer(
134 			_observer_messenger,
135 			_target_messenger,
136 			reply, timeout);
137 		if(err < B_OK) {
138 			PRINT((
139 				"! observer_handle<>(): add_observer() failed:\n"
140 				"  %s\n", strerror(err)));
141 #if DEBUG
142 			PRINT((
143 				"  * target's reply:\n"));
144 			reply.PrintToStream();
145 #endif
146 		}
147 		else _valid = true;
148 	}
149 
150 public:										// interface
151 
152 	virtual void release() {
153 		if(!_valid) {
154 			PRINT((
155 				"! observer_handle<>::release(): invalid or already released.\n"));
156 			return;
157 		}
158 
159 		BMessage reply;
160 		status_t err = remove_observer(
161 			_observer_messenger,
162 			_target_messenger,
163 			reply,
164 			_timeout);
165 		if(err < B_OK) {
166 			PRINT((
167 				"! observer_handle<>::release(): remove_observer() failed:\n"
168 				"  %s\n", strerror(err)));
169 #if DEBUG
170 			PRINT((
171 				"  * target's reply:\n"));
172 			reply.PrintToStream();
173 #endif
174 		}
175 
176 		_valid = false;
177 	}
178 
179 private:
180 	const BMessenger				_observer_messenger;
181 	BMessenger							_target_messenger;
182 	_observable_t*					_target_cache;
183 	bigtime_t								_timeout;
184 	bool										_valid;
185 };
186 
187 
188 __END_CORTEX_NAMESPACE
189 #endif /*__Observe_H__*/
190