155076Sache//------------------------------------------------------------------------------
255076Sache//	Copyright (c) 2001-2002, OpenBeOS
355076Sache//
455076Sache//	Permission is hereby granted, free of charge, to any person obtaining a
555076Sache//	copy of this software and associated documentation files (the "Software"),
655076Sache//	to deal in the Software without restriction, including without limitation
755076Sache//	the rights to use, copy, modify, merge, publish, distribute, sublicense,
855076Sache//	and/or sell copies of the Software, and to permit persons to whom the
955076Sache//	Software is furnished to do so, subject to the following conditions:
1055076Sache//
1155076Sache//	The above copyright notice and this permission notice shall be included in
1255076Sache//	all copies or substantial portions of the Software.
1355076Sache//
1455076Sache//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1555076Sache//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1655076Sache//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1755076Sache//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1855076Sache//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1955076Sache//	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2055076Sache//	DEALINGS IN THE SOFTWARE.
2155076Sache//
2255076Sache//	File Name:		WatchingService.cpp
2355076Sache//	Author:			Ingo Weinhold (bonefish@users.sf.net)
2455076Sache//	Description:	Features everything needed to provide a watching service.
2555076Sache//------------------------------------------------------------------------------
2655076Sache
2755076Sache#include <List.h>
2855076Sache
2955076Sache#include "Watcher.h"
3055076Sache#include "WatchingService.h"
3155076Sache
3255076Sacheusing namespace std;
3355076Sache
3455076Sache/*!	\class WatchingService
3555076Sache	\brief Features everything needed to provide a watching service.
3655076Sache
3755076Sache	A watcher is represented by an object of the Watcher or a derived class.
3855076Sache	It is identified by its target BMessenger. The service can't contain
3955076Sache	more than one watcher with the same target BMessenger at a time.
4055076Sache
4155076Sache	New watchers can be registered with AddWatcher(), registered ones
4255076Sache	unregistered via RemoveRegister(). NotifyWatchers() sends a specified
4355076Sache	message to all registered watchers, or, if an optional WatcherFilter is
4455076Sache	supplied, only to those watchers it selects.
4555076Sache*/
4655076Sache
4755076Sache/*!	\var typedef map<BMessenger,Watcher*> WatchingService::watcher_map
4855076Sache	\brief Watcher container type.
4955076Sache
5055076Sache	Defined for convenience.
5155076Sache*/
5255076Sache
5355076Sache/*!	\var WatchingService::watcher_map WatchingService::fWatchers
5455076Sache	\brief Container for the watchers registered to the service.
5555076Sache
5655076Sache	For each registered watcher \code Watcher *watcher \endcode, the map
5755076Sache	contains an entry \code (watcher->Target(), watcher) \endcode.
5855076Sache*/
5955076Sache
6055076Sache
6155076Sache// constructor
6255076Sache/*!	\brief Creates a new watching service.
6355076Sache
6455076Sache	The list of watchers is initially empty.
6555076Sache*/
6655076SacheWatchingService::WatchingService()
6755076Sache	: fWatchers()
6855076Sache{
6955076Sache}
7055076Sache
7155076Sache// destructor
7255076Sache/*!	\brief Frees all resources associated with the object.
7355076Sache
7455076Sache	All registered watchers are deleted.
7555076Sache*/
7655076SacheWatchingService::~WatchingService()
7755076Sache{
7855076Sache	// delete the watchers
7955076Sache	for (watcher_map::iterator it = fWatchers.begin();
8055076Sache		 it != fWatchers.end();
8155076Sache		 ++it) {
8255076Sache		delete it->second;
8355076Sache	}
8455076Sache}
8555076Sache
8655076Sache// AddWatcher
8755076Sache/*!	\brief Registers a new watcher to the watching service.
8855076Sache
8955076Sache	The ownership of \a watcher is transfered to the watching service, that
9055076Sache	is the caller must not delete it after the method returns.
9155076Sache
9255076Sache	If the service already contains a Watcher with the same target BMessenger
9355076Sache	(Watcher::Target()), the old watcher is removed and deleted before the
9455076Sache	new one is added..
9555076Sache
9655076Sache	\param watcher The watcher to be registered.
9755076Sache	\return \c true, if \a watcher is not \c NULL and adding was successfully,
9855076Sache			\c false otherwise.
9955076Sache*/
10055076Sachebool
10155076SacheWatchingService::AddWatcher(Watcher *watcher)
10255076Sache{
10355076Sache	bool result = (watcher);
10455076Sache	if (result) {
10555076Sache		RemoveWatcher(watcher->Target(), true);
10655076Sache		fWatchers[watcher->Target()] = watcher;
10755076Sache	}
10855076Sache	return result;
10955076Sache}
11055076Sache
11155076Sache// AddWatcher
11255076Sache/*!	\brief Registers a new watcher to the watching service.
11355076Sache
11455076Sache	A new \c Watcher is created with \a target as its target and added to
11555076Sache	the watching service. The caller retains ownership of \a target, but the
11655076Sache	newly created Watcher is owned by the watching service.
11755076Sache
11855076Sache	If the service already contains a Watcher with the same target BMessenger
11955076Sache	(Watcher::Target()), the old watcher is removed and deleted before the
12055076Sache	new one is added..
12155076Sache
12255076Sache	\param target The target BMessenger a Watcher shall be registered for.
12355076Sache	\return \c true, if a new Watcher could be created and added successfully,
12455076Sache			\c false otherwise.
12555076Sache*/
12655076Sachebool
12755076SacheWatchingService::AddWatcher(const BMessenger &target)
12855076Sache{
12955076Sache	return AddWatcher(new(nothrow) Watcher(target));
13055076Sache}
13155076Sache
13255076Sache// RemoveWatcher
13355076Sache/*!	\brief Unregisters a watcher from the watching service and optionally
13455076Sache		   deletes it.
13555076Sache
13655076Sache	If \a deleteWatcher is \c false, the ownership of \a watcher is transfered
13755076Sache	to the caller, otherwise it is deleted.
13855076Sache
13955076Sache	\param watcher The watcher to be unregistered.
14055076Sache	\param deleteWatcher If \c true, the watcher is deleted after being
14155076Sache		   removed.
14255076Sache	\return \c true, if \a watcher was not \c NULL and registered to the
14355076Sache			watching service before, \c false otherwise.
14455076Sache*/
14555076Sachebool
14655076SacheWatchingService::RemoveWatcher(Watcher *watcher, bool deleteWatcher)
14755076Sache{
14855076Sache	watcher_map::iterator it = fWatchers.find(watcher->Target());
14955076Sache	bool result = (it != fWatchers.end() && it->second == watcher);
15055076Sache	if (result) {
15155076Sache		if (deleteWatcher)
15255076Sache			delete it->second;
15355076Sache		fWatchers.erase(it);
15455076Sache	}
15555076Sache	return result;
15655076Sache}
15755076Sache
15855076Sache// RemoveWatcher
15955076Sache/*!	\brief Unregisters a watcher from the watching service and optionally
16055076Sache		   deletes it.
16155076Sache
16255076Sache	The watcher is identified by its target BMessenger.
16355076Sache
16455076Sache	If \a deleteWatcher is \c false, the ownership of the concerned watcher is
16555076Sache	transfered to the caller, otherwise it is deleted.
16655076Sache
16755076Sache	\param target The target BMessenger identifying the watcher to be
16855076Sache		   unregistered.
16955076Sache	\param deleteWatcher If \c true, the watcher is deleted after being
17055076Sache		   removed.
17155076Sache	\return \c true, if a watcher with the specified target was registered to
17255076Sache			the watching service before, \c false otherwise.
17355076Sache*/
17455076Sachebool
17555076SacheWatchingService::RemoveWatcher(const BMessenger &target, bool deleteWatcher)
176{
177	watcher_map::iterator it = fWatchers.find(target);
178	bool result = (it != fWatchers.end());
179	if (result) {
180		if (deleteWatcher)
181			delete it->second;
182		fWatchers.erase(it);
183	}
184	return result;
185}
186
187// NotifyWatchers
188/*!	\brief Sends a notification message to all watcher targets selected by a
189		   supplied filter.
190
191	If no filter is supplied the message is sent to all watchers. Otherwise
192	each watcher (and the notification message) is passed to its
193	WatcherFilter::Filter() method and the message is sent only to those
194	watchers for which \c true is returned.
195
196	If a sending a message to a watcher's target failed, because it became
197	invalid, the watcher is unregistered and deleted.
198
199	\param message The message to be sent to the watcher targets.
200	\param filter The filter selecting the watchers to which the message
201		   is be sent. May be \c NULL.
202*/
203void
204WatchingService::NotifyWatchers(BMessage *message, WatcherFilter *filter)
205{
206	if (message) {
207		BList staleWatchers;
208		// deliver the message
209		for (watcher_map::iterator it = fWatchers.begin();
210			 it != fWatchers.end();
211			 ++it) {
212			Watcher *watcher = it->second;
213// TODO: If a watcher is invalid, but the filter never selects it, it will
214// not be removed.
215			if (!filter || filter->Filter(watcher, message)) {
216				status_t error = watcher->SendMessage(message);
217				if (error != B_OK && !watcher->Target().IsValid())
218					staleWatchers.AddItem(watcher);
219			}
220		}
221		// remove the stale watchers
222		for (int32 i = 0;
223			 Watcher *watcher = (Watcher*)staleWatchers.ItemAt(i);
224			 i++) {
225			RemoveWatcher(watcher, true);
226		}
227	}
228}
229
230