blob: 37b091ead2f6edadb43938d99dcf73ef3e4bf729 [file] [log] [blame]
/**
*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;
}