http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/capability.c ---------------------------------------------------------------------- diff --git a/framework/src/capability.c b/framework/src/capability.c new file mode 100644 index 0000000..9e4dc3a --- /dev/null +++ b/framework/src/capability.c @@ -0,0 +1,100 @@ +/** + *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. + */ +/* + * capability.c + * + * \date Jul 12, 2010 + * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ +#include <stdlib.h> + +#include "capability_private.h" +#include "attribute.h" +#include "celix_log.h" + +celix_status_t capability_create(module_pt module, hash_map_pt directives, hash_map_pt attributes, capability_pt *capability) { + celix_status_t status; + *capability = (capability_pt) malloc(sizeof(**capability)); + if (!*capability) { + status = CELIX_ENOMEM; + } else { + (*capability)->module = module; + (*capability)->attributes = attributes; + (*capability)->directives = directives; + (*capability)->version = NULL; + + attribute_pt versionAttribute = NULL; + attribute_pt serviceAttribute = (attribute_pt) hashMap_get(attributes, "service"); + status = attribute_getValue(serviceAttribute, &(*capability)->serviceName); + if (status == CELIX_SUCCESS) { + versionAttribute = (attribute_pt) hashMap_get(attributes, "version"); + if (versionAttribute != NULL) { + char *versionStr = NULL; + attribute_getValue(versionAttribute, &versionStr); + status = version_createVersionFromString(versionStr, &(*capability)->version); + } else { + status = version_createEmptyVersion(&(*capability)->version); + } + } + + } + + framework_logIfError(logger, status, NULL, "Failed to create capability"); + + return status; +} + +celix_status_t capability_destroy(capability_pt capability) { + hash_map_iterator_pt attrIter = hashMapIterator_create(capability->attributes); + while (hashMapIterator_hasNext(attrIter)) { + attribute_pt attr = hashMapIterator_nextValue(attrIter); + hashMapIterator_remove(attrIter); + attribute_destroy(attr); + } + hashMapIterator_destroy(attrIter); + hashMap_destroy(capability->attributes, false, false); + hashMap_destroy(capability->directives, false, false); + + capability->attributes = NULL; + capability->directives = NULL; + capability->module = NULL; + + version_destroy(capability->version); + capability->version = NULL; + + free(capability); + + return CELIX_SUCCESS; +} + +celix_status_t capability_getServiceName(capability_pt capability, const char **serviceName) { + *serviceName = capability->serviceName; + return CELIX_SUCCESS; +} + +celix_status_t capability_getVersion(capability_pt capability, version_pt *version) { + *version = capability->version; + return CELIX_SUCCESS; +} + +celix_status_t capability_getModule(capability_pt capability, module_pt *module) { + *module = capability->module; + return CELIX_SUCCESS; +}
http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/capability_private.h ---------------------------------------------------------------------- diff --git a/framework/src/capability_private.h b/framework/src/capability_private.h new file mode 100644 index 0000000..5e302a5 --- /dev/null +++ b/framework/src/capability_private.h @@ -0,0 +1,41 @@ +/** + *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. + */ +/* + * capability_private.h + * + * \date Feb 11, 2013 + * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ + + +#ifndef CAPABILITY_PRIVATE_H_ +#define CAPABILITY_PRIVATE_H_ + +#include "capability.h" + +struct capability { + char * serviceName; + module_pt module; + version_pt version; + hash_map_pt attributes; + hash_map_pt directives; +}; + +#endif /* CAPABILITY_PRIVATE_H_ */ http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/celix_errorcodes.c ---------------------------------------------------------------------- diff --git a/framework/src/celix_errorcodes.c b/framework/src/celix_errorcodes.c new file mode 100644 index 0000000..80323e7 --- /dev/null +++ b/framework/src/celix_errorcodes.c @@ -0,0 +1,64 @@ +/** + *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. + */ +/* + * celix_errorcodes.c + * + * \date Aug 30, 2011 + * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ +#include <stdio.h> +#include <string.h> + +#include "celix_errno.h" + +static char* celix_error_string(celix_status_t statcode) { + switch (statcode) { + case CELIX_BUNDLE_EXCEPTION: + return "Bundle exception"; + case CELIX_INVALID_BUNDLE_CONTEXT: + return "Invalid bundle context"; + case CELIX_ILLEGAL_ARGUMENT: + return "Illegal argument"; + case CELIX_INVALID_SYNTAX: + return "Invalid syntax"; + case CELIX_FRAMEWORK_SHUTDOWN: + return "Framework shutdown"; + case CELIX_ILLEGAL_STATE: + return "Illegal state"; + case CELIX_FRAMEWORK_EXCEPTION: + return "Framework exception"; + case CELIX_FILE_IO_EXCEPTION: + return "File I/O exception"; + case CELIX_SERVICE_EXCEPTION: + return "Service exception"; + default: + return "Unknown code"; + } +} + +char* celix_strerror(celix_status_t errorcode, char *buffer, size_t bufferSize) { + if (errorcode < CELIX_START_ERROR) { + return strerror(errorcode); + } else { + char * str = celix_error_string(errorcode); + strncpy(buffer, str, bufferSize); + return buffer; + } +} http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/celix_launcher.c ---------------------------------------------------------------------- diff --git a/framework/src/celix_launcher.c b/framework/src/celix_launcher.c new file mode 100644 index 0000000..ba83f25 --- /dev/null +++ b/framework/src/celix_launcher.c @@ -0,0 +1,242 @@ +/** + *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. + */ +/* + * celix_launcher.c + * + * \date Mar 23, 2010 + * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ + +#include "celix_launcher.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <libgen.h> +#include <signal.h> + +#ifndef CELIX_NO_CURLINIT +#include <curl/curl.h> +#endif + +#include <string.h> +#include <curl/curl.h> +#include <signal.h> +#include <libgen.h> +#include "celix_launcher.h" +#include "framework.h" +#include "linked_list_iterator.h" + +static void show_usage(char* prog_name); +static void shutdown_framework(int signal); +static void ignore(int signal); + +#define DEFAULT_CONFIG_FILE "config.properties" + +static framework_pt framework = NULL; + +int celixLauncher_launchWithArgs(int argc, char *argv[]) { + // Perform some minimal command-line option parsing... + char *opt = NULL; + if (argc > 1) { + opt = argv[1]; + } + + char *config_file = NULL; + + if (opt) { + // Check whether the user wants some help... + if (strcmp("-h", opt) == 0 || strcmp("-help", opt) == 0) { + show_usage(argv[0]); + return 0; + } else { + config_file = opt; + } + } else { + config_file = DEFAULT_CONFIG_FILE; + } + + struct sigaction sigact; + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_handler = shutdown_framework; + sigaction(SIGINT, &sigact, NULL); + sigaction(SIGTERM, &sigact, NULL); + + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_handler = ignore; + sigaction(SIGUSR1, &sigact, NULL); + sigaction(SIGUSR2, &sigact, NULL); + + int rc = celixLauncher_launch(config_file, &framework); + if (rc == 0) { + celixLauncher_waitForShutdown(framework); + celixLauncher_destroy(framework); + } + return rc; +} + +static void show_usage(char* prog_name) { + printf("Usage:\n %s [path/to/config.properties]\n\n", basename(prog_name)); +} + +static void shutdown_framework(int signal) { + if (framework != NULL) { + celixLauncher_stop(framework); //NOTE main thread will destroy + } +} + +static void ignore(int signal) { + //ignoring for signal SIGUSR1, SIGUSR2. Can be used on threads +} + +int celixLauncher_launch(const char *configFile, framework_pt *framework) { + int status = 0; + FILE *config = fopen(configFile, "r"); + if (config != NULL) { + status = celixLauncher_launchWithStream(config, framework); + } else { + fprintf(stderr, "Error: invalid or non-existing configuration file: '%s'.", configFile); + perror(""); + status = 1; + } + return status; +} + +int celixLauncher_launchWithStream(FILE *stream, framework_pt *framework) { + int status = 0; + + properties_pt config = properties_loadWithStream(stream); + fclose(stream); + // Make sure we've read it and that nothing went wrong with the file access... + if (config == NULL) { + fprintf(stderr, "Error: invalid configuration file"); + perror(NULL); + status = 1; + } + else { + status = celixLauncher_launchWithProperties(config, framework); + } + + return status; +} + + +int celixLauncher_launchWithProperties(properties_pt config, framework_pt *framework) { + celix_status_t status; +#ifndef CELIX_NO_CURLINIT + // Before doing anything else, let's setup Curl + curl_global_init(CURL_GLOBAL_NOTHING); +#endif + + const char* autoStartProp = properties_get(config, "cosgi.auto.start.1"); + char* autoStart = NULL; + if (autoStartProp != NULL) { + autoStart = strndup(autoStartProp, 1024*10); + } + + status = framework_create(framework, config); + bundle_pt fwBundle = NULL; + if (status == CELIX_SUCCESS) { + status = fw_init(*framework); + if (status == CELIX_SUCCESS) { + // Start the system bundle + status = framework_getFrameworkBundle(*framework, &fwBundle); + + if(status == CELIX_SUCCESS){ + bundle_start(fwBundle); + + char delims[] = " "; + char *result = NULL; + char *save_ptr = NULL; + linked_list_pt bundles; + array_list_pt installed = NULL; + bundle_context_pt context = NULL; + linked_list_iterator_pt iter = NULL; + unsigned int i; + + linkedList_create(&bundles); + result = strtok_r(autoStart, delims, &save_ptr); + while (result != NULL) { + char *location = strdup(result); + linkedList_addElement(bundles, location); + result = strtok_r(NULL, delims, &save_ptr); + } + // First install all bundles + // Afterwards start them + arrayList_create(&installed); + bundle_getContext(fwBundle, &context); + iter = linkedListIterator_create(bundles, 0); + while (linkedListIterator_hasNext(iter)) { + bundle_pt current = NULL; + char *location = (char *) linkedListIterator_next(iter); + if (bundleContext_installBundle(context, location, ¤t) == CELIX_SUCCESS) { + // Only add bundle if it is installed correctly + arrayList_add(installed, current); + } else { + printf("Could not install bundle from %s\n", location); + } + linkedListIterator_remove(iter); + free(location); + } + linkedListIterator_destroy(iter); + linkedList_destroy(bundles); + + for (i = 0; i < arrayList_size(installed); i++) { + bundle_pt installedBundle = (bundle_pt) arrayList_get(installed, i); + bundle_startWithOptions(installedBundle, 0); + } + + arrayList_destroy(installed); + } + } + } + + if (status != CELIX_SUCCESS) { + printf("Problem creating framework\n"); + } + + printf("Launcher: Framework Started\n"); + + free(autoStart); + + return status; +} + +void celixLauncher_waitForShutdown(framework_pt framework) { + framework_waitForStop(framework); +} + +void celixLauncher_destroy(framework_pt framework) { + framework_destroy(framework); + +#ifndef CELIX_NO_CURLINIT + // Cleanup Curl + curl_global_cleanup(); +#endif + + printf("Launcher: Exit\n"); +} + +void celixLauncher_stop(framework_pt framework) { + bundle_pt fwBundle = NULL; + if( framework_getFrameworkBundle(framework, &fwBundle) == CELIX_SUCCESS){ + bundle_stop(fwBundle); + } +} http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/celix_log.c ---------------------------------------------------------------------- diff --git a/framework/src/celix_log.c b/framework/src/celix_log.c new file mode 100644 index 0000000..c4d51e2 --- /dev/null +++ b/framework/src/celix_log.c @@ -0,0 +1,83 @@ +/** + *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. + */ +/* + * celix_log.c + * + * \date 6 Oct 2013 + * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ +#include <stdarg.h> + +#include "celix_errno.h" +#include "celix_log.h" + +void framework_log(framework_logger_pt logger, framework_log_level_t level, const char *func, const char *file, int line, const char *fmsg, ...) { + char msg[512]; + va_list listPointer; + va_start(listPointer, fmsg); + vsprintf(msg, fmsg, listPointer); + + //FIXME logger and/or logger->logFucntion can be null. But this solution is not thread safe! + if (logger != NULL && logger->logFunction != NULL) { + logger->logFunction(level, func, file, line, msg); + } + + va_end(listPointer); +} + +void framework_logCode(framework_logger_pt logger, framework_log_level_t level, const char *func, const char *file, int line, celix_status_t code, const char *fmsg, ...) { + char message[256]; + celix_strerror(code, message, 256); + char msg[512]; + va_list listPointer; + va_start(listPointer, fmsg); + vsprintf(msg, fmsg, listPointer); + + framework_log(logger, level, func, file, line, "%s [%d]: %s", message, code, msg); + + va_end(listPointer); +} + +celix_status_t frameworkLogger_log(framework_log_level_t level, const char *func, const char *file, int line, const char *msg) { + char *levelStr = NULL; + switch (level) { + case OSGI_FRAMEWORK_LOG_ERROR: + levelStr = "ERROR"; + break; + case OSGI_FRAMEWORK_LOG_WARNING: + levelStr = "WARNING"; + break; + case OSGI_FRAMEWORK_LOG_INFO: + levelStr = "INFO"; + break; + case OSGI_FRAMEWORK_LOG_DEBUG: + default: + levelStr = "DEBUG"; + break; + } + + if (level == OSGI_FRAMEWORK_LOG_ERROR) { + printf("%s: %s\n\tat %s(%s:%d)\n", levelStr, msg, func, file, line); + } else { + printf("%s: %s\n", levelStr, msg); + } + + return CELIX_SUCCESS; +} http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/filter.c ---------------------------------------------------------------------- diff --git a/framework/src/filter.c b/framework/src/filter.c new file mode 100644 index 0000000..f06d6e8 --- /dev/null +++ b/framework/src/filter.c @@ -0,0 +1,687 @@ +/** + *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:[email protected]">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> + +#include "celix_log.h" +#include "filter_private.h" + +static void filter_skipWhiteSpace(char* filterString, int* pos); +static filter_pt filter_parseFilter(char* filterString, int* pos); +static filter_pt filter_parseFilterComp(char* filterString, int* pos); +static filter_pt filter_parseAnd(char* filterString, int* pos); +static filter_pt filter_parseOr(char* filterString, int* pos); +static filter_pt filter_parseNot(char* filterString, int* pos); +static filter_pt 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(OPERAND operand, char * string, void * value2, bool *result); +static celix_status_t filter_compareString(OPERAND operand, char * string, void * value2, bool *result); + +static void filter_skipWhiteSpace(char * filterString, int * pos) { + int length; + for (length = strlen(filterString); (*pos < length) && isspace(filterString[*pos]);) { + (*pos)++; + } +} + +filter_pt filter_create(const char* filterString) { + filter_pt filter = NULL; + char* filterStr = (char*) filterString; + int pos = 0; + filter = filter_parseFilter(filterStr, &pos); + if (pos != strlen(filterStr)) { + fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Error: Extraneous trailing characters."); + filter_destroy(filter); + return NULL; + } + if(filter != NULL){ + filter->filterStr = filterStr; + } + + return filter; +} + +void filter_destroy(filter_pt filter) { + if (filter != NULL) { + if(filter->value!=NULL){ + if (filter->operand == SUBSTRING) { + int size = arrayList_size(filter->value); + for (; size > 0; --size) { + char* operand = (char*) arrayList_remove(filter->value, 0); + free(operand); + } + arrayList_destroy(filter->value); + filter->value = NULL; + } else if ( (filter->operand == OR) || (filter->operand == AND) ) { + int size = arrayList_size(filter->value); + unsigned int i = 0; + for (i = 0; i < size; i++) { + filter_pt f = arrayList_get(filter->value, i); + filter_destroy(f); + } + arrayList_destroy(filter->value); + filter->value = NULL; + } else if (filter->operand == NOT) { + filter_destroy(filter->value); + filter->value = NULL; + } else { + free(filter->value); + filter->value = NULL; + } + } + free(filter->attribute); + filter->attribute = NULL; + free(filter); + filter = NULL; + } +} + +static filter_pt filter_parseFilter(char * filterString, int * pos) { + filter_pt 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); + + if(filter != NULL){ + if(filter->value == NULL && filter->operand!=PRESENT){ + filter_destroy(filter); + return NULL; + } + } + + return filter; +} + +static filter_pt filter_parseFilterComp(char * filterString, int * pos) { + char c; + filter_skipWhiteSpace(filterString, pos); + + c = filterString[*pos]; + + switch (c) { + case '&': { + (*pos)++; + return filter_parseAnd(filterString, pos); + } + case '|': { + (*pos)++; + return filter_parseOr(filterString, pos); + } + case '!': { + (*pos)++; + return filter_parseNot(filterString, pos); + } + } + return filter_parseItem(filterString, pos); +} + +static filter_pt filter_parseAnd(char * filterString, int * pos) { + + array_list_pt operands = NULL; + filter_skipWhiteSpace(filterString, pos); + bool failure = false; + + if (filterString[*pos] != '(') { + fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Error: Missing '('."); + return NULL; + } + + arrayList_create(&operands); + while(filterString[*pos] == '(') { + filter_pt child = filter_parseFilter(filterString, pos); + if(child == NULL){ + failure = true; + break; + } + arrayList_add(operands, child); + } + + if(failure == true){ + array_list_iterator_pt listIt = arrayListIterator_create(operands); + while(arrayListIterator_hasNext(listIt)){ + filter_pt f = arrayListIterator_next(listIt); + filter_destroy(f); + } + arrayListIterator_destroy(listIt); + arrayList_destroy(operands); + operands = NULL; + } + + filter_pt filter = (filter_pt) malloc(sizeof(*filter)); + filter->operand = AND; + filter->attribute = NULL; + filter->value = operands; + + return filter; +} + +static filter_pt filter_parseOr(char * filterString, int * pos) { + + array_list_pt operands = NULL; + + filter_skipWhiteSpace(filterString, pos); + bool failure = false; + + if (filterString[*pos] != '(') { + fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Error: Missing '('."); + return NULL; + } + + arrayList_create(&operands); + while(filterString[*pos] == '(') { + filter_pt child = filter_parseFilter(filterString, pos); + if(child == NULL){ + failure = true; + break; + } + arrayList_add(operands, child); + } + + if(failure == true){ + array_list_iterator_pt listIt = arrayListIterator_create(operands); + while(arrayListIterator_hasNext(listIt)){ + filter_pt f = arrayListIterator_next(listIt); + filter_destroy(f); + } + arrayListIterator_destroy(listIt); + arrayList_destroy(operands); + operands = NULL; + } + + filter_pt filter = (filter_pt) malloc(sizeof(*filter)); + filter->operand = OR; + filter->attribute = NULL; + filter->value = operands; + + return filter; +} + +static filter_pt filter_parseNot(char * filterString, int * pos) { + filter_pt 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); + + + filter_pt filter = (filter_pt) malloc(sizeof(*filter)); + filter->operand = NOT; + filter->attribute = NULL; + filter->value = child; + + return filter; +} + +static filter_pt 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] == '=') { + filter_pt filter = (filter_pt) malloc(sizeof(*filter)); + *pos += 2; + filter->operand = APPROX; + filter->attribute = attr; + filter->value = filter_parseValue(filterString, pos); + return filter; + } + break; + } + case '>': { + if (filterString[*pos + 1] == '=') { + filter_pt filter = (filter_pt) malloc(sizeof(*filter)); + *pos += 2; + filter->operand = GREATEREQUAL; + filter->attribute = attr; + filter->value = filter_parseValue(filterString, pos); + return filter; + } + else { + filter_pt filter = (filter_pt) malloc(sizeof(*filter)); + *pos += 1; + filter->operand = GREATER; + filter->attribute = attr; + filter->value = filter_parseValue(filterString, pos); + return filter; + } + break; + } + case '<': { + if (filterString[*pos + 1] == '=') { + filter_pt filter = (filter_pt) malloc(sizeof(*filter)); + *pos += 2; + filter->operand = LESSEQUAL; + filter->attribute = attr; + filter->value = filter_parseValue(filterString, pos); + return filter; + } + else { + filter_pt filter = (filter_pt) malloc(sizeof(*filter)); + *pos += 1; + filter->operand = LESS; + filter->attribute = attr; + filter->value = filter_parseValue(filterString, pos); + return filter; + } + break; + } + case '=': { + filter_pt filter = NULL; + array_list_pt subs; + if (filterString[*pos + 1] == '*') { + int oldPos = *pos; + *pos += 2; + filter_skipWhiteSpace(filterString, pos); + if (filterString[*pos] == ')') { + filter_pt filter = (filter_pt) malloc(sizeof(*filter)); + filter->operand = PRESENT; + filter->attribute = attr; + filter->value = NULL; + return filter; + } + *pos = oldPos; + } + filter = (filter_pt) malloc(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 = EQUAL; + filter->attribute = attr; + filter->value = string; + + arrayList_clear(subs); + arrayList_destroy(subs); + + return filter; + } + } + } + filter->operand = SUBSTRING; + filter->attribute = attr; + filter->value = 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 *) malloc(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(filter_pt filter, properties_pt properties, bool *result) { + switch (filter->operand) { + case AND: { + array_list_pt filters = (array_list_pt) filter->value; + unsigned int i; + for (i = 0; i < arrayList_size(filters); i++) { + filter_pt sfilter = (filter_pt) arrayList_get(filters, i); + bool mresult; + filter_match(sfilter, properties, &mresult); + if (!mresult) { + *result = 0; + return CELIX_SUCCESS; + } + } + *result = 1; + return CELIX_SUCCESS; + } + case OR: { + array_list_pt filters = (array_list_pt) filter->value; + unsigned int i; + for (i = 0; i < arrayList_size(filters); i++) { + filter_pt sfilter = (filter_pt) arrayList_get(filters, i); + bool mresult; + filter_match(sfilter, properties, &mresult); + if (mresult) { + *result = 1; + return CELIX_SUCCESS; + } + } + *result = 0; + return CELIX_SUCCESS; + } + case NOT: { + filter_pt sfilter = (filter_pt) filter->value; + bool mresult; + filter_match(sfilter, properties, &mresult); + *result = !mresult; + return CELIX_SUCCESS; + } + case SUBSTRING : + case EQUAL : + case GREATER : + case GREATEREQUAL : + case LESS : + case LESSEQUAL : + case APPROX : { + char * value = (properties == NULL) ? NULL: (char*)properties_get(properties, filter->attribute); + + return filter_compare(filter->operand, value, filter->value, result); + } + case 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(OPERAND operand, char * string, void * value2, bool *result) { + if (string == NULL) { + *result = 0; + return CELIX_SUCCESS; + } + return filter_compareString(operand, string, value2, result); + +} + +static celix_status_t filter_compareString(OPERAND operand, char * string, void * value2, bool *result) { + switch (operand) { + case SUBSTRING: { + array_list_pt subs = (array_list_pt) value2; + int pos = 0; + unsigned int i; + int size = arrayList_size(subs); + for (i = 0; i < size; i++) { + char * substr = (char *) arrayList_get(subs, i); + + if (i + 1 < size) { + if (substr == NULL) { + unsigned int index; + char * substr2 = (char *) arrayList_get(subs, i + 1); + if (substr2 == NULL) { + continue; + } + index = strcspn(string+pos, substr2); + if (index == strlen(string+pos)) { + *result = false; + return CELIX_SUCCESS; + } + + pos = index + strlen(substr2); + if (i + 2 < size) { + i++; + } + } else { + unsigned int len = strlen(substr); + char * region = (char *)malloc(len+1); + strncpy(region, string+pos, len); + region[len] = '\0'; + if (strcmp(region, substr) == 0) { + pos += len; + } else { + free(region); + *result = false; + return CELIX_SUCCESS; + } + free(region); + } + } else { + unsigned int len; + int begin; + + if (substr == NULL) { + *result = true; + return CELIX_SUCCESS; + } + len = strlen(substr); + begin = strlen(string)-len; + *result = (strcmp(string+begin, substr) == 0); + return CELIX_SUCCESS; + } + } + *result = true; + return CELIX_SUCCESS; + } + case APPROX: //TODO: Implement strcmp with ignorecase and ignorespaces + case EQUAL: { + *result = (strcmp(string, (char *) value2) == 0); + return CELIX_SUCCESS; + } + case GREATER: { + *result = (strcmp(string, (char *) value2) > 0); + return CELIX_SUCCESS; + } + case GREATEREQUAL: { + *result = (strcmp(string, (char *) value2) >= 0); + return CELIX_SUCCESS; + } + case LESS: { + *result = (strcmp(string, (char *) value2) < 0); + return CELIX_SUCCESS; + } + case LESSEQUAL: { + *result = (strcmp(string, (char *) value2) <= 0); + return CELIX_SUCCESS; + } + case AND: + case NOT: + case OR: + case PRESENT: { + } + /* no break */ + } + *result = false; + return CELIX_SUCCESS; +} + +celix_status_t filter_getString(filter_pt filter, const char **filterStr) { + if (filter != NULL) { + *filterStr = filter->filterStr; + } + return CELIX_SUCCESS; +} + +celix_status_t filter_match_filter(filter_pt src, filter_pt dest, bool *result) { + char *srcStr = NULL; + char *destStr = NULL; + *result = false; + + if (src) srcStr = src->filterStr; + if (dest) destStr = dest->filterStr; + + if ((srcStr != NULL) && (destStr != NULL)) { + // TODO: should be done smarted, e.g. src="&(a=1)(b=2)" and dest="&(b=2)(a=1)" should result in true + *result = (strcmp(srcStr, destStr) == 0); + } + + return CELIX_SUCCESS; +} http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/filter_private.h ---------------------------------------------------------------------- diff --git a/framework/src/filter_private.h b/framework/src/filter_private.h new file mode 100644 index 0000000..d19de2d --- /dev/null +++ b/framework/src/filter_private.h @@ -0,0 +1,57 @@ +/** + *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_private.h + * + * \date Feb 13, 2013 + * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ + + +#ifndef FILTER_PRIVATE_H_ +#define FILTER_PRIVATE_H_ + +#include "filter.h" +#include "array_list.h" + +typedef enum operand +{ + EQUAL, + APPROX, + GREATER, + GREATEREQUAL, + LESS, + LESSEQUAL, + PRESENT, + SUBSTRING, + AND, + OR, + NOT, +} OPERAND; + +struct filter { + OPERAND operand; + char * attribute; + void * value; + char *filterStr; +}; + + +#endif /* FILTER_PRIVATE_H_ */
