xref: /haiku/src/apps/cortex/support/ObservableHandler.cpp (revision d3d8b26997fac34a84981e6d2b649521de2cc45a)
1 // ObservableHandler.cpp
2 
3 #include "ObservableHandler.h"
4 
5 #include <Debug.h>
6 #include <Looper.h>
7 
8 __USE_CORTEX_NAMESPACE
9 
10 // ---------------------------------------------------------------- //
11 // *** deletion
12 // ---------------------------------------------------------------- //
13 
14 // clients must call release() rather than deleting,
15 // to ensure that all observers are notified of the
16 // object's demise.  if the object has already been
17 // released, return an error.
18 
19 status_t ObservableHandler::release() {
20 	if(m_released)
21 		return B_NOT_ALLOWED;
22 
23 //	PRINT((
24 //		"ObservableHandler::release(): %ld targets\n", CountTargets()));
25 
26 	if(!LockLooper()) {
27 		ASSERT(!"failed to lock looper");
28 	}
29 
30 	m_released = true;
31 
32 	if(CountTargets()) {
33 		// notify
34 		notifyRelease();
35 		UnlockLooper();
36 	}
37 	else {
38 		releaseComplete();
39 		UnlockLooper();
40 		delete this;
41 	}
42 
43 	return B_OK;
44 }
45 
46 // ---------------------------------------------------------------- //
47 // *** ctor/dtor
48 // ---------------------------------------------------------------- //
49 
50 ObservableHandler::~ObservableHandler() {
51 	if(CountTargets()) {
52 		PRINT((
53 			"*** ~ObservableHandler() '%s': %ld observers remain\n",
54 			Name(), CountTargets()));
55 	}
56 }
57 
58 ObservableHandler::ObservableHandler(
59 	const char*							name) :
60 	BHandler(name),
61 	m_released(false) {}
62 
63 ObservableHandler::ObservableHandler(
64 	BMessage*								archive) :
65 	BHandler(archive),
66 	m_released(false) {}
67 
68 // ---------------------------------------------------------------- //
69 // *** accessors
70 // ---------------------------------------------------------------- //
71 
72 // return true if release() has been called, false otherwise.
73 bool ObservableHandler::isReleased() const {
74 	return m_released;
75 }
76 
77 // ---------------------------------------------------------------- //
78 // *** hooks
79 // ---------------------------------------------------------------- //
80 
81 // sends M_OBSERVER_ADDED to the newly-added observer
82 void ObservableHandler::observerAdded(
83 	const BMessenger&				observer) {
84 
85 	BMessage m(M_OBSERVER_ADDED);
86 	m.AddMessenger("target", BMessenger(this));
87 	observer.SendMessage(&m);
88 }
89 
90 // sends M_OBSERVER_REMOVED to the newly-removed observer
91 void ObservableHandler::observerRemoved(
92 	const BMessenger&				observer) {
93 
94 	BMessage m(M_OBSERVER_REMOVED);
95 	m.AddMessenger("target", BMessenger(this));
96 	observer.SendMessage(&m);
97 }
98 
99 // ---------------------------------------------------------------- //
100 // *** internal operations
101 // ---------------------------------------------------------------- //
102 
103 // call to send the given message to all observers.
104 // Responsibility for deletion of the message remains with
105 // the caller.
106 
107 status_t ObservableHandler::notify(
108 	BMessage*								message) {
109 #if DEBUG
110 	BLooper* l = Looper();
111 	ASSERT(l);
112 	ASSERT(l->IsLocked());
113 #endif
114 
115 	return Invoke(message);
116 }
117 
118 // sends M_RELEASE_OBSERVABLE
119 void ObservableHandler::notifyRelease() {
120 	BMessage m(M_RELEASE_OBSERVABLE);
121 	m.AddMessenger("target", BMessenger(this));
122 	notify(&m);
123 }
124 
125 // ---------------------------------------------------------------- //
126 // *** BHandler
127 // ---------------------------------------------------------------- //
128 
129 void ObservableHandler::MessageReceived(
130 	BMessage*								message) {
131 
132 //	PRINT((
133 //		"### ObservableHandler::MessageReceived()\n"));
134 //	message->PrintToStream();
135 
136 	switch(message->what) {
137 		case M_ADD_OBSERVER:
138 			_handleAddObserver(message);
139 			break;
140 
141 		case M_REMOVE_OBSERVER:
142 			_handleRemoveObserver(message);
143 			break;
144 
145 		case M_KILL_OBSERVABLE:
146 			// +++++ this should be an optional feature
147 			releaseComplete();
148 			delete this; // BOOM!
149 			break;
150 
151 		default:
152 			_inherited::MessageReceived(message);
153 	}
154 }
155 
156 // ---------------------------------------------------------------- //
157 // *** BArchivable
158 // ---------------------------------------------------------------- //
159 
160 status_t ObservableHandler::Archive(
161 	BMessage*								archive,
162 	bool										deep) const {
163 
164 #if DEBUG
165 	BLooper* l = Looper();
166 	ASSERT(l);
167 	ASSERT(l->IsLocked());
168 #endif
169 	if(m_released)
170 		return B_NOT_ALLOWED; // can't archive a dead object
171 
172 	return _inherited::Archive(archive, deep);
173 }
174 
175 // ---------------------------------------------------------------- //
176 // implementation
177 // ---------------------------------------------------------------- //
178 
179 void ObservableHandler::_handleAddObserver(
180 	BMessage*								message) {
181 
182 #if DEBUG
183 	BLooper* l = Looper();
184 	ASSERT(l);
185 	ASSERT(l->IsLocked());
186 #endif
187 	BMessage reply;
188 
189 	BMessenger observer;
190 	status_t err = message->FindMessenger(
191 		"observer", &observer);
192 	if(err < B_OK) {
193 		PRINT((
194 			"* ObservableHandler::_handleAddObserver(): no observer specified!\n"));
195 		// send reply? +++++
196 		return;
197 	}
198 
199 	if(m_released) {
200 		// already quitting
201 		reply.what = M_BAD_TARGET;
202 		reply.AddMessenger("target", BMessenger(this));
203 		reply.AddMessenger("observer", observer);
204 		message->SendReply(&reply);
205 
206 		return;
207 	}
208 	else if(IndexOfTarget(observer.Target(0)) != -1) {
209 		// observer already added
210 		reply.what = M_BAD_OBSERVER;
211 		reply.AddMessenger("target", BMessenger(this));
212 		reply.AddMessenger("observer", observer);
213 		message->SendReply(&reply);
214 
215 		return;
216 	}
217 
218 	// valid observer given
219 
220 	// add it
221 	err = AddTarget(observer.Target(0));
222 	ASSERT(err == B_OK);
223 
224 	// call hook
225 	observerAdded(observer);
226 }
227 
228 void ObservableHandler::_handleRemoveObserver(
229 	BMessage*								message) {
230 
231 #if DEBUG
232 	BLooper* l = Looper();
233 	ASSERT(l);
234 	ASSERT(l->IsLocked());
235 #endif
236 	BMessage reply;
237 
238 	BMessenger observer;
239 	status_t err = message->FindMessenger(
240 		"observer", &observer);
241 	if(err < B_OK) {
242 		PRINT((
243 			"* ObservableHandler::_handleRemoveObserver(): no observer specified!\n"));
244 		// send reply? +++++
245 		return;
246 	}
247 
248 	int32 index = IndexOfTarget(observer.Target(0));
249 	if(index == -1) {
250 		reply.what = M_BAD_OBSERVER;
251 
252 		reply.AddMessenger("target", BMessenger(this));
253 		reply.AddMessenger("observer", observer);
254 		message->SendReply(&reply);
255 		return;
256 	}
257 
258 	// valid observer given; remove it & call notification hook
259 	RemoveTarget(index);
260 	observerRemoved(observer);
261 
262 	// time to shut down?
263 	if(m_released && !CountTargets()) {
264 		releaseComplete();
265 		delete this; // BOOM!
266 	}
267 }
268 
269 
270 // END -- ObservableHandler.cpp --