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);
+
+}
+
+