| /** |
| *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. |
| */ |
| /* |
| * configuration_store.c |
| * |
| * \date Aug 12, 2013 |
| * \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a> |
| * \copyright Apache License, Version 2.0 |
| */ |
| |
| #include <stdbool.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <dirent.h> |
| #include <unistd.h> |
| #include <limits.h> |
| |
| /* celix.config_admin.ConfigurationStore */ |
| #include "configuration_store.h" |
| |
| /* celix.utils */ |
| #include "hash_map.h" |
| /* celix.framework */ |
| #include "properties.h" |
| #include "utils.h" |
| /* celix.config_admin.private*/ |
| #include "configuration_admin_factory.h" |
| #include "configuration.h" |
| #include "configuration_impl.h" |
| |
| #define STORE_DIR "store" |
| #define PID_EXT ".pid" |
| #define MAX_CONFIG_PROPERTY_LEN 128 |
| |
| |
| struct configuration_store { |
| |
| bundle_context_pt context; |
| |
| celix_thread_mutex_t mutex; |
| |
| configuration_admin_factory_pt configurationAdminFactory; |
| |
| hash_map_pt configurations; |
| // int createdPidCount; |
| |
| }; |
| |
| static celix_status_t configurationStore_createCache(configuration_store_pt store); |
| static celix_status_t configurationStore_getConfigurationFile(char *pid, char* storePath, int *file); |
| static celix_status_t configurationStore_writeConfigurationFile(int fd, properties_pt properties); |
| static celix_status_t configurationStore_readCache(configuration_store_pt store); |
| static celix_status_t configurationStore_readConfigurationFile(const char *name, int size, properties_pt *dictionary); |
| static celix_status_t configurationStore_parseDataConfigurationFile(char *data, properties_pt *dictionary); |
| |
| /* ========== CONSTRUCTOR ========== */ |
| |
| celix_status_t configurationStore_create(bundle_context_pt context, configuration_admin_factory_pt factory, configuration_store_pt *store) { |
| |
| *store = calloc(1, sizeof(**store)); |
| |
| if (!*store) { |
| printf("[ ERROR ]: ConfigStore - Not initialized (ENOMEM) \n"); |
| return CELIX_ENOMEM; |
| } |
| |
| (*store)->context = context; |
| |
| (*store)->configurationAdminFactory = factory; |
| |
| (*store)->configurations = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL); |
| // (*store)->createdPidCount = 0; |
| |
| if (configurationStore_createCache((*store)) != CELIX_SUCCESS) { |
| printf("[ ERROR ]: ConfigStore - Not initialized (CACHE) \n"); |
| return CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| celix_status_t mutexStatus = celixThreadMutex_create(&(*store)->mutex, NULL); |
| if (mutexStatus != CELIX_SUCCESS) { |
| printf("[ ERROR ]: ConfigStore - Not initialized (MUTEX) \n"); |
| return CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| configurationStore_readCache((*store)); |
| |
| return CELIX_SUCCESS; |
| } |
| |
| celix_status_t configurationStore_destroy(configuration_store_pt store) { |
| celixThreadMutex_destroy(&store->mutex); |
| hashMap_destroy(store->configurations, false, true); |
| free(store); |
| |
| return CELIX_SUCCESS; |
| } |
| |
| /* ========== IMPLEMENTATION ========== */ |
| |
| /* ---------- public ---------- */ |
| // org.eclipse.equinox.internal.cm |
| celix_status_t configurationStore_lock(configuration_store_pt store) { |
| celixThreadMutex_lock(&store->mutex); |
| return CELIX_SUCCESS; |
| } |
| |
| celix_status_t configurationStore_unlock(configuration_store_pt store) { |
| celixThreadMutex_unlock(&store->mutex); |
| return CELIX_SUCCESS; |
| } |
| |
| celix_status_t configurationStore_saveConfiguration(configuration_store_pt store, char *pid, configuration_pt configuration) { |
| |
| celix_status_t status; |
| |
| //(1) config.checkLocked |
| |
| //(2) configurationStore.getFile |
| int configFile; |
| status = configurationStore_getConfigurationFile(pid, (char *) STORE_DIR, &configFile); |
| if (status != CELIX_SUCCESS) { |
| return status; |
| } |
| |
| //(4) configProperties = config.getAllProperties |
| |
| properties_pt configProperties = NULL; |
| status = configuration_getAllProperties(configuration->handle, &configProperties); |
| if (status != CELIX_SUCCESS) { |
| printf("[ ERROR ]: ConfigStore - config{PID=%s}.getAllProperties \n", pid); |
| return status; |
| } |
| |
| |
| //(5) configStore.writeFile(file,properties) |
| status = configurationStore_writeConfigurationFile(configFile, configProperties); |
| |
| if (status != CELIX_SUCCESS) { |
| return status; |
| } |
| |
| return CELIX_SUCCESS; |
| } |
| |
| celix_status_t configurationStore_removeConfiguration(configuration_store_pt store, char *pid) { |
| return CELIX_SUCCESS; |
| } |
| |
| celix_status_t configurationStore_getConfiguration(configuration_store_pt store, char *pid, char *location, configuration_pt *configuration) { |
| |
| celix_status_t status; |
| |
| configuration_pt config; |
| config = hashMap_get(store->configurations, pid); |
| |
| if (config == NULL) { |
| |
| status = configuration_create(store->configurationAdminFactory, store, NULL, pid, location, &config); |
| if (status != CELIX_SUCCESS) { |
| printf("[ ERROR ]: ConfigStore - getConfig(PID=%s) (unable to create) \n", pid); |
| return status; |
| } |
| |
| hashMap_put(store->configurations, pid, config); |
| } |
| |
| *configuration = config; |
| return CELIX_SUCCESS; |
| } |
| |
| celix_status_t configurationStore_createFactoryConfiguration(configuration_store_pt store, char *factoryPid, char *location, configuration_pt *configuration) { |
| return CELIX_SUCCESS; |
| } |
| |
| celix_status_t configurationStore_findConfiguration(configuration_store_pt store, char *pid, configuration_pt *configuration) { |
| |
| *configuration = hashMap_get(store->configurations, pid); |
| return CELIX_SUCCESS; |
| |
| } |
| |
| celix_status_t configurationStore_getFactoryConfigurations(configuration_store_pt store, char *factoryPid, configuration_pt *configuration) { |
| return CELIX_SUCCESS; |
| } |
| |
| celix_status_t configurationStore_listConfigurations(configuration_store_pt store, filter_pt filter, array_list_pt *configurations) { |
| return CELIX_SUCCESS; |
| } |
| |
| celix_status_t configurationStore_unbindConfigurations(configuration_store_pt store, bundle_pt bundle) { |
| return CELIX_SUCCESS; |
| } |
| |
| /* ---------- private ---------- */ |
| |
| celix_status_t configurationStore_createCache(configuration_store_pt store) { |
| |
| int result = mkdir((const char*) STORE_DIR, 0777); |
| |
| if ((result == 0) || ((result == -1) && (errno == EEXIST))) { |
| return CELIX_SUCCESS; |
| } |
| |
| printf("[ ERROR ]: ConfigStore - Create Cache \n"); |
| return CELIX_FILE_IO_EXCEPTION; |
| |
| } |
| |
| celix_status_t configurationStore_getConfigurationFile(char *pid, char* storePath, int *file) { |
| |
| // (1) The full path to the file |
| char fname[PATH_MAX]; |
| strcpy(fname, storePath); |
| strcat(fname, "/"); |
| strcat(fname, (const char *) pid); |
| strcat(fname, (const char *) PID_EXT); |
| |
| // (2) configuration.getPool |
| // (3) file.open |
| if ((*file = open((const char*) fname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) { |
| printf("[ ERROR ]: ConfigStore - getFile(IO_EXCEPTION) \n"); |
| return CELIX_FILE_IO_EXCEPTION; |
| } |
| return CELIX_SUCCESS; |
| } |
| |
| celix_status_t configurationStore_writeConfigurationFile(int file, properties_pt properties) { |
| |
| if (properties == NULL || hashMap_size(properties) <= 0) { |
| return CELIX_SUCCESS; |
| } |
| // size >0 |
| |
| char buffer[256]; |
| |
| hash_map_iterator_pt iterator = hashMapIterator_create(properties); |
| while (hashMapIterator_hasNext(iterator)) { |
| |
| hash_map_entry_pt entry = hashMapIterator_nextEntry(iterator); |
| |
| char* key = hashMapEntry_getKey(entry); |
| char* val = hashMapEntry_getValue(entry); |
| |
| snprintf(buffer, 256, "%s=%s\n", key, val); |
| |
| int buffLength = strlen((const char *) buffer); |
| |
| if (write(file, (const void *) buffer, buffLength) != buffLength) { |
| printf("[ ERROR ]: ConfigStore - writing in Cache incomplete \n"); |
| return CELIX_FILE_IO_EXCEPTION; |
| } |
| } |
| hashMapIterator_destroy(iterator); |
| return CELIX_SUCCESS; |
| |
| } |
| |
| celix_status_t configurationStore_readCache(configuration_store_pt store) { |
| |
| celix_status_t status; |
| |
| DIR *cache; // directory handle |
| |
| properties_pt properties = NULL; |
| configuration_pt configuration = NULL; |
| char *pid; |
| |
| // (1) cache.open |
| cache = opendir((const char*) STORE_DIR); |
| if (cache == NULL) { |
| printf("[ ERROR ]: ConfigStore - Read Cache \n"); |
| return CELIX_FILE_IO_EXCEPTION; |
| } |
| |
| // (2) directory.read |
| struct dirent *dp; |
| int res; |
| struct stat st; |
| union { |
| struct dirent d; |
| char b[offsetof (struct dirent, d_name) + NAME_MAX + 1]; |
| } u; |
| res = readdir_r(cache, (struct dirent*) &u, &dp); |
| while ((res == 0) && (dp != NULL)) { |
| |
| if ((strcmp((dp->d_name), ".") != 0) && (strcmp((dp->d_name), "..") != 0) && (strpbrk(dp->d_name, "~") == NULL)) { |
| char storeRoot[512]; |
| snprintf(storeRoot, sizeof(storeRoot), "%s/%s", STORE_DIR, dp->d_name); |
| // (2.1) file.readData |
| if (stat(storeRoot, &st) == 0) { |
| status = configurationStore_readConfigurationFile(dp->d_name, st.st_size, &properties); |
| if (status != CELIX_SUCCESS) { |
| closedir(cache); |
| return status; |
| } |
| } |
| else |
| perror("stat"); |
| // (2.2) new configuration |
| status = configuration_create2(store->configurationAdminFactory, store, properties, &configuration); |
| if (status != CELIX_SUCCESS) { |
| closedir(cache); |
| return status; |
| } |
| |
| // (2.3) configurations.put |
| configuration_getPid(configuration->handle, &pid); |
| hashMap_put(store->configurations, pid, configuration); |
| } |
| res = readdir_r(cache, (struct dirent*) &u, &dp); |
| } |
| |
| closedir(cache); |
| |
| return CELIX_SUCCESS; |
| } |
| |
| celix_status_t configurationStore_readConfigurationFile(const char *name, int size, properties_pt *dictionary) { |
| |
| char fname[256]; // file name |
| char *buffer; // file buffer |
| int fd; |
| celix_status_t status = CELIX_SUCCESS; |
| |
| properties_pt properties = NULL; |
| |
| // (1) The full path to the file |
| snprintf(fname, 256, "%s/%s", STORE_DIR, name); |
| |
| // (2) pool.new |
| |
| // (3) file.open |
| fd = open((const char*) fname, O_RDONLY); |
| if (fd < 0) { |
| printf("[ ERROR ]: ConfigStore - open File{%s} for reading (IO_EXCEPTION) \n", name); |
| return CELIX_FILE_IO_EXCEPTION; |
| } |
| |
| // (4) buffer.new |
| buffer = calloc(1, size+1); |
| if (!buffer) { |
| close(fd); |
| return CELIX_ENOMEM; |
| } |
| |
| // (5) file.read |
| if (read(fd, (void *) buffer, size) != size) { |
| printf("[ ERROR ]: ConfigStore - reading File{%s} \n", name); |
| status = CELIX_FILE_IO_EXCEPTION; |
| } |
| |
| status = CELIX_DO_IF(status, configurationStore_parseDataConfigurationFile(buffer, &properties)); |
| |
| // (6) file.close & buffer.destroy |
| free(buffer); |
| close(fd); |
| // (7) return |
| *dictionary = properties; |
| return status; |
| |
| } |
| |
| celix_status_t configurationStore_parseDataConfigurationFile(char *data, properties_pt *dictionary) { |
| |
| properties_pt properties = properties_create(); |
| |
| |
| char *token; |
| char *key; |
| char *value; |
| char *saveptr; |
| |
| bool isKey = true; |
| token = strtok_r(data, "=", &saveptr); |
| |
| while (token != NULL) { |
| |
| if (isKey) { |
| key = strdup(token); |
| isKey = false; |
| |
| } else { // isValue |
| value = strdup(token); |
| properties_set(properties, key, value); |
| isKey = true; |
| } |
| |
| token = strtok_r(NULL, "=\n", &saveptr); |
| } |
| |
| if (hashMap_isEmpty(properties)) { |
| return CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| *dictionary = properties; |
| return CELIX_SUCCESS; |
| } |