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/27 15:10:34 UTC

[1/3] celix git commit: CELIX-446: Adds initial impl for celix_bundleContext_trackServiceTrackers.

Repository: celix
Updated Branches:
  refs/heads/develop 7b427160b -> d44047d20


http://git-wip-us.apache.org/repos/asf/celix/blob/8e716743/utils/src/filter.c
----------------------------------------------------------------------
diff --git a/utils/src/filter.c b/utils/src/filter.c
new file mode 100644
index 0000000..7cfa218
--- /dev/null
+++ b/utils/src/filter.c
@@ -0,0 +1,724 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+#include <utils.h>
+
+#include "celix_filter.h"
+#include "filter.h"
+#include "celix_errno.h"
+
+static void filter_skipWhiteSpace(char* filterString, int* pos);
+static celix_filter_t * filter_parseFilter(char* filterString, int* pos);
+static celix_filter_t * filter_parseFilterComp(char* filterString, int* pos);
+static celix_filter_t * filter_parseAndOrOr(char* filterString, celix_filter_operand_t andOrOr, int* pos);
+static celix_filter_t * filter_parseNot(char* filterString, int* pos);
+static celix_filter_t * filter_parseItem(char* filterString, int* pos);
+static char * filter_parseAttr(char* filterString, int* pos);
+static char * filter_parseValue(char* filterString, int* pos);
+static array_list_pt filter_parseSubstring(char* filterString, int* pos);
+
+static celix_status_t filter_compare(const celix_filter_t* filter, const char *propertyValue, bool *result);
+
+static void filter_skipWhiteSpace(char * filterString, int * pos) {
+	int length;
+	for (length = strlen(filterString); (*pos < length) && isspace(filterString[*pos]);) {
+		(*pos)++;
+	}
+}
+
+celix_filter_t * filter_create(const char* filterString) {
+	return celix_filter_create(filterString);
+}
+
+void filter_destroy(celix_filter_t * filter) {
+	return celix_filter_destroy(filter);
+}
+
+static celix_filter_t * filter_parseFilter(char * filterString, int * pos) {
+	celix_filter_t * filter;
+	filter_skipWhiteSpace(filterString, pos);
+	if (filterString[*pos] != '(') {
+	    fprintf(stderr, "Filter Error: Missing '(' in filter string '%s'.", filterString);
+		return NULL;
+	}
+	(*pos)++;
+
+	filter = filter_parseFilterComp(filterString, pos);
+
+	filter_skipWhiteSpace(filterString, pos);
+
+	if (filterString[*pos] != ')') {
+        fprintf(stderr, "Filter Error: Missing ')' in filter string '%s'.", filterString);
+		if(filter!=NULL){
+			filter_destroy(filter);
+		}
+		return NULL;
+	}
+	(*pos)++;
+	filter_skipWhiteSpace(filterString, pos);
+
+	return filter;
+}
+
+static celix_filter_t * filter_parseFilterComp(char * filterString, int * pos) {
+	char c;
+	filter_skipWhiteSpace(filterString, pos);
+
+	c = filterString[*pos];
+
+	switch (c) {
+		case '&': {
+			(*pos)++;
+			return filter_parseAndOrOr(filterString, CELIX_FILTER_OPERAND_AND, pos);
+		}
+		case '|': {
+			(*pos)++;
+			return filter_parseAndOrOr(filterString, CELIX_FILTER_OPERAND_OR, pos);
+		}
+		case '!': {
+			(*pos)++;
+			return filter_parseNot(filterString, pos);
+		}
+	}
+	return filter_parseItem(filterString, pos);
+}
+
+static celix_filter_t * filter_parseAndOrOr(char * filterString, celix_filter_operand_t andOrOr, int * pos) {
+
+	array_list_pt children = NULL;
+	filter_skipWhiteSpace(filterString, pos);
+	bool failure = false;
+
+	if (filterString[*pos] != '(') {
+        fprintf(stderr, "Filter Error: Missing '('.");
+		return NULL;
+	}
+
+	arrayList_create(&children);
+	while(filterString[*pos] == '(') {
+		celix_filter_t * child = filter_parseFilter(filterString, pos);
+		if(child == NULL) {
+			failure = true;
+			break;
+		}
+		arrayList_add(children, child);
+	}
+
+	if(failure == true){
+        int i;
+		for (i = 0; i < arrayList_size(children); ++i) {
+			celix_filter_t * f = arrayList_get(children, i);
+			filter_destroy(f);
+		}
+		arrayList_destroy(children);
+        children = NULL;
+	}
+
+	celix_filter_t * filter = (celix_filter_t *) calloc(1, sizeof(*filter));
+	filter->operand = andOrOr;
+    filter->children = children;
+
+	return filter;
+}
+
+static celix_filter_t * filter_parseNot(char * filterString, int * pos) {
+	celix_filter_t * child = NULL;
+	filter_skipWhiteSpace(filterString, pos);
+
+	if (filterString[*pos] != '(') {
+        fprintf(stderr, "Filter Error: Missing '('.");
+		return NULL;
+	}
+
+	child = filter_parseFilter(filterString, pos);
+
+    array_list_t* children = NULL;
+    arrayList_create(&children);
+    arrayList_add(children, child);
+
+	celix_filter_t * filter = (celix_filter_t *) calloc(1, sizeof(*filter));
+	filter->operand = CELIX_FILTER_OPERAND_NOT;
+	filter->children = children;
+
+	return filter;
+}
+
+static celix_filter_t * filter_parseItem(char * filterString, int * pos) {
+	char * attr = filter_parseAttr(filterString, pos);
+	if(attr == NULL){
+		return NULL;
+	}
+
+	filter_skipWhiteSpace(filterString, pos);
+	switch(filterString[*pos]) {
+		case '~': {
+			if (filterString[*pos + 1] == '=') {
+				celix_filter_t * filter = (celix_filter_t *) calloc(1, sizeof(*filter));
+				*pos += 2;
+				filter->operand = CELIX_FILTER_OPERAND_APPROX;
+				filter->attribute = attr;
+				filter->value = filter_parseValue(filterString, pos);
+				return filter;
+			}
+			break;
+		}
+		case '>': {
+			if (filterString[*pos + 1] == '=') {
+				celix_filter_t * filter = (celix_filter_t *) calloc(1, sizeof(*filter));
+				*pos += 2;
+				filter->operand = CELIX_FILTER_OPERAND_GREATEREQUAL;
+				filter->attribute = attr;
+				filter->value = filter_parseValue(filterString, pos);
+				return filter;
+			}
+			else {
+                celix_filter_t * filter = (celix_filter_t *) calloc(1, sizeof(*filter));
+                *pos += 1;
+                filter->operand = CELIX_FILTER_OPERAND_GREATER;
+                filter->attribute = attr;
+                filter->value = filter_parseValue(filterString, pos);
+                return filter;
+			}
+			break;
+		}
+		case '<': {
+			if (filterString[*pos + 1] == '=') {
+				celix_filter_t * filter = (celix_filter_t *) calloc(1, sizeof(*filter));
+				*pos += 2;
+				filter->operand = CELIX_FILTER_OPERAND_LESSEQUAL;
+				filter->attribute = attr;
+				filter->value = filter_parseValue(filterString, pos);
+				return filter;
+			}
+			else {
+                celix_filter_t * filter = (celix_filter_t *) calloc(1, sizeof(*filter));
+                *pos += 1;
+                filter->operand = CELIX_FILTER_OPERAND_LESS;
+                filter->attribute = attr;
+                filter->value = filter_parseValue(filterString, pos);
+                return filter;
+			}
+			break;
+		}
+		case '=': {
+			celix_filter_t * filter = NULL;
+			array_list_pt subs;
+			if (filterString[*pos + 1] == '*') {
+				int oldPos = *pos;
+				*pos += 2;
+				filter_skipWhiteSpace(filterString, pos);
+				if (filterString[*pos] == ')') {
+					celix_filter_t * filter = (celix_filter_t *) calloc(1, sizeof(*filter));
+					filter->operand = CELIX_FILTER_OPERAND_PRESENT;
+					filter->attribute = attr;
+					filter->value = NULL;
+					return filter;
+				}
+				*pos = oldPos;
+			}
+			filter = (celix_filter_t *) calloc(1, sizeof(*filter));			
+			(*pos)++;
+			subs = filter_parseSubstring(filterString, pos);
+			if(subs!=NULL){
+				if (arrayList_size(subs) == 1) {
+					char * string = (char *) arrayList_get(subs, 0);
+					if (string != NULL) {
+						filter->operand = CELIX_FILTER_OPERAND_EQUAL;
+						filter->attribute = attr;
+						filter->value = string;
+
+						arrayList_clear(subs);
+						arrayList_destroy(subs);
+
+						return filter;
+					}
+				}
+			}
+			filter->operand = CELIX_FILTER_OPERAND_SUBSTRING;
+			filter->attribute = attr;
+            filter->children = subs;
+			return filter;
+		}
+	}
+    fprintf(stderr, "Filter Error: Invalid operator.");
+	free(attr);
+	return NULL;
+}
+
+static char * filter_parseAttr(char * filterString, int * pos) {
+	char c;
+	int begin = *pos;
+	int end = *pos;
+	int length = 0;
+
+	filter_skipWhiteSpace(filterString, pos);
+	c = filterString[*pos];
+
+	while (c != '~' && c != '<' && c != '>' && c != '=' && c != '(' && c != ')') {
+		(*pos)++;
+
+		if (!isspace(c)) {
+			end = *pos;
+		}
+
+		c = filterString[*pos];
+	}
+
+	length = end - begin;
+
+	if (length == 0) {
+        fprintf(stderr, "Filter Error: Missing attr.");
+		return NULL;
+	} else {
+		char * attr = (char *) calloc(1, length+1);
+		strncpy(attr, filterString+begin, length);
+		attr[length] = '\0';
+		return attr;
+	}
+}
+
+static char * filter_parseValue(char * filterString, int * pos) {
+	char *value = calloc(strlen(filterString) + 1, sizeof(*value));
+	int keepRunning = 1;
+
+	while (keepRunning) {
+		char c = filterString[*pos];
+
+		switch (c) {
+			case ')': {
+				keepRunning = 0;
+				break;
+			}
+			case '(': {
+                fprintf(stderr, "Filter Error: Invalid value.");
+				free(value);
+				return NULL;
+			}
+			case '\0':{
+                fprintf(stderr, "Filter Error: Unclosed bracket.");
+				free(value);
+				return NULL;
+			}
+			case '\\': {
+				(*pos)++;
+				c = filterString[*pos];
+			}
+			/* no break */
+			default: {
+				char ch[2];
+				ch[0] = c;
+				ch[1] = '\0';
+				strcat(value, ch);
+				(*pos)++;
+				break;
+			}
+		}
+	}
+
+	if (strlen(value) == 0) {
+        fprintf(stderr, "Filter Error: Missing value.");
+		free(value);
+		return NULL;
+	}
+	return value;
+}
+
+static array_list_pt filter_parseSubstring(char * filterString, int * pos) {
+	char *sub = calloc(strlen(filterString) + 1, sizeof(*sub));
+	array_list_pt operands = NULL;
+	int keepRunning = 1;
+
+	arrayList_create(&operands);
+	while (keepRunning) {
+		char c = filterString[*pos];
+		
+
+		switch (c) {
+			case ')': {
+				if (strlen(sub) > 0) {
+					arrayList_add(operands, strdup(sub));
+				}
+				keepRunning = 0;
+				break;
+			}
+			case '\0':{
+                fprintf(stderr, "Filter Error: Unclosed bracket.");
+				keepRunning = false;
+				break;
+			}
+			case '(': {
+                fprintf(stderr, "Filter Error: Invalid value.");
+				keepRunning = false;
+				break;
+			}
+			case '*': {
+				if (strlen(sub) > 0) {
+					arrayList_add(operands, strdup(sub));
+				}
+				sub[0] = '\0';
+				arrayList_add(operands, NULL);
+				(*pos)++;
+				break;
+			}
+			case '\\': {
+				(*pos)++;
+				c = filterString[*pos];
+			}
+			/* no break */
+			default: {
+				char ch[2];
+				ch[0] = c;
+				ch[1] = '\0';
+				strcat(sub, ch);
+				(*pos)++;
+				break;
+			}
+		}
+	}
+	free(sub);
+
+	if (arrayList_size(operands) == 0) {
+        fprintf(stderr, "Filter Error: Missing value.");
+		arrayList_destroy(operands);
+		return NULL;
+	}
+
+	return operands;
+}
+
+celix_status_t filter_match(celix_filter_t * filter, properties_pt properties, bool *out) {
+	bool result = celix_filter_match(filter, properties);
+	if (out != NULL) {
+		*out = result;
+	}
+	return CELIX_SUCCESS;
+}
+
+static celix_status_t filter_compare(const celix_filter_t* filter, const char *propertyValue, bool *out) {
+    celix_status_t  status = CELIX_SUCCESS;
+    bool result = false;
+
+    if (filter == NULL || propertyValue == NULL) {
+        *out = false;
+        return status;
+    }
+
+    switch (filter->operand) {
+        case CELIX_FILTER_OPERAND_SUBSTRING: {
+            int pos = 0;
+            unsigned int i;
+            int size = arrayList_size(filter->children);
+            for (i = 0; i < size; i++) {
+                char * substr = (char *) arrayList_get(filter->children, i);
+
+                if (i + 1 < size) {
+                    if (substr == NULL) {
+                        unsigned int index;
+                        char * substr2 = (char *) arrayList_get(filter->children, i + 1);
+                        if (substr2 == NULL) {
+                            continue;
+                        }
+                        index = strcspn(propertyValue+pos, substr2);
+                        if (index == strlen(propertyValue+pos)) {
+                            *out = false;
+                            return CELIX_SUCCESS;
+                        }
+
+                        pos = index + strlen(substr2);
+                        if (i + 2 < size) {
+                            i++;
+                        }
+                    } else {
+                        unsigned int len = strlen(substr);
+                        char * region = (char *)calloc(1, len+1);
+                        strncpy(region, propertyValue+pos, len);
+                        region[len]	= '\0';
+                        if (strcmp(region, substr) == 0) {
+                            pos += len;
+                        } else {
+                            free(region);
+                            *out = false;
+                            return CELIX_SUCCESS;
+                        }
+                        free(region);
+                    }
+                } else {
+                    unsigned int len;
+                    int begin;
+
+                    if (substr == NULL) {
+                        *out = true;
+                        return CELIX_SUCCESS;
+                    }
+                    len = strlen(substr);
+                    begin = strlen(propertyValue)-len;
+                    *out = (strcmp(propertyValue+begin, substr) == 0);
+                    return CELIX_SUCCESS;
+                }
+            }
+            *out = true;
+            return CELIX_SUCCESS;
+        }
+        case CELIX_FILTER_OPERAND_APPROX: //TODO: Implement strcmp with ignorecase and ignorespaces
+        case CELIX_FILTER_OPERAND_EQUAL: {
+            *out = (strcmp(propertyValue, filter->value) == 0);
+            return CELIX_SUCCESS;
+        }
+        case CELIX_FILTER_OPERAND_GREATER: {
+            *out = (strcmp(propertyValue, filter->value) > 0);
+            return CELIX_SUCCESS;
+        }
+        case CELIX_FILTER_OPERAND_GREATEREQUAL: {
+            *out = (strcmp(propertyValue, filter->value) >= 0);
+            return CELIX_SUCCESS;
+        }
+        case CELIX_FILTER_OPERAND_LESS: {
+            *out = (strcmp(propertyValue, filter->value) < 0);
+            return CELIX_SUCCESS;
+        }
+        case CELIX_FILTER_OPERAND_LESSEQUAL: {
+            *out = (strcmp(propertyValue, filter->value) <= 0);
+            return CELIX_SUCCESS;
+        }
+        case CELIX_FILTER_OPERAND_AND:
+        case CELIX_FILTER_OPERAND_NOT:
+        case CELIX_FILTER_OPERAND_OR:
+        case CELIX_FILTER_OPERAND_PRESENT: {
+        }
+            /* no break */
+    }
+
+    if (status == CELIX_SUCCESS && out != NULL) {
+        *out = result;
+    }
+    return status;
+}
+
+celix_status_t filter_getString(celix_filter_t * filter, const char **filterStr) {
+	if (filter != NULL) {
+		*filterStr = filter->filterStr;
+	}
+	return CELIX_SUCCESS;
+}
+
+celix_status_t filter_match_filter(celix_filter_t *src, celix_filter_t *dest, bool *out) {
+    bool result = celix_filter_matchFilter(src, dest);
+    if (out != NULL) {
+    	*out = result;
+    }
+    return CELIX_SUCCESS;
+}
+
+
+celix_filter_t* celix_filter_create(const char *filterString) {
+	celix_filter_t * filter = NULL;
+	char* filterStr = string_ndup(filterString, 1024*1024);
+	int pos = 0;
+	filter = filter_parseFilter(filterStr, &pos);
+	if (filter != NULL && pos != strlen(filterStr)) {
+        fprintf(stderr, "Filter Error: Extraneous trailing characters.");
+		filter_destroy(filter);
+		filter = NULL;
+	} else if (filter != NULL) {
+		if (filter->operand != CELIX_FILTER_OPERAND_OR && filter->operand != CELIX_FILTER_OPERAND_AND &&
+			filter->operand != CELIX_FILTER_OPERAND_NOT && filter->operand != CELIX_FILTER_OPERAND_SUBSTRING &&
+			filter->operand != CELIX_FILTER_OPERAND_PRESENT) {
+			if (filter->attribute == NULL || filter->value == NULL) {
+				filter_destroy(filter);
+				filter = NULL;
+			}
+		}
+	}
+
+	if (filter == NULL) {
+		free(filterStr);
+	} else {
+		filter->filterStr = filterStr;
+	}
+
+	return filter;
+}
+
+void celix_filter_destroy(celix_filter_t *filter) {
+	if (filter != NULL) {
+		if(filter->children != NULL){
+			if (filter->operand == CELIX_FILTER_OPERAND_SUBSTRING) {
+				int size = arrayList_size(filter->children);
+				int i = 0;
+				for (i = 0; i < size; i++) {
+					char *operand = arrayList_get(filter->children, i);
+					free(operand);
+				}
+				arrayList_destroy(filter->children);
+				filter->children = NULL;
+			} else if (filter->operand == CELIX_FILTER_OPERAND_OR || filter->operand == CELIX_FILTER_OPERAND_AND || filter->operand == CELIX_FILTER_OPERAND_NOT) {
+				int size = arrayList_size(filter->children);
+				int i = 0;
+				for (i = 0; i < size; i++) {
+					celix_filter_t *f = arrayList_get(filter->children, i);
+					filter_destroy(f);
+				}
+				arrayList_destroy(filter->children);
+				filter->children = NULL;
+			} else {
+                fprintf(stderr, "Filter Error: Corrupt filter. children has a value, but not an expected operand");
+			}
+		}
+		free((char*)filter->value);
+		filter->value = NULL;
+		free((char*)filter->attribute);
+		filter->attribute = NULL;
+		free((char*)filter->filterStr);
+		filter->filterStr = NULL;
+		free(filter);
+	}
+}
+
+bool celix_filter_match(const celix_filter_t *filter, const celix_properties_t* properties) {
+	bool result = false;
+	switch (filter->operand) {
+		case CELIX_FILTER_OPERAND_AND: {
+			array_list_pt children = filter->children;
+			unsigned int i;
+			for (i = 0; i < arrayList_size(children); i++) {
+				celix_filter_t * sfilter = (celix_filter_t *) arrayList_get(children, i);
+				bool mresult = celix_filter_match(sfilter, properties);
+				if (!mresult) {
+					return false;
+				}
+			}
+			return true;
+		}
+		case CELIX_FILTER_OPERAND_OR: {
+			array_list_pt children = filter->children;
+			unsigned int i;
+			for (i = 0; i < arrayList_size(children); i++) {
+				celix_filter_t * sfilter = (celix_filter_t *) arrayList_get(children, i);
+				bool mresult = celix_filter_match(sfilter, properties);
+				if (mresult) {
+					return true;
+				}
+			}
+			return false;
+		}
+		case CELIX_FILTER_OPERAND_NOT: {
+			celix_filter_t * sfilter = arrayList_get(filter->children, 0);
+			bool mresult = celix_filter_match(sfilter, properties);
+			return !mresult;
+		}
+		case CELIX_FILTER_OPERAND_SUBSTRING :
+		case CELIX_FILTER_OPERAND_EQUAL :
+		case CELIX_FILTER_OPERAND_GREATER :
+		case CELIX_FILTER_OPERAND_GREATEREQUAL :
+		case CELIX_FILTER_OPERAND_LESS :
+		case CELIX_FILTER_OPERAND_LESSEQUAL :
+		case CELIX_FILTER_OPERAND_APPROX : {
+			char * value = (properties == NULL) ? NULL: (char*)celix_properties_get(properties, filter->attribute);
+			filter_compare(filter, value, &result);
+			return result;
+		}
+		case CELIX_FILTER_OPERAND_PRESENT: {
+			char * value = (properties == NULL) ? NULL: (char*)celix_properties_get(properties, filter->attribute);
+			return value != NULL;
+		}
+	}
+	return result;
+}
+
+bool celix_filter_matchFilter(const celix_filter_t *filter1, const celix_filter_t *filter2) {
+	bool result = false;
+	if (filter1 == filter2) {
+		result = true; //NOTE. also means NULL filter are equal
+	} else if (filter1 != NULL && filter2 != NULL && filter1->operand == filter2->operand) {
+		if (filter1->operand == CELIX_FILTER_OPERAND_AND || filter1->operand == CELIX_FILTER_OPERAND_OR || filter1->operand == CELIX_FILTER_OPERAND_NOT) {
+			assert(filter1->children != NULL);
+			assert(filter2->children != NULL);
+			size_t sizeSrc = celix_arrayList_size(filter1->children);
+			size_t sizeDest = celix_arrayList_size(filter2->children);
+			if (sizeSrc == sizeDest) {
+				int i;
+				int k;
+				int sameCount = 0;
+				for (i =0; i < sizeSrc; ++i) {
+					bool same = false;
+					celix_filter_t *srcPart = arrayList_get(filter1->children, i);
+					for (k = 0; k < sizeDest; ++k) {
+						celix_filter_t *destPart = arrayList_get(filter2->children, k);
+						filter_match_filter(srcPart, destPart, &same);
+						if (same) {
+							sameCount += 1;
+							break;
+						}
+					}
+				}
+				result = sameCount == sizeSrc;
+			}
+		} else { //compare attr and value
+			bool attrSame = false;
+			bool valSame = false;
+			if (filter1->attribute == NULL && filter2->attribute == NULL) {
+				attrSame = true;
+			} else if (filter1->attribute != NULL && filter2->attribute != NULL) {
+				attrSame = strncmp(filter1->attribute, filter2->attribute, 1024 * 1024) == 0;
+			}
+
+			if (filter1->value == NULL  && filter2->value == NULL) {
+				valSame = true;
+			} else if (filter1->value != NULL && filter2->value != NULL) {
+				valSame = strncmp(filter1->value, filter2->value, 1024 * 1024) == 0;
+			}
+
+			result = attrSame && valSame;
+		}
+	}
+
+	return result;
+}
+
+const char* celix_filter_getFilterString(const celix_filter_t *filter) {
+	if (filter != NULL) {
+		return filter->filterStr;
+	}
+	return NULL;
+}
+
+
+const char* celix_filter_findAttribute(const celix_filter_t *filter, const char *attribute) {
+	const char *result = NULL;
+	if (filter != NULL && attribute != NULL) {
+	    if (filter->operand == CELIX_FILTER_OPERAND_AND || filter->operand == CELIX_FILTER_OPERAND_OR || filter->operand == CELIX_FILTER_OPERAND_NOT) {
+            size_t size = celix_arrayList_size(filter->children);
+            for (unsigned int i = 0; i < size; ++i) {
+                celix_filter_t *child = celix_arrayList_get(filter->children, i);
+                result = celix_filter_findAttribute(child, attribute);
+                if (result != NULL) {
+                    break;
+                }
+            }
+	    } else if (strncmp(filter->attribute, attribute, 1024 * 1024) == 0) {
+	        result = filter->value;
+        }
+	}
+	return result;
+}
\ No newline at end of file


[3/3] celix git commit: CELIX-426: Adds required linker options for the depenedency managet on OSX systems

Posted by pn...@apache.org.
CELIX-426: Adds required linker options for the depenedency managet on OSX systems


Project: http://git-wip-us.apache.org/repos/asf/celix/repo
Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/d44047d2
Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/d44047d2
Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/d44047d2

Branch: refs/heads/develop
Commit: d44047d201007c94179e26a983ba726b9b2d3135
Parents: 8e71674
Author: Pepijn Noltes <pe...@gmail.com>
Authored: Sun May 27 17:09:43 2018 +0200
Committer: Pepijn Noltes <pe...@gmail.com>
Committed: Sun May 27 17:09:43 2018 +0200

----------------------------------------------------------------------
 dependency_manager/CMakeLists.txt | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/celix/blob/d44047d2/dependency_manager/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/dependency_manager/CMakeLists.txt b/dependency_manager/CMakeLists.txt
index a95a36b..52051ab 100644
--- a/dependency_manager/CMakeLists.txt
+++ b/dependency_manager/CMakeLists.txt
@@ -21,14 +21,22 @@ target_include_directories(dependency_manager_static PUBLIC
         $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/api>
         $<INSTALL_INTERFACE:include/celix/dependency_manager>
 )
-target_link_libraries(dependency_manager_static PUBLIC Celix::framework)
+if (APPLE)
+    target_link_libraries(dependency_manager_static Celix::framework "-undefined dynamic_lookup")
+else()
+    target_link_libraries(dependency_manager_static Celix::framework)
+endif()
 
 add_library(dependency_manager_so SHARED src/dm_activator.c)
 target_include_directories(dependency_manager_so PUBLIC
         $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/api>
         $<INSTALL_INTERFACE:include/celix/dependency_manager>
 )
-target_link_libraries(dependency_manager_so PUBLIC Celix::framework)
+if (APPLE)
+    target_link_libraries(dependency_manager_so Celix::framework "-undefined dynamic_lookup")
+else()
+    target_link_libraries(dependency_manager_so Celix::framework)
+endif()
 
 #now part of the the shell bundle
 add_library(dm_shell INTERFACE)


[2/3] celix git commit: CELIX-446: Adds initial impl for celix_bundleContext_trackServiceTrackers.

Posted by pn...@apache.org.
CELIX-446: Adds initial impl for celix_bundleContext_trackServiceTrackers.

- Also move filter impl to utils
- Adds celix_ prefixed filter api
- Adds filter call to extract attribute values


Project: http://git-wip-us.apache.org/repos/asf/celix/repo
Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/8e716743
Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/8e716743
Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/8e716743

Branch: refs/heads/develop
Commit: 8e7167436d39939d078b36e81627e4a2c1bcf78b
Parents: 7b42716
Author: Pepijn Noltes <pe...@gmail.com>
Authored: Sun May 27 16:59:23 2018 +0200
Committer: Pepijn Noltes <pe...@gmail.com>
Committed: Sun May 27 17:00:48 2018 +0200

----------------------------------------------------------------------
 framework/CMakeLists.txt                       |   9 +-
 framework/include/celix_bundle_context.h       |  51 +-
 framework/include/filter.h                     |  87 ---
 framework/src/bundle_context.c                 | 135 +++-
 framework/src/bundle_context_private.h         |  23 +-
 framework/src/filter.c                         | 692 -------------------
 framework/tst/bundle_context_services_test.cpp |  37 +
 utils/CMakeLists.txt                           |   5 +
 utils/include/celix_array_list.h               |   6 +-
 utils/include/celix_filter.h                   |  81 +++
 utils/include/filter.h                         |  51 ++
 utils/private/test/filter_test.cpp             | 537 +++++++++++++++
 utils/src/filter.c                             | 724 ++++++++++++++++++++
 13 files changed, 1616 insertions(+), 822 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/celix/blob/8e716743/framework/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/framework/CMakeLists.txt b/framework/CMakeLists.txt
index 9f237af..1f0f423 100644
--- a/framework/CMakeLists.txt
+++ b/framework/CMakeLists.txt
@@ -26,7 +26,7 @@ endif(WIN32)
 set(SOURCES
         src/attribute.c src/bundle.c src/bundle_archive.c src/bundle_cache.c
         src/bundle_context.c src/bundle_revision.c src/capability.c src/celix_errorcodes.c
-        src/filter.c src/framework.c src/manifest.c src/ioapi.c
+        src/framework.c src/manifest.c src/ioapi.c
         src/manifest_parser.c src/miniunz.c src/module.c
         src/requirement.c src/resolver.c src/service_reference.c src/service_registration.c
         src/service_registry.c src/service_tracker.c src/service_tracker_customizer.c
@@ -164,13 +164,6 @@ if (ENABLE_TESTING AND FRAMEWORK_TESTS)
         src/celix_errorcodes.c)
     target_link_libraries(celix_errorcodes_test ${CPPUTEST_LIBRARY} Celix::utils)
 
-    add_executable(filter_test
-        private/test/filter_test.cpp
-        src/filter.c
-        src/celix_errorcodes.c
-        private/mock/celix_log_mock.c)
-    target_link_libraries(filter_test ${CPPUTEST_LIBRARY} ${CPPUTEST_EXT_LIBRARY} Celix::utils pthread)
-
     add_executable(framework_test
         private/test/framework_test.cpp
         #private/mock/properties_mock.c

http://git-wip-us.apache.org/repos/asf/celix/blob/8e716743/framework/include/celix_bundle_context.h
----------------------------------------------------------------------
diff --git a/framework/include/celix_bundle_context.h b/framework/include/celix_bundle_context.h
index 1e8dff5..50968e1 100644
--- a/framework/include/celix_bundle_context.h
+++ b/framework/include/celix_bundle_context.h
@@ -673,9 +673,58 @@ void celix_bundleContext_useBundles(
 );
 
 
+
 //TODO add useBundleWithOptions (e.g. which state)
 //TODO findBundles
-//TODO trackServiceTracker
+
+/**
+ * Service Tracker Info provided to the service tracker tracker callbacks.
+ */
+typedef struct celix_service_tracker_info {
+    /**
+     * The parsed service filter, e.g. parsed "(&(objectClass=example_calc)(service.language=C)(meta.info=foo))"
+     */
+    celix_filter_t *filter;
+
+    /**
+     *The service name filter attribute parsed from the service filter (i.e. the value of the objectClass attribute key)
+     */
+    const char *serviceName;
+
+    /**
+     * The service language filter attribute parsed from the service filter. Can be null
+     */
+    const char *serviceLanguage;
+
+    /**
+     * Bundle id of the owner of the service tracker.
+     */
+    long bundleId;
+} celix_service_tracker_info_t;
+
+/**
+ * Track the service tracker targeting the provided service name. This can be used to track if there is an interest
+ * in a certain service and ad-hoc act on that interest.
+ *
+ * Note that the celix_service_tracker_info_t pointer in the trackerAdd/trackerRemove callbacks are only valid during
+ * the callback.
+ *
+ * This tracker can be stopped with the celix_bundleContext_stopTracker function.
+ *
+ * @param ctx The bundle context
+ * @param serviceName The target service name for the service tracker to track.
+ * @param callbackHandle The callback handle which will be provided as handle in the trackerAdd and trackerRemove callback.
+ * @param trackerAdd Called when a service tracker is added, which tracks the provided service name. Will also be called
+ *                   for all existing service tracker when this tracker is started.
+ * @param trackerRemove Called when a service tracker is removed, which tracks the provided service name
+ * @return The tracker id or <0 if something went wrong (will log an error).
+ */
+long celix_bundleContext_trackServiceTrackers(
+        celix_bundle_context_t *ctx,
+        const char *serviceName,
+        void *callbackHandle,
+        void (*trackerAdd)(void *handle, const celix_service_tracker_info_t *info),
+        void (*trackerRemove)(void *handle, const celix_service_tracker_info_t *info));
 
 /**
  * Gets the dependency manager for this bundle context.

http://git-wip-us.apache.org/repos/asf/celix/blob/8e716743/framework/include/filter.h
----------------------------------------------------------------------
diff --git a/framework/include/filter.h b/framework/include/filter.h
deleted file mode 100644
index b636c74..0000000
--- a/framework/include/filter.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- *Licensed to the Apache Software Foundation (ASF) under one
- *or more contributor license agreements.  See the NOTICE file
- *distributed with this work for additional information
- *regarding copyright ownership.  The ASF licenses this file
- *to you under the Apache License, Version 2.0 (the
- *"License"); you may not use this file except in compliance
- *with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- *Unless required by applicable law or agreed to in writing,
- *software distributed under the License is distributed on an
- *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- *specific language governing permissions and limitations
- *under the License.
- */
-/*
- * filter.h
- *
- *  \date       Apr 28, 2010
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
-
-#ifndef FILTER_H_
-#define FILTER_H_
-
-#include "celix_errno.h"
-#include "properties.h"
-#include "celixbool.h"
-#include "framework_exports.h"
-#include "array_list.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum celix_filter_operand_enum
-{
-    CELIX_FILTER_OPERAND_EQUAL,
-    CELIX_FILTER_OPERAND_APPROX,
-    CELIX_FILTER_OPERAND_GREATER,
-    CELIX_FILTER_OPERAND_GREATEREQUAL,
-    CELIX_FILTER_OPERAND_LESS,
-    CELIX_FILTER_OPERAND_LESSEQUAL,
-    CELIX_FILTER_OPERAND_PRESENT,
-    CELIX_FILTER_OPERAND_SUBSTRING,
-    CELIX_FILTER_OPERAND_AND,
-    CELIX_FILTER_OPERAND_OR,
-    CELIX_FILTER_OPERAND_NOT,
-} celix_filter_operand_t;
-
-typedef struct celix_filter_struct filter_t; //deprecated
-typedef struct celix_filter_struct *filter_pt; //deprecated
-
-typedef struct celix_filter_struct celix_filter_t;
-
-struct celix_filter_struct {
-    celix_filter_operand_t operand;
-    const char *attribute; //NULL for operands AND, OR ot NOT
-    const char *value; //NULL for operands AND, OR or NOT NOT
-    const char *filterStr;
-
-    //type is celix_filter_t* for AND, OR and NOT operator and char* for SUBSTRING
-    //for other operands childern is NULL
-    array_list_t *children;
-};
-
-FRAMEWORK_EXPORT celix_filter_t* filter_create(const char *filterString);
-
-FRAMEWORK_EXPORT void filter_destroy(celix_filter_t *filter);
-
-FRAMEWORK_EXPORT celix_status_t filter_match(celix_filter_t *filter, properties_t *properties, bool *result);
-
-FRAMEWORK_EXPORT celix_status_t filter_match_filter(celix_filter_t *src, filter_t *dest, bool *result);
-
-FRAMEWORK_EXPORT celix_status_t filter_getString(celix_filter_t *filter, const char **filterStr);
-
-FRAMEWORK_EXPORT celix_status_t filter_getString(celix_filter_t *filter, const char **filterStr);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* FILTER_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/8e716743/framework/src/bundle_context.c
----------------------------------------------------------------------
diff --git a/framework/src/bundle_context.c b/framework/src/bundle_context.c
index 3e075d0..4fac5e7 100644
--- a/framework/src/bundle_context.c
+++ b/framework/src/bundle_context.c
@@ -33,8 +33,9 @@
 #include "celix_array_list.h"
 
 static celix_status_t bundleContext_bundleChanged(void *handle, bundle_event_t *event);
-static void bundleContext_cleanupBundleTracker(bundle_context_t *ct);
-static void bundleContext_cleanupServiceTracker(bundle_context_t *ctx);
+static void bundleContext_cleanupBundleTrackers(bundle_context_t *ct);
+static void bundleContext_cleanupServiceTrackers(bundle_context_t *ctx);
+static void bundleContext_cleanupServiceTrackerTrackers(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;
@@ -56,6 +57,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->serviceTrackerTrackers =  hashMap_create(NULL,NULL,NULL,NULL);
             context->nextTrackerId = 1L;
 
             *bundle_context = context;
@@ -74,8 +76,12 @@ celix_status_t bundleContext_destroy(bundle_context_pt context) {
 	if (context != NULL) {
 	    celixThreadMutex_lock(&context->mutex);
 
-	    bundleContext_cleanupBundleTracker(context);
-	    bundleContext_cleanupServiceTracker(context);
+
+	    bundleContext_cleanupBundleTrackers(context);
+	    bundleContext_cleanupServiceTrackers(context);
+        bundleContext_cleanupServiceTrackerTrackers(context);
+
+        //TODO cleanup service registrations
 
 	    //NOTE still present service registrations will be cleared during bundle stop in the
 	    //service registry (serviceRegistry_clearServiceRegistrations).
@@ -523,7 +529,7 @@ dm_dependency_manager_t* celix_bundleContext_getDependencyManager(bundle_context
 static celix_status_t bundleContext_bundleChanged(void *listenerSvc, bundle_event_t *event) {
     celix_status_t status = CELIX_SUCCESS;
     bundle_listener_t *listener = listenerSvc;
-    celix_bundle_context_bundle_tracker_t *tracker = NULL;
+    celix_bundle_context_bundle_tracker_entry_t *tracker = NULL;
     if (listener != NULL) {
         tracker = listener->handle;
     }
@@ -549,33 +555,33 @@ static celix_status_t bundleContext_bundleChanged(void *listenerSvc, bundle_even
 long celix_bundleContext_trackBundlesWithOptions(
         bundle_context_t* ctx,
         const celix_bundle_tracking_options_t *opts) {
-    long trackId = -1;
-    struct celix_bundle_context_bundle_tracker *tracker = calloc(1, sizeof(*tracker));
-    if (tracker != NULL) {
-        memcpy(&tracker->opts, opts, sizeof(*opts));
-        tracker->ctx = ctx;
-        tracker->listener.handle = tracker;
-        tracker->listener.bundleChanged = bundleContext_bundleChanged;
-        fw_addBundleListener(ctx->framework, ctx->bundle, &tracker->listener);
+    long trackerId = -1;
+    celix_bundle_context_bundle_tracker_entry_t *entry = calloc(1, sizeof(*entry));
+    if (entry != NULL) {
+        memcpy(&entry->opts, opts, sizeof(*opts));
+        entry->ctx = ctx;
+        entry->listener.handle = entry;
+        entry->listener.bundleChanged = bundleContext_bundleChanged;
+        fw_addBundleListener(ctx->framework, ctx->bundle, &entry->listener);
 
         celixThreadMutex_lock(&ctx->mutex);
-        tracker->trackId = ctx->nextTrackerId++;
+        entry->trackerId = ctx->nextTrackerId++;
         celixThreadMutex_unlock(&ctx->mutex);
-        trackId = tracker->trackId;
+        trackerId = entry->trackerId;
 
         //loop through all already installed bundles.
         // FIXME there is a race condition between installing the listener and looping through the started bundles.
         // NOTE move this to the framework, so that the framework can ensure locking to ensure not bundles is missed.
-        if (tracker->opts.onStarted != NULL) {
-            celix_framework_useBundles(ctx->framework, tracker->opts.callbackHandle, tracker->opts.onStarted);
+        if (entry->opts.onStarted != NULL) {
+            celix_framework_useBundles(ctx->framework, entry->opts.callbackHandle, entry->opts.onStarted);
         }
 
         celixThreadMutex_lock(&ctx->mutex);
-        hashMap_put(ctx->bundleTrackers, (void*)tracker->trackId, tracker);
+        hashMap_put(ctx->bundleTrackers, (void*)entry->trackerId, entry);
         celixThreadMutex_unlock(&ctx->mutex);
 
     }
-    return trackId;
+    return trackerId;
 }
 
 long celix_bundleContext_trackBundles(
@@ -607,17 +613,17 @@ void celix_bundleContext_useBundle(
     celix_framework_useBundle(ctx->framework, bundleId, callbackHandle, use);
 }
 
-static void bundleContext_cleanupBundleTracker(bundle_context_t *ctx) {
+static void bundleContext_cleanupBundleTrackers(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);
+        celix_bundle_context_bundle_tracker_entry_t *tracker = hashMapIterator_nextValue(&iter);
         fw_removeBundleListener(ctx->framework, ctx->bundle, &tracker->listener);
         free(tracker);
     }
     hashMap_destroy(ctx->bundleTrackers, false, false);
 }
 
-static void bundleContext_cleanupServiceTracker(bundle_context_t *ctx) {
+static void bundleContext_cleanupServiceTrackers(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);
@@ -626,6 +632,16 @@ static void bundleContext_cleanupServiceTracker(bundle_context_t *ctx) {
     hashMap_destroy(ctx->serviceTrackers, false, false);
 }
 
+static void bundleContext_cleanupServiceTrackerTrackers(bundle_context_t *ctx) {
+    hash_map_iterator_t iter = hashMapIterator_construct(ctx->serviceTrackerTrackers);
+    while (hashMapIterator_hasNext(&iter)) {
+        celix_bundle_context_service_tracker_tracker_entry_t *entry = hashMapIterator_nextValue(&iter);
+        serviceRegistration_unregister(entry->hookReg);
+        free(entry);
+    }
+    hashMap_destroy(ctx->serviceTrackerTrackers, false, false);
+}
+
 
 void celix_bundleContext_stopTracker(bundle_context_t *ctx, long trackerId) {
     if (ctx != NULL && trackerId >0) {
@@ -633,15 +649,19 @@ void celix_bundleContext_stopTracker(bundle_context_t *ctx, long trackerId) {
         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);
+            celix_bundle_context_bundle_tracker_entry_t *tracker = hashMap_remove(ctx->bundleTrackers, (void*)trackerId);
             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);
+        } else if (hashMap_containsKey(ctx->serviceTrackerTrackers, (void*)trackerId)) {
+            found = true;
+            celix_bundle_context_service_tracker_tracker_entry_t *entry = hashMap_remove(ctx->serviceTrackerTrackers, (void*)trackerId);
+            serviceRegistration_unregister(entry->hookReg);
+            free(entry);
         }
-        //TODO service tracker tracker
 
         if (!found) {
             framework_logIfError(logger, CELIX_ILLEGAL_ARGUMENT, NULL, "No tracker with id %li found'", trackerId);
@@ -868,4 +888,71 @@ celix_array_list_t* celix_bundleContext_findServicesWithOptions(celix_bundle_con
     useOpts.useWithProperties = bundleContext_retrieveSvcIds;
     celix_bundleContext_useServicesWithOptions(ctx, &useOpts);
     return list;
+}
+
+static celix_status_t bundleContext_callServicedTrackerTrackerCallback(void *handle, celix_array_list_t *listeners, bool add) {
+    celix_bundle_context_service_tracker_tracker_entry_t *entry = handle;
+    if (entry != NULL) {
+        size_t size = celix_arrayList_size(listeners);
+        for (unsigned int i = 0; i < size; ++i) {
+            listener_hook_info_pt info = arrayList_get(listeners, i);
+            celix_bundle_t *bnd = NULL;
+            bundleContext_getBundle(info->context, &bnd);
+
+            celix_service_tracker_info_t trkInfo;
+            memset(&trkInfo, 0, sizeof(trkInfo));
+            trkInfo.bundleId = celix_bundle_getId(bnd);
+            trkInfo.filter = celix_filter_create(info->filter);
+            trkInfo.serviceName = celix_filter_findAttribute(trkInfo.filter, OSGI_FRAMEWORK_OBJECTCLASS);
+            trkInfo.serviceLanguage = celix_filter_findAttribute(trkInfo.filter, CELIX_FRAMEWORK_SERVICE_LANGUAGE);
+            if (add && entry->add != NULL) {
+                entry->add(entry->callbackHandle, &trkInfo);
+            } else if (entry->remove != NULL) {
+                entry->remove(entry->callbackHandle, &trkInfo);
+            }
+            celix_filter_destroy(trkInfo.filter);
+        }
+    }
+    return CELIX_SUCCESS;
+}
+
+static celix_status_t bundleContext_callServicedTrackerTrackerAdd(void *handle, celix_array_list_t *listeners) {
+    return bundleContext_callServicedTrackerTrackerCallback(handle, listeners, true);
+}
+
+static celix_status_t bundleContext_callServicedTrackerTrackerRemove(void *handle, celix_array_list_t *listeners) {
+    return bundleContext_callServicedTrackerTrackerCallback(handle, listeners, false);
+}
+
+long celix_bundleContext_trackServiceTrackers(
+        celix_bundle_context_t *ctx,
+        const char *serviceName,
+        void *callbackHandle,
+        void (*trackerAdd)(void *handle, const celix_service_tracker_info_t *info),
+        void (*trackerRemove)(void *handle, const celix_service_tracker_info_t *info)) {
+
+    long trackerId = -1L;
+
+    celix_bundle_context_service_tracker_tracker_entry_t *entry = calloc(1, sizeof(*entry));
+
+    entry->callbackHandle = callbackHandle;
+    entry->add = trackerAdd;
+    entry->remove = trackerRemove;
+
+    entry->hook.handle = entry;
+    entry->hook.added = bundleContext_callServicedTrackerTrackerAdd;
+    entry->hook.removed = bundleContext_callServicedTrackerTrackerRemove;
+    bundleContext_registerService(ctx, OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME, &entry->hook, NULL, &entry->hookReg);
+
+    if (entry->hookReg != NULL) {
+        celixThreadMutex_lock(&ctx->mutex);
+        entry->trackerId = ctx->nextTrackerId++;
+        hashMap_put(ctx->serviceTrackerTrackers, (void*)entry->trackerId, entry);
+        trackerId = entry->trackerId;
+        celixThreadMutex_unlock(&ctx->mutex);
+    } else {
+        framework_log(ctx->framework->logger, OSGI_FRAMEWORK_LOG_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__, "Error registering service listener hook for service tracker tracker\n");
+        free(entry);
+    }
+    return trackerId;
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/celix/blob/8e716743/framework/src/bundle_context_private.h
----------------------------------------------------------------------
diff --git a/framework/src/bundle_context_private.h b/framework/src/bundle_context_private.h
index fc3077f..bdd20f8 100644
--- a/framework/src/bundle_context_private.h
+++ b/framework/src/bundle_context_private.h
@@ -32,13 +32,25 @@
 #include "celix_log.h"
 #include "bundle_listener.h"
 #include "celix_bundle_context.h"
+#include "listener_hook_service.h"
 
-typedef struct celix_bundle_context_bundle_tracker {
-	bundle_context_t *ctx;
-	long trackId;
+typedef struct celix_bundle_context_bundle_tracker_entry {
+	celix_bundle_context_t *ctx;
+	long trackerId;
 	bundle_listener_t listener;
 	celix_bundle_tracking_options_t opts;
-} celix_bundle_context_bundle_tracker_t;
+} celix_bundle_context_bundle_tracker_entry_t;
+
+typedef struct celix_bundle_context_service_tracker_tracker_entry {
+	long trackerId;
+
+	struct listener_hook_service hook;
+	service_registration_t *hookReg;
+
+	void *callbackHandle;
+	void (*add)(void *handle, const celix_service_tracker_info_t *info);
+	void (*remove)(void *handle, const celix_service_tracker_info_t *info);
+} celix_bundle_context_service_tracker_tracker_entry_t;
 
 struct bundleContext {
 	struct framework * framework;
@@ -48,8 +60,9 @@ struct bundleContext {
 	array_list_t *svcRegistrations;
 	dm_dependency_manager_t *mng;
 	long nextTrackerId;
-	hash_map_t *bundleTrackers; //key = trackerId, value = celix_bundle_context_bundle_tracker_t*
+	hash_map_t *bundleTrackers; //key = trackerId, value = celix_bundle_context_bundle_tracker_entry_t*
 	hash_map_t *serviceTrackers; //key = trackerId, value = celix_service_tracker_t*
+	hash_map_t *serviceTrackerTrackers; //key = trackerId, value = celix_bundle_context_service_tracker_tracker_entry_t*
 };
 
 

http://git-wip-us.apache.org/repos/asf/celix/blob/8e716743/framework/src/filter.c
----------------------------------------------------------------------
diff --git a/framework/src/filter.c b/framework/src/filter.c
deleted file mode 100644
index b2d942b..0000000
--- a/framework/src/filter.c
+++ /dev/null
@@ -1,692 +0,0 @@
-/**
- *Licensed to the Apache Software Foundation (ASF) under one
- *or more contributor license agreements.  See the NOTICE file
- *distributed with this work for additional information
- *regarding copyright ownership.  The ASF licenses this file
- *to you under the Apache License, Version 2.0 (the
- *"License"); you may not use this file except in compliance
- *with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- *Unless required by applicable law or agreed to in writing,
- *software distributed under the License is distributed on an
- *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- *specific language governing permissions and limitations
- *under the License.
- */
-/*
- * filter.c
- *
- *  \date       Apr 28, 2010
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <assert.h>
-#include <utils.h>
-
-#include "celix_log.h"
-#include "filter.h"
-
-static void filter_skipWhiteSpace(char* filterString, int* pos);
-static celix_filter_t * filter_parseFilter(char* filterString, int* pos);
-static celix_filter_t * filter_parseFilterComp(char* filterString, int* pos);
-static celix_filter_t * filter_parseAndOrOr(char* filterString, celix_filter_operand_t andOrOr, int* pos);
-static celix_filter_t * filter_parseNot(char* filterString, int* pos);
-static celix_filter_t * filter_parseItem(char* filterString, int* pos);
-static char * filter_parseAttr(char* filterString, int* pos);
-static char * filter_parseValue(char* filterString, int* pos);
-static array_list_pt filter_parseSubstring(char* filterString, int* pos);
-
-static celix_status_t filter_compare(celix_filter_t* filter, const char *propertyValue, bool *result);
-
-static void filter_skipWhiteSpace(char * filterString, int * pos) {
-	int length;
-	for (length = strlen(filterString); (*pos < length) && isspace(filterString[*pos]);) {
-		(*pos)++;
-	}
-}
-
-celix_filter_t * filter_create(const char* filterString) {
-	celix_filter_t * filter = NULL;
-	char* filterStr = string_ndup(filterString, 1024*1024);
-	int pos = 0;
-	filter = filter_parseFilter(filterStr, &pos);
-	if (filter != NULL && pos != strlen(filterStr)) {
-		fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR,  "Error: Extraneous trailing characters.");
-		filter_destroy(filter);
-		filter = NULL;
-	} else if (filter != NULL) {
-        if (filter->operand != CELIX_FILTER_OPERAND_OR && filter->operand != CELIX_FILTER_OPERAND_AND &&
-            filter->operand != CELIX_FILTER_OPERAND_NOT && filter->operand != CELIX_FILTER_OPERAND_SUBSTRING &&
-            filter->operand != CELIX_FILTER_OPERAND_PRESENT) {
-            if (filter->attribute == NULL || filter->value == NULL) {
-                filter_destroy(filter);
-                filter = NULL;
-            }
-        }
-    }
-
-	if (filter == NULL) {
-		free(filterStr);
-	} else {
-		filter->filterStr = filterStr;
-	}
-
-	return filter;
-}
-
-void filter_destroy(celix_filter_t * filter) {
-	if (filter != NULL) {
-		if(filter->children != NULL){
-			if (filter->operand == CELIX_FILTER_OPERAND_SUBSTRING) {
-				int size = arrayList_size(filter->children);
-				int i = 0;
-				for (i = 0; i < size; i++) {
-					char *operand = arrayList_get(filter->children, i);
-					free(operand);
-				}
-				arrayList_destroy(filter->children);
-				filter->children = NULL;
-			} else if (filter->operand == CELIX_FILTER_OPERAND_OR || filter->operand == CELIX_FILTER_OPERAND_AND || filter->operand == CELIX_FILTER_OPERAND_NOT) {
-                int size = arrayList_size(filter->children);
-                int i = 0;
-                for (i = 0; i < size; i++) {
-                    celix_filter_t *f = arrayList_get(filter->children, i);
-                    filter_destroy(f);
-                }
-                arrayList_destroy(filter->children);
-                filter->children = NULL;
-            } else {
-                fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR,  "Error: Corrupt filter. childern has a value, but not an expected operand");
-            }
-		}
-        free((char*)filter->value);
-        filter->value = NULL;
-		free((char*)filter->attribute);
-		filter->attribute = NULL;
-        free((char*)filter->filterStr);
-        filter->filterStr = NULL;
-        free(filter);
-	}
-}
-
-static celix_filter_t * filter_parseFilter(char * filterString, int * pos) {
-	celix_filter_t * filter;
-	filter_skipWhiteSpace(filterString, pos);
-	if (filterString[*pos] != '(') {
-		fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Error: Missing '(' in filter string '%s'.", filterString);
-		return NULL;
-	}
-	(*pos)++;
-
-	filter = filter_parseFilterComp(filterString, pos);
-
-	filter_skipWhiteSpace(filterString, pos);
-
-	if (filterString[*pos] != ')') {
-		fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Error: Missing ')' in filter string '%s'.", filterString);
-		if(filter!=NULL){
-			filter_destroy(filter);
-		}
-		return NULL;
-	}
-	(*pos)++;
-	filter_skipWhiteSpace(filterString, pos);
-
-	return filter;
-}
-
-static celix_filter_t * filter_parseFilterComp(char * filterString, int * pos) {
-	char c;
-	filter_skipWhiteSpace(filterString, pos);
-
-	c = filterString[*pos];
-
-	switch (c) {
-		case '&': {
-			(*pos)++;
-			return filter_parseAndOrOr(filterString, CELIX_FILTER_OPERAND_AND, pos);
-		}
-		case '|': {
-			(*pos)++;
-			return filter_parseAndOrOr(filterString, CELIX_FILTER_OPERAND_OR, pos);
-		}
-		case '!': {
-			(*pos)++;
-			return filter_parseNot(filterString, pos);
-		}
-	}
-	return filter_parseItem(filterString, pos);
-}
-
-static celix_filter_t * filter_parseAndOrOr(char * filterString, celix_filter_operand_t andOrOr, int * pos) {
-
-	array_list_pt children = NULL;
-	filter_skipWhiteSpace(filterString, pos);
-	bool failure = false;
-
-	if (filterString[*pos] != '(') {
-		fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Error: Missing '('.");
-		return NULL;
-	}
-
-	arrayList_create(&children);
-	while(filterString[*pos] == '(') {
-		celix_filter_t * child = filter_parseFilter(filterString, pos);
-		if(child == NULL) {
-			failure = true;
-			break;
-		}
-		arrayList_add(children, child);
-	}
-
-	if(failure == true){
-        int i;
-		for (i = 0; i < arrayList_size(children); ++i) {
-			celix_filter_t * f = arrayList_get(children, i);
-			filter_destroy(f);
-		}
-		arrayList_destroy(children);
-        children = NULL;
-	}
-
-	celix_filter_t * filter = (celix_filter_t *) calloc(1, sizeof(*filter));
-	filter->operand = andOrOr;
-    filter->children = children;
-
-	return filter;
-}
-
-static celix_filter_t * filter_parseNot(char * filterString, int * pos) {
-	celix_filter_t * child = NULL;
-	filter_skipWhiteSpace(filterString, pos);
-
-	if (filterString[*pos] != '(') {
-		fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Error: Missing '('.");
-		return NULL;
-	}
-
-	child = filter_parseFilter(filterString, pos);
-
-    array_list_t* children = NULL;
-    arrayList_create(&children);
-    arrayList_add(children, child);
-
-	celix_filter_t * filter = (celix_filter_t *) calloc(1, sizeof(*filter));
-	filter->operand = CELIX_FILTER_OPERAND_NOT;
-	filter->children = children;
-
-	return filter;
-}
-
-static celix_filter_t * filter_parseItem(char * filterString, int * pos) {
-	char * attr = filter_parseAttr(filterString, pos);
-	if(attr == NULL){
-		return NULL;
-	}
-
-	filter_skipWhiteSpace(filterString, pos);
-	switch(filterString[*pos]) {
-		case '~': {
-			if (filterString[*pos + 1] == '=') {
-				celix_filter_t * filter = (celix_filter_t *) calloc(1, sizeof(*filter));
-				*pos += 2;
-				filter->operand = CELIX_FILTER_OPERAND_APPROX;
-				filter->attribute = attr;
-				filter->value = filter_parseValue(filterString, pos);
-				return filter;
-			}
-			break;
-		}
-		case '>': {
-			if (filterString[*pos + 1] == '=') {
-				celix_filter_t * filter = (celix_filter_t *) calloc(1, sizeof(*filter));
-				*pos += 2;
-				filter->operand = CELIX_FILTER_OPERAND_GREATEREQUAL;
-				filter->attribute = attr;
-				filter->value = filter_parseValue(filterString, pos);
-				return filter;
-			}
-			else {
-                celix_filter_t * filter = (celix_filter_t *) calloc(1, sizeof(*filter));
-                *pos += 1;
-                filter->operand = CELIX_FILTER_OPERAND_GREATER;
-                filter->attribute = attr;
-                filter->value = filter_parseValue(filterString, pos);
-                return filter;
-			}
-			break;
-		}
-		case '<': {
-			if (filterString[*pos + 1] == '=') {
-				celix_filter_t * filter = (celix_filter_t *) calloc(1, sizeof(*filter));
-				*pos += 2;
-				filter->operand = CELIX_FILTER_OPERAND_LESSEQUAL;
-				filter->attribute = attr;
-				filter->value = filter_parseValue(filterString, pos);
-				return filter;
-			}
-			else {
-                celix_filter_t * filter = (celix_filter_t *) calloc(1, sizeof(*filter));
-                *pos += 1;
-                filter->operand = CELIX_FILTER_OPERAND_LESS;
-                filter->attribute = attr;
-                filter->value = filter_parseValue(filterString, pos);
-                return filter;
-			}
-			break;
-		}
-		case '=': {
-			celix_filter_t * filter = NULL;
-			array_list_pt subs;
-			if (filterString[*pos + 1] == '*') {
-				int oldPos = *pos;
-				*pos += 2;
-				filter_skipWhiteSpace(filterString, pos);
-				if (filterString[*pos] == ')') {
-					celix_filter_t * filter = (celix_filter_t *) calloc(1, sizeof(*filter));
-					filter->operand = CELIX_FILTER_OPERAND_PRESENT;
-					filter->attribute = attr;
-					filter->value = NULL;
-					return filter;
-				}
-				*pos = oldPos;
-			}
-			filter = (celix_filter_t *) calloc(1, sizeof(*filter));			
-			(*pos)++;
-			subs = filter_parseSubstring(filterString, pos);
-			if(subs!=NULL){
-				if (arrayList_size(subs) == 1) {
-					char * string = (char *) arrayList_get(subs, 0);
-					if (string != NULL) {
-						filter->operand = CELIX_FILTER_OPERAND_EQUAL;
-						filter->attribute = attr;
-						filter->value = string;
-
-						arrayList_clear(subs);
-						arrayList_destroy(subs);
-
-						return filter;
-					}
-				}
-			}
-			filter->operand = CELIX_FILTER_OPERAND_SUBSTRING;
-			filter->attribute = attr;
-            filter->children = subs;
-			return filter;
-		}
-	}
-	fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Invalid operator.");
-	free(attr);
-	return NULL;
-}
-
-static char * filter_parseAttr(char * filterString, int * pos) {
-	char c;
-	int begin = *pos;
-	int end = *pos;
-	int length = 0;
-
-	filter_skipWhiteSpace(filterString, pos);
-	c = filterString[*pos];
-
-	while (c != '~' && c != '<' && c != '>' && c != '=' && c != '(' && c != ')') {
-		(*pos)++;
-
-		if (!isspace(c)) {
-			end = *pos;
-		}
-
-		c = filterString[*pos];
-	}
-
-	length = end - begin;
-
-	if (length == 0) {
-		fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Missing attr.");
-		return NULL;
-	} else {
-		char * attr = (char *) calloc(1, length+1);
-		strncpy(attr, filterString+begin, length);
-		attr[length] = '\0';
-		return attr;
-	}
-}
-
-static char * filter_parseValue(char * filterString, int * pos) {
-	char *value = calloc(strlen(filterString) + 1, sizeof(*value));
-	int keepRunning = 1;
-
-	while (keepRunning) {
-		char c = filterString[*pos];
-
-		switch (c) {
-			case ')': {
-				keepRunning = 0;
-				break;
-			}
-			case '(': {
-				fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Invalid value.");
-				free(value);
-				return NULL;
-			}
-			case '\0':{
-				fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Unclosed bracket.");
-				free(value);
-				return NULL;
-			}
-			case '\\': {
-				(*pos)++;
-				c = filterString[*pos];
-			}
-			/* no break */
-			default: {
-				char ch[2];
-				ch[0] = c;
-				ch[1] = '\0';
-				strcat(value, ch);
-				(*pos)++;
-				break;
-			}
-		}
-	}
-
-	if (strlen(value) == 0) {
-		fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Missing value.");
-		free(value);
-		return NULL;
-	}
-	return value;
-}
-
-static array_list_pt filter_parseSubstring(char * filterString, int * pos) {
-	char *sub = calloc(strlen(filterString) + 1, sizeof(*sub));
-	array_list_pt operands = NULL;
-	int keepRunning = 1;
-
-	arrayList_create(&operands);
-	while (keepRunning) {
-		char c = filterString[*pos];
-		
-
-		switch (c) {
-			case ')': {
-				if (strlen(sub) > 0) {
-					arrayList_add(operands, strdup(sub));
-				}
-				keepRunning = 0;
-				break;
-			}
-			case '\0':{
-				fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Unclosed bracket.");
-				keepRunning = false;
-				break;
-			}
-			case '(': {
-				fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Invalid value.");
-				keepRunning = false;
-				break;
-			}
-			case '*': {
-				if (strlen(sub) > 0) {
-					arrayList_add(operands, strdup(sub));
-				}
-				sub[0] = '\0';
-				arrayList_add(operands, NULL);
-				(*pos)++;
-				break;
-			}
-			case '\\': {
-				(*pos)++;
-				c = filterString[*pos];
-			}
-			/* no break */
-			default: {
-				char ch[2];
-				ch[0] = c;
-				ch[1] = '\0';
-				strcat(sub, ch);
-				(*pos)++;
-				break;
-			}
-		}
-	}
-	free(sub);
-
-	if (arrayList_size(operands) == 0) {
-		fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Missing value.");
-		arrayList_destroy(operands);
-		return NULL;
-	}
-
-	return operands;
-}
-
-celix_status_t filter_match(celix_filter_t * filter, properties_pt properties, bool *result) {
-	switch (filter->operand) {
-		case CELIX_FILTER_OPERAND_AND: {
-			array_list_pt children = filter->children;
-			unsigned int i;
-			for (i = 0; i < arrayList_size(children); i++) {
-				celix_filter_t * sfilter = (celix_filter_t *) arrayList_get(children, i);
-				bool mresult;
-				filter_match(sfilter, properties, &mresult);
-				if (!mresult) {
-					*result = 0;
-					return CELIX_SUCCESS;
-				}
-			}
-			*result = 1;
-			return CELIX_SUCCESS;
-		}
-		case CELIX_FILTER_OPERAND_OR: {
-			array_list_pt children = filter->children;
-			unsigned int i;
-			for (i = 0; i < arrayList_size(children); i++) {
-				celix_filter_t * sfilter = (celix_filter_t *) arrayList_get(children, i);
-				bool mresult;
-				filter_match(sfilter, properties, &mresult);
-				if (mresult) {
-					*result = 1;
-					return CELIX_SUCCESS;
-				}
-			}
-			*result = 0;
-			return CELIX_SUCCESS;
-		}
-		case CELIX_FILTER_OPERAND_NOT: {
-			celix_filter_t * sfilter = arrayList_get(filter->children, 0);
-			bool mresult;
-			filter_match(sfilter, properties, &mresult);
-			*result = !mresult;
-			return CELIX_SUCCESS;
-		}
-		case CELIX_FILTER_OPERAND_SUBSTRING :
-		case CELIX_FILTER_OPERAND_EQUAL :
-		case CELIX_FILTER_OPERAND_GREATER :
-        case CELIX_FILTER_OPERAND_GREATEREQUAL :
-		case CELIX_FILTER_OPERAND_LESS :
-        case CELIX_FILTER_OPERAND_LESSEQUAL :
-		case CELIX_FILTER_OPERAND_APPROX : {
-			char * value = (properties == NULL) ? NULL: (char*)properties_get(properties, filter->attribute);
-
-			return filter_compare(filter, value, result);
-		}
-		case CELIX_FILTER_OPERAND_PRESENT: {
-			char * value = (properties == NULL) ? NULL: (char*)properties_get(properties, filter->attribute);
-			*result = value != NULL;
-			return CELIX_SUCCESS;
-		}
-	}
-	*result = 0;
-	return CELIX_SUCCESS;
-}
-
-static celix_status_t filter_compare(celix_filter_t* filter, const char *propertyValue, bool *out) {
-    celix_status_t  status = CELIX_SUCCESS;
-    bool result = false;
-
-    if (filter == NULL || propertyValue == NULL) {
-        *out = false;
-        return status;
-    }
-
-    switch (filter->operand) {
-        case CELIX_FILTER_OPERAND_SUBSTRING: {
-            int pos = 0;
-            unsigned int i;
-            int size = arrayList_size(filter->children);
-            for (i = 0; i < size; i++) {
-                char * substr = (char *) arrayList_get(filter->children, i);
-
-                if (i + 1 < size) {
-                    if (substr == NULL) {
-                        unsigned int index;
-                        char * substr2 = (char *) arrayList_get(filter->children, i + 1);
-                        if (substr2 == NULL) {
-                            continue;
-                        }
-                        index = strcspn(propertyValue+pos, substr2);
-                        if (index == strlen(propertyValue+pos)) {
-                            *out = false;
-                            return CELIX_SUCCESS;
-                        }
-
-                        pos = index + strlen(substr2);
-                        if (i + 2 < size) {
-                            i++;
-                        }
-                    } else {
-                        unsigned int len = strlen(substr);
-                        char * region = (char *)calloc(1, len+1);
-                        strncpy(region, propertyValue+pos, len);
-                        region[len]	= '\0';
-                        if (strcmp(region, substr) == 0) {
-                            pos += len;
-                        } else {
-                            free(region);
-                            *out = false;
-                            return CELIX_SUCCESS;
-                        }
-                        free(region);
-                    }
-                } else {
-                    unsigned int len;
-                    int begin;
-
-                    if (substr == NULL) {
-                        *out = true;
-                        return CELIX_SUCCESS;
-                    }
-                    len = strlen(substr);
-                    begin = strlen(propertyValue)-len;
-                    *out = (strcmp(propertyValue+begin, substr) == 0);
-                    return CELIX_SUCCESS;
-                }
-            }
-            *out = true;
-            return CELIX_SUCCESS;
-        }
-        case CELIX_FILTER_OPERAND_APPROX: //TODO: Implement strcmp with ignorecase and ignorespaces
-        case CELIX_FILTER_OPERAND_EQUAL: {
-            *out = (strcmp(propertyValue, filter->value) == 0);
-            return CELIX_SUCCESS;
-        }
-        case CELIX_FILTER_OPERAND_GREATER: {
-            *out = (strcmp(propertyValue, filter->value) > 0);
-            return CELIX_SUCCESS;
-        }
-        case CELIX_FILTER_OPERAND_GREATEREQUAL: {
-            *out = (strcmp(propertyValue, filter->value) >= 0);
-            return CELIX_SUCCESS;
-        }
-        case CELIX_FILTER_OPERAND_LESS: {
-            *out = (strcmp(propertyValue, filter->value) < 0);
-            return CELIX_SUCCESS;
-        }
-        case CELIX_FILTER_OPERAND_LESSEQUAL: {
-            *out = (strcmp(propertyValue, filter->value) <= 0);
-            return CELIX_SUCCESS;
-        }
-        case CELIX_FILTER_OPERAND_AND:
-        case CELIX_FILTER_OPERAND_NOT:
-        case CELIX_FILTER_OPERAND_OR:
-        case CELIX_FILTER_OPERAND_PRESENT: {
-        }
-            /* no break */
-    }
-
-    if (status == CELIX_SUCCESS && out != NULL) {
-        *out = result;
-    }
-    return status;
-}
-
-celix_status_t filter_getString(celix_filter_t * filter, const char **filterStr) {
-	if (filter != NULL) {
-		*filterStr = filter->filterStr;
-	}
-	return CELIX_SUCCESS;
-}
-
-celix_status_t filter_match_filter(celix_filter_t *src, celix_filter_t *dest, bool *out) {
-    celix_status_t  status = CELIX_SUCCESS;
-	bool result = false;
-
-    if (src == dest) {
-        result = true; //NOTE. also means NULL filter are equal
-    } else if (src != NULL && dest != NULL && src->operand == dest->operand) {
-        if (src->operand == CELIX_FILTER_OPERAND_AND || src->operand == CELIX_FILTER_OPERAND_OR || src->operand == CELIX_FILTER_OPERAND_NOT) {
-            assert(src->children != NULL);
-            assert(dest->children != NULL);
-            int sizeSrc = arrayList_size(src->children);
-            int sizeDest = arrayList_size(dest->children);
-            if (sizeSrc == sizeDest) {
-                int i;
-                int k;
-                int sameCount = 0;
-                for (i =0; i < sizeSrc; ++i) {
-                    bool same = false;
-                    celix_filter_t *srcPart = arrayList_get(src->children, i);
-                    for (k = 0; k < sizeDest; ++k) {
-                        celix_filter_t *destPart = arrayList_get(dest->children, k);
-                        filter_match_filter(srcPart, destPart, &same);
-                        if (same) {
-                            sameCount += 1;
-                            break;
-                        }
-                    }
-                }
-                result = sameCount == sizeSrc;
-            }
-        } else { //compare attr and value
-            bool attrSame = false;
-            bool valSame = false;
-            if (src->attribute == NULL && dest->attribute == NULL) {
-                attrSame = true;
-            } else if (src->attribute != NULL && dest->attribute != NULL) {
-                attrSame = strncmp(src->attribute, dest->attribute, 1024 * 1024) == 0;
-            }
-
-            if (src->value == NULL  && dest->value == NULL) {
-                valSame = true;
-            } else if (src->value != NULL && dest->value != NULL) {
-                valSame = strncmp(src->value, dest->value, 1024 * 1024) == 0;
-            }
-
-            result = attrSame && valSame;
-        }
-    }
-
-    if (status == CELIX_SUCCESS && out != NULL) {
-        *out = result;
-    }
-
-	return status;
-}

http://git-wip-us.apache.org/repos/asf/celix/blob/8e716743/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 1302f0a..eb46351 100644
--- a/framework/tst/bundle_context_services_test.cpp
+++ b/framework/tst/bundle_context_services_test.cpp
@@ -653,3 +653,40 @@ TEST(CelixBundleContextServicesTests, findServicesTest) {
 
     celix_bundleContext_unregisterService(ctx, svcId2);
 }
+
+TEST(CelixBundleContextServicesTests, trackServiceTrackerTest) {
+
+    int count = 0;
+
+    auto add = [](void *handle, const celix_service_tracker_info_t *info) {
+        STRCMP_EQUAL("example", info->serviceName);
+        STRCMP_EQUAL(CELIX_FRAMEWORK_SERVICE_C_LANGUAGE, info->serviceLanguage);
+        auto *c = static_cast<int*>(handle);
+        *c += 1;
+    };
+    auto remove = [](void *handle, const celix_service_tracker_info_t *info) {
+        STRCMP_EQUAL("example", info->serviceName);
+        STRCMP_EQUAL(CELIX_FRAMEWORK_SERVICE_C_LANGUAGE, info->serviceLanguage);
+        auto *c = static_cast<int*>(handle);
+        *c -= 1;
+    };
+
+    long trackerId = celix_bundleContext_trackServiceTrackers(ctx, "example", &count, add, remove);
+    CHECK_TRUE(trackerId >= 0);
+    CHECK_EQUAL(0, count);
+
+    long tracker2 = celix_bundleContext_trackService(ctx, "example", NULL, NULL);
+    CHECK_TRUE(tracker2 >= 0);
+    CHECK_EQUAL(1, count);
+
+    long tracker3 = celix_bundleContext_trackServices(ctx, "example", NULL, NULL, NULL);
+    CHECK_TRUE(tracker3 >= 0);
+    CHECK_EQUAL(2, count);
+
+    celix_bundleContext_stopTracker(ctx, tracker2);
+    CHECK_EQUAL(1, count);
+    celix_bundleContext_stopTracker(ctx, tracker3);
+    CHECK_EQUAL(0, count);
+
+    celix_bundleContext_stopTracker(ctx, trackerId);
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/8e716743/utils/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
index 1826902..e8d80bf 100644
--- a/utils/CMakeLists.txt
+++ b/utils/CMakeLists.txt
@@ -34,6 +34,7 @@ add_library(utils SHARED
     src/thpool.c
     src/properties.c
     src/utils.c
+    src/filter.c
     ${MEMSTREAM_SOURCES}
 )
 set_target_properties(utils PROPERTIES OUTPUT_NAME "celix_utils")
@@ -98,6 +99,9 @@ if (ENABLE_TESTING AND UTILS-TESTS)
     add_executable(utils_test private/test/utils_test.cpp)
     target_link_libraries(utils_test ${CPPUTEST_LIBRARY}  Celix::utils pthread)
 
+    add_executable(filter_test private/test/filter_test.cpp)
+    target_link_libraries(filter_test ${CPPUTEST_LIBRARY}  Celix::utils pthread)
+
     configure_file(private/resources-test/properties.txt ${CMAKE_BINARY_DIR}/utils/resources-test/properties.txt COPYONLY)
 
     add_test(NAME run_array_list_test COMMAND array_list_test)
@@ -107,6 +111,7 @@ if (ENABLE_TESTING AND UTILS-TESTS)
     add_test(NAME run_linked_list_test COMMAND linked_list_test)
     add_test(NAME run_properties_test COMMAND properties_test)
     add_test(NAME run_utils_test COMMAND utils_test)
+    add_test(NAME filter_test COMMAND filter_test)
 
     SETUP_TARGET_FOR_COVERAGE(array_list_test array_list_test ${CMAKE_BINARY_DIR}/coverage/array_list_test/array_list_test)
     SETUP_TARGET_FOR_COVERAGE(hash_map hash_map_test ${CMAKE_BINARY_DIR}/coverage/hash_map_test/hash_map_test)

http://git-wip-us.apache.org/repos/asf/celix/blob/8e716743/utils/include/celix_array_list.h
----------------------------------------------------------------------
diff --git a/utils/include/celix_array_list.h b/utils/include/celix_array_list.h
index 550004c..681929e 100644
--- a/utils/include/celix_array_list.h
+++ b/utils/include/celix_array_list.h
@@ -17,6 +17,7 @@
  *under the License.
  */
 
+#include "array_list.h"
 #include "celixbool.h"
 #include "exports.h"
 #include "celix_errno.h"
@@ -29,11 +30,6 @@
 extern "C" {
 #endif
 
-/**********************************************************************************************************************
- **********************************************************************************************************************
- * Updated API
- **********************************************************************************************************************
- **********************************************************************************************************************/
 
 typedef struct celix_arrayList celix_array_list_t;
 

http://git-wip-us.apache.org/repos/asf/celix/blob/8e716743/utils/include/celix_filter.h
----------------------------------------------------------------------
diff --git a/utils/include/celix_filter.h b/utils/include/celix_filter.h
new file mode 100644
index 0000000..4d0d7fa
--- /dev/null
+++ b/utils/include/celix_filter.h
@@ -0,0 +1,81 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#ifndef CELIX_FILTER_H_
+#define CELIX_FILTER_H_
+
+#include "celix_properties.h"
+#include "celix_array_list.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum celix_filter_operand_enum
+{
+    CELIX_FILTER_OPERAND_EQUAL,
+    CELIX_FILTER_OPERAND_APPROX,
+    CELIX_FILTER_OPERAND_GREATER,
+    CELIX_FILTER_OPERAND_GREATEREQUAL,
+    CELIX_FILTER_OPERAND_LESS,
+    CELIX_FILTER_OPERAND_LESSEQUAL,
+    CELIX_FILTER_OPERAND_PRESENT,
+    CELIX_FILTER_OPERAND_SUBSTRING,
+    CELIX_FILTER_OPERAND_AND,
+    CELIX_FILTER_OPERAND_OR,
+    CELIX_FILTER_OPERAND_NOT,
+} celix_filter_operand_t;
+
+typedef struct celix_filter_struct celix_filter_t;
+
+struct celix_filter_struct {
+    celix_filter_operand_t operand;
+    const char *attribute; //NULL for operands AND, OR ot NOT
+    const char *value; //NULL for operands AND, OR or NOT NOT
+    const char *filterStr;
+
+    //type is celix_filter_t* for AND, OR and NOT operator and char* for SUBSTRING
+    //for other operands children is NULL
+    celix_array_list_t *children;
+};
+
+
+
+celix_filter_t* celix_filter_create(const char *filterStr);
+
+void celix_filter_destroy(celix_filter_t *filter);
+
+bool celix_filter_match(const celix_filter_t *filter, const celix_properties_t* props);
+
+bool celix_filter_matchFilter(const celix_filter_t *filter1, const celix_filter_t *filter2);
+
+const char* celix_filter_getFilterString(const celix_filter_t *filter);
+
+/**
+ * Find the filter attribute.
+ * @return The attribute value or NULL if the attribute is not found.
+ */
+const char* celix_filter_findAttribute(const celix_filter_t *filter, const char *attribute);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CELIX_FILTER_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/8e716743/utils/include/filter.h
----------------------------------------------------------------------
diff --git a/utils/include/filter.h b/utils/include/filter.h
new file mode 100644
index 0000000..1fc194a
--- /dev/null
+++ b/utils/include/filter.h
@@ -0,0 +1,51 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#ifndef FILTER_H_
+#define FILTER_H_
+
+#include "celix_errno.h"
+#include "properties.h"
+#include "celix_properties.h"
+#include "celix_filter.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct celix_filter_struct filter_t; //deprecated
+typedef struct celix_filter_struct *filter_pt; //deprecated
+
+
+celix_filter_t* filter_create(const char *filterString);
+
+void filter_destroy(celix_filter_t *filter);
+
+celix_status_t filter_match(celix_filter_t *filter, properties_t *properties, bool *result);
+
+celix_status_t filter_match_filter(celix_filter_t *src, filter_t *dest, bool *result);
+
+celix_status_t filter_getString(celix_filter_t *filter, const char **filterStr);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FILTER_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/8e716743/utils/private/test/filter_test.cpp
----------------------------------------------------------------------
diff --git a/utils/private/test/filter_test.cpp b/utils/private/test/filter_test.cpp
new file mode 100644
index 0000000..0dbe61f
--- /dev/null
+++ b/utils/private/test/filter_test.cpp
@@ -0,0 +1,537 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "CppUTest/TestHarness.h"
+#include "CppUTest/TestHarness_c.h"
+#include "CppUTest/CommandLineTestRunner.h"
+
+#include "celix_filter.h"
+#include "filter.h"
+
+int main(int argc, char** argv) {
+	return RUN_ALL_TESTS(argc, argv);
+}
+
+static char* my_strdup(const char* s){
+	if(s==NULL){
+		return NULL;
+	}
+
+	size_t len = strlen(s);
+
+	char *d = (char*) calloc (len + 1,sizeof(char));
+
+	if (d == NULL){
+		return NULL;
+	}
+
+	strncpy (d,s,len);
+	return d;
+}
+
+//----------------TESTGROUPS----------------
+TEST_GROUP(filter) {
+	void setup(void) {
+	}
+
+	void teardown() {
+	}
+};
+
+//----------------FILTER TESTS----------------
+TEST(filter, create_destroy){
+	char * filter_str = my_strdup("(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3=attr3)))");
+	celix_filter_t * get_filter;
+
+	get_filter = filter_create(filter_str);
+	CHECK(get_filter != NULL);
+
+	filter_destroy(get_filter);
+
+	//cleanup
+	free(filter_str);
+}
+
+TEST(filter, create_fail_missing_opening_brackets){
+	celix_filter_t * get_filter;
+
+	//test missing opening brackets in main filter
+	//mock().expectNCalls(2, "framework_log");
+	const char *filter_str1 = "&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3=attr3))";
+	get_filter = filter_create(filter_str1);
+	POINTERS_EQUAL(NULL, get_filter);
+
+	//test missing opening brackets in AND comparator
+	//mock().expectNCalls(3, "framework_log");
+	const char *filter_str2 = "(&test_attr1=attr1|(test_attr2=attr2)(test_attr3=attr3))";
+	get_filter = filter_create(filter_str2);
+	POINTERS_EQUAL(NULL, get_filter);
+
+	//test missing opening brackets in AND comparator
+	//mock().expectNCalls(4, "framework_log");
+	const char *filter_str3 = "(&(test_attr1=attr1)(|test_attr2=attr2(test_attr3=attr3))";
+	get_filter = filter_create(filter_str3);
+	POINTERS_EQUAL(NULL, get_filter);
+
+	//test missing opening brackets in NOT comparator
+	//mock().expectNCalls(4, "framework_log");
+	const char *filter_str4 = "(&(test_attr1=attr1)(!test_attr2=attr2)";
+	get_filter = filter_create(filter_str4);
+	POINTERS_EQUAL(NULL, get_filter);
+}
+
+TEST(filter, create_fail_missing_closing_brackets){
+	char * filter_str;
+	celix_filter_t * get_filter;
+	//test missing closing brackets in substring
+	filter_str = my_strdup("(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3=attr3");
+	get_filter = filter_create(filter_str);
+	POINTERS_EQUAL(NULL, get_filter);
+	free(filter_str);
+
+	//test missing closing brackets in value
+	filter_str = my_strdup("(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3>=attr3");
+	get_filter = filter_create(filter_str);
+	POINTERS_EQUAL(NULL, get_filter);
+	free(filter_str);
+}
+
+TEST(filter, create_fail_invalid_closing_brackets){
+	char * filter_str;
+	celix_filter_t * get_filter;
+
+	//test missing closing brackets in substring
+	//mock().expectNCalls(6, "framework_log");
+	filter_str = my_strdup("(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3=at(tr3)))");
+	get_filter = filter_create(filter_str);
+	POINTERS_EQUAL(NULL, get_filter);
+	free(filter_str);
+
+	//test missing closing brackets in value
+	//mock().expectNCalls(5, "framework_log");
+	filter_str = my_strdup("(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3>=att(r3)))");
+	get_filter = filter_create(filter_str);
+	POINTERS_EQUAL(NULL, get_filter);
+	free(filter_str);
+}
+
+TEST(filter, create_misc){
+	celix_filter_t * get_filter;
+
+	//test trailing chars
+	//mock().expectOneCall("framework_log");
+	const char *filter_str1 = "(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3=attr3))) oh no! trailing chars";
+	get_filter = filter_create(filter_str1);
+	POINTERS_EQUAL(NULL, get_filter);
+
+	//test half APPROX operator (should be "~=", instead is "~")
+	//mock().expectNCalls(5, "framework_log");
+	const char* filter_str2 = "(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3~attr3)))";
+	get_filter = filter_create(filter_str2);
+	POINTERS_EQUAL(NULL, get_filter);
+
+	//test PRESENT operator with trailing chars (should just register as substrings: "*" and "attr3")
+	const char *filter_str3 = "(test_attr3=*attr3)";
+	get_filter = filter_create(filter_str3);
+	CHECK(get_filter != NULL);
+	LONGS_EQUAL(CELIX_FILTER_OPERAND_SUBSTRING, get_filter->operand)
+	LONGS_EQUAL(2, arrayList_size((array_list_pt) get_filter->children));
+	filter_destroy(get_filter);
+
+	//test parsing a attribute of 0 length
+	//mock().expectNCalls(3, "framework_log");
+	const char* filter_str4 = "(>=attr3)";
+	get_filter = filter_create(filter_str4);
+	POINTERS_EQUAL(NULL, get_filter);
+
+	//test parsing a value of 0 length
+	//mock().expectOneCall("framework_log");
+	const char* filter_str5 = "(test_attr3>=)";
+	get_filter = filter_create(filter_str5);
+	POINTERS_EQUAL(NULL, get_filter);
+
+	//test parsing a value with a escaped closing bracket "\)"
+	const char* filter_str6 = "(test_attr3>=strWith\\)inIt)";
+	get_filter = filter_create(filter_str6);
+	CHECK(get_filter != NULL);
+	STRCMP_EQUAL("strWith)inIt", (char*)get_filter->value);
+	filter_destroy(get_filter);
+
+	//test parsing a substring with a escaped closing bracket "\)"
+	const char *filter_str7 = "(test_attr3=strWith\\)inIt)";
+	get_filter = filter_create(filter_str7);
+	CHECK(get_filter != NULL);
+	STRCMP_EQUAL("strWith)inIt", (char*)get_filter->value);
+	filter_destroy(get_filter);
+}
+
+TEST(filter, match_comparators){
+	char * filter_str;
+	celix_filter_t * filter;
+	properties_pt props = properties_create();
+	char * key = my_strdup("test_attr1");
+	char * val = my_strdup("attr1");
+	char * key2 = my_strdup("test_attr2");
+	char * val2 = my_strdup("attr2");
+	properties_set(props, key, val);
+	properties_set(props, key2, val2);
+
+	//test AND
+	filter_str = my_strdup("(&(test_attr1=attr1)(|(test_attr2=attr2)(!(test_attr3=attr3))))");
+	filter = filter_create(filter_str);
+	bool result = false;
+	filter_match(filter, props, &result);
+	CHECK(result);
+
+	//test AND false
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(&(test_attr1=attr1)(test_attr1=attr2))");
+	filter = filter_create(filter_str);
+	result = true;
+	filter_match(filter, props, &result);
+	CHECK_FALSE(result);
+
+	//cleanup
+	properties_destroy(props);
+	filter_destroy(filter);
+	free(filter_str);
+	free(key);
+	free(key2);
+	free(val);
+	free(val2);
+
+}
+
+TEST(filter, match_operators){
+	char * filter_str;
+	celix_filter_t * filter;
+	properties_pt props = properties_create();
+	char * key = my_strdup("test_attr1");
+	char * val = my_strdup("attr1");
+	char * key2 = my_strdup("test_attr2");
+	char * val2 = my_strdup("attr2");
+	properties_set(props, key, val);
+	properties_set(props, key2, val2);
+
+	//test EQUALS
+	filter_str = my_strdup("(test_attr1=attr1)");
+	filter = filter_create(filter_str);
+	bool result = false;
+	filter_match(filter, props, &result);
+	CHECK(result);
+
+	//test EQUALS false
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr1=falseString)");
+	filter = filter_create(filter_str);
+	result = true;
+	filter_match(filter, props, &result);
+	CHECK_FALSE(result);
+
+	//test APPROX TODO: update this test once APPROX is implemented
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr1~=attr1)");
+	filter = filter_create(filter_str);
+	result = false;
+	filter_match(filter, props, &result);
+	CHECK(result);
+
+	//test APROX false TODO: update this test once APPROX is implemented
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr1~=ATTR1)");
+	filter = filter_create(filter_str);
+	result = true;
+	filter_match(filter, props, &result);
+	CHECK_FALSE(result);
+
+	//test PRESENT
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr1=*)");
+	filter = filter_create(filter_str);
+	result = false;
+	filter_match(filter, props, &result);
+	CHECK(result);
+
+	//test PRESENT false
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr3=*)");
+	filter = filter_create(filter_str);
+	result = true;
+	filter_match(filter, props, &result);
+	CHECK_FALSE(result);
+
+	//test LESSEQUAL less
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr1<=attr5)");
+	filter = filter_create(filter_str);
+	result = false;
+	filter_match(filter, props, &result);
+	CHECK(result);
+
+	//test LESSEQUAL equals
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr2<=attr2)");
+	filter = filter_create(filter_str);
+	result = false;
+	filter_match(filter, props, &result);
+	CHECK(result);
+
+	//test LESSEQUAL false
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr2<=attr1)");
+	filter = filter_create(filter_str);
+	result = true;
+	filter_match(filter, props, &result);
+	CHECK_FALSE(result);
+
+	//test GREATEREQUAL greater
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr2>=attr1)");
+	filter = filter_create(filter_str);
+	result = false;
+	filter_match(filter, props, &result);
+	CHECK(result);
+
+	//test GREATEREQUAL equals
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr2>=attr2)");
+	filter = filter_create(filter_str);
+	result = false;
+	filter_match(filter, props, &result);
+	CHECK(result);
+
+	//test GREATEREQUAL false
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr1>=attr5)");
+	filter = filter_create(filter_str);
+	result = true;
+	filter_match(filter, props, &result);
+	CHECK_FALSE(result);
+
+	//test LESS less
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr1<attr5)");
+	filter = filter_create(filter_str);
+	result = false;
+	filter_match(filter, props, &result);
+	CHECK(result);
+
+	//test LESS equals
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr2<attr2)");
+	filter = filter_create(filter_str);
+	result = true;
+	filter_match(filter, props, &result);
+	CHECK_FALSE(result);
+
+	//test LESS false
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr2<attr1)");
+	filter = filter_create(filter_str);
+	result = true;
+	filter_match(filter, props, &result);
+	CHECK_FALSE(result);
+
+	//test GREATER greater
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr2>attr1)");
+	filter = filter_create(filter_str);
+	result = false;
+	filter_match(filter, props, &result);
+	CHECK(result);
+
+	//test GREATER equals
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr2>attr2)");
+	filter = filter_create(filter_str);
+	result = true;
+	filter_match(filter, props, &result);
+	CHECK_FALSE(result);
+
+	//test GREATER false
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr1>attr5)");
+	filter = filter_create(filter_str);
+	result = true;
+	filter_match(filter, props, &result);
+	CHECK_FALSE(result);
+
+	//test SUBSTRING equals
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr1=attr*)");
+	filter = filter_create(filter_str);
+	result = true;
+	filter_match(filter, props, &result);
+	CHECK(result);
+
+	//test SUBSTRING false
+	filter_destroy(filter);
+	free(filter_str);
+	filter_str = my_strdup("(test_attr1=attr*charsNotPresent)");
+	filter = filter_create(filter_str);
+	result = true;
+	filter_match(filter, props, &result);
+	CHECK_FALSE(result);
+
+	//cleanup
+	properties_destroy(props);
+	filter_destroy(filter);
+	free(filter_str);
+	free(key);
+	free(key2);
+	free(val);
+	free(val2);
+
+}
+
+TEST(filter, match_recursion){
+
+	char * filter_str = my_strdup("(&(test_attr1=attr1)(|(&(test_attr2=attr2)(!(&(test_attr1=attr1)(test_attr3=attr3))))(test_attr3=attr3)))");
+	celix_filter_t * filter = filter_create(filter_str);
+	properties_pt props = properties_create();
+	char * key = my_strdup("test_attr1");
+	char * val = my_strdup("attr1");
+	char * key2 = my_strdup("test_attr2");
+	char * val2 = my_strdup("attr2");
+	properties_set(props, key, val);
+	properties_set(props, key2, val2);
+
+	bool result = false;
+	filter_match(filter, props, &result);
+	CHECK(result);
+
+	//cleanup
+	properties_destroy(props);
+	filter_destroy(filter);
+	free(filter_str);
+	free(key);
+	free(key2);
+	free(val);
+	free(val2);
+
+}
+
+TEST(filter, match_false){
+	char * filter_str = my_strdup("(&(test_attr1=attr1)(&(test_attr2=attr2)(test_attr3=attr3)))");
+	celix_filter_t * filter = filter_create(filter_str);
+	properties_pt props = properties_create();
+	char * key = my_strdup("test_attr1");
+	char * val = my_strdup("attr1");
+	char * key2 = my_strdup("test_attr2");
+	char * val2 = my_strdup("attr2");
+	properties_set(props, key, val);
+	properties_set(props, key2, val2);
+
+	bool result = true;
+	filter_match(filter, props, &result);
+	CHECK_FALSE(result);
+
+	//cleanup
+	properties_destroy(props);
+	filter_destroy(filter);
+	free(filter_str);
+	free(key);
+	free(key2);
+	free(val);
+	free(val2);
+
+}
+
+TEST(filter, match_filter){
+
+	celix_filter_t *filter = filter_create("(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3=attr3)))");
+    celix_filter_t *compareTo = filter_create("(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3=attr3)))");
+
+	bool result;
+	filter_match_filter(filter, compareTo, &result); //equal same order
+    CHECK_TRUE(result);
+	//cleanup
+	filter_destroy(filter);
+	filter_destroy(compareTo);
+
+    filter = filter_create("(&(test_attr1=attr1)(test_attr2=attr2)(test_attr3=attr3))");
+    compareTo = filter_create("(&(test_attr3=attr3)(test_attr2=attr2)(test_attr1=attr1))");
+	CHECK(filter != NULL);
+	CHECK(compareTo != NULL);
+    filter_match_filter(filter, compareTo, &result); //equal not same order
+    CHECK_TRUE(result);
+    //cleanup
+    filter_destroy(filter);
+    filter_destroy(compareTo);
+
+    filter = filter_create("(&(test_attr1=attr1)(test_attr2=attr2)(test_attr3=attr3))");
+    compareTo = filter_create("(&(test_attr1=attr1)(test_attr2=attr2)(test_attr4=attr4))");
+	CHECK(filter != NULL);
+	CHECK(compareTo != NULL);
+    filter_match_filter(filter, compareTo, &result); //almost, but not equal
+    CHECK_FALSE(result);
+    //cleanup
+    filter_destroy(filter);
+    filter_destroy(compareTo);
+
+	filter_match_filter(NULL, NULL, &result); //both null  -> equal
+	CHECK_TRUE(result);
+
+	filter = filter_create("(attr1=)");
+	filter_match_filter(filter, NULL, &result); //one null  -> not equal
+	CHECK_FALSE(result);
+
+	filter_match_filter(NULL, filter, &result); //one null  -> not equal
+	CHECK_FALSE(result);
+
+	filter_destroy(filter);
+}
+
+TEST(filter, getString){
+	char * filter_str = my_strdup("(&(test_attr1=attr1)(|(test_attr2=attr2)(test_attr3=attr3)))");
+	celix_filter_t * filter = filter_create(filter_str);
+
+	const char * get_str;
+	filter_getString(filter, &get_str);
+
+	//cleanup
+	filter_destroy(filter);
+	free(filter_str);
+
+}
+
+