xref: /haiku/src/apps/cortex/support/ObservableHandler.cpp (revision 1a7bcf6962e1c99906cce0fe602e08c3fcda46f6)
1 /*
2  * Copyright (c) 1999-2000, Eric Moon.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions, and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions, and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 
32 // ObservableHandler.cpp
33 
34 #include "ObservableHandler.h"
35 
36 #include <Debug.h>
37 #include <Looper.h>
38 
39 __USE_CORTEX_NAMESPACE
40 
41 // ---------------------------------------------------------------- //
42 // *** deletion
43 // ---------------------------------------------------------------- //
44 
45 // clients must call release() rather than deleting,
46 // to ensure that all observers are notified of the
47 // object's demise.  if the object has already been
48 // released, return an error.
49 
release()50 status_t ObservableHandler::release() {
51 	if(m_released)
52 		return B_NOT_ALLOWED;
53 
54 //	PRINT((
55 //		"ObservableHandler::release(): %ld targets\n", CountTargets()));
56 
57 	if(!LockLooper()) {
58 		ASSERT(!"failed to lock looper");
59 	}
60 
61 	m_released = true;
62 
63 	if(CountTargets()) {
64 		// notify
65 		notifyRelease();
66 		UnlockLooper();
67 	}
68 	else {
69 		releaseComplete();
70 		UnlockLooper();
71 		delete this;
72 	}
73 
74 	return B_OK;
75 }
76 
77 // ---------------------------------------------------------------- //
78 // *** ctor/dtor
79 // ---------------------------------------------------------------- //
80 
~ObservableHandler()81 ObservableHandler::~ObservableHandler() {
82 	if(CountTargets()) {
83 		PRINT((
84 			"*** ~ObservableHandler() '%s': %" B_PRId32 " observers remain\n",
85 			Name(), CountTargets()));
86 	}
87 }
88 
ObservableHandler(const char * name)89 ObservableHandler::ObservableHandler(
90 	const char*							name) :
91 	BHandler(name),
92 	m_released(false) {}
93 
ObservableHandler(BMessage * archive)94 ObservableHandler::ObservableHandler(
95 	BMessage*								archive) :
96 	BHandler(archive),
97 	m_released(false) {}
98 
99 // ---------------------------------------------------------------- //
100 // *** accessors
101 // ---------------------------------------------------------------- //
102 
103 // return true if release() has been called, false otherwise.
isReleased() const104 bool ObservableHandler::isReleased() const {
105 	return m_released;
106 }
107 
108 // ---------------------------------------------------------------- //
109 // *** hooks
110 // ---------------------------------------------------------------- //
111 
112 // sends M_OBSERVER_ADDED to the newly-added observer
observerAdded(const BMessenger & observer)113 void ObservableHandler::observerAdded(
114 	const BMessenger&				observer) {
115 
116 	BMessage m(M_OBSERVER_ADDED);
117 	m.AddMessenger("target", BMessenger(this));
118 	observer.SendMessage(&m);
119 }
120 
121 // sends M_OBSERVER_REMOVED to the newly-removed observer
observerRemoved(const BMessenger & observer)122 void ObservableHandler::observerRemoved(
123 	const BMessenger&				observer) {
124 
125 	BMessage m(M_OBSERVER_REMOVED);
126 	m.AddMessenger("target", BMessenger(this));
127 	observer.SendMessage(&m);
128 }
129 
130 // ---------------------------------------------------------------- //
131 // *** internal operations
132 // ---------------------------------------------------------------- //
133 
134 // call to send the given message to all observers.
135 // Responsibility for deletion of the message remains with
136 // the caller.
137 
notify(BMessage * message)138 status_t ObservableHandler::notify(
139 	BMessage*								message) {
140 #if DEBUG
141 	BLooper* l = Looper();
142 	ASSERT(l);
143 	ASSERT(l->IsLocked());
144 #endif
145 
146 	return Invoke(message);
147 }
148 
149 // sends M_RELEASE_OBSERVABLE
notifyRelease()150 void ObservableHandler::notifyRelease() {
151 	BMessage m(M_RELEASE_OBSERVABLE);
152 	m.AddMessenger("target", BMessenger(this));
153 	notify(&m);
154 }
155 
156 // ---------------------------------------------------------------- //
157 // *** BHandler
158 // ---------------------------------------------------------------- //
159 
MessageReceived(BMessage * message)160 void ObservableHandler::MessageReceived(
161 	BMessage*								message) {
162 
163 //	PRINT((
164 //		"### ObservableHandler::MessageReceived()\n"));
165 //	message->PrintToStream();
166 
167 	switch(message->what) {
168 		case M_ADD_OBSERVER:
169 			_handleAddObserver(message);
170 			break;
171 
172 		case M_REMOVE_OBSERVER:
173 			_handleRemoveObserver(message);
174 			break;
175 
176 		case M_KILL_OBSERVABLE:
177 			// +++++ this should be an optional feature
178 			releaseComplete();
179 			delete this; // BOOM!
180 			break;
181 
182 		default:
183 			_inherited::MessageReceived(message);
184 	}
185 }
186 
187 // ---------------------------------------------------------------- //
188 // *** BArchivable
189 // ---------------------------------------------------------------- //
190 
Archive(BMessage * archive,bool deep) const191 status_t ObservableHandler::Archive(
192 	BMessage*								archive,
193 	bool										deep) const {
194 
195 #if DEBUG
196 	BLooper* l = Looper();
197 	ASSERT(l);
198 	ASSERT(l->IsLocked());
199 #endif
200 	if(m_released)
201 		return B_NOT_ALLOWED; // can't archive a dead object
202 
203 	return _inherited::Archive(archive, deep);
204 }
205 
206 // ---------------------------------------------------------------- //
207 // implementation
208 // ---------------------------------------------------------------- //
209 
_handleAddObserver(BMessage * message)210 void ObservableHandler::_handleAddObserver(
211 	BMessage*								message) {
212 
213 #if DEBUG
214 	BLooper* l = Looper();
215 	ASSERT(l);
216 	ASSERT(l->IsLocked());
217 #endif
218 	BMessage reply;
219 
220 	BMessenger observer;
221 	status_t err = message->FindMessenger(
222 		"observer", &observer);
223 	if(err < B_OK) {
224 		PRINT((
225 			"* ObservableHandler::_handleAddObserver(): no observer specified!\n"));
226 		// send reply? +++++
227 		return;
228 	}
229 
230 	if(m_released) {
231 		// already quitting
232 		reply.what = M_BAD_TARGET;
233 		reply.AddMessenger("target", BMessenger(this));
234 		reply.AddMessenger("observer", observer);
235 		message->SendReply(&reply);
236 
237 		return;
238 	}
239 	else if(IndexOfTarget(observer.Target(0)) != -1) {
240 		// observer already added
241 		reply.what = M_BAD_OBSERVER;
242 		reply.AddMessenger("target", BMessenger(this));
243 		reply.AddMessenger("observer", observer);
244 		message->SendReply(&reply);
245 
246 		return;
247 	}
248 
249 	// valid observer given
250 
251 	// add it
252 	err = AddTarget(observer.Target(0));
253 	ASSERT(err == B_OK);
254 
255 	// call hook
256 	observerAdded(observer);
257 }
258 
_handleRemoveObserver(BMessage * message)259 void ObservableHandler::_handleRemoveObserver(
260 	BMessage*								message) {
261 
262 #if DEBUG
263 	BLooper* l = Looper();
264 	ASSERT(l);
265 	ASSERT(l->IsLocked());
266 #endif
267 	BMessage reply;
268 
269 	BMessenger observer;
270 	status_t err = message->FindMessenger(
271 		"observer", &observer);
272 	if(err < B_OK) {
273 		PRINT((
274 			"* ObservableHandler::_handleRemoveObserver(): no observer specified!\n"));
275 		// send reply? +++++
276 		return;
277 	}
278 
279 	int32 index = IndexOfTarget(observer.Target(0));
280 	if(index == -1) {
281 		reply.what = M_BAD_OBSERVER;
282 
283 		reply.AddMessenger("target", BMessenger(this));
284 		reply.AddMessenger("observer", observer);
285 		message->SendReply(&reply);
286 		return;
287 	}
288 
289 	// valid observer given; remove it & call notification hook
290 	RemoveTarget(index);
291 	observerRemoved(observer);
292 
293 	// time to shut down?
294 	if(m_released && !CountTargets()) {
295 		releaseComplete();
296 		delete this; // BOOM!
297 	}
298 }
299 
300 
301 // END -- ObservableHandler.cpp --
302