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