diff --git a/Core/CppMicroServices/src/service/usServiceReferenceBase.cpp b/Core/CppMicroServices/src/service/usServiceReferenceBase.cpp index 0ccd9d6559..6bc722f85e 100644 --- a/Core/CppMicroServices/src/service/usServiceReferenceBase.cpp +++ b/Core/CppMicroServices/src/service/usServiceReferenceBase.cpp @@ -1,201 +1,218 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include "usServiceReferenceBase.h" #include "usServiceReferenceBasePrivate.h" #include "usServiceRegistrationBasePrivate.h" #include "usModule.h" #include "usModulePrivate.h" US_BEGIN_NAMESPACE typedef ServiceRegistrationBasePrivate::MutexType MutexType; typedef MutexLock MutexLocker; ServiceReferenceBase::ServiceReferenceBase() : d(new ServiceReferenceBasePrivate(0)) { } ServiceReferenceBase::ServiceReferenceBase(const ServiceReferenceBase& ref) : d(ref.d) { d->ref.Ref(); } ServiceReferenceBase::ServiceReferenceBase(ServiceRegistrationBasePrivate* reg) : d(new ServiceReferenceBasePrivate(reg)) { } void ServiceReferenceBase::SetInterfaceId(const std::string& interfaceId) { if (d->ref > 1) { // detach d->ref.Deref(); d = new ServiceReferenceBasePrivate(d->registration); } d->interfaceId = interfaceId; } ServiceReferenceBase::operator bool() const { return GetModule() != 0; } ServiceReferenceBase& ServiceReferenceBase::operator=(int null) { if (null == 0) { if (!d->ref.Deref()) delete d; d = new ServiceReferenceBasePrivate(0); } return *this; } ServiceReferenceBase::~ServiceReferenceBase() { if (!d->ref.Deref()) delete d; } Any ServiceReferenceBase::GetProperty(const std::string& key) const { MutexLocker lock(d->registration->propsLock); return d->registration->properties.Value(key); } void ServiceReferenceBase::GetPropertyKeys(std::vector& keys) const { MutexLocker lock(d->registration->propsLock); const std::vector& ks = d->registration->properties.Keys(); keys.assign(ks.begin(), ks.end()); } Module* ServiceReferenceBase::GetModule() const { if (d->registration == 0 || d->registration->module == 0) { return 0; } return d->registration->module->q; } void ServiceReferenceBase::GetUsingModules(std::vector& modules) const { MutexLocker lock(d->registration->propsLock); ServiceRegistrationBasePrivate::ModuleToRefsMap::const_iterator end = d->registration->dependents.end(); for (ServiceRegistrationBasePrivate::ModuleToRefsMap::const_iterator iter = d->registration->dependents.begin(); iter != end; ++iter) { modules.push_back(iter->first); } } bool ServiceReferenceBase::operator<(const ServiceReferenceBase& reference) const { int r1 = 0; int r2 = 0; + if (!(*this)) + { + return true; + } + + if (!reference) + { + return false; + } + Any anyR1 = GetProperty(ServiceConstants::SERVICE_RANKING()); Any anyR2 = reference.GetProperty(ServiceConstants::SERVICE_RANKING()); if (anyR1.Type() == typeid(int)) r1 = any_cast(anyR1); if (anyR2.Type() == typeid(int)) r2 = any_cast(anyR2); if (r1 != r2) { // use ranking if ranking differs return r1 < r2; } else { long int id1 = any_cast(GetProperty(ServiceConstants::SERVICE_ID())); long int id2 = any_cast(reference.GetProperty(ServiceConstants::SERVICE_ID())); // otherwise compare using IDs, // is less than if it has a higher ID. return id2 < id1; } } bool ServiceReferenceBase::operator==(const ServiceReferenceBase& reference) const { return d->registration == reference.d->registration; } ServiceReferenceBase& ServiceReferenceBase::operator=(const ServiceReferenceBase& reference) { ServiceReferenceBasePrivate* curr_d = d; d = reference.d; d->ref.Ref(); if (!curr_d->ref.Deref()) delete curr_d; return *this; } bool ServiceReferenceBase::IsConvertibleTo(const std::string& interfaceId) const { return d->IsConvertibleTo(interfaceId); } std::string ServiceReferenceBase::GetInterfaceId() const { return d->interfaceId; } std::size_t ServiceReferenceBase::Hash() const { using namespace US_HASH_FUNCTION_NAMESPACE; return US_HASH_FUNCTION(ServiceRegistrationBasePrivate*, this->d->registration); } US_END_NAMESPACE US_USE_NAMESPACE std::ostream& operator<<(std::ostream& os, const ServiceReferenceBase& serviceRef) { - os << "Reference for service object registered from " - << serviceRef.GetModule()->GetName() << " " << serviceRef.GetModule()->GetVersion() - << " ("; - std::vector keys; - serviceRef.GetPropertyKeys(keys); - size_t keySize = keys.size(); - for(size_t i = 0; i < keySize; ++i) + if (serviceRef) + { + os << "Reference for service object registered from " + << serviceRef.GetModule()->GetName() << " " << serviceRef.GetModule()->GetVersion() + << " ("; + std::vector keys; + serviceRef.GetPropertyKeys(keys); + size_t keySize = keys.size(); + for(size_t i = 0; i < keySize; ++i) + { + os << keys[i] << "=" << serviceRef.GetProperty(keys[i]).ToString(); + if (i < keySize-1) os << ","; + } + os << ")"; + } + else { - os << keys[i] << "=" << serviceRef.GetProperty(keys[i]).ToString(); - if (i < keySize-1) os << ","; + os << "Invalid service reference"; } - os << ")"; return os; } diff --git a/Core/CppMicroServices/src/service/usServiceTracker.h b/Core/CppMicroServices/src/service/usServiceTracker.h index 1dee7e7eec..b0835bec14 100644 --- a/Core/CppMicroServices/src/service/usServiceTracker.h +++ b/Core/CppMicroServices/src/service/usServiceTracker.h @@ -1,600 +1,600 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #ifndef USSERVICETRACKER_H #define USSERVICETRACKER_H #include #include "usServiceReference.h" #include "usServiceTrackerCustomizer.h" #include "usLDAPFilter.h" US_BEGIN_NAMESPACE template class TrackedService; template class ServiceTrackerPrivate; class ModuleContext; /** * \ingroup MicroServices * * A base class template for type traits for objects tracked by a * ServiceTracker instance. It provides the \c TrackedType typedef * and two dummy method definitions. * * Tracked type traits (TTT) classes must additionally provide the * following methods: * *
    *
  • static bool IsValid(const TrackedType& t) Returns \c true if \c t is a valid object, \c false otherwise.
  • *
  • static void Dispose(TrackedType& t) Clears any resources held by the tracked object \c t.
  • *
  • static TrackedType DefaultValue() Returns the default value for newly created tracked objects.
  • *
* * @tparam T The type of the tracked object. * @tparam TTT The tracked type traits class deriving from this class. * * @see ServiceTracker */ template struct TrackedTypeTraitsBase { typedef T TrackedType; // Needed for S == void static TrackedType ConvertToTrackedType(const InterfaceMap&) { throw std::runtime_error("A custom ServiceTrackerCustomizer instance is required for custom tracked objects."); return TTT::DefaultValue(); } // Needed for S != void static TrackedType ConvertToTrackedType(void*) { throw std::runtime_error("A custom ServiceTrackerCustomizer instance is required for custom tracked objects."); return TTT::DefaultValue(); } }; /// \cond template struct TrackedTypeTraits; /// \endcond /** * \ingroup MicroServices * * Default type traits for custom tracked objects of pointer type. * * Use this tracked type traits template for custom tracked objects of * pointer type with the ServiceTracker class. * * @tparam S The type of the service being tracked. * @tparam T The type of the tracked object. */ template struct TrackedTypeTraits : public TrackedTypeTraitsBase > { typedef T* TrackedType; static bool IsValid(const TrackedType& t) { return t != NULL; } static TrackedType DefaultValue() { return NULL; } static void Dispose(TrackedType& t) { t = 0; } }; /// \cond template struct TrackedTypeTraits { typedef S* TrackedType; static bool IsValid(const TrackedType& t) { return t != NULL; } static TrackedType DefaultValue() { return NULL; } static void Dispose(TrackedType& t) { t = 0; } static TrackedType ConvertToTrackedType(S* s) { return s; } }; /// \endcond /// \cond /* * This specialization is "special" because the tracked type is not * void* (as specified in the second template parameter) but InterfaceMap. * This is in line with the ModuleContext::GetService(...) overloads to * return either S* or InterfaceMap dependening on the template parameter. */ template<> struct TrackedTypeTraits { typedef InterfaceMap TrackedType; static bool IsValid(const TrackedType& t) { return !t.empty(); } static TrackedType DefaultValue() { return TrackedType(); } static void Dispose(TrackedType& t) { t.clear(); } static TrackedType ConvertToTrackedType(const InterfaceMap& im) { return im; } }; /// \endcond /** * \ingroup MicroServices * * The ServiceTracker class simplifies using services from the * framework's service registry. *

* A ServiceTracker object is constructed with search criteria and * a ServiceTrackerCustomizer object. A ServiceTracker * can use a ServiceTrackerCustomizer to customize the service * objects to be tracked. The ServiceTracker can then be opened to * begin tracking all services in the framework's service registry that match * the specified search criteria. The ServiceTracker correctly * handles all of the details of listening to ServiceEvents and * getting and ungetting services. *

* The GetServiceReferences method can be called to get references * to the services being tracked. The GetService and * GetServices methods can be called to get the service objects for * the tracked service. * * \note The ServiceTracker class is thread-safe. It does not call a * ServiceTrackerCustomizer while holding any locks. * ServiceTrackerCustomizer implementations must also be * thread-safe. * * Customization of the services to be tracked requires a custom tracked type traits * class if the custom tracked type is not a pointer type. To customize a tracked * service using a custom type with value-semantics like * \snippet uServices-servicetracker/main.cpp tt * the custom tracked type traits class should look like this: * \snippet uServices-servicetracker/main.cpp ttt * * For a custom tracked type, a ServiceTrackerCustomizer is required, which knows * how to associate the tracked service with the custom tracked type: * \snippet uServices-servicetracker/main.cpp customizer * The custom tracking type traits class and customizer can now be used to instantiate * a ServiceTracker: * \snippet uServices-servicetracker/main.cpp tracker * * If the custom tracked type is a pointer type, a suitable tracked type traits * template is provided by the framework and only a ServiceTrackerCustomizer needs * to be provided: * \snippet uServices-servicetracker/main.cpp tracker2 * * * @tparam S The type of the service being tracked. The type S* must be an * assignable datatype. Further, if the * ServiceTracker(ModuleContext*, ServiceTrackerCustomizer*) * constructor is used, the type must have an associated interface id via * #US_DECLARE_SERVICE_INTERFACE. * @tparam TTT Type traits of the tracked object. The type traits class provides * information about the customized service object, see TrackedTypeTraitsBase. * * @remarks This class is thread safe. */ template > class ServiceTracker : protected ServiceTrackerCustomizer { public: /// The type of the service being tracked typedef S ServiceT; /// The type of the tracked object typedef typename TTT::TrackedType T; typedef ServiceReference ServiceReferenceT; typedef std::map,T> TrackingMap; ~ServiceTracker(); /** * Create a ServiceTracker on the specified * ServiceReference. * *

* The service referenced by the specified ServiceReference * will be tracked by this ServiceTracker. * * @param context The ModuleContext against which the tracking * is done. * @param reference The ServiceReference for the service to be * tracked. * @param customizer The customizer object to call when services are added, * modified, or removed in this ServiceTracker. If * customizer is null, then this * ServiceTracker will be used as the * ServiceTrackerCustomizer and this * ServiceTracker will call the * ServiceTrackerCustomizer methods on itself. */ ServiceTracker(ModuleContext* context, const ServiceReferenceT& reference, ServiceTrackerCustomizer* customizer = 0); /** * Create a ServiceTracker on the specified class name. * *

* Services registered under the specified class name will be tracked by * this ServiceTracker. * * @param context The ModuleContext against which the tracking * is done. * @param clazz The class name of the services to be tracked. * @param customizer The customizer object to call when services are added, * modified, or removed in this ServiceTracker. If * customizer is null, then this * ServiceTracker will be used as the * ServiceTrackerCustomizer and this * ServiceTracker will call the * ServiceTrackerCustomizer methods on itself. */ ServiceTracker(ModuleContext* context, const std::string& clazz, ServiceTrackerCustomizer* customizer = 0); /** * Create a ServiceTracker on the specified * LDAPFilter object. * *

* Services which match the specified LDAPFilter object will be * tracked by this ServiceTracker. * * @param context The ModuleContext against which the tracking * is done. * @param filter The LDAPFilter to select the services to be * tracked. * @param customizer The customizer object to call when services are added, * modified, or removed in this ServiceTracker. If * customizer is null, then this ServiceTracker will be * used as the ServiceTrackerCustomizer and this * ServiceTracker will call the * ServiceTrackerCustomizer methods on itself. */ ServiceTracker(ModuleContext* context, const LDAPFilter& filter, ServiceTrackerCustomizer* customizer = 0); /** * Create a ServiceTracker on the class template * argument S. * *

* Services registered under the interface name of the class template * argument S will be tracked by this ServiceTracker. * * @param context The ModuleContext against which the tracking * is done. * @param customizer The customizer object to call when services are added, * modified, or removed in this ServiceTracker. If * customizer is null, then this ServiceTracker will be * used as the ServiceTrackerCustomizer and this * ServiceTracker will call the * ServiceTrackerCustomizer methods on itself. */ ServiceTracker(ModuleContext* context, ServiceTrackerCustomizer* customizer = 0); /** * Open this ServiceTracker and begin tracking services. * *

* Services which match the search criteria specified when this * ServiceTracker was created are now tracked by this * ServiceTracker. * * @throws std::logic_error If the ModuleContext * with which this ServiceTracker was created is no * longer valid. */ virtual void Open(); /** * Close this ServiceTracker. * *

* This method should be called when this ServiceTracker should * end the tracking of services. * *

* This implementation calls GetServiceReferences() to get the list * of tracked services to remove. */ virtual void Close(); /** * Wait for at least one service to be tracked by this * ServiceTracker. This method will also return when this * ServiceTracker is closed. * *

* It is strongly recommended that WaitForService is not used * during the calling of the ModuleActivator methods. * ModuleActivator methods are expected to complete in a short * period of time. * *

* This implementation calls GetService() to determine if a service * is being tracked. * * @return Returns the result of GetService(). */ virtual T WaitForService(unsigned long timeoutMillis = 0); /** * Return a list of ServiceReferences for all services being * tracked by this ServiceTracker. * - * @param refs List of ServiceReferences. + * @return List of ServiceReferences. */ - virtual void GetServiceReferences(std::vector& refs) const; + virtual std::vector GetServiceReferences() const; /** * Returns a ServiceReference for one of the services being * tracked by this ServiceTracker. * *

* If multiple services are being tracked, the service with the highest * ranking (as specified in its service.ranking property) is * returned. If there is a tie in ranking, the service with the lowest * service ID (as specified in its service.id property); that * is, the service that was registered first is returned. This is the same * algorithm used by ModuleContext::GetServiceReference(). * *

* This implementation calls GetServiceReferences() to get the list * of references for the tracked services. * * @return A ServiceReference for a tracked service. * @throws ServiceException if no services are being tracked. */ virtual ServiceReferenceT GetServiceReference() const; /** * Returns the service object for the specified * ServiceReference if the specified referenced service is * being tracked by this ServiceTracker. * * @param reference The reference to the desired service. * @return A service object or null if the service referenced * by the specified ServiceReference is not being * tracked. */ virtual T GetService(const ServiceReferenceT& reference) const; /** * Return a list of service objects for all services being tracked by this * ServiceTracker. * *

* This implementation calls GetServiceReferences() to get the list * of references for the tracked services and then calls * GetService(const ServiceReference&) for each reference to get the * tracked service object. * - * @param services A list of service objects or an empty list if no services + * @return A list of service objects or an empty list if no services * are being tracked. */ - virtual void GetServices(std::vector& services) const; + virtual std::vector GetServices() const; /** * Returns a service object for one of the services being tracked by this * ServiceTracker. * *

* If any services are being tracked, this implementation returns the result * of calling %GetService(%GetServiceReference()). * * @return A service object or null if no services are being * tracked. */ virtual T GetService() const; /** * Remove a service from this ServiceTracker. * * The specified service will be removed from this * ServiceTracker. If the specified service was being tracked * then the ServiceTrackerCustomizer::RemovedService method will * be called for that service. * * @param reference The reference to the service to be removed. */ virtual void Remove(const ServiceReferenceT& reference); /** * Return the number of services being tracked by this * ServiceTracker. * * @return The number of services being tracked. */ virtual int Size() const; /** * Returns the tracking count for this ServiceTracker. * * The tracking count is initialized to 0 when this * ServiceTracker is opened. Every time a service is added, * modified or removed from this ServiceTracker, the tracking * count is incremented. * *

* The tracking count can be used to determine if this * ServiceTracker has added, modified or removed a service by * comparing a tracking count value previously collected with the current * tracking count value. If the value has not changed, then no service has * been added, modified or removed from this ServiceTracker * since the previous tracking count was collected. * * @return The tracking count for this ServiceTracker or -1 if * this ServiceTracker is not open. */ virtual int GetTrackingCount() const; /** * Return a sorted map of the ServiceReferences and * service objects for all services being tracked by this * ServiceTracker. The map is sorted in natural order * of ServiceReference. That is, the last entry is the service * with the highest ranking and the lowest service id. * * @param tracked A TrackingMap with the ServiceReferences * and service objects for all services being tracked by this * ServiceTracker. If no services are being tracked, * then the returned map is empty. */ virtual void GetTracked(TrackingMap& tracked) const; /** * Return if this ServiceTracker is empty. * * @return true if this ServiceTracker is not tracking any * services. */ virtual bool IsEmpty() const; protected: /** * Default implementation of the * ServiceTrackerCustomizer::AddingService method. * *

* This method is only called when this ServiceTracker has been * constructed with a null ServiceTrackerCustomizer argument. * *

* This implementation returns the result of calling GetService * on the ModuleContext with which this * ServiceTracker was created passing the specified * ServiceReference. *

* This method can be overridden in a subclass to customize the service * object to be tracked for the service being added. In that case, take care * not to rely on the default implementation of * \link RemovedService(const ServiceReferenceT&, T service) removedService\endlink * to unget the service. * * @param reference The reference to the service being added to this * ServiceTracker. * @return The service object to be tracked for the service added to this * ServiceTracker. * @see ServiceTrackerCustomizer::AddingService(const ServiceReference&) */ T AddingService(const ServiceReferenceT& reference); /** * Default implementation of the * ServiceTrackerCustomizer::ModifiedService method. * *

* This method is only called when this ServiceTracker has been * constructed with a null ServiceTrackerCustomizer argument. * *

* This implementation does nothing. * * @param reference The reference to modified service. * @param service The service object for the modified service. * @see ServiceTrackerCustomizer::ModifiedService(const ServiceReference&, T) */ void ModifiedService(const ServiceReferenceT& reference, T service); /** * Default implementation of the * ServiceTrackerCustomizer::RemovedService method. * *

* This method is only called when this ServiceTracker has been * constructed with a null ServiceTrackerCustomizer argument. * *

* This implementation calls UngetService, on the * ModuleContext with which this ServiceTracker * was created, passing the specified ServiceReference. *

* This method can be overridden in a subclass. If the default * implementation of \link AddingService(const ServiceReferenceT&) AddingService\endlink * method was used, this method must unget the service. * * @param reference The reference to removed service. * @param service The service object for the removed service. * @see ServiceTrackerCustomizer::RemovedService(const ServiceReferenceT&, T) */ void RemovedService(const ServiceReferenceT& reference, T service); private: typedef ServiceTracker _ServiceTracker; typedef TrackedService _TrackedService; typedef ServiceTrackerPrivate _ServiceTrackerPrivate; typedef ServiceTrackerCustomizer _ServiceTrackerCustomizer; friend class TrackedService; friend class ServiceTrackerPrivate; _ServiceTrackerPrivate* const d; }; US_END_NAMESPACE #include "usServiceTracker.tpp" #endif // USSERVICETRACKER_H diff --git a/Core/CppMicroServices/src/service/usServiceTracker.tpp b/Core/CppMicroServices/src/service/usServiceTracker.tpp index ea9319d4c1..1e5e9467c8 100644 --- a/Core/CppMicroServices/src/service/usServiceTracker.tpp +++ b/Core/CppMicroServices/src/service/usServiceTracker.tpp @@ -1,459 +1,463 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include "usServiceTrackerPrivate.h" #include "usTrackedService_p.h" #include "usServiceException.h" #include "usModuleContext.h" #include #include US_BEGIN_NAMESPACE template ServiceTracker::~ServiceTracker() { Close(); delete d; } #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4355) #endif template ServiceTracker::ServiceTracker(ModuleContext* context, const ServiceReferenceT& reference, _ServiceTrackerCustomizer* customizer) : d(new _ServiceTrackerPrivate(this, context, reference, customizer)) { } template ServiceTracker::ServiceTracker(ModuleContext* context, const std::string& clazz, _ServiceTrackerCustomizer* customizer) : d(new _ServiceTrackerPrivate(this, context, clazz, customizer)) { } template ServiceTracker::ServiceTracker(ModuleContext* context, const LDAPFilter& filter, _ServiceTrackerCustomizer* customizer) : d(new _ServiceTrackerPrivate(this, context, filter, customizer)) { } template ServiceTracker::ServiceTracker(ModuleContext *context, _ServiceTrackerCustomizer* customizer) : d(new _ServiceTrackerPrivate(this, context, us_service_interface_iid(), customizer)) { const char* clazz = us_service_interface_iid(); if (clazz == 0) throw ServiceException("The service interface class has no US_DECLARE_SERVICE_INTERFACE macro"); } #ifdef _MSC_VER #pragma warning(pop) #endif template void ServiceTracker::Open() { _TrackedService* t; { typename _ServiceTrackerPrivate::Lock l(d); if (d->trackedService) { return; } US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::Open: " << d->filter; t = new _TrackedService(this, d->customizer); { typename _TrackedService::Lock l(*t); try { d->context->AddServiceListener(t, &_TrackedService::ServiceChanged, d->listenerFilter); std::vector references; if (!d->trackClass.empty()) { references = d->GetInitialReferences(d->trackClass, std::string()); } else { if (d->trackReference.GetModule() != 0) { references.push_back(d->trackReference); } else { /* user supplied filter */ references = d->GetInitialReferences(std::string(), (d->listenerFilter.empty()) ? d->filter.ToString() : d->listenerFilter); } } /* set tracked with the initial references */ t->SetInitial(references); } catch (const std::invalid_argument& e) { throw std::runtime_error(std::string("unexpected std::invalid_argument exception: ") + e.what()); } } d->trackedService = t; } /* Call tracked outside of synchronized region */ t->TrackInitial(); /* process the initial references */ } template void ServiceTracker::Close() { _TrackedService* outgoing; std::vector references; { typename _ServiceTrackerPrivate::Lock l(d); outgoing = d->trackedService; if (outgoing == 0) { return; } US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::close:" << d->filter; outgoing->Close(); - GetServiceReferences(references); + references = GetServiceReferences(); d->trackedService = 0; try { d->context->RemoveServiceListener(outgoing, &_TrackedService::ServiceChanged); } catch (const std::logic_error& /*e*/) { /* In case the context was stopped. */ } } d->Modified(); /* clear the cache */ { typename _TrackedService::Lock l(outgoing); outgoing->NotifyAll(); /* wake up any waiters */ } for(typename std::vector::const_iterator ref = references.begin(); ref != references.end(); ++ref) { outgoing->Untrack(*ref, ServiceEvent()); } if (d->DEBUG_OUTPUT) { typename _ServiceTrackerPrivate::Lock l(d); if ((d->cachedReference.GetModule() == 0) && !TTT::IsValid(d->cachedService)) { US_DEBUG(true) << "ServiceTracker::close[cached cleared]:" << d->filter; } } delete outgoing; d->trackedService = 0; } template typename ServiceTracker::T ServiceTracker::WaitForService(unsigned long timeoutMillis) { T object = GetService(); while (!TTT::IsValid(object)) { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return TTT::DefaultValue(); } { typename _TrackedService::Lock l(t); if (t->Size() == 0) { t->Wait(timeoutMillis); } } object = GetService(); } return object; } template -void ServiceTracker::GetServiceReferences(std::vector& refs) const +std::vector::ServiceReferenceT> +ServiceTracker::GetServiceReferences() const { + std::vector refs; _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ - return; + return refs; } { typename _TrackedService::Lock l(t); d->GetServiceReferences_unlocked(refs, t); } + return refs; } template typename ServiceTracker::ServiceReferenceT ServiceTracker::GetServiceReference() const { ServiceReferenceT reference; { typename _ServiceTrackerPrivate::Lock l(d); reference = d->cachedReference; } if (reference.GetModule() != 0) { US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::getServiceReference[cached]:" << d->filter; return reference; } US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::getServiceReference:" << d->filter; - std::vector references; - GetServiceReferences(references); + std::vector references = GetServiceReferences(); std::size_t length = references.size(); if (length == 0) { /* if no service is being tracked */ throw ServiceException("No service is being tracked"); } typename std::vector::const_iterator selectedRef = references.begin(); if (length > 1) { /* if more than one service, select highest ranking */ std::vector rankings(length); int count = 0; int maxRanking = std::numeric_limits::min(); typename std::vector::const_iterator refIter = references.begin(); for (std::size_t i = 0; i < length; i++) { Any rankingAny = refIter->GetProperty(ServiceConstants::SERVICE_RANKING()); int ranking = 0; if (rankingAny.Type() == typeid(int)) { ranking = any_cast(rankingAny); } rankings[i] = ranking; if (ranking > maxRanking) { selectedRef = refIter; maxRanking = ranking; count = 1; } else { if (ranking == maxRanking) { count++; } } ++refIter; } if (count > 1) { /* if still more than one service, select lowest id */ long int minId = std::numeric_limits::max(); refIter = references.begin(); for (std::size_t i = 0; i < length; i++) { if (rankings[i] == maxRanking) { Any idAny = refIter->GetProperty(ServiceConstants::SERVICE_ID()); long int id = 0; if (idAny.Type() == typeid(long int)) { id = any_cast(idAny); } if (id < minId) { selectedRef = refIter; minId = id; } } ++refIter; } } } { typename _ServiceTrackerPrivate::Lock l(d); d->cachedReference = *selectedRef; return d->cachedReference; } } template typename ServiceTracker::T ServiceTracker::GetService(const ServiceReferenceT& reference) const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return TTT::DefaultValue(); } { typename _TrackedService::Lock l(t); return t->GetCustomizedObject(reference); } } template -void ServiceTracker::GetServices(std::vector& services) const +std::vector::T> ServiceTracker::GetServices() const { + std::vector services; _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ - return; + return services; } { typename _TrackedService::Lock l(t); std::vector references; d->GetServiceReferences_unlocked(references, t); for(typename std::vector::const_iterator ref = references.begin(); ref != references.end(); ++ref) { services.push_back(t->GetCustomizedObject(*ref)); } } + return services; } template typename ServiceTracker::T ServiceTracker::GetService() const { { typename _ServiceTrackerPrivate::Lock l(d); const T& service = d->cachedService; if (TTT::IsValid(service)) { US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::getService[cached]:" << d->filter; return service; } } US_DEBUG(d->DEBUG_OUTPUT) << "ServiceTracker::getService:" << d->filter; try { ServiceReferenceT reference = GetServiceReference(); if (reference.GetModule() == 0) { return TTT::DefaultValue(); } { typename _ServiceTrackerPrivate::Lock l(d); return d->cachedService = GetService(reference); } } catch (const ServiceException&) { return TTT::DefaultValue(); } } template void ServiceTracker::Remove(const ServiceReferenceT& reference) { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return; } t->Untrack(reference, ServiceEvent()); } template int ServiceTracker::Size() const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return 0; } { typename _TrackedService::Lock l(t); return static_cast(t->Size()); } } template int ServiceTracker::GetTrackingCount() const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return -1; } { typename _TrackedService::Lock l(t); return t->GetTrackingCount(); } } template void ServiceTracker::GetTracked(TrackingMap& map) const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return; } { typename _TrackedService::Lock l(t); t->CopyEntries(map); } } template bool ServiceTracker::IsEmpty() const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return true; } { typename _TrackedService::Lock l(t); return t->IsEmpty(); } } template typename ServiceTracker::T ServiceTracker::AddingService(const ServiceReferenceT& reference) { return TTT::ConvertToTrackedType(d->context->GetService(reference)); } template void ServiceTracker::ModifiedService(const ServiceReferenceT& /*reference*/, T /*service*/) { /* do nothing */ } template void ServiceTracker::RemovedService(const ServiceReferenceT& reference, T /*service*/) { d->context->UngetService(reference); } US_END_NAMESPACE diff --git a/Core/CppMicroServices/src/service/usTrackedService.tpp b/Core/CppMicroServices/src/service/usTrackedService.tpp index 8851affbbe..59765b8d6a 100644 --- a/Core/CppMicroServices/src/service/usTrackedService.tpp +++ b/Core/CppMicroServices/src/service/usTrackedService.tpp @@ -1,124 +1,128 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ US_BEGIN_NAMESPACE template TrackedService::TrackedService(ServiceTracker* serviceTracker, ServiceTrackerCustomizer* customizer) : serviceTracker(serviceTracker), customizer(customizer) { } template void TrackedService::ServiceChanged(const ServiceEvent event) { /* * Check if we had a delayed call (which could happen when we * close). */ if (this->closed) { return; } ServiceReference reference = event.GetServiceReference(InterfaceT()); US_DEBUG(serviceTracker->d->DEBUG_OUTPUT) << "TrackedService::ServiceChanged[" - << event.GetType() << "]: " << reference; + << event.GetType() << "]: " << reference; + if (!reference) + { + return; + } switch (event.GetType()) { case ServiceEvent::REGISTERED : case ServiceEvent::MODIFIED : { if (!serviceTracker->d->listenerFilter.empty()) { // service listener added with filter this->Track(reference, event); /* * If the customizer throws an unchecked exception, it * is safe to let it propagate */ } else { // service listener added without filter if (serviceTracker->d->filter.Match(reference)) { this->Track(reference, event); /* * If the customizer throws an unchecked exception, * it is safe to let it propagate */ } else { this->Untrack(reference, event); /* * If the customizer throws an unchecked exception, * it is safe to let it propagate */ } } break; } case ServiceEvent::MODIFIED_ENDMATCH : case ServiceEvent::UNREGISTERING : this->Untrack(reference, event); /* * If the customizer throws an unchecked exception, it is * safe to let it propagate */ break; } } template void TrackedService::Modified() { Superclass::Modified(); /* increment the modification count */ serviceTracker->d->Modified(); } template typename TrackedService::T TrackedService::CustomizerAdding(ServiceReference item, const ServiceEvent& /*related*/) { return customizer->AddingService(item); } template void TrackedService::CustomizerModified(ServiceReference item, const ServiceEvent& /*related*/, T object) { customizer->ModifiedService(item, object); } template void TrackedService::CustomizerRemoved(ServiceReference item, const ServiceEvent& /*related*/, T object) { customizer->RemovedService(item, object); } US_END_NAMESPACE diff --git a/Core/CppMicroServices/test/modules/libH/usTestModuleH.cpp b/Core/CppMicroServices/test/modules/libH/usTestModuleH.cpp index 2352c039a4..b004be226a 100644 --- a/Core/CppMicroServices/test/modules/libH/usTestModuleH.cpp +++ b/Core/CppMicroServices/test/modules/libH/usTestModuleH.cpp @@ -1,147 +1,147 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include #include #include #include #include #include US_BEGIN_NAMESPACE struct TestModuleH { virtual ~TestModuleH() {} }; struct TestModuleH2 { virtual ~TestModuleH2() {} }; US_END_NAMESPACE US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(TestModuleH), "org.cppmicroservices.TestModuleH") US_DECLARE_SERVICE_INTERFACE(US_PREPEND_NAMESPACE(TestModuleH2), "org.cppmicroservices.TestModuleH2") US_BEGIN_NAMESPACE class TestProduct : public TestModuleH { - Module* caller; + // Module* caller; public: - TestProduct(Module* caller) - : caller(caller) + TestProduct(Module* /*caller*/) + //: caller(caller) {} }; class TestProduct2 : public TestProduct, public TestModuleH2 { public: TestProduct2(Module* caller) : TestProduct(caller) {} }; class TestModuleHPrototypeServiceFactory : public PrototypeServiceFactory { std::map > fcbind; // Map calling module with implementation public: InterfaceMap GetService(Module* caller, const ServiceRegistrationBase& /*sReg*/) { std::cout << "GetService (prototype) in H" << std::endl; TestProduct2* product = new TestProduct2(caller); fcbind[caller->GetModuleId()].push_back(product); return MakeInterfaceMap(product); } void UngetService(Module* caller, const ServiceRegistrationBase& /*sReg*/, const InterfaceMap& service) { TestProduct2* product = dynamic_cast(ExtractInterface(service)); delete product; fcbind[caller->GetModuleId()].remove(product); } }; class TestModuleHActivator : public ModuleActivator, public ServiceFactory { std::string thisServiceName; ServiceRegistration factoryService; ServiceRegistration prototypeFactoryService; ModuleContext* mc; std::map fcbind; // Map calling module with implementation TestModuleHPrototypeServiceFactory prototypeFactory; public: TestModuleHActivator() : thisServiceName(us_service_interface_iid()) , mc(NULL) {} void Load(ModuleContext* mc) { std::cout << "start in H" << std::endl; this->mc = mc; factoryService = mc->RegisterService(this); prototypeFactoryService = mc->RegisterService(static_cast(&prototypeFactory)); } void Unload(ModuleContext* /*mc*/) { factoryService.Unregister(); } InterfaceMap GetService(Module* caller, const ServiceRegistrationBase& /*sReg*/) { std::cout << "GetService in H" << std::endl; TestProduct* product = new TestProduct(caller); fcbind.insert(std::make_pair(caller->GetModuleId(), product)); return MakeInterfaceMap(product); } void UngetService(Module* caller, const ServiceRegistrationBase& /*sReg*/, const InterfaceMap& service) { TestModuleH* product = ExtractInterface(service); delete product; fcbind.erase(caller->GetModuleId()); } }; US_END_NAMESPACE US_EXPORT_MODULE_ACTIVATOR(TestModuleH, us::TestModuleHActivator) diff --git a/Core/CppMicroServices/test/usServiceTrackerTest.cpp b/Core/CppMicroServices/test/usServiceTrackerTest.cpp index d602d4bd02..0ea92e94bc 100644 --- a/Core/CppMicroServices/test/usServiceTrackerTest.cpp +++ b/Core/CppMicroServices/test/usServiceTrackerTest.cpp @@ -1,223 +1,283 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include "usServiceControlInterface.h" #include US_USE_NAMESPACE bool CheckConvertibility(const std::vector& refs, std::vector::const_iterator idBegin, std::vector::const_iterator idEnd) { std::vector ids; ids.assign(idBegin, idEnd); for (std::vector::const_iterator sri = refs.begin(); sri != refs.end(); ++sri) { for (std::vector::iterator idIter = ids.begin(); idIter != ids.end(); ++idIter) { if (sri->IsConvertibleTo(*idIter)) { ids.erase(idIter); break; } } } return ids.empty(); } +struct MyInterfaceOne { + virtual ~MyInterfaceOne() {} +}; +US_DECLARE_SERVICE_INTERFACE(MyInterfaceOne, "org.cppmicroservices.servicetrackertest.MyInterfaceOne") -int usServiceTrackerTest(int /*argc*/, char* /*argv*/[]) +struct MyInterfaceTwo { + virtual ~MyInterfaceTwo() {} +}; +US_DECLARE_SERVICE_INTERFACE(MyInterfaceTwo, "org.cppmicroservices.servicetrackertest.MyInterfaceTwo") + +class MyCustomizer : public us::ServiceTrackerCustomizer +{ + +public: + + MyCustomizer(us::ModuleContext* context) + : m_context(context) + {} + + virtual MyInterfaceOne* AddingService(const ServiceReferenceT& reference) + { + US_TEST_CONDITION_REQUIRED(reference, "AddingService() valid reference") + return m_context->GetService(reference); + } + + virtual void ModifiedService(const ServiceReferenceT& reference, MyInterfaceOne* service) + { + US_TEST_CONDITION(reference, "ModifiedService() valid reference") + US_TEST_CONDITION(service, "ModifiedService() valid service") + } + + virtual void RemovedService(const ServiceReferenceT& reference, MyInterfaceOne* service) + { + US_TEST_CONDITION(reference, "RemovedService() valid reference") + US_TEST_CONDITION(service, "RemovedService() valid service") + } + +private: + + us::ModuleContext* m_context; +}; + +void TestFilterString() +{ + us::ModuleContext* context = us::GetModuleContext(); + MyCustomizer customizer(context); + + us::LDAPFilter filter("(" + us::ServiceConstants::SERVICE_ID() + ">=0)"); + us::ServiceTracker tracker(context, filter, &customizer); + tracker.Open(); + + struct MyServiceOne : public MyInterfaceOne {}; + struct MyServiceTwo : public MyInterfaceTwo {}; + + MyServiceOne serviceOne; + MyServiceTwo serviceTwo; + + context->RegisterService(&serviceOne); + context->RegisterService(&serviceTwo); + + US_TEST_CONDITION(tracker.GetServiceReferences().size() == 1, "tracking count") +} + +void TestServiceTracker() { - US_TEST_BEGIN("ServiceTrackerTest") #ifdef US_PLATFORM_WINDOWS const std::string LIB_PATH = US_RUNTIME_OUTPUT_DIRECTORY; #else const std::string LIB_PATH = US_LIBRARY_OUTPUT_DIRECTORY; #endif ModuleContext* mc = GetModuleContext(); SharedLibrary libS(LIB_PATH, "TestModuleS"); #ifdef US_BUILD_SHARED_LIBS // Start the test target to get a service published. try { libS.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what() ); } #endif // 1. Create a ServiceTracker with ServiceTrackerCustomizer == null std::string s1("org.cppmicroservices.TestModuleSService"); ServiceReferenceU servref = mc->GetServiceReference(s1 + "0"); US_TEST_CONDITION_REQUIRED(servref != 0, "Test if registered service of id org.cppmicroservices.TestModuleSService0"); ServiceReference servCtrlRef = mc->GetServiceReference(); US_TEST_CONDITION_REQUIRED(servCtrlRef != 0, "Test if constrol service was registered"); ServiceControlInterface* serviceController = mc->GetService(servCtrlRef); US_TEST_CONDITION_REQUIRED(serviceController != 0, "Test valid service controller"); std::auto_ptr > st1(new ServiceTracker(mc, servref)); // 2. Check the size method with an unopened service tracker US_TEST_CONDITION_REQUIRED(st1->Size() == 0, "Test if size == 0"); // 3. Open the service tracker and see what it finds, // expect to find one instance of the implementation, // "org.cppmicroservices.TestModuleSService0" st1->Open(); - std::vector sa2; - st1->GetServiceReferences(sa2); + std::vector sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 1, "Checking ServiceTracker size"); US_TEST_CONDITION_REQUIRED(s1 + "0" == sa2[0].GetInterfaceId(), "Checking service implementation name"); // 5. Close this service tracker st1->Close(); // 6. Check the size method, now when the servicetracker is closed US_TEST_CONDITION_REQUIRED(st1->Size() == 0, "Checking ServiceTracker size"); // 7. Check if we still track anything , we should get null - sa2.clear(); - st1->GetServiceReferences(sa2); + sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.empty(), "Checking ServiceTracker size"); // 8. A new Servicetracker, this time with a filter for the object std::string fs = std::string("(") + ServiceConstants::OBJECTCLASS() + "=" + s1 + "*" + ")"; LDAPFilter f1(fs); st1.reset(new ServiceTracker(mc, f1)); // add a service serviceController->ServiceControl(1, "register", 7); // 9. Open the service tracker and see what it finds, // expect to find two instances of references to // "org.cppmicroservices.TestModuleSService*" // i.e. they refer to the same piece of code std::vector ids; ids.push_back((s1 + "0")); ids.push_back((s1 + "1")); ids.push_back((s1 + "2")); ids.push_back((s1 + "3")); st1->Open(); - sa2.clear(); - st1->GetServiceReferences(sa2); + sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 2, "Checking service reference count"); US_TEST_CONDITION_REQUIRED(CheckConvertibility(sa2, ids.begin(), ids.begin()+2), "Check for expected interface id [0]"); US_TEST_CONDITION_REQUIRED(sa2[1].IsConvertibleTo(s1 + "1"), "Check for expected interface id [1]"); // 10. Get libTestModuleS to register one more service and see if it appears serviceController->ServiceControl(2, "register", 1); - sa2.clear(); - st1->GetServiceReferences(sa2); + sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 3, "Checking service reference count"); US_TEST_CONDITION_REQUIRED(CheckConvertibility(sa2, ids.begin(), ids.begin()+3), "Check for expected interface id [2]"); // 11. Get libTestModuleS to register one more service and see if it appears serviceController->ServiceControl(3, "register", 2); - sa2.clear(); - st1->GetServiceReferences(sa2); + sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 4, "Checking service reference count"); US_TEST_CONDITION_REQUIRED(CheckConvertibility(sa2, ids.begin(), ids.end()), "Check for expected interface id [3]"); // 12. Get libTestModuleS to unregister one service and see if it disappears serviceController->ServiceControl(3, "unregister", 0); - sa2.clear(); - st1->GetServiceReferences(sa2); + sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 3, "Checking service reference count"); // 13. Get the highest ranking service reference, it should have ranking 7 ServiceReferenceU h1 = st1->GetServiceReference(); int rank = any_cast(h1.GetProperty(ServiceConstants::SERVICE_RANKING())); US_TEST_CONDITION_REQUIRED(rank == 7, "Check service rank"); // 14. Get the service of the highest ranked service reference InterfaceMap o1 = st1->GetService(h1); US_TEST_CONDITION_REQUIRED(!o1.empty(), "Check for non-null service"); // 14a Get the highest ranked service, directly this time InterfaceMap o3 = st1->GetService(); US_TEST_CONDITION_REQUIRED(!o3.empty(), "Check for non-null service"); US_TEST_CONDITION_REQUIRED(o1 == o3, "Check for equal service instances"); // 15. Now release the tracking of that service and then try to get it // from the servicetracker, which should yield a null object serviceController->ServiceControl(1, "unregister", 7); InterfaceMap o2 = st1->GetService(h1); US_TEST_CONDITION_REQUIRED(o2.empty(), "Checkt that service is null"); // 16. Get all service objects this tracker tracks, it should be 2 - std::vector ts1; - st1->GetServices(ts1); + std::vector ts1 = st1->GetServices(); US_TEST_CONDITION_REQUIRED(ts1.size() == 2, "Check service count"); // 17. Test the remove method. // First register another service, then remove it being tracked serviceController->ServiceControl(1, "register", 7); h1 = st1->GetServiceReference(); - std::vector sa3; - st1->GetServiceReferences(sa3); + std::vector sa3 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa3.size() == 3, "Check service reference count"); US_TEST_CONDITION_REQUIRED(CheckConvertibility(sa3, ids.begin(), ids.begin()+3), "Check for expected interface id [0]"); st1->Remove(h1); // remove tracking on one servref - sa2.clear(); - st1->GetServiceReferences(sa2); + sa2 = st1->GetServiceReferences(); US_TEST_CONDITION_REQUIRED(sa2.size() == 2, "Check service reference count"); // 18. Test the addingService method,add a service reference // 19. Test the removedService method, remove a service reference // 20. Test the waitForService method InterfaceMap o9 = st1->WaitForService(50); US_TEST_CONDITION_REQUIRED(!o9.empty(), "Checking WaitForService method"); +} + +int usServiceTrackerTest(int /*argc*/, char* /*argv*/[]) +{ + US_TEST_BEGIN("ServiceTrackerTest") + + TestFilterString(); + TestServiceTracker(); US_TEST_END() }