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 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 81 ObservableHandler::~ObservableHandler() { 82 if(CountTargets()) { 83 PRINT(( 84 "*** ~ObservableHandler() '%s': %ld observers remain\n", 85 Name(), CountTargets())); 86 } 87 } 88 89 ObservableHandler::ObservableHandler( 90 const char* name) : 91 BHandler(name), 92 m_released(false) {} 93 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. 104 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 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 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 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 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 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 191 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 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 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