You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2018/05/02 16:55:18 UTC
celix git commit: CELIX-446: Adds celix_bundleContext_trackService(s)
impl to the bundle context/service tracker
Repository: celix
Updated Branches:
refs/heads/develop cd9e84149 -> 668ae88fa
CELIX-446: Adds celix_bundleContext_trackService(s) impl to the bundle context/service tracker
- Also adds an updated api to the properties impl
Project: http://git-wip-us.apache.org/repos/asf/celix/repo
Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/668ae88f
Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/668ae88f
Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/668ae88f
Branch: refs/heads/develop
Commit: 668ae88fa589982dcfd32f4882ddfcdb1726d32c
Parents: cd9e841
Author: Pepijn Noltes <pe...@gmail.com>
Authored: Wed May 2 18:54:13 2018 +0200
Committer: Pepijn Noltes <pe...@gmail.com>
Committed: Wed May 2 18:54:13 2018 +0200
----------------------------------------------------------------------
framework/include/bundle_context.h | 136 ++++++--
framework/include/bundle_event.h | 1 +
framework/include/celix/dm/DependencyManager.h | 4 +-
framework/include/celix_types.h | 2 +
framework/include/dm_dependency_manager.h | 1 +
framework/include/service_tracker.h | 30 +-
framework/private/mock/bundle_context_mock.c | 8 +-
framework/src/bundle_context.c | 113 ++++--
framework/src/bundle_context_private.h | 4 +-
framework/src/framework.c | 1 -
framework/src/service_tracker.c | 221 ++++++++----
framework/src/service_tracker_private.h | 21 +-
framework/tst/bundle_context_bundles_tests.cpp | 2 +-
framework/tst/bundle_context_services_test.cpp | 341 +++++++++++++++++++
utils/include/properties.h | 42 +++
utils/src/properties.c | 359 ++++++++++++--------
16 files changed, 1001 insertions(+), 285 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/celix/blob/668ae88f/framework/include/bundle_context.h
----------------------------------------------------------------------
diff --git a/framework/include/bundle_context.h b/framework/include/bundle_context.h
index 7a75af7..36547c4 100644
--- a/framework/include/bundle_context.h
+++ b/framework/include/bundle_context.h
@@ -193,7 +193,7 @@ bundleContext_getPropertyWithDefault(bundle_context_pt context, const char *name
*
* @return the dependency manager or NULL if unsuccessful.
*/
-dm_dependency_manager_t* celix_bundleContext_getDependencyManager(bundle_context_t *ctx);
+dm_dependency_manager_t* celix_bundleContext_getDependencyManager(celix_bundle_context_t *ctx);
/**
* Register a C lang service to the framework.
@@ -201,10 +201,10 @@ dm_dependency_manager_t* celix_bundleContext_getDependencyManager(bundle_context
* @param ctx The bundle context
* @param serviceName the service name, cannot be NULL
* @param svc the service object. Normally a pointer to a service struct (e.g. a struct with function pointers)
- * @param properties The meta properties assiated with the service. The service registration will take ownership of the properties
+ * @param properties The meta properties assiated with the service. The service registration will take ownership of the properties (e.g. no destroy needed)
* @return The serviceId, which should be >= 0. If < 0 then the registration was unsuccessful.
*/
-long celix_bundleContext_registerService(bundle_context_t *ctx, const char *serviceName, void *svc, properties_t *properties, const char *serviceVersion);
+long celix_bundleContext_registerService(celix_bundle_context_t *ctx, const char *serviceName, void *svc, const char *serviceVersion, celix_properties_t *properties);
/**
* Register a service for the specified language to the framework.
@@ -215,7 +215,7 @@ long celix_bundleContext_registerService(bundle_context_t *ctx, const char *serv
* @param properties The meta properties assiated with the service. The service registration will take ownership of the properties
* @return The serviceId, which should >= 0. If < 0 then the registration was unsuccessful.
*/
-long celix_bundleContext_registerServiceForLang(bundle_context_t *ctx, const char *serviceName, void *svc, properties_t *properties, const char *serviceVersion, const char* lang);
+long celix_bundleContext_registerServiceForLang(celix_bundle_context_t *ctx, const char *serviceName, void *svc, const char *serviceVersion, const char* lang, celix_properties_t *properties);
//TODO register service factory
@@ -228,11 +228,90 @@ long celix_bundleContext_registerServiceForLang(bundle_context_t *ctx, const cha
* @param ctx The bundle context
* @param serviceId The service id
*/
-void celix_bundleContext_unregisterService(bundle_context_t *ctx, long serviceId);
+void celix_bundleContext_unregisterService(celix_bundle_context_t *ctx, long serviceId);
+/**
+ * track service for the provided serviceName and/or filter.
+ * The highest ranking services will used for the callback.
+ * If a new and higher ranking services the callback with be called again with the new service.
+ * If a service is removed a the callback with be called with next highest ranking service or NULL as service.
+ *
+ * @param ctx The bundle context.
+ * @param serviceName The required service name to track
+ * @param serviceVersionRange Optional the service version range to track
+ * @param filter Optional the LDAP filter to use
+ * @param callbackHandle The data pointer, which will be used in the callbacks
+ * @param set is a required callback, which will be called when a new highest ranking service is set.
+ * @return the tracker id or < 0 if unsuccessful.
+ */
+long celix_bundleContext_trackService(
+ celix_bundle_context_t* ctx,
+ const char* serviceName,
+ const char* versioRange,
+ const char* filter,
+ void* callbackHandle,
+ void (*set)(void* handle, void* svc)
+);
+
+/**
+ * track services for the provided serviceName and/or filter.
+ *
+ * @param ctx The bundle context.
+ * @param serviceName The required service name to track
+ * @param serviceVersionRange Optional the service version range to track
+ * @param filter Optional the LDAP filter to use
+ * @param callbackHandle The data pointer, which will be used in the callbacks
+ * @param add is a required callback, which will be called when a service is added and initially for the existing service.
+ * @param remove is a required callback, which will be called when a service is removed
+ * @return the tracker id or < 0 if unsuccessful.
+ */
+long celix_bundleContext_trackServices(
+ celix_bundle_context_t* ctx,
+ const char* serviceName,
+ const char* versioRange,
+ const char* filter,
+ void* callbackHandle,
+ void (*add)(void* handle, void* svc),
+ void (*remove)(void* handle, void* svc)
+);
+
+typedef struct celix_service_tracker_options {
+ //service filter options
+ const char* serviceName;
+ const char* versionRange;
+ const char* filter;
+ const char* lang; //NULL -> 'CELIX_LANG_C'
+
+ //callback options
+ void* callbackHandle;
+
+ void (*set)(void *handle, void *svc); //highest ranking
+ void (*add)(void *handle, void *svc);
+ void (*remove)(void *handle, void *svc);
+ void (*modified)(void *handle, void *svc);
+
+ void (*setWithProperties)(void *handle, void *svc, const celix_properties_t *props); //highest ranking
+ void (*addWithProperties)(void *handle, void *svc, const celix_properties_t *props);
+ void (*removeWithProperties)(void *handle, void *svc, const celix_properties_t *props);
+ void (*modifiedWithProperties)(void *handle, void *svc, const celix_properties_t *props);
+
+ void (*setWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *owner); //highest ranking
+ void (*addWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *owner);
+ void (*removeWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *owner);
+ void (*modifiedWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *owner);
+} celix_service_tracker_options_t;
+
+/**
+ * Tracks services using the provided tracker options.
+ * The tracker options are only using during this call and can safely be freed/reused after this call returns.
+ *
+ * @param ctx The bundle context.
+ * @param opts The pointer to the tracker options.
+ * @return the tracker id or < 0 if unsuccessful.
+ */
+long celix_bundleContext_trackServicesWithOptions(celix_bundle_context_t *ctx, const celix_service_tracker_options_t *opts);
-//TODO track services
/**
* Get and lock the service with the provided service id
@@ -251,11 +330,11 @@ void celix_bundleContext_unregisterService(bundle_context_t *ctx, long serviceId
* @param bool returns true if a service was found.
*/
bool celix_bundleContext_useServiceWithId(
- bundle_context_t *ctx,
+ celix_bundle_context_t *ctx,
long serviceId,
const char *serviceName /*sanity check*/,
void *callbackHandle,
- void (*use)(void *handle, void* svc, const properties_t *props, const bundle_t *owner)
+ void (*use)(void *handle, void* svc, const celix_properties_t *props, const celix_bundle_t *owner)
);
/**
@@ -277,12 +356,12 @@ bool celix_bundleContext_useServiceWithId(
* @return True if a service was found.
*/
bool celix_bundleContext_useService(
- bundle_context_t *ctx,
+ celix_bundle_context_t *ctx,
const char* serviceName,
const char* versionRange,
const char* filter,
void *callbackHandle,
- void (*use)(void *handle, void *svc, const properties_t *props, const bundle_t *owner)
+ void (*use)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *owner)
);
/**
@@ -303,12 +382,12 @@ bool celix_bundleContext_useService(
* @param use The callback, which will be called when service is retrieved.
*/
void celix_bundleContext_useServices(
- bundle_context_t *ctx,
+ celix_bundle_context_t *ctx,
const char* serviceName,
const char* versionRange,
const char* filter,
void *callbackHandle,
- void (*use)(void *handle, void *svc, const properties_t *props, const bundle_t *owner)
+ void (*use)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *owner)
);
@@ -320,7 +399,7 @@ void celix_bundleContext_useServices(
* @param autoStart If the bundle should also be started.
* @return the bundleId >= 0 or < 0 if the bundle could not be installed and possibly started.
*/
-long celix_bundleContext_installBundle(bundle_context_t *ctx, const char *bundleLoc, bool autoStart);
+long celix_bundleContext_installBundle(celix_bundle_context_t *ctx, const char *bundleLoc, bool autoStart);
/**
* Uninstall the bundle with the provided bundle id. If needed the bundle will be stopped first.
@@ -329,7 +408,7 @@ long celix_bundleContext_installBundle(bundle_context_t *ctx, const char *bundle
* @param bundleId The bundle id to stop
* @return true if the bundle is correctly uninstalled. False if not.
*/
-bool celix_bundleContext_uninstallBundle(bundle_context_t *ctx, long bundleId);
+bool celix_bundleContext_uninstallBundle(celix_bundle_context_t *ctx, long bundleId);
/**
@@ -337,6 +416,8 @@ bool celix_bundleContext_uninstallBundle(bundle_context_t *ctx, long bundleId);
* requested bundle tracker ootions.
*/
typedef struct celix_bundle_tracker_options {
+ //TODO options to track framework & own bundle
+
/**
* Handle used in the tracker callbacks.
*/
@@ -348,7 +429,7 @@ typedef struct celix_bundle_tracker_options {
* @param bundle The bundle which has been started.
* The bundle pointer is only guaranteed to be valid during the callback.
*/
- void (*onStarted)(void *handle, const bundle_t *bundle); //highest ranking
+ void (*onStarted)(void *handle, const celix_bundle_t *bundle); //highest ranking
/**
* Tracker callback when a bundle is removed.
@@ -356,7 +437,7 @@ typedef struct celix_bundle_tracker_options {
* @param bundle The bundle which has been started.
* The bundle pointer is only guaranteed to be valid during the callback.
*/
- void (*onStopped)(void *handle, const bundle_t *bundle);
+ void (*onStopped)(void *handle, const celix_bundle_t *bundle);
//TODO callback for on installed, resolved, uninstalled ??
@@ -365,7 +446,7 @@ typedef struct celix_bundle_tracker_options {
* @param handle The handle, contains the value of the callbackHandle.
* @param event The bundle event. Is only valid during the callback.
*/
- void (*onBundleEvent)(void *handle, const bundle_event_t *event);
+ void (*onBundleEvent)(void *handle, const celix_bundle_event_t *event);
} celix_bundle_tracker_options_t;
/**
@@ -378,10 +459,11 @@ typedef struct celix_bundle_tracker_options {
* @return The bundle tracker id or < 0 if unsuccessful.
*/
long celix_bundleContext_trackBundlesWithOptions(
- bundle_context_t* ctx,
+ celix_bundle_context_t* ctx,
const celix_bundle_tracker_options_t *opts
);
+//TODO except framework & own bundle
/**
* track bundles
* The add bundle callback will also be called for already installed bundles.
@@ -393,10 +475,10 @@ long celix_bundleContext_trackBundlesWithOptions(
* @return The bundle tracker id or < 0 if unsuccessful.
*/
long celix_bundleContext_trackBundles(
- bundle_context_t* ctx,
+ celix_bundle_context_t* ctx,
void* callbackHandle,
- void (*onStarted)(void* handle, const bundle_t *bundle),
- void (*onStopped)(void *handle, const bundle_t *bundle)
+ void (*onStarted)(void* handle, const celix_bundle_t *bundle),
+ void (*onStopped)(void *handle, const celix_bundle_t *bundle)
);
/**
@@ -410,14 +492,16 @@ long celix_bundleContext_trackBundles(
* The bundle pointers are only guaranteed to be valid during the callback.
*/
void celix_bundleContext_useBundle(
- bundle_context_t *ctx,
+ celix_bundle_context_t *ctx,
long bundleId,
void *callbackHandle,
- void (*use)(void *handle, const bundle_t *bundle)
+ void (*use)(void *handle, const celix_bundle_t *bundle)
);
//TODO add useBundleWithState (bit wise or?)
+
+//TODO except framework & own bundle
/**
* Use the currently active (started) bundles.
* The provided callback will be called for all the currently started bundles.
@@ -428,9 +512,9 @@ void celix_bundleContext_useBundle(
* The bundle pointers are only guaranteed to be valid during the callback.
*/
void celix_bundleContext_useBundles(
- bundle_context_t *ctx,
+ celix_bundle_context_t *ctx,
void *callbackHandle,
- void (*use)(void *handle, const bundle_t *bundle)
+ void (*use)(void *handle, const celix_bundle_t *bundle)
);
@@ -443,7 +527,7 @@ void celix_bundleContext_useBundles(
*
* Will log a error if the provided tracker id is unknown. Will silently ignore trackerId < 0.
*/
-void celix_bundleContext_stopTracking(bundle_context_t *ctx, long trackerId);
+void celix_bundleContext_stopTracker(celix_bundle_context_t *ctx, long trackerId);
http://git-wip-us.apache.org/repos/asf/celix/blob/668ae88f/framework/include/bundle_event.h
----------------------------------------------------------------------
diff --git a/framework/include/bundle_event.h b/framework/include/bundle_event.h
index 5ab604b..5a1a8bc 100644
--- a/framework/include/bundle_event.h
+++ b/framework/include/bundle_event.h
@@ -47,6 +47,7 @@ enum bundle_event_type {
typedef enum bundle_event_type bundle_event_type_e;
typedef struct bundle_event *bundle_event_pt;
typedef struct bundle_event bundle_event_t;
+typedef struct bundle_event celix_bundle_event_t;
#include "service_reference.h"
#include "bundle.h"
http://git-wip-us.apache.org/repos/asf/celix/blob/668ae88f/framework/include/celix/dm/DependencyManager.h
----------------------------------------------------------------------
diff --git a/framework/include/celix/dm/DependencyManager.h b/framework/include/celix/dm/DependencyManager.h
index 8648bc9..258a311 100644
--- a/framework/include/celix/dm/DependencyManager.h
+++ b/framework/include/celix/dm/DependencyManager.h
@@ -36,12 +36,10 @@ namespace celix { namespace dm {
class DependencyManager {
public:
DependencyManager(bundle_context_pt ctx) : context(ctx) {
- this->cDepMan = nullptr;
- dependencyManager_create(context, &this->cDepMan);
+ this->cDepMan = celix_bundleContext_getDependencyManager(ctx);
}
virtual ~DependencyManager() {
- dependencyManager_destroy(this->cDepMan);
this->cDepMan = nullptr;
}
http://git-wip-us.apache.org/repos/asf/celix/blob/668ae88f/framework/include/celix_types.h
----------------------------------------------------------------------
diff --git a/framework/include/celix_types.h b/framework/include/celix_types.h
index 49e2548..7846c1c 100644
--- a/framework/include/celix_types.h
+++ b/framework/include/celix_types.h
@@ -27,6 +27,7 @@
typedef struct bundle * bundle_pt;
typedef struct bundle bundle_t;
+typedef struct bundle celix_bundle_t;
typedef struct bundleArchive *bundle_archive_pt;
typedef struct bundleArchive bundle_archive_t;
@@ -36,6 +37,7 @@ typedef struct bundleRevision bundle_revision_t;
typedef struct bundleContext *bundle_context_pt;
typedef struct bundleContext bundle_context_t;
+typedef struct bundleContext celix_bundle_context_t;
typedef struct dm_dependency_manager *dm_dependency_manager_pt;
typedef struct dm_dependency_manager dm_dependency_manager_t;
http://git-wip-us.apache.org/repos/asf/celix/blob/668ae88f/framework/include/dm_dependency_manager.h
----------------------------------------------------------------------
diff --git a/framework/include/dm_dependency_manager.h b/framework/include/dm_dependency_manager.h
index f48056e..1fce27f 100644
--- a/framework/include/dm_dependency_manager.h
+++ b/framework/include/dm_dependency_manager.h
@@ -42,6 +42,7 @@ extern "C" {
* Creates a dependency manager.
* Caller has ownership.
*/
+ //TODO make this private, dep man should always be retrieved from the bundle context
celix_status_t dependencyManager_create(bundle_context_t *context, dm_dependency_manager_t **manager);
/**
http://git-wip-us.apache.org/repos/asf/celix/blob/668ae88f/framework/include/service_tracker.h
----------------------------------------------------------------------
diff --git a/framework/include/service_tracker.h b/framework/include/service_tracker.h
index 84057b8..6b9fb2c 100644
--- a/framework/include/service_tracker.h
+++ b/framework/include/service_tracker.h
@@ -77,19 +77,10 @@ FRAMEWORK_EXPORT void serviceTracker_serviceChanged(service_listener_pt listener
**********************************************************************************************************************
**********************************************************************************************************************/
-typedef struct celix_service_tracker_options {
- const char *serviceName; //required serviceName
- const char *versionRange; //optional service range (e.g. "[1,2)" or "[1.1.0,1.2.0)")
- const char *filter;
-
- void *callbackHandle;
-
- //TODO adding for interceptors??
- void (*add)(void *handle, void *svc, const properties_t *svcProps, const bundle_t *svcOwner);
- void (*remove)(void *handle, void *svc, const properties_t *svcProps, const bundle_t *svcOwner);
- void (*modified)(void *handle, void *svc, const properties_t *svcProps, const bundle_t *svcOwner);
-} celix_service_tracker_options_t;
-
+/**
+ * Creates and starts (open) a service tracker.
+ * Note that is different from the serviceTracker_create function, because is also starts the service tracker
+ */
celix_service_tracker_t* celix_serviceTracker_create(
bundle_context_t *ctx,
const char *serviceName,
@@ -98,12 +89,21 @@ celix_service_tracker_t* celix_serviceTracker_create(
);
+/**
+ * Creates and starts (open) a service tracker.
+ * Note that is different from the serviceTracker_create function, because is also starts the service tracker
+ */
celix_service_tracker_t* celix_serviceTracker_createWithOptions(
bundle_context_t *ctx,
const celix_service_tracker_options_t *opts
);
+/**
+ * Stops (close) and destroys a service tracker.
+ * Note that is different from the serviceTracker_destroy function, because is also stops the service tracker
+ */
+void celix_serviceTracker_destroy(celix_service_tracker_t *tracker);
/**
* Use the highest ranking service of the service tracker.
@@ -116,7 +116,7 @@ bool celix_serviceTracker_useHighestRankingService(
celix_service_tracker_t *tracker,
const char *serviceName /*sanity*/,
void *callbackHandle,
- void (*use)(void *handle, void *svc, const properties_t *props, const bundle_t *owner)
+ void (*use)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *owner)
);
@@ -127,7 +127,7 @@ void celix_serviceTracker_useServices(
service_tracker_t *tracker,
const char* serviceName /*sanity*/,
void *callbackHandle,
- void (*use)(void *handle, void *svc, const properties_t *props, const bundle_t *owner)
+ void (*use)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *owner)
);
#ifdef __cplusplus
http://git-wip-us.apache.org/repos/asf/celix/blob/668ae88f/framework/private/mock/bundle_context_mock.c
----------------------------------------------------------------------
diff --git a/framework/private/mock/bundle_context_mock.c b/framework/private/mock/bundle_context_mock.c
index ba7c0fc..67bf3be 100644
--- a/framework/private/mock/bundle_context_mock.c
+++ b/framework/private/mock/bundle_context_mock.c
@@ -194,7 +194,7 @@ celix_status_t bundleContext_getProperty(bundle_context_pt context, const char *
return mock_c()->returnValue().value.intValue;
}
-long celix_bundleContext_registerService(bundle_context_t *ctx, const char *serviceName, void *svc, properties_t *properties, const char *serviceVersion) {
+long celix_bundleContext_registerService(bundle_context_t *ctx, const char *serviceName, void *svc, const char *serviceVersion, properties_t *properties) {
mock_c()->actualCall("celix_bundleContext_registerCService")
->withPointerParameters("ctx", ctx)
->withStringParameters("serviceName", serviceName)
@@ -204,7 +204,7 @@ long celix_bundleContext_registerService(bundle_context_t *ctx, const char *serv
return mock_c()->returnValue().value.longIntValue;
}
-long celix_bundleContext_registerServiceForLang(bundle_context_t *ctx, const char *serviceName, void *svc, properties_t *properties, const char *serviceVersion, const char* lang) {
+long celix_bundleContext_registerServiceForLang(bundle_context_t *ctx, const char *serviceName, void *svc, const char *serviceVersion, const char* lang, properties_t *properties) {
mock_c()->actualCall("celix_bundleContext_registerServiceForLang")
->withPointerParameters("ctx", ctx)
->withStringParameters("serviceName", serviceName)
@@ -288,8 +288,8 @@ void celix_bundleContext_useBundle(
->withPointerParameters("use", use);
}
-void celix_bundleContext_stopTracking(bundle_context_t *ctx, long trackerId) {
- mock_c()->actualCall("celix_bundleContext_stopTracking")
+void celix_bundleContext_stopTracker(bundle_context_t *ctx, long trackerId) {
+ mock_c()->actualCall("celix_bundleContext_stopTracker")
->withPointerParameters("ctx", ctx)
->withLongIntParameters("trackerId", trackerId);
}
http://git-wip-us.apache.org/repos/asf/celix/blob/668ae88f/framework/src/bundle_context.c
----------------------------------------------------------------------
diff --git a/framework/src/bundle_context.c b/framework/src/bundle_context.c
index 955985f..b058d88 100644
--- a/framework/src/bundle_context.c
+++ b/framework/src/bundle_context.c
@@ -31,7 +31,8 @@
#include "dm_dependency_manager.h"
static celix_status_t bundleContext_bundleChanged(void *handle, bundle_event_t *event);
-static void bundleContext_stopAndDestroyBundleTracker(bundle_context_t *ctx, celix_bundle_context_bundle_tracker_t *tracker);
+static void bundleContext_cleanupBundleTracker(bundle_context_t *ct);
+static void bundleContext_cleanupServiceTracker(bundle_context_t *ctx);
celix_status_t bundleContext_create(framework_pt framework, framework_logger_pt logger, bundle_pt bundle, bundle_context_pt *bundle_context) {
celix_status_t status = CELIX_SUCCESS;
@@ -52,6 +53,7 @@ celix_status_t bundleContext_create(framework_pt framework, framework_logger_pt
arrayList_create(&context->svcRegistrations);
context->bundleTrackers = hashMap_create(NULL,NULL,NULL,NULL);
+ context->serviceTrackers = hashMap_create(NULL,NULL,NULL,NULL);
context->nextTrackerId = 1L;
*bundle_context = context;
@@ -68,14 +70,14 @@ celix_status_t bundleContext_destroy(bundle_context_pt context) {
celix_status_t status = CELIX_SUCCESS;
if (context != NULL) {
- hash_map_iterator_t iter = hashMapIterator_construct(context->bundleTrackers);
- while (hashMapIterator_hasNext(&iter)) {
- celix_bundle_context_bundle_tracker_t *tracker = hashMapIterator_nextValue(&iter);
- bundleContext_stopAndDestroyBundleTracker(context, tracker);
- }
+ celixThreadMutex_lock(&context->mutex);
+
+ bundleContext_cleanupBundleTracker(context);
+ bundleContext_cleanupServiceTracker(context);
//NOTE still present service registrations will be cleared during bundle stop in the
//service registry (serviceRegistry_clearServiceRegistrations).
+ celixThreadMutex_unlock(&context->mutex);
celixThreadMutex_destroy(&context->mutex);
arrayList_destroy(context->svcRegistrations);
@@ -423,12 +425,12 @@ celix_status_t bundleContext_getPropertyWithDefault(bundle_context_pt context, c
**********************************************************************************************************************/
-long celix_bundleContext_registerService(bundle_context_t *ctx, const char *serviceName, void *svc, properties_t *properties, const char *serviceVersion) {
- return celix_bundleContext_registerServiceForLang(ctx, serviceName, svc, properties, serviceVersion, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
+long celix_bundleContext_registerService(bundle_context_t *ctx, const char *serviceName, void *svc, const char *serviceVersion, properties_t *properties) {
+ return celix_bundleContext_registerServiceForLang(ctx, serviceName, svc, serviceVersion, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE, properties);
}
-long celix_bundleContext_registerServiceForLang(bundle_context_t *ctx, const char *serviceName, void *svc, properties_t *properties, const char *serviceVersion, const char* lang) {
+long celix_bundleContext_registerServiceForLang(bundle_context_t *ctx, const char *serviceName, void *svc, const char *serviceVersion, const char* lang, properties_t *properties) {
long svcId = -1;
if (properties == NULL) {
properties = properties_create();
@@ -541,7 +543,7 @@ long celix_bundleContext_trackBundlesWithOptions(
fw_addBundleListener(ctx->framework, ctx->bundle, &tracker->listener);
celixThreadMutex_lock(&ctx->mutex);
- tracker->trackId = ++ctx->nextTrackerId;
+ tracker->trackId = ctx->nextTrackerId++;
celixThreadMutex_unlock(&ctx->mutex);
trackId = tracker->trackId;
@@ -589,21 +591,42 @@ void celix_bundleContext_useBundle(
celix_framework_useBundle(ctx->framework, bundleId, callbackHandle, use);
}
-static void bundleContext_stopAndDestroyBundleTracker(bundle_context_t *ctx, celix_bundle_context_bundle_tracker_t *tracker) {
- fw_removeBundleListener(ctx->framework, ctx->bundle, &tracker->listener);
- free(tracker);
+static void bundleContext_cleanupBundleTracker(bundle_context_t *ctx) {
+ hash_map_iterator_t iter = hashMapIterator_construct(ctx->bundleTrackers);
+ while (hashMapIterator_hasNext(&iter)) {
+ celix_bundle_context_bundle_tracker_t *tracker = hashMapIterator_nextValue(&iter);
+ fw_removeBundleListener(ctx->framework, ctx->bundle, &tracker->listener);
+ free(tracker);
+ }
+ hashMap_destroy(ctx->bundleTrackers, false, false);
}
-void celix_bundleContext_stopTracking(bundle_context_t *ctx, long trackerId) {
- //TODO service tracker, service tracker tracker
+static void bundleContext_cleanupServiceTracker(bundle_context_t *ctx) {
+ hash_map_iterator_t iter = hashMapIterator_construct(ctx->serviceTrackers);
+ while (hashMapIterator_hasNext(&iter)) {
+ celix_service_tracker_t *tracker = hashMapIterator_nextValue(&iter);
+ celix_serviceTracker_destroy(tracker);
+ }
+ hashMap_destroy(ctx->serviceTrackers, false, false);
+}
+
+
+void celix_bundleContext_stopTracker(bundle_context_t *ctx, long trackerId) {
if (ctx != NULL && trackerId >0) {
bool found = false;
celixThreadMutex_lock(&ctx->mutex);
if (hashMap_containsKey(ctx->bundleTrackers, (void*)trackerId)) {
found = true;
celix_bundle_context_bundle_tracker_t *tracker = hashMap_remove(ctx->bundleTrackers, (void*)trackerId);
- bundleContext_stopAndDestroyBundleTracker(ctx, tracker);
+ fw_removeBundleListener(ctx->framework, ctx->bundle, &tracker->listener);
+ free(tracker);
+ } else if (hashMap_containsKey(ctx->serviceTrackers, (void*)trackerId)) {
+ found = true;
+ service_tracker_t *tracker = hashMap_remove(ctx->serviceTrackers, (void*)trackerId);
+ celix_serviceTracker_destroy(tracker);
}
+ //TODO service tracker tracker
+
if (!found) {
framework_logIfError(logger, CELIX_ILLEGAL_ARGUMENT, NULL, "No tracker with id %li found'", trackerId);
}
@@ -669,10 +692,8 @@ bool celix_bundleContext_useService(
bool called = false;
service_tracker_t *trk = celix_serviceTracker_create(ctx, serviceName, versionRange, filter);
if (trk != NULL) {
- serviceTracker_open(trk);
called = celix_serviceTracker_useHighestRankingService(trk, serviceName, callbackHandle, use);
- serviceTracker_close(trk);
- serviceTracker_destroy(trk);
+ celix_serviceTracker_destroy(trk);
}
return called;
}
@@ -687,9 +708,57 @@ void celix_bundleContext_useServices(
void (*use)(void *handle, void *svc, const properties_t *props, const bundle_t *owner)) {
service_tracker_t *trk = celix_serviceTracker_create(ctx, serviceName, versionRange, filter);
if (trk != NULL) {
- serviceTracker_open(trk);
celix_serviceTracker_useServices(trk, serviceName, callbackHandle, use);
- serviceTracker_close(trk);
- serviceTracker_destroy(trk);
+ celix_serviceTracker_destroy(trk);
+ }
+}
+
+long celix_bundleContext_trackService(
+ bundle_context_t* ctx,
+ const char* serviceName,
+ const char* versionRange,
+ const char* filter,
+ void* callbackHandle,
+ void (*set)(void* handle, void* svc)) {
+ celix_service_tracker_options_t opts;
+ memset(&opts, 0, sizeof(opts));
+ opts.serviceName = serviceName;
+ opts.versionRange = versionRange;
+ opts.filter = filter;
+ opts.callbackHandle = callbackHandle;
+ opts.set = set;
+ return celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+}
+
+
+long celix_bundleContext_trackServices(
+ bundle_context_t* ctx,
+ const char* serviceName,
+ const char* versionRange,
+ const char* filter,
+ void* callbackHandle,
+ void (*add)(void* handle, void* svc),
+ void (*remove)(void* handle, void* svc)) {
+ celix_service_tracker_options_t opts;
+ memset(&opts, 0, sizeof(opts));
+ opts.serviceName = serviceName;
+ opts.versionRange = versionRange;
+ opts.filter = filter;
+ opts.callbackHandle = callbackHandle;
+ opts.add = add;
+ opts.remove = remove;
+ return celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+}
+
+
+long celix_bundleContext_trackServicesWithOptions(bundle_context_t *ctx, const celix_service_tracker_options_t *opts) {
+ long trackerId = -1;
+ celix_service_tracker_t *tracker = celix_serviceTracker_createWithOptions(ctx, opts);
+ if (tracker != NULL) {
+ celixThreadMutex_lock(&ctx->mutex);
+ trackerId = ctx->nextTrackerId++;
+ hashMap_put(ctx->serviceTrackers, (void*)trackerId, tracker);
+ celixThreadMutex_unlock(&ctx->mutex);
}
+ return trackerId;
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/celix/blob/668ae88f/framework/src/bundle_context_private.h
----------------------------------------------------------------------
diff --git a/framework/src/bundle_context_private.h b/framework/src/bundle_context_private.h
index b8160eb..43533f8 100644
--- a/framework/src/bundle_context_private.h
+++ b/framework/src/bundle_context_private.h
@@ -47,8 +47,8 @@ struct bundleContext {
array_list_t *svcRegistrations;
dm_dependency_manager_t *mng;
long nextTrackerId;
- hash_map_t *bundleTrackers; //key = trackId, value = celix_bundle_context_bundle_tracker_t
-
+ hash_map_t *bundleTrackers; //key = trackerId, value = celix_bundle_context_bundle_tracker_t*
+ hash_map_t *serviceTrackers; //key = trackerId, value = celix_service_tracker_t*
};
http://git-wip-us.apache.org/repos/asf/celix/blob/668ae88f/framework/src/framework.c
----------------------------------------------------------------------
diff --git a/framework/src/framework.c b/framework/src/framework.c
index 37e2cd4..b6cb825 100644
--- a/framework/src/framework.c
+++ b/framework/src/framework.c
@@ -1631,7 +1631,6 @@ void fw_removeServiceListener(framework_pt framework, bundle_pt bundle, service_
match->filter = NULL;
match->listener = NULL;
free(match);
- match = NULL;
}
}
http://git-wip-us.apache.org/repos/asf/celix/blob/668ae88f/framework/src/service_tracker.c
----------------------------------------------------------------------
diff --git a/framework/src/service_tracker.c b/framework/src/service_tracker.c
index c254acd..30040e6 100644
--- a/framework/src/service_tracker.c
+++ b/framework/src/service_tracker.c
@@ -16,13 +16,6 @@
*specific language governing permissions and limitations
*under the License.
*/
-/*
- * service_tracker.c
- *
- * \date Apr 20, 2010
- * \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- * \copyright Apache License, Version 2.0
- */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -36,13 +29,16 @@
#include "service_reference.h"
#include "celix_log.h"
#include "service_tracker_customizer_private.h"
+#include "bundle_context_private.h"
static celix_status_t serviceTracker_track(service_tracker_pt tracker, service_reference_pt reference, service_event_pt event);
static celix_status_t serviceTracker_untrack(service_tracker_pt tracker, service_reference_pt reference, service_event_pt event);
+static void serviceTracker_untrackTracked(celix_service_tracker_t *tracker, celix_tracked_entry_t *tracked);
static celix_status_t serviceTracker_invokeAddingService(celix_service_tracker_t *tracker, service_reference_pt ref, void **svcOut);
static celix_status_t serviceTracker_invokeAddService(celix_service_tracker_t *tracker, celix_tracked_entry_t *tracked);
static celix_status_t serviceTracker_invokeModifiedService(celix_service_tracker_t *tracker, celix_tracked_entry_t *tracked);
static celix_status_t serviceTracker_invokeRemovingService(celix_service_tracker_t *tracker, celix_tracked_entry_t *tracked);
+static void serviceTracker_checkAndInvokeSetService(void *handle, void *highestSvc, const properties_t *props, const bundle_t *bnd);
static inline void tracked_increaseUse(celix_tracked_entry_t *tracked);
static inline void tracked_decreaseUse(celix_tracked_entry_t *tracked);
@@ -78,6 +74,9 @@ celix_status_t serviceTracker_createWithFilter(bundle_context_pt context, const
arrayList_create(&(*tracker)->trackedServices);
(*tracker)->customizer = customizer;
(*tracker)->listener = NULL;
+
+ celixThreadMutex_create(&(*tracker)->mutex, NULL);
+ (*tracker)->currentHighestServiceId = -1;
}
framework_logIfError(logger, status, NULL, "Cannot create service tracker [filter=%s]", filter);
@@ -149,29 +148,28 @@ celix_status_t serviceTracker_open(service_tracker_pt tracker) {
}
celix_status_t serviceTracker_close(service_tracker_pt tracker) {
- celix_status_t status = CELIX_SUCCESS;
- if (status == CELIX_SUCCESS) {
- array_list_pt refs = serviceTracker_getServiceReferences(tracker);
- if (refs != NULL) {
- unsigned int i;
- for (i = 0; i < arrayList_size(refs); i++) {
- service_reference_pt ref = (service_reference_pt) arrayList_get(refs, i);
- status = serviceTracker_untrack(tracker, ref, NULL);
- }
- }
- arrayList_destroy(refs);
- }
- if (status == CELIX_SUCCESS) {
- status = bundleContext_removeServiceListener(tracker->context, tracker->listener);
- if(status == CELIX_SUCCESS) {
- free(tracker->listener);
- tracker->listener = NULL;
- }
+ //put all tracked entries in tmp array list, so that the untrack (etc) calls are not blocked.
+ int i;
+ celixThreadRwlock_writeLock(&tracker->lock);
+ fw_removeServiceListener(tracker->context->framework, tracker->context->bundle, tracker->listener); //remove in lock, to ensure no new tracked entry is added
+ size_t size = celix_arrayList_size(tracker->trackedServices);
+ celix_tracked_entry_t* trackedEntries[size];
+ for (i = 0; i < arrayList_size(tracker->trackedServices); i++) {
+ trackedEntries[i] = (celix_tracked_entry_t*)arrayList_get(tracker->trackedServices, i);
}
- framework_logIfError(logger, status, NULL, "Cannot close tracker");
+ arrayList_clear(tracker->trackedServices);
+ celixThreadRwlock_unlock(&tracker->lock);
- return status;
+ //loop trough tracked entries an untrack
+ for (i = 0; i < size; i++) {
+ serviceTracker_untrackTracked(tracker, trackedEntries[i]);
+ }
+
+ free(tracker->listener);
+ tracker->listener = NULL;
+
+ return CELIX_SUCCESS;
}
service_reference_pt serviceTracker_getServiceReference(service_tracker_pt tracker) {
@@ -334,6 +332,7 @@ static celix_status_t serviceTracker_track(service_tracker_pt tracker, service_r
celixThreadRwlock_unlock(&tracker->lock);
serviceTracker_invokeAddService(tracker, tracked);
+ celix_serviceTracker_useHighestRankingService(tracker, tracked->serviceName, tracker, serviceTracker_checkAndInvokeSetService);
tracked_decreaseUse(tracked);
}
}
@@ -343,6 +342,39 @@ static celix_status_t serviceTracker_track(service_tracker_pt tracker, service_r
return status;
}
+static void serviceTracker_checkAndInvokeSetService(void *handle, void *highestSvc, const celix_properties_t *props, const celix_bundle_t *bnd) {
+ celix_service_tracker_t *tracker = handle;
+ bool update = false;
+ long svcId = -1;
+ if (highestSvc == NULL) {
+ //no services available anymore -> unset == call with NULL
+ update = true;
+ } else {
+ svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1);
+ }
+ if (svcId > 0) {
+ celixThreadMutex_lock(&tracker->mutex);
+ if (tracker->currentHighestServiceId != svcId) {
+ tracker->currentHighestServiceId = svcId;
+ update = true;
+ //update
+ }
+ celixThreadMutex_unlock(&tracker->mutex);
+ }
+ if (update) {
+ void *h = tracker->callbackHandle;
+ if (tracker->set != NULL) {
+ tracker->set(h, highestSvc);
+ }
+ if (tracker->setWithProperties != NULL) {
+ tracker->setWithProperties(h, highestSvc, props);
+ }
+ if (tracker->setWithOwner != NULL) {
+ tracker->setWithOwner(h, highestSvc, props, bnd);
+ }
+ }
+}
+
static celix_status_t serviceTracker_invokeModifiedService(service_tracker_pt tracker, celix_tracked_entry_t *tracked) {
celix_status_t status = CELIX_SUCCESS;
if (tracker->customizer != NULL) {
@@ -355,9 +387,16 @@ static celix_status_t serviceTracker_invokeModifiedService(service_tracker_pt tr
if (function != NULL) {
function(handle, tracked->reference, tracked->service);
}
- if (tracker->modified != NULL) {
- tracker->modified(tracker->callbackHandle, tracked->service, tracked->properties, tracked->serviceOwner);
- }
+ }
+ void *handle = tracker->callbackHandle;
+ if (tracker->modified != NULL) {
+ tracker->modified(handle, tracked->service);
+ }
+ if (tracker->modifiedWithProperties != NULL) {
+ tracker->modifiedWithProperties(handle, tracked->service, tracked->properties);
+ }
+ if (tracker->modifiedWithOwner != NULL) {
+ tracker->modifiedWithOwner(handle, tracked->service, tracked->properties, tracked->serviceOwner);
}
return status;
}
@@ -374,9 +413,16 @@ static celix_status_t serviceTracker_invokeAddService(service_tracker_pt tracker
if (function != NULL) {
function(handle, tracked->reference, tracked->service);
}
- if (tracker->add != NULL) {
- tracker->add(tracker->callbackHandle, tracked->service, tracked->properties, tracked->serviceOwner);
- }
+ }
+ void *handle = tracker->callbackHandle;
+ if (tracker->add != NULL) {
+ tracker->add(handle, tracked->service);
+ }
+ if (tracker->addWithProperties != NULL) {
+ tracker->addWithProperties(handle, tracked->service, tracked->properties);
+ }
+ if (tracker->addWithOwner != NULL) {
+ tracker->addWithOwner(handle, tracked->service, tracked->properties, tracked->serviceOwner);
}
return status;
}
@@ -412,11 +458,15 @@ static celix_status_t serviceTracker_untrack(service_tracker_pt tracker, service
celix_status_t status = CELIX_SUCCESS;
celix_tracked_entry_t *remove = NULL;
unsigned int i;
+ unsigned int size;
+ const char *serviceName = NULL;
celixThreadRwlock_writeLock(&tracker->lock);
- for (i = 0; i < arrayList_size(tracker->trackedServices); i++) {
+ size = arrayList_size(tracker->trackedServices);
+ for (i = 0; i < size; i++) {
bool equals;
celix_tracked_entry_t *tracked = (celix_tracked_entry_t*) arrayList_get(tracker->trackedServices, i);
+ serviceName = tracked->serviceName;
serviceReference_equals(reference, tracked->reference, &equals);
if (equals) {
remove = tracked;
@@ -425,29 +475,40 @@ static celix_status_t serviceTracker_untrack(service_tracker_pt tracker, service
break;
}
}
+ size = arrayList_size(tracker->trackedServices); //updated size
celixThreadRwlock_unlock(&tracker->lock);
- serviceTracker_invokeRemovingService(tracker, remove);
-
- celixThreadMutex_lock(&remove->mutex);
- while (remove->useCount > 0) {
- celixThreadCondition_wait(&remove->useCond, &remove->mutex);
+ serviceTracker_untrackTracked(tracker, remove);
+ if (size == 0) {
+ serviceTracker_checkAndInvokeSetService(tracker, NULL, NULL, NULL);
+ } else {
+ celix_serviceTracker_useHighestRankingService(tracker, serviceName, tracker, serviceTracker_checkAndInvokeSetService);
}
- celixThreadMutex_unlock(&remove->mutex);
-
- //use count == 0, tracked entry is removed from trackedServices so there is no way it can be used again ->
- //safe to destroy.
-
- bundleContext_ungetServiceReference(tracker->context, reference);
- celixThreadMutex_destroy(&remove->mutex);
- celixThreadCondition_destroy(&remove->useCond);
- free(remove);
framework_logIfError(logger, status, NULL, "Cannot untrack reference");
return status;
}
+static void serviceTracker_untrackTracked(celix_service_tracker_t *tracker, celix_tracked_entry_t *tracked) {
+ if (tracked != NULL) {
+ serviceTracker_invokeRemovingService(tracker, tracked);
+ celixThreadMutex_lock(&tracked->mutex);
+ while (tracked->useCount > 0) {
+ celixThreadCondition_wait(&tracked->useCond, &tracked->mutex);
+ }
+ celixThreadMutex_unlock(&tracked->mutex);
+
+ //use count == 0, tracked entry is removed from trackedServices so there is no way it can be used again ->
+ //safe to destroy.
+
+ bundleContext_ungetServiceReference(tracker->context, tracked->reference);
+ celixThreadMutex_destroy(&tracked->mutex);
+ celixThreadCondition_destroy(&tracked->useCond);
+ free(tracked);
+ }
+}
+
static celix_status_t serviceTracker_invokeRemovingService(service_tracker_pt tracker, celix_tracked_entry_t *tracked) {
celix_status_t status = CELIX_SUCCESS;
bool ungetSuccess = true;
@@ -461,13 +522,20 @@ static celix_status_t serviceTracker_invokeRemovingService(service_tracker_pt tr
if (function != NULL) {
status = function(handle, tracked->reference, tracked->service);
}
- if (tracker->remove != NULL) {
- tracker->remove(tracker->callbackHandle, tracked->service, tracked->properties, tracked->serviceOwner);
- }
- if (status == CELIX_SUCCESS) {
- status = bundleContext_ungetService(tracker->context, tracked->reference, &ungetSuccess);
- }
- } else {
+ }
+
+ void *handle = tracker->callbackHandle;
+ if (tracker->remove != NULL) {
+ tracker->remove(handle, tracked->service);
+ }
+ if (tracker->addWithProperties != NULL) {
+ tracker->removeWithProperties(handle, tracked->service, tracked->properties);
+ }
+ if (tracker->removeWithOwner != NULL) {
+ tracker->removeWithOwner(handle, tracked->service, tracked->properties, tracked->serviceOwner);
+ }
+
+ if (status == CELIX_SUCCESS) {
status = bundleContext_ungetService(tracker->context, tracked->reference, &ungetSuccess);
}
@@ -487,7 +555,6 @@ static celix_status_t serviceTracker_invokeRemovingService(service_tracker_pt tr
**********************************************************************************************************************
**********************************************************************************************************************/
-
celix_service_tracker_t* celix_serviceTracker_create(
bundle_context_t *ctx,
const char *serviceName,
@@ -514,37 +581,65 @@ celix_service_tracker_t* celix_serviceTracker_createWithOptions(
tracker->trackedServices = celix_arrayList_create();
tracker->listener = NULL;
+ //setting callbacks
tracker->callbackHandle = opts->callbackHandle;
+ tracker->set = opts->set;
tracker->add = opts->add;
tracker->remove = opts->remove;
tracker->modified = opts->modified;
-
+ tracker->setWithProperties = opts->setWithProperties;
+ tracker->addWithProperties = opts->addWithProperties;
+ tracker->removeWithProperties = opts->removeWithProperties;
+ tracker->modifiedWithProperties = opts->modifiedWithProperties;
+ tracker->setWithOwner = opts->setWithOwner;
+ tracker->addWithOwner = opts->addWithOwner;
+ tracker->removeWithOwner = opts->removeWithOwner;
+ tracker->modifiedWithOwner = opts->modifiedWithOwner;
+
+ //highest service state
+ celixThreadMutex_create(&tracker->mutex, NULL);
+ tracker->currentHighestServiceId = -1;
+
+ //setting filter
+ const char *lang = opts->lang != NULL ? opts->lang : CELIX_FRAMEWORK_SERVICE_C_LANGUAGE;
if (opts->filter != NULL && opts->versionRange != NULL) {
//TODO version range
- asprintf(&tracker->filter, "&((%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, opts->serviceName, opts->filter);
+ asprintf(&tracker->filter, "&((%s=%s)(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, opts->serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang, opts->filter);
} else if (opts->versionRange != NULL) {
//TODO version range
- asprintf(&tracker->filter, "(%s=%s)", OSGI_FRAMEWORK_OBJECTCLASS, opts->serviceName);
+ asprintf(&tracker->filter, "&((%s=%s)(%s=%s))", OSGI_FRAMEWORK_OBJECTCLASS, opts->serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang);
} else if (opts->filter != NULL) {
- asprintf(&tracker->filter, "(&(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, opts->serviceName, opts->filter);
+ asprintf(&tracker->filter, "(&(%s=%s)(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, opts->serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang, opts->filter);
} else {
- asprintf(&tracker->filter, "(%s=%s)", OSGI_FRAMEWORK_OBJECTCLASS, opts->serviceName);
+ asprintf(&tracker->filter, "(&(%s=%s)(%s=%s))", OSGI_FRAMEWORK_OBJECTCLASS, opts->serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang);
}
+ //TODO open on other thread?
+ serviceTracker_open(tracker);
}
} else {
- framework_log(logger, OSGI_FRAMEWORK_LOG_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__, "Error incorrect arguments");
+ if (opts != NULL && opts->serviceName == NULL) {
+ framework_log(logger, OSGI_FRAMEWORK_LOG_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__, "Error incorrect arguments. Missing service name.");
+ } else {
+ framework_log(logger, OSGI_FRAMEWORK_LOG_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__, "Error incorrect arguments. Required context (%p) or opts (%p) is NULL", ctx, opts);
+ }
}
return tracker;
}
+void celix_serviceTracker_destroy(celix_service_tracker_t *tracker) {
+ if (tracker != NULL) {
+ serviceTracker_close(tracker);
+ serviceTracker_destroy(tracker);
+ }
+}
bool celix_serviceTracker_useHighestRankingService(
celix_service_tracker_t *tracker,
const char *serviceName /*sanity*/,
void *callbackHandle,
- void (*use)(void *handle, void *svc, const properties_t *props, const bundle_t *owner)) {
+ void (*use)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *owner)) {
bool called = false;
celix_tracked_entry_t *tracked = NULL;
celix_tracked_entry_t *highest = NULL;
http://git-wip-us.apache.org/repos/asf/celix/blob/668ae88f/framework/src/service_tracker_private.h
----------------------------------------------------------------------
diff --git a/framework/src/service_tracker_private.h b/framework/src/service_tracker_private.h
index efd43f6..b5c3abb 100644
--- a/framework/src/service_tracker_private.h
+++ b/framework/src/service_tracker_private.h
@@ -38,12 +38,27 @@ struct celix_serviceTracker {
service_listener_pt listener;
void *callbackHandle;
- void (*add)(void *handle, void *svc, const properties_t *svcProps, const bundle_t *svcOwner);
- void (*remove)(void *handle, void *svc, const properties_t *svcProps, const bundle_t *svcOwner);
- void (*modified)(void *handle, void *svc, const properties_t *svcProps, const bundle_t *svcOwner);
+
+ void (*set)(void *handle, void *svc); //highest ranking
+ void (*add)(void *handle, void *svc);
+ void (*remove)(void *handle, void *svc);
+ void (*modified)(void *handle, void *svc);
+
+ void (*setWithProperties)(void *handle, void *svc, const properties_t *props); //highest ranking
+ void (*addWithProperties)(void *handle, void *svc, const properties_t *props);
+ void (*removeWithProperties)(void *handle, void *svc, const properties_t *props);
+ void (*modifiedWithProperties)(void *handle, void *svc, const properties_t *props);
+
+ void (*setWithOwner)(void *handle, void *svc, const properties_t *props, const bundle_t *owner); //highest ranking
+ void (*addWithOwner)(void *handle, void *svc, const properties_t *props, const bundle_t *owner);
+ void (*removeWithOwner)(void *handle, void *svc, const properties_t *props, const bundle_t *owner);
+ void (*modifiedWithOwner)(void *handle, void *svc, const properties_t *props, const bundle_t *owner);
celix_thread_rwlock_t lock; //projects trackedServices
array_list_t *trackedServices;
+
+ celix_thread_mutex_t mutex; //protect current highest service id
+ long currentHighestServiceId;
};
struct celix_tracked_entry {
http://git-wip-us.apache.org/repos/asf/celix/blob/668ae88f/framework/tst/bundle_context_bundles_tests.cpp
----------------------------------------------------------------------
diff --git a/framework/tst/bundle_context_bundles_tests.cpp b/framework/tst/bundle_context_bundles_tests.cpp
index 4e3d11d..39fdb6c 100644
--- a/framework/tst/bundle_context_bundles_tests.cpp
+++ b/framework/tst/bundle_context_bundles_tests.cpp
@@ -167,7 +167,7 @@ TEST(CelixBundleContextBundlesTests, trackBundlesTest) {
*/
- celix_bundleContext_stopTracking(ctx, trackerId);
+ celix_bundleContext_stopTracker(ctx, trackerId);
};
/* IGNORE TODO need to add locks
http://git-wip-us.apache.org/repos/asf/celix/blob/668ae88f/framework/tst/bundle_context_services_test.cpp
----------------------------------------------------------------------
diff --git a/framework/tst/bundle_context_services_test.cpp b/framework/tst/bundle_context_services_test.cpp
index dbd06c9..69bae0b 100644
--- a/framework/tst/bundle_context_services_test.cpp
+++ b/framework/tst/bundle_context_services_test.cpp
@@ -25,6 +25,7 @@
#include <CppUTest/TestHarness.h>
#include <CppUTest/CommandLineTestRunner.h>
#include <zconf.h>
+#include <constants.h>
#include "bundle.h"
#include "properties.h"
@@ -246,3 +247,343 @@ TEST(CelixBundleContextServicesTests, registerAndUseWithForcedRaceCondition) {
unregisterThread.join();
std::cout << "unregister thread joined" << std::endl;
};
+
+
+TEST(CelixBundleContextServicesTests, servicesTrackerTest) {
+ int count = 0;
+ auto add = [](void *handle, void *svc) {
+ CHECK(svc != NULL);
+ int *c = static_cast<int*>(handle);
+ *c += 1;
+ };
+ auto remove = [](void *handle, void *svc) {
+ CHECK(svc != NULL);
+ int *c = static_cast<int*>(handle);
+ *c -= 1;
+ };
+
+ long trackerId = celix_bundleContext_trackServices(ctx, "calc", NULL, NULL, &count, add, remove);
+ CHECK(trackerId > 0);
+ CHECK_EQUAL(0, count);
+
+ long svcId1 = celix_bundleContext_registerService(ctx, "calc", (void*)0x100, NULL, NULL);
+ CHECK(svcId1 > 0);
+ CHECK_EQUAL(1, count);
+
+ long svcId2 = celix_bundleContext_registerService(ctx, "calc", (void*)0x200, NULL, NULL);
+ CHECK(svcId2 > 0);
+ CHECK_EQUAL(2, count);
+
+ celix_bundleContext_unregisterService(ctx, svcId1);
+ CHECK_EQUAL(1, count);
+
+ celix_bundleContext_stopTracker(ctx, trackerId);
+ celix_bundleContext_unregisterService(ctx, svcId2);
+}
+
+TEST(CelixBundleContextServicesTests, servicesTrackerInvalidArgsTest) {
+ long trackerId = celix_bundleContext_trackServices(NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ CHECK(trackerId < 0); //required ctx and service name missing
+ trackerId = celix_bundleContext_trackServices(ctx, NULL, NULL, NULL, NULL, NULL, NULL);
+ CHECK(trackerId < 0); //required service name missing
+ trackerId = celix_bundleContext_trackServices(ctx, "calc", NULL, NULL, NULL, NULL, NULL);
+ CHECK(trackerId >= 0); //valid
+ celix_bundleContext_stopTracker(ctx, trackerId);
+
+
+ //opts
+ trackerId = celix_bundleContext_trackServicesWithOptions(NULL, NULL);
+ CHECK(trackerId < 0); //required ctx and opts missing
+ trackerId = celix_bundleContext_trackServicesWithOptions(ctx, NULL);
+ CHECK(trackerId < 0); //required opts missing
+ celix_service_tracker_options_t opts{};
+ memset(&opts, 0, sizeof(opts));
+ trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+ CHECK(trackerId < 0); //required opts->serviceName missing
+ opts.serviceName = "calc";
+ trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+ CHECK(trackerId >= 0); //valid
+ celix_bundleContext_stopTracker(ctx, trackerId);
+}
+
+TEST(CelixBundleContextServicesTests, servicesTrackerTestWithAlreadyRegisteredServices) {
+ int count = 0;
+ auto add = [](void *handle, void *svc) {
+ CHECK(svc != NULL);
+ int *c = static_cast<int*>(handle);
+ *c += 1;
+ };
+ auto remove = [](void *handle, void *svc) {
+ CHECK(svc != NULL);
+ int *c = static_cast<int*>(handle);
+ *c -= 1;
+ };
+
+ long svcId1 = celix_bundleContext_registerService(ctx, "calc", (void*)0x010, NULL, NULL);
+ long svcId2 = celix_bundleContext_registerService(ctx, "calc", (void*)0x020, NULL, NULL);
+
+
+
+ long trackerId = celix_bundleContext_trackServices(ctx, "calc", NULL, NULL, &count, add, remove);
+ CHECK(trackerId > 0);
+ CHECK_EQUAL(2, count);
+
+ long svcId3 = celix_bundleContext_registerService(ctx, "calc", (void*)0x100, NULL, NULL);
+ CHECK(svcId1 > 0);
+ CHECK_EQUAL(3, count);
+
+ long svcId4 = celix_bundleContext_registerService(ctx, "calc", (void*)0x200, NULL, NULL);
+ CHECK(svcId2 > 0);
+ CHECK_EQUAL(4, count);
+
+ celix_bundleContext_unregisterService(ctx, svcId1);
+ celix_bundleContext_unregisterService(ctx, svcId3);
+ CHECK_EQUAL(2, count);
+
+ celix_bundleContext_stopTracker(ctx, trackerId);
+ celix_bundleContext_unregisterService(ctx, svcId2);
+ celix_bundleContext_unregisterService(ctx, svcId4);
+}
+
+TEST(CelixBundleContextServicesTests, servicesTrackerTestWithProperties) {
+ int count = 0;
+ auto add = [](void *handle, void *svc, const properties_t *props) {
+ CHECK(svc != NULL);
+ STRCMP_EQUAL("C", celix_properties_get(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE));
+ int *c = static_cast<int*>(handle);
+ *c += 1;
+ };
+ auto remove = [](void *handle, void *svc, const properties_t *props) {
+ CHECK(svc != NULL);
+ STRCMP_EQUAL("C", celix_properties_get(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE));
+ int *c = static_cast<int*>(handle);
+ *c -= 1;
+ };
+
+ long svcId1 = celix_bundleContext_registerService(ctx, "calc", (void*)0x100, NULL, NULL);
+
+ celix_service_tracker_options_t opts{};
+ memset(&opts, 0, sizeof(opts));
+ opts.serviceName = "calc";
+ opts.callbackHandle = &count;
+ opts.addWithProperties = add;
+ opts.removeWithProperties = remove;
+ long trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+ CHECK(trackerId > 0);
+ CHECK_EQUAL(1, count);
+
+ long svcId2 = celix_bundleContext_registerService(ctx, "calc", (void*)0x200, NULL, NULL);
+ CHECK(svcId1 > 0);
+ CHECK_EQUAL(2, count);
+
+ celix_bundleContext_unregisterService(ctx, svcId1);
+ celix_bundleContext_unregisterService(ctx, svcId2);
+ CHECK_EQUAL(0, count);
+
+ celix_bundleContext_stopTracker(ctx, trackerId);
+}
+
+TEST(CelixBundleContextServicesTests, servicesTrackerTestWithOwner) {
+ int count = 0;
+ auto add = [](void *handle, void *svc, const properties_t *props, const bundle_t *svcOwner) {
+ CHECK(svc != NULL);
+ STRCMP_EQUAL("C", celix_properties_get(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE));
+ CHECK(celix_bundle_getId(svcOwner) >= 0);
+ int *c = static_cast<int*>(handle);
+ *c += 1;
+ };
+ auto remove = [](void *handle, void *svc, const properties_t *props, const bundle_t *svcOwner) {
+ CHECK(svc != NULL);
+ STRCMP_EQUAL("C", celix_properties_get(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE));
+ CHECK(celix_bundle_getId(svcOwner) >= 0);
+ int *c = static_cast<int*>(handle);
+ *c -= 1;
+ };
+
+ long svcId1 = celix_bundleContext_registerService(ctx, "calc", (void*)0x100, NULL, NULL);
+
+ celix_service_tracker_options_t opts{};
+ memset(&opts, 0, sizeof(opts));
+ opts.serviceName = "calc";
+ opts.callbackHandle = &count;
+ opts.addWithOwner = add;
+ opts.removeWithOwner = remove;
+ long trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+ CHECK(trackerId > 0);
+ CHECK_EQUAL(1, count);
+
+ long svcId2 = celix_bundleContext_registerService(ctx, "calc", (void*)0x200, NULL, NULL);
+ CHECK(svcId1 > 0);
+ CHECK_EQUAL(2, count);
+
+ celix_bundleContext_unregisterService(ctx, svcId1);
+ celix_bundleContext_unregisterService(ctx, svcId2);
+ CHECK_EQUAL(0, count);
+
+ celix_bundleContext_stopTracker(ctx, trackerId);
+}
+
+TEST(CelixBundleContextServicesTests, serviceTrackerWithRaceConditionTest) {
+ struct calc {
+ int (*calc)(int);
+ };
+
+ const char *calcName = "calc";
+ struct calc svc;
+ svc.calc = [](int n) -> int {
+ return n * 42;
+ };
+
+ struct data {
+ std::mutex mutex{};
+ std::condition_variable sync{};
+ long svcId {-1};
+ bool inAddCall{false};
+ bool inRemoveCall{false};
+ bool readyToExit{false};
+ int result{0};
+ };
+ struct data data{};
+
+ auto add = [](void *handle, void *svc) {
+ CHECK(svc != NULL);
+
+ struct data *d = static_cast<struct data*>(handle);
+
+ std::unique_lock<std::mutex> lock(d->mutex);
+ d->inAddCall = true;
+ d->sync.notify_all();
+ d->sync.wait(lock, [d]{return d->readyToExit;});
+ lock.unlock();
+
+ struct calc *calc = static_cast<struct calc *>(svc);
+ int tmp = calc->calc(2);
+
+ lock.lock();
+ d->result = tmp;
+ lock.unlock();
+ };
+
+ auto remove = [](void *handle, void *svc) {
+ CHECK(svc != NULL);
+
+ struct data *d = static_cast<struct data*>(handle);
+
+ std::unique_lock<std::mutex> lock(d->mutex);
+ std::cout << "In Remove call. waiting for ready to exit" << std::endl;
+ d->inRemoveCall = true;
+ d->sync.notify_all();
+ d->sync.wait(lock, [d]{return d->readyToExit;});
+ lock.unlock();
+ };
+
+ long trackerId = trackerId = celix_bundleContext_trackServices(ctx, calcName, NULL, NULL, &data, add, remove);
+
+ std::thread registerThread{[&]{
+ long id = celix_bundleContext_registerService(ctx, calcName, &svc, NULL, NULL);
+ std::cout << "registered service with id " << id << std::endl;
+ std::lock_guard<std::mutex> lock{data.mutex};
+ data.svcId = id;
+ data.sync.notify_all();
+ }};
+
+ std::thread unregisterThread{[&]{
+ long id = -1;
+ std::unique_lock<std::mutex> lock(data.mutex);
+ data.sync.wait(lock, [&]{return data.svcId > 0;});
+ id = data.svcId;
+ lock.unlock();
+ std::cout << "trying to unregister ... with id " << id << std::endl;
+ celix_bundleContext_unregisterService(ctx, id);
+ std::cout << "done unregistering" << std::endl;
+ }};
+
+
+ std::cout << "waiting till inAddCall" << std::endl;
+ std::unique_lock<std::mutex> lock{data.mutex};
+ data.sync.wait(lock, [&]{return data.inAddCall;});
+ data.readyToExit = true;
+ data.sync.notify_all();
+ lock.unlock();
+
+ //let unregister sink in.
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ lock.lock();
+ std::cout << "triggering ready to exit" << std::endl;
+ data.readyToExit = true;
+ data.sync.notify_all();
+ lock.unlock();
+
+ registerThread.join();
+ unregisterThread.join();
+ std::cout << "threads joined" << std::endl;
+
+ CHECK_EQUAL(84, data.result);
+ CHECK(data.inAddCall);
+ CHECK(data.inRemoveCall);
+
+ celix_bundleContext_stopTracker(ctx, trackerId);
+};
+
+TEST(CelixBundleContextServicesTests, servicesTrackerSetTest) {
+ int count = 0;
+
+ void *svc1 = (void*)0x100; //no ranking
+ void *svc2 = (void*)0x200; //no ranking
+ void *svc3 = (void*)0x300; //10 ranking
+ void *svc4 = (void*)0x400; //5 ranking
+
+ auto set = [](void *handle, void *svc) {
+ CHECK(svc != NULL);
+ static int callCount = 0;
+ callCount += 1;
+ if (callCount == 1) {
+ //first time svc1 should be set (oldest service with equal ranking
+ CHECK_EQUAL(0x100, (long)svc);
+ } else if (callCount == 2) {
+ CHECK_EQUAL(0x300, (long)svc);
+ //second time svc3 should be set (highest ranking)
+ } else if (callCount == 3) {
+ //third time svc4 should be set (highest ranking
+ CHECK_EQUAL(0x400, (long)svc);
+ }
+
+ int *c = static_cast<int*>(handle);
+ *c = callCount;
+ };
+
+ long svcId1 = celix_bundleContext_registerService(ctx, "NA", svc1, NULL, NULL);
+ long svcId2 = celix_bundleContext_registerService(ctx, "NA", svc2, NULL, NULL);
+
+ //starting tracker should lead to first set call
+ celix_service_tracker_options_t opts;
+ memset(&opts, 0, sizeof(opts));
+ opts.callbackHandle = (void*)&count;
+ opts.serviceName = "NA";
+ opts.set = set;
+ long trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+ CHECK(trackerId > 0);
+
+ //register svc3 should lead to second set call
+ properties_t *props3 = celix_properties_create();
+ celix_properties_set(props3, OSGI_FRAMEWORK_SERVICE_RANKING, "10");
+ long svcId3 = celix_bundleContext_registerService(ctx, "NA", svc3, NULL, props3);
+
+ //register svc4 should lead to no set (lower ranking)
+ properties_t *props4 = celix_properties_create();
+ celix_properties_set(props4, OSGI_FRAMEWORK_SERVICE_RANKING, "10");
+ long svcId4 = celix_bundleContext_registerService(ctx, "NA", svc4, NULL, props4);
+
+ //unregister svc3 should lead to set (new highest ranking)
+ celix_bundleContext_unregisterService(ctx, svcId3);
+
+ celix_bundleContext_stopTracker(ctx, trackerId);
+ celix_bundleContext_unregisterService(ctx, svcId1);
+ celix_bundleContext_unregisterService(ctx, svcId2);
+ celix_bundleContext_unregisterService(ctx, svcId4);
+
+ CHECK_EQUAL(3, count); //check if the set is called the expected times
+}
+
+//TODO test tracker with options for properties & service owners
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/celix/blob/668ae88f/utils/include/properties.h
----------------------------------------------------------------------
diff --git a/utils/include/properties.h b/utils/include/properties.h
index 582a242..5a19cb7 100644
--- a/utils/include/properties.h
+++ b/utils/include/properties.h
@@ -38,6 +38,8 @@ extern "C" {
typedef hash_map_pt properties_pt;
typedef hash_map_t properties_t;
+typedef hash_map_t celix_properties_t;
+
UTILS_EXPORT properties_pt properties_create(void);
UTILS_EXPORT void properties_destroy(properties_pt properties);
@@ -63,6 +65,46 @@ UTILS_EXPORT celix_status_t properties_copy(properties_pt properties, properties
#define PROPERTIES_FOR_EACH(props, key) \
for(hash_map_iterator_t iter = hashMapIterator_construct(props); \
hashMapIterator_hasNext(&iter), (key) = (const char*)hashMapIterator_nextKey(&iter);)
+
+
+/**********************************************************************************************************************
+ **********************************************************************************************************************
+ * Updated API
+ **********************************************************************************************************************
+ **********************************************************************************************************************/
+
+celix_properties_t* celix_properties_create(void);
+
+void celix_properties_destroy(celix_properties_t *properties);
+
+celix_properties_t* celix_properties_load(const char *filename);
+
+celix_properties_t* celix_properties_loadWithStream(FILE *stream);
+
+celix_properties_t* celix_properties_loadFromString(const char *input);
+
+void celix_properties_store(celix_properties_t *properties, const char *file, const char *header);
+
+const char* celix_properties_get(const celix_properties_t *properties, const char *key);
+
+const char* celix_properties_getWithDefault(const celix_properties_t *properties, const char *key, const char *defaultValue);
+
+void celix_properties_set(celix_properties_t *properties, const char *key, const char *value);
+
+void celix_properties_unset(celix_properties_t *properties, const char *key);
+
+celix_properties_t* celix_properties_copy(celix_properties_t *properties);
+
+long celix_properties_getAsLong(const celix_properties_t *props, const char *key, long defaultValue);
+
+void celix_properties_setLong(celix_properties_t *props, const char *key, long value);
+
+#define CELIX_PROPERTIES_FOR_EACH(props, key) \
+ for(hash_map_iterator_t iter = hashMapIterator_construct(props); \
+ hashMapIterator_hasNext(&iter), (key) = (const char*)hashMapIterator_nextKey(&iter);)
+
+
+
#ifdef __cplusplus
}
#endif
http://git-wip-us.apache.org/repos/asf/celix/blob/668ae88f/utils/src/properties.c
----------------------------------------------------------------------
diff --git a/utils/src/properties.c b/utils/src/properties.c
index 860b9bb..5af5646 100644
--- a/utils/src/properties.c
+++ b/utils/src/properties.c
@@ -36,92 +36,23 @@
static void parseLine(const char* line, properties_pt props);
properties_pt properties_create(void) {
- return hashMap_create(utils_stringHash, utils_stringHash, utils_stringEquals, utils_stringEquals);
+ return celix_properties_create();
}
void properties_destroy(properties_pt properties) {
- hash_map_iterator_pt iter = hashMapIterator_create(properties);
- while (hashMapIterator_hasNext(iter)) {
- hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
- free(hashMapEntry_getKey(entry));
- free(hashMapEntry_getValue(entry));
- }
- hashMapIterator_destroy(iter);
- hashMap_destroy(properties, false, false);
+ celix_properties_destroy(properties);
}
properties_pt properties_load(const char* filename) {
- FILE *file = fopen(filename, "r");
- if(file==NULL){
- return NULL;
- }
- properties_pt props = properties_loadWithStream(file);
- fclose(file);
- return props;
+ return celix_properties_load(filename);
}
properties_pt properties_loadWithStream(FILE *file) {
- properties_pt props = NULL;
-
-
- if (file != NULL ) {
- char *saveptr;
- char *filebuffer = NULL;
- char *line = NULL;
- size_t file_size = 0;
-
- props = properties_create();
- fseek(file, 0, SEEK_END);
- file_size = ftell(file);
- fseek(file, 0, SEEK_SET);
-
- if(file_size > 0){
- filebuffer = calloc(file_size + 1, sizeof(char));
- if(filebuffer) {
- size_t rs = fread(filebuffer, sizeof(char), file_size, file);
- if(rs != file_size){
- fprintf(stderr,"fread read only %lu bytes out of %lu\n",rs,file_size);
- }
- filebuffer[file_size]='\0';
- line = strtok_r(filebuffer, "\n", &saveptr);
- while ( line != NULL ) {
- parseLine(line, props);
- line = strtok_r(NULL, "\n", &saveptr);
- }
- free(filebuffer);
- }
- }
- }
-
- return props;
+ return celix_properties_loadWithStream(file);
}
properties_pt properties_loadFromString(const char *input){
- properties_pt props = properties_create();
-
- char *in = strdup(input);
- char *line = NULL;
- char *saveLinePointer = NULL;
-
- bool firstTime = true;
- do {
- if (firstTime){
- line = strtok_r(in, "\n", &saveLinePointer);
- firstTime = false;
- }else {
- line = strtok_r(NULL, "\n", &saveLinePointer);
- }
-
- if (line == NULL){
- break;
- }
-
- parseLine(line, props);
- } while(line != NULL);
-
- free(in);
-
- return props;
+ return celix_properties_loadFromString(input);
}
@@ -129,92 +60,29 @@ properties_pt properties_loadFromString(const char *input){
* Header is ignored for now, cannot handle comments yet
*/
void properties_store(properties_pt properties, const char* filename, const char* header) {
- FILE *file = fopen ( filename, "w+" );
- char *str;
-
- if (file != NULL) {
- if (hashMap_size(properties) > 0) {
- hash_map_iterator_pt iterator = hashMapIterator_create(properties);
- while (hashMapIterator_hasNext(iterator)) {
- hash_map_entry_pt entry = hashMapIterator_nextEntry(iterator);
- str = hashMapEntry_getKey(entry);
- for (int i = 0; i < strlen(str); i += 1) {
- if (str[i] == '#' || str[i] == '!' || str[i] == '=' || str[i] == ':') {
- fputc('\\', file);
- }
- fputc(str[i], file);
- }
-
- fputc('=', file);
-
- str = hashMapEntry_getValue(entry);
- for (int i = 0; i < strlen(str); i += 1) {
- if (str[i] == '#' || str[i] == '!' || str[i] == '=' || str[i] == ':') {
- fputc('\\', file);
- }
- fputc(str[i], file);
- }
-
- fputc('\n', file);
-
- }
- hashMapIterator_destroy(iterator);
- }
- fclose(file);
- } else {
- perror("File is null");
- }
+ return celix_properties_store(properties, filename, header);
}
celix_status_t properties_copy(properties_pt properties, properties_pt *out) {
- celix_status_t status = CELIX_SUCCESS;
- properties_pt copy = properties_create();
-
- if (copy != NULL) {
- hash_map_iterator_pt iter = hashMapIterator_create(properties);
- while (hashMapIterator_hasNext(iter)) {
- hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
- char *key = hashMapEntry_getKey(entry);
- char *value = hashMapEntry_getValue(entry);
- properties_set(copy, key, value);
- }
- hashMapIterator_destroy(iter);
- } else {
- status = CELIX_ENOMEM;
- }
-
- if (status == CELIX_SUCCESS) {
- *out = copy;
- }
-
- return status;
+ celix_properties_t *copy = celix_properties_copy(properties);
+ *out = copy;
+ return copy == NULL ? CELIX_BUNDLE_EXCEPTION : CELIX_SUCCESS;
}
const char* properties_get(properties_pt properties, const char* key) {
- return hashMap_get(properties, (void*)key);
+ return celix_properties_get(properties, key);
}
const char* properties_getWithDefault(properties_pt properties, const char* key, const char* defaultValue) {
- const char* value = properties_get(properties, key);
- return value == NULL ? defaultValue : value;
+ return celix_properties_getWithDefault(properties, key, defaultValue);
}
void properties_set(properties_pt properties, const char* key, const char* value) {
- hash_map_entry_pt entry = hashMap_getEntry(properties, key);
- char* oldValue = NULL;
- if (entry != NULL) {
- char* oldKey = hashMapEntry_getKey(entry);
- oldValue = hashMapEntry_getValue(entry);
- hashMap_put(properties, oldKey, strndup(value, 1024*10));
- } else {
- hashMap_put(properties, strndup(key, 1024*10), strndup(value, 1024*10));
- }
- free(oldValue);
+ celix_properties_set(properties, key, value);
}
void properties_unset(properties_pt properties, const char* key) {
- char* oldValue = hashMap_remove(properties, key);
- free(oldValue);
+ celix_properties_unset(properties, key);
}
static void updateBuffers(char **key, char ** value, char **output, int outputPos, int *key_len, int *value_len) {
@@ -333,3 +201,204 @@ static void parseLine(const char* line, properties_pt props) {
}
}
+
+
+
+/**********************************************************************************************************************
+ **********************************************************************************************************************
+ * Updated API
+ **********************************************************************************************************************
+ **********************************************************************************************************************/
+
+
+
+celix_properties_t* celix_properties_create(void) {
+ return hashMap_create(utils_stringHash, utils_stringHash, utils_stringEquals, utils_stringEquals);
+}
+
+void celix_properties_destroy(celix_properties_t *properties) {
+ hash_map_iterator_pt iter = hashMapIterator_create(properties);
+ while (hashMapIterator_hasNext(iter)) {
+ hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+ free(hashMapEntry_getKey(entry));
+ free(hashMapEntry_getValue(entry));
+ }
+ hashMapIterator_destroy(iter);
+ hashMap_destroy(properties, false, false);
+}
+
+celix_properties_t* celix_properties_load(const char *filename) {
+ FILE *file = fopen(filename, "r");
+ if(file==NULL){
+ return NULL;
+ }
+ properties_pt props = celix_properties_loadWithStream(file);
+ fclose(file);
+ return props;
+}
+
+celix_properties_t* celix_properties_loadWithStream(FILE *file) {
+ properties_pt props = NULL;
+
+
+ if (file != NULL ) {
+ char *saveptr;
+ char *filebuffer = NULL;
+ char *line = NULL;
+ size_t file_size = 0;
+
+ props = celix_properties_create();
+ fseek(file, 0, SEEK_END);
+ file_size = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ if(file_size > 0){
+ filebuffer = calloc(file_size + 1, sizeof(char));
+ if(filebuffer) {
+ size_t rs = fread(filebuffer, sizeof(char), file_size, file);
+ if(rs != file_size){
+ fprintf(stderr,"fread read only %lu bytes out of %lu\n",rs,file_size);
+ }
+ filebuffer[file_size]='\0';
+ line = strtok_r(filebuffer, "\n", &saveptr);
+ while ( line != NULL ) {
+ parseLine(line, props);
+ line = strtok_r(NULL, "\n", &saveptr);
+ }
+ free(filebuffer);
+ }
+ }
+ }
+
+ return props;
+}
+
+celix_properties_t* celix_properties_loadFromString(const char *input) {
+ properties_pt props = celix_properties_create();
+
+ char *in = strdup(input);
+ char *line = NULL;
+ char *saveLinePointer = NULL;
+
+ bool firstTime = true;
+ do {
+ if (firstTime){
+ line = strtok_r(in, "\n", &saveLinePointer);
+ firstTime = false;
+ }else {
+ line = strtok_r(NULL, "\n", &saveLinePointer);
+ }
+
+ if (line == NULL){
+ break;
+ }
+
+ parseLine(line, props);
+ } while(line != NULL);
+
+ free(in);
+
+ return props;
+}
+
+void celix_properties_store(celix_properties_t *properties, const char *filename, const char *header) {
+ FILE *file = fopen (filename, "w+" );
+ char *str;
+
+ if (file != NULL) {
+ if (hashMap_size(properties) > 0) {
+ hash_map_iterator_pt iterator = hashMapIterator_create(properties);
+ while (hashMapIterator_hasNext(iterator)) {
+ hash_map_entry_pt entry = hashMapIterator_nextEntry(iterator);
+ str = hashMapEntry_getKey(entry);
+ for (int i = 0; i < strlen(str); i += 1) {
+ if (str[i] == '#' || str[i] == '!' || str[i] == '=' || str[i] == ':') {
+ fputc('\\', file);
+ }
+ fputc(str[i], file);
+ }
+
+ fputc('=', file);
+
+ str = hashMapEntry_getValue(entry);
+ for (int i = 0; i < strlen(str); i += 1) {
+ if (str[i] == '#' || str[i] == '!' || str[i] == '=' || str[i] == ':') {
+ fputc('\\', file);
+ }
+ fputc(str[i], file);
+ }
+
+ fputc('\n', file);
+
+ }
+ hashMapIterator_destroy(iterator);
+ }
+ fclose(file);
+ } else {
+ perror("File is null");
+ }
+}
+
+celix_properties_t* celix_properties_copy(celix_properties_t *properties) {
+ celix_properties_t *copy = celix_properties_create();
+ if (copy != NULL) {
+ hash_map_iterator_t iter = hashMapIterator_construct(properties);
+ while (hashMapIterator_hasNext(&iter)) {
+ hash_map_entry_pt entry = hashMapIterator_nextEntry(&iter);
+ char *key = hashMapEntry_getKey(entry);
+ char *value = hashMapEntry_getValue(entry);
+ celix_properties_set(copy, key, value);
+ }
+ }
+ return copy;
+}
+
+const char* celix_properties_get(const celix_properties_t *properties, const char *key) {
+ return hashMap_get((hash_map_t*)properties, (void*)key);
+}
+
+const char* celix_properties_getWithDefault(const celix_properties_t *properties, const char *key, const char *defaultValue) {
+ const char* value = celix_properties_get(properties, key);
+ return value == NULL ? defaultValue : value;
+}
+
+void celix_properties_set(celix_properties_t *properties, const char *key, const char *value) {
+ hash_map_entry_pt entry = hashMap_getEntry(properties, key);
+ char* oldValue = NULL;
+ if (entry != NULL) {
+ char* oldKey = hashMapEntry_getKey(entry);
+ oldValue = hashMapEntry_getValue(entry);
+ hashMap_put(properties, oldKey, strndup(value, 1024*10));
+ } else {
+ hashMap_put(properties, strndup(key, 1024*10), strndup(value, 1024*10));
+ }
+ free(oldValue);
+}
+
+void celix_properties_unset(celix_properties_t *properties, const char *key) {
+ char* oldValue = hashMap_remove(properties, key);
+ free(oldValue);
+}
+
+long celix_properties_getAsLong(const celix_properties_t *props, const char *key, long defaultValue) {
+ long result = defaultValue;
+ const char *val = celix_properties_get(props, key);
+ if (val != NULL) {
+ long r = strtol(val, NULL, 10);
+ if (errno == 0) {
+ result = r;
+ }
+ errno = 0;
+ }
+ return result;
+}
+
+void celix_properties_setLong(celix_properties_t *props, const char *key, long value) {
+ char buf[32]; //should be enough to store long long int
+ int writen = snprintf(buf, 32, "%li", value);
+ if (writen <= 31) {
+ celix_properties_set(props, key, buf);
+ } else {
+ fprintf(stderr,"buf to small for value '%li'\n", value);
+ }
+}