blob: 1af4665a782b421a1dd7a87ffa37fb290775ac87 [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.
*/
/*
* manifest_parser.c
*
* \date Jul 12, 2010
* \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
* \copyright Apache License, Version 2.0
*/
#include <stdlib.h>
#include <string.h>
#include "utils.h"
#include "constants.h"
#include "manifest_parser.h"
#include "capability.h"
#include "requirement.h"
#include "attribute.h"
#include "hash_map.h"
#include "celix_errno.h"
#include "linked_list_iterator.h"
#include "celix_log.h"
//FIXME the manifest parser has no destroy function and as result contains memory leaks.
struct manifestParser {
module_pt owner;
manifest_pt manifest;
version_pt bundleVersion;
char * bundleSymbolicName;
linked_list_pt capabilities;
linked_list_pt requirements;
};
static linked_list_pt manifestParser_parseImportHeader(char * header);
static linked_list_pt manifestParser_parseExportHeader(module_pt module, char * header);
static linked_list_pt manifestParser_parseDelimitedString(char * value, char * delim);
static linked_list_pt manifestParser_parseStandardHeaderClause(char * clauseString);
static linked_list_pt manifestParser_parseStandardHeader(char * header);
celix_status_t manifestParser_create(module_pt owner, manifest_pt manifest, manifest_parser_pt *manifest_parser) {
celix_status_t status;
manifest_parser_pt parser;
status = CELIX_SUCCESS;
parser = (manifest_parser_pt) malloc(sizeof(*parser));
if (parser) {
char * bundleVersion = NULL;
char * bundleSymbolicName = NULL;
parser->manifest = manifest;
parser->owner = owner;
bundleVersion = manifest_getValue(manifest, OSGI_FRAMEWORK_BUNDLE_VERSION);
if (bundleVersion != NULL) {
parser->bundleVersion = NULL;
version_createVersionFromString(bundleVersion, &parser->bundleVersion);
} else {
parser->bundleVersion = NULL;
version_createEmptyVersion(&parser->bundleVersion);
}
bundleSymbolicName = manifest_getValue(manifest, OSGI_FRAMEWORK_BUNDLE_SYMBOLICNAME);
if (bundleSymbolicName != NULL) {
parser->bundleSymbolicName = bundleSymbolicName;
}
parser->capabilities = manifestParser_parseExportHeader(owner, manifest_getValue(manifest, OSGI_FRAMEWORK_EXPORT_LIBRARY));
parser->requirements = manifestParser_parseImportHeader(manifest_getValue(manifest, OSGI_FRAMEWORK_IMPORT_LIBRARY));
*manifest_parser = parser;
status = CELIX_SUCCESS;
} else {
status = CELIX_ENOMEM;
}
framework_logIfError(logger, status, NULL, "Cannot create manifest parser");
return status;
}
celix_status_t manifestParser_destroy(manifest_parser_pt mp) {
linkedList_destroy(mp->capabilities);
mp->capabilities = NULL;
linkedList_destroy(mp->requirements);
mp->requirements = NULL;
mp->bundleSymbolicName = NULL;
version_destroy(mp->bundleVersion);
mp->bundleVersion = NULL;
mp->manifest = NULL;
mp->owner = NULL;
free(mp);
return CELIX_SUCCESS;
}
static linked_list_pt manifestParser_parseDelimitedString(char * value, char * delim) {
linked_list_pt list;
if (linkedList_create(&list) == CELIX_SUCCESS) {
if (value != NULL) {
int CHAR = 1;
int DELIMITER = 2;
int STARTQUOTE = 4;
int ENDQUOTE = 8;
char buffer[512];
int expecting = (CHAR | DELIMITER | STARTQUOTE);
unsigned int i;
buffer[0] = '\0';
for (i = 0; i < strlen(value); i++) {
char c = value[i];
bool isDelimiter = (strchr(delim, c) != NULL);
bool isQuote = (c == '"');
if (isDelimiter && ((expecting & DELIMITER) > 0)) {
linkedList_addElement(list, strdup(buffer));
buffer[0] = '\0';
expecting = (CHAR | DELIMITER | STARTQUOTE);
} else if (isQuote && ((expecting & STARTQUOTE) > 0)) {
char tmp[2];
tmp[0] = c;
tmp[1] = '\0';
strcat(buffer, tmp);
expecting = CHAR | ENDQUOTE;
} else if (isQuote && ((expecting & ENDQUOTE) > 0)) {
char tmp[2];
tmp[0] = c;
tmp[1] = '\0';
strcat(buffer, tmp);
expecting = (CHAR | STARTQUOTE | DELIMITER);
} else if ((expecting & CHAR) > 0) {
char tmp[2];
tmp[0] = c;
tmp[1] = '\0';
strcat(buffer, tmp);
} else {
return NULL;
}
}
if (strlen(buffer) > 0) {
linkedList_addElement(list, strdup(utils_stringTrim(buffer)));
}
}
}
return list;
}
static linked_list_pt manifestParser_parseStandardHeaderClause(char * clauseString) {
linked_list_pt paths;
linked_list_pt clause;
linked_list_pt pieces;
clause = NULL;
pieces = manifestParser_parseDelimitedString(clauseString, ";");
if (linkedList_create(&paths) == CELIX_SUCCESS) {
int pathCount = 0;
int pieceIdx;
hash_map_pt dirsMap = NULL;
hash_map_pt attrsMap = NULL;
char * sep;
for (pieceIdx = 0; pieceIdx < linkedList_size(pieces); pieceIdx++) {
char * piece = linkedList_get(pieces, pieceIdx);
if (strchr(piece, '=') != NULL) {
break;
} else {
linkedList_addElement(paths, strdup(piece));
pathCount++;
}
}
if (pathCount == 0) {
return NULL;
}
dirsMap = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
attrsMap = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
for (pieceIdx = pathCount; pieceIdx < linkedList_size(pieces); pieceIdx++) {
char * sepPtr;
char * key;
char * value;
char * DIRECTIVE_SEP = ":=";
char * ATTRIBUTE_SEP = "=";
char * piece = linkedList_get(pieces, pieceIdx);
if ((sepPtr = strstr(piece, DIRECTIVE_SEP)) != NULL) {
sep = DIRECTIVE_SEP;
} else if ((sepPtr = strstr(piece, ATTRIBUTE_SEP)) != NULL) {
sep = ATTRIBUTE_SEP;
} else {
return NULL;
}
key = string_ndup(piece, sepPtr - piece);
value = strdup(sepPtr+strlen(sep));
if (value[0] == '"' && value[strlen(value) -1] == '"') {
char * oldV = strdup(value);
int len = strlen(oldV) - 2;
value = (char *) realloc(value, (sizeof(char) * len+1));
value[0] = '\0';
value = strncpy(value, oldV+1, strlen(oldV) - 2);
value[len] = '\0';
//check if correct
free(oldV);
}
if (strcmp(sep, DIRECTIVE_SEP) == 0) {
// Not implemented
} else {
attribute_pt attr = NULL;
if (hashMap_containsKey(attrsMap, key)) {
return NULL;
}
if (attribute_create(key, value, &attr) == CELIX_SUCCESS) {
hashMap_put(attrsMap, key, attr);
}
}
}
if (linkedList_create(&clause) == CELIX_SUCCESS) {
linkedList_addElement(clause, paths);
linkedList_addElement(clause, dirsMap);
linkedList_addElement(clause, attrsMap);
}
}
for(int listIdx = 0; listIdx < linkedList_size(pieces); listIdx++){
void * element = linkedList_get(pieces, listIdx);
free(element);
}
linkedList_destroy(pieces);
return clause;
}
static linked_list_pt manifestParser_parseStandardHeader(char * header) {
linked_list_pt clauseStrings = NULL;
linked_list_pt completeList = NULL;
if (linkedList_create(&completeList) == CELIX_SUCCESS) {
if (header != NULL) {
if (strlen(header) == 0) {
return NULL;
}
char *hdr = strdup(header);
clauseStrings = manifestParser_parseDelimitedString(hdr, ",");
free(hdr);
if (clauseStrings != NULL) {
int i;
for (i = 0; i < linkedList_size(clauseStrings); i++) {
char *clauseString = (char *) linkedList_get(clauseStrings, i);
linkedList_addElement(completeList, manifestParser_parseStandardHeaderClause(clauseString));
free(clauseString);
}
linkedList_destroy(clauseStrings);
}
}
}
return completeList;
}
static linked_list_pt manifestParser_parseImportHeader(char * header) {
linked_list_pt clauses;
linked_list_pt requirements;
int clauseIdx;
linked_list_iterator_pt iter;
clauses = manifestParser_parseStandardHeader(header);
linkedList_create(&requirements);
for (clauseIdx = 0; clauseIdx < linkedList_size(clauses); clauseIdx++) {
linked_list_pt clause = linkedList_get(clauses, clauseIdx);
linked_list_pt paths = linkedList_get(clause, 0);
hash_map_pt directives = linkedList_get(clause, 1);
hash_map_pt attributes = linkedList_get(clause, 2);
int pathIdx;
for (pathIdx = 0; pathIdx < linkedList_size(paths); pathIdx++) {
attribute_pt name = NULL;
requirement_pt req = NULL;
char * path = (char *) linkedList_get(paths, pathIdx);
if (strlen(path) == 0) {
return NULL;
}
if (attribute_create(strdup("service"), path, &name) == CELIX_SUCCESS) {
char *key = NULL;
attribute_getKey(name, &key);
hashMap_put(attributes, key, name);
}
requirement_create(directives, attributes, &req);
linkedList_addElement(requirements, req);
}
}
iter = linkedListIterator_create(clauses, 0);
while(linkedListIterator_hasNext(iter)) {
linked_list_pt clause = linkedListIterator_next(iter);
linked_list_pt paths = linkedList_get(clause, 0);
linkedList_destroy(paths);
linkedListIterator_remove(iter);
linkedList_destroy(clause);
}
linkedListIterator_destroy(iter);
linkedList_destroy(clauses);
return requirements;
}
static linked_list_pt manifestParser_parseExportHeader(module_pt module, char * header) {
linked_list_pt clauses;
linked_list_pt capabilities;
int clauseIdx;
linked_list_iterator_pt iter;
clauses = manifestParser_parseStandardHeader(header);
linkedList_create(&capabilities);
for (clauseIdx = 0; clauseIdx < linkedList_size(clauses); clauseIdx++) {
linked_list_pt clause = linkedList_get(clauses, clauseIdx);
linked_list_pt paths = linkedList_get(clause, 0);
hash_map_pt directives = linkedList_get(clause, 1);
hash_map_pt attributes = linkedList_get(clause, 2);
int pathIdx;
for (pathIdx = 0; pathIdx < linkedList_size(paths); pathIdx++) {
char * path = (char *) linkedList_get(paths, pathIdx);
attribute_pt name = NULL;
capability_pt cap = NULL;
if (strlen(path) == 0) {
return NULL;
}
if (attribute_create(strdup("service"), path, &name) == CELIX_SUCCESS) {
char *key = NULL;
attribute_getKey(name, &key);
hashMap_put(attributes, key, name);
}
capability_create(module, directives, attributes, &cap);
linkedList_addElement(capabilities, cap);
}
}
iter = linkedListIterator_create(clauses, 0);
while(linkedListIterator_hasNext(iter)) {
linked_list_pt clause = linkedListIterator_next(iter);
linked_list_pt paths = linkedList_get(clause, 0);
linkedList_destroy(paths);
linkedListIterator_remove(iter);
linkedList_destroy(clause);
}
linkedListIterator_destroy(iter);
linkedList_destroy(clauses);
return capabilities;
}
celix_status_t manifestParser_getSymbolicName(manifest_parser_pt parser, char **symbolicName) {
*symbolicName = strdup(parser->bundleSymbolicName);
return CELIX_SUCCESS;
}
celix_status_t manifestParser_getBundleVersion(manifest_parser_pt parser, version_pt *version) {
return version_clone(parser->bundleVersion, version);
}
celix_status_t manifestParser_getCapabilities(manifest_parser_pt parser, linked_list_pt *capabilities) {
celix_status_t status;
status = linkedList_clone(parser->capabilities, capabilities);
return status;
}
celix_status_t manifestParser_getRequirements(manifest_parser_pt parser, linked_list_pt *requirements) {
celix_status_t status;
status = linkedList_clone(parser->requirements, requirements);
return status;
}