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