blob: 256eff5a36ea38d26af8457d93205acc7e3f0993 [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.
*/
/*
* resolver.c
*
* \date Jul 13, 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 <stdio.h>
#include "resolver.h"
#include "linked_list_iterator.h"
#include "bundle.h"
#include "celix_log.h"
struct capabilityList {
char * serviceName;
linked_list_pt capabilities;
};
typedef struct capabilityList * capability_list_pt;
struct candidateSet {
module_pt module;
requirement_pt requirement;
linked_list_pt candidates;
};
typedef struct candidateSet * candidate_set_pt;
// List containing module_ts
linked_list_pt m_modules = NULL;
// List containing capability_t_LISTs
linked_list_pt m_unresolvedServices = NULL;
// List containing capability_t_LISTs
linked_list_pt m_resolvedServices = NULL;
int resolver_populateCandidatesMap(hash_map_pt candidatesMap, module_pt targetModule);
capability_list_pt resolver_getCapabilityList(linked_list_pt list, const char* name);
void resolver_removeInvalidCandidate(module_pt module, hash_map_pt candidates, linked_list_pt invalid);
linked_list_pt resolver_populateWireMap(hash_map_pt candidates, module_pt importer, linked_list_pt wireMap);
linked_list_pt resolver_resolve(module_pt root) {
hash_map_pt candidatesMap = NULL;
linked_list_pt wireMap = NULL;
linked_list_pt resolved = NULL;
hash_map_iterator_pt iter = NULL;
if (module_isResolved(root)) {
return NULL;
}
candidatesMap = hashMap_create(NULL, NULL, NULL, NULL);
if (resolver_populateCandidatesMap(candidatesMap, root) != 0) {
hash_map_iterator_pt iter = hashMapIterator_create(candidatesMap);
while (hashMapIterator_hasNext(iter)) {
hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
linked_list_pt value = hashMapEntry_getValue(entry);
hashMapIterator_remove(iter);
if (value != NULL) {
linked_list_iterator_pt candSetIter = linkedListIterator_create(value, 0);
while (linkedListIterator_hasNext(candSetIter)) {
candidate_set_pt set = linkedListIterator_next(candSetIter);
linkedList_destroy(set->candidates);
free(set);
linkedListIterator_remove(candSetIter);
}
linkedListIterator_destroy(candSetIter);
linkedList_destroy(value);
}
}
hashMapIterator_destroy(iter);
hashMap_destroy(candidatesMap, false, false);
return NULL;
}
linkedList_create(&wireMap);
resolved = resolver_populateWireMap(candidatesMap, root, wireMap);
iter = hashMapIterator_create(candidatesMap);
while (hashMapIterator_hasNext(iter)) {
hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
linked_list_pt value = hashMapEntry_getValue(entry);
hashMapIterator_remove(iter);
if (value != NULL) {
linked_list_iterator_pt candSetIter = linkedListIterator_create(value, 0);
while (linkedListIterator_hasNext(candSetIter)) {
candidate_set_pt set = linkedListIterator_next(candSetIter);
linkedList_destroy(set->candidates);
free(set);
linkedListIterator_remove(candSetIter);
}
linkedListIterator_destroy(candSetIter);
linkedList_destroy(value);
}
}
hashMapIterator_destroy(iter);
hashMap_destroy(candidatesMap, false, false);
return resolved;
}
int resolver_populateCandidatesMap(hash_map_pt candidatesMap, module_pt targetModule) {
linked_list_pt candSetList;
linked_list_pt candidates;
linked_list_pt invalid;
if (hashMap_containsKey(candidatesMap, targetModule)) {
return 0;
}
hashMap_put(candidatesMap, targetModule, NULL);
if (linkedList_create(&candSetList) == CELIX_SUCCESS) {
int i;
for (i = 0; i < linkedList_size(module_getRequirements(targetModule)); i++) {
capability_list_pt capList;
requirement_pt req;
const char *targetName = NULL;
req = (requirement_pt) linkedList_get(module_getRequirements(targetModule), i);
requirement_getTargetName(req, &targetName);
capList = resolver_getCapabilityList(m_resolvedServices, targetName);
if (linkedList_create(&candidates) == CELIX_SUCCESS) {
int c;
for (c = 0; (capList != NULL) && (c < linkedList_size(capList->capabilities)); c++) {
capability_pt cap = (capability_pt) linkedList_get(capList->capabilities, c);
bool satisfied = false;
requirement_isSatisfied(req, cap, &satisfied);
if (satisfied) {
linkedList_addElement(candidates, cap);
}
}
capList = resolver_getCapabilityList(m_unresolvedServices, targetName);
for (c = 0; (capList != NULL) && (c < linkedList_size(capList->capabilities)); c++) {
capability_pt cap = (capability_pt) linkedList_get(capList->capabilities, c);
bool satisfied = false;
requirement_isSatisfied(req, cap, &satisfied);
if (satisfied) {
linkedList_addElement(candidates, cap);
}
}
if (linkedList_size(candidates) > 0) {
linked_list_iterator_pt iterator = NULL;
for (iterator = linkedListIterator_create(candidates, 0); linkedListIterator_hasNext(iterator);) {
capability_pt candidate = (capability_pt) linkedListIterator_next(iterator);
module_pt module = NULL;
capability_getModule(candidate, &module);
if (!module_isResolved(module)) {
if (resolver_populateCandidatesMap(candidatesMap, module) != 0) {
linkedListIterator_remove(iterator);
}
}
}
linkedListIterator_destroy(iterator);
}
if (linkedList_size(candidates) == 0) {
if (linkedList_create(&invalid) == CELIX_SUCCESS) {
const char *name = NULL;
resolver_removeInvalidCandidate(targetModule, candidatesMap, invalid);
module_getSymbolicName(targetModule, &name);
linkedList_destroy(invalid);
fw_log(logger, OSGI_FRAMEWORK_LOG_INFO, "Unable to resolve: %s, %s\n", name, targetName);
}
linkedList_destroy(candidates);
linkedList_destroy(candSetList);
return -1;
} else if (linkedList_size(candidates) > 0) {
candidate_set_pt cs = (candidate_set_pt) malloc(sizeof(*cs));
cs->candidates = candidates;
cs->module = targetModule;
cs->requirement = req;
linkedList_addElement(candSetList, cs);
}
}
}
hashMap_put(candidatesMap, targetModule, candSetList);
}
return 0;
}
void resolver_removeInvalidCandidate(module_pt invalidModule, hash_map_pt candidates, linked_list_pt invalid) {
hash_map_iterator_pt iterator;
hashMap_remove(candidates, invalidModule);
for (iterator = hashMapIterator_create(candidates); hashMapIterator_hasNext(iterator);) {
hash_map_entry_pt entry = hashMapIterator_nextEntry(iterator);
linked_list_pt candSetList = (linked_list_pt) hashMapEntry_getValue(entry);
if (candSetList != NULL) {
linked_list_iterator_pt itCandSetList;
for (itCandSetList = linkedListIterator_create(candSetList, 0); linkedListIterator_hasNext(itCandSetList);) {
candidate_set_pt set = (candidate_set_pt) linkedListIterator_next(itCandSetList);
linked_list_iterator_pt candIter;
for (candIter = linkedListIterator_create(set->candidates, 0); linkedListIterator_hasNext(candIter);) {
capability_pt candCap = (capability_pt) linkedListIterator_next(candIter);
module_pt module = NULL;
capability_getModule(candCap, &module);
if (module == invalidModule) {
linkedListIterator_remove(candIter);
if (linkedList_size(set->candidates) == 0) {
linkedListIterator_remove(itCandSetList);
if (module != invalidModule && linkedList_contains(invalid, module)) {
linkedList_addElement(invalid, module);
}
}
break;
}
}
linkedListIterator_destroy(candIter);
}
linkedListIterator_destroy(itCandSetList);
}
}
hashMapIterator_destroy(iterator);
if (linkedList_size(invalid) > 0) {
while (!linkedList_isEmpty(invalid)) {
module_pt m = (module_pt) linkedList_removeIndex(invalid, 0);
resolver_removeInvalidCandidate(m, candidates, invalid);
}
}
}
void resolver_addModule(module_pt module) {
if (m_modules == NULL) {
linkedList_create(&m_modules);
linkedList_create(&m_unresolvedServices);
linkedList_create(&m_resolvedServices);
}
if (m_modules != NULL && m_unresolvedServices != NULL) {
int i;
linkedList_addElement(m_modules, module);
for (i = 0; i < linkedList_size(module_getCapabilities(module)); i++) {
const char *serviceName = NULL;
capability_list_pt list = NULL;
capability_pt cap;
cap = (capability_pt) linkedList_get(module_getCapabilities(module), i);
capability_getServiceName(cap, &serviceName);
list = resolver_getCapabilityList(m_unresolvedServices, serviceName);
if (list == NULL) {
list = (capability_list_pt) malloc(sizeof(*list));
if (list != NULL) {
list->serviceName = strdup(serviceName);
if (linkedList_create(&list->capabilities) == CELIX_SUCCESS) {
linkedList_addElement(m_unresolvedServices, list);
}
else{
free(list->serviceName);
free(list);
list=NULL;
}
}
}
if(list != NULL){
linkedList_addElement(list->capabilities, cap);
}
}
}
}
void resolver_removeModule(module_pt module) {
linked_list_pt caps = NULL;
linkedList_removeElement(m_modules, module);
caps = module_getCapabilities(module);
if (caps != NULL) {
int i = 0;
for (i = 0; i < linkedList_size(caps); i++) {
capability_pt cap = (capability_pt) linkedList_get(caps, i);
const char *serviceName = NULL;
capability_list_pt list;
capability_getServiceName(cap, &serviceName);
list = resolver_getCapabilityList(m_unresolvedServices, serviceName);
if (list != NULL) {
linkedList_removeElement(list->capabilities, cap);
if (linkedList_isEmpty(list->capabilities)) {
linkedList_removeElement(m_unresolvedServices, list);
linkedList_destroy(list->capabilities);
free(list->serviceName);
free(list);
}
}
list = resolver_getCapabilityList(m_resolvedServices, serviceName);
if (list != NULL) {
linkedList_removeElement(list->capabilities, cap);
if (linkedList_isEmpty(list->capabilities)) {
linkedList_removeElement(m_resolvedServices, list);
linkedList_destroy(list->capabilities);
free(list->serviceName);
free(list);
}
}
}
}
if (linkedList_isEmpty(m_modules)) {
linkedList_destroy(m_modules);
m_modules = NULL;
if (!linkedList_isEmpty(m_unresolvedServices)) {
// #TODO: Something is wrong, not all modules have been removed from the resolver
fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Unexpected entries in unresolved module list");
}
linkedList_destroy(m_unresolvedServices);
m_unresolvedServices = NULL;
if (!linkedList_isEmpty(m_resolvedServices)) {
// #TODO: Something is wrong, not all modules have been removed from the resolver
fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Unexpected entries in resolved module list");
}
linkedList_destroy(m_resolvedServices);
m_resolvedServices = NULL;
}
}
void resolver_moduleResolved(module_pt module) {
if (module_isResolved(module)) {
linked_list_pt capsCopy = NULL;
if (linkedList_create(&capsCopy) == CELIX_SUCCESS) {
linked_list_pt wires = NULL;
int capIdx;
for (capIdx = 0; (module_getCapabilities(module) != NULL) && (capIdx < linkedList_size(module_getCapabilities(module))); capIdx++) {
capability_pt cap = (capability_pt) linkedList_get(module_getCapabilities(module), capIdx);
const char *serviceName = NULL;
capability_list_pt list;
capability_getServiceName(cap, &serviceName);
list = resolver_getCapabilityList(m_unresolvedServices, serviceName);
if(list != NULL){
linkedList_removeElement(list->capabilities, cap);
}
linkedList_addElement(capsCopy, cap);
}
wires = module_getWires(module);
for (capIdx = 0; (capsCopy != NULL) && (capIdx < linkedList_size(capsCopy)); capIdx++) {
capability_pt cap = linkedList_get(capsCopy, capIdx);
int wireIdx = 0;
for (wireIdx = 0; (wires != NULL) && (wireIdx < linkedList_size(wires)); wireIdx++) {
wire_pt wire = (wire_pt) linkedList_get(wires, wireIdx);
requirement_pt req = NULL;
bool satisfied = false;
wire_getRequirement(wire, &req);
requirement_isSatisfied(req, cap, &satisfied);
if (satisfied) {
linkedList_set(capsCopy, capIdx, NULL);
break;
}
}
}
for (capIdx = 0; (capsCopy != NULL) && (capIdx < linkedList_size(capsCopy)); capIdx++) {
capability_pt cap = linkedList_get(capsCopy, capIdx);
if (cap != NULL) {
const char *serviceName = NULL;
capability_list_pt list = NULL;
capability_getServiceName(cap, &serviceName);
list = resolver_getCapabilityList(m_resolvedServices, serviceName);
if (list == NULL) {
list = (capability_list_pt) malloc(sizeof(*list));
if (list != NULL) {
list->serviceName = strdup(serviceName);
if (linkedList_create(&list->capabilities) == CELIX_SUCCESS) {
linkedList_addElement(m_resolvedServices, list);
}
else{
free(list->serviceName);
free(list);
list=NULL;
}
}
}
if(list != NULL){
linkedList_addElement(list->capabilities, cap);
}
}
}
linkedList_destroy(capsCopy);
}
}
}
capability_list_pt resolver_getCapabilityList(linked_list_pt list, const char * name) {
capability_list_pt capabilityList = NULL;
linked_list_iterator_pt iterator = linkedListIterator_create(list, 0);
while (linkedListIterator_hasNext(iterator)) {
capability_list_pt services = (capability_list_pt) linkedListIterator_next(iterator);
if (strcmp(services->serviceName, name) == 0) {
capabilityList = services;
break;
}
}
linkedListIterator_destroy(iterator);
return capabilityList;
}
linked_list_pt resolver_populateWireMap(hash_map_pt candidates, module_pt importer, linked_list_pt wireMap) {
linked_list_pt serviceWires;
if (candidates && importer && wireMap) {
linked_list_pt candSetList = NULL;
bool resolved = false;
if (module_isResolved(importer)) {
// already resolved
resolved = true;
}
if (!resolved) {
bool self = false;
linked_list_iterator_pt wit = linkedListIterator_create(wireMap, 0);
while (linkedListIterator_hasNext(wit)) {
importer_wires_pt iw = linkedListIterator_next(wit);
if (iw->importer == importer) {
// Do not resolve yourself
self = true;
break;
}
}
linkedListIterator_destroy(wit);
if (!self) {
candSetList = (linked_list_pt) hashMap_get(candidates, importer);
if (linkedList_create(&serviceWires) == CELIX_SUCCESS) {
// if (linkedList_create(&emptyWires) == CELIX_SUCCESS) {
int candSetIdx = 0;
// hashMap_put(wireMap, importer, emptyWires);
const char *mname = NULL;
module_getSymbolicName(importer, &mname);
importer_wires_pt importerWires = malloc(sizeof(*importerWires));
importerWires->importer = importer;
importerWires->wires = NULL;
linkedList_addElement(wireMap, importerWires);
for (candSetIdx = 0; candSetIdx < linkedList_size(candSetList); candSetIdx++) {
candidate_set_pt cs = (candidate_set_pt) linkedList_get(candSetList, candSetIdx);
module_pt module = NULL;
capability_getModule(((capability_pt) linkedList_get(cs->candidates, 0)), &module);
if (importer != module) {
wire_pt wire = NULL;
wire_create(importer, cs->requirement, module, ((capability_pt) linkedList_get(cs->candidates, 0)), &wire);
linkedList_addElement(serviceWires, wire);
}
wireMap = resolver_populateWireMap(candidates, module, wireMap);
}
importerWires->wires = serviceWires;
// hashMap_put(wireMap, importer, serviceWires);
// }
}
}
}
}
return wireMap;
}