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 50status_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 81ObservableHandler::~ObservableHandler() { 82 if(CountTargets()) { 83 PRINT(( 84 "*** ~ObservableHandler() '%s': %" B_PRId32 " observers remain\n", 85 Name(), CountTargets())); 86 } 87} 88 89ObservableHandler::ObservableHandler( 90 const char* name) : 91 BHandler(name), 92 m_released(false) {} 93 94ObservableHandler::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. 104bool ObservableHandler::isReleased() const { 105 return m_released; 106} 107 108// ---------------------------------------------------------------- // 109// *** hooks 110// ---------------------------------------------------------------- // 111 112// sends M_OBSERVER_ADDED to the newly-added observer 113void 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 122void 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 138status_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 150void ObservableHandler::notifyRelease() { 151 BMessage m(M_RELEASE_OBSERVABLE); 152 m.AddMessenger("target", BMessenger(this)); 153 notify(&m); 154} 155 156// ---------------------------------------------------------------- // 157// *** BHandler 158// ---------------------------------------------------------------- // 159 160void 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 191status_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 210void 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 259void 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