celix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pnol...@apache.org
Subject celix git commit: CELIX-446: Adds celix_bundleContext_trackService(s) impl to the bundle context/service tracker
Date Wed, 02 May 2018 16:55:18 GMT
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 <pepijnnoltes@gmail.com>
Authored: Wed May 2 18:54:13 2018 +0200
Committer: Pepijn Noltes <pepijnnoltes@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);
+	}
+}


Mime
View raw message