blob: 5b9103d9777e7cdd78499273274d2ae6f6cf4963 [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.
*/
/*
* driver_matcher.c
*
* \date Jun 20, 2011
* \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
* \copyright Apache License, Version 2.0
*/
#include <stdlib.h>
#include "hash_map.h"
#include "constants.h"
#include "driver_matcher.h"
#include "log_helper.h"
#include "log_service.h"
struct driver_matcher {
hash_map_pt attributes;
array_list_pt matches;
log_helper_pt loghelper;
bundle_context_pt context;
};
typedef struct match_key {
int matchValue;
}*match_key_t;
static celix_status_t driverMatcher_get(driver_matcher_pt matcher, int key, array_list_pt *attributesV);
static celix_status_t driverMatcher_getBestMatchInternal(driver_matcher_pt matcher, match_pt *match);
unsigned int driverMatcher_matchKeyHash(void * match_key) {
match_key_t key = match_key;
return key->matchValue;
}
int driverMatcher_matchKeyEquals(void * key, void * toCompare) {
return ((match_key_t) key)->matchValue == ((match_key_t) toCompare)->matchValue;
}
celix_status_t driverMatcher_create(bundle_context_pt context, driver_matcher_pt *matcher) {
celix_status_t status = CELIX_SUCCESS;
*matcher = calloc(1, sizeof(**matcher));
if (!*matcher) {
status = CELIX_ENOMEM;
} else {
(*matcher)->matches = NULL;
(*matcher)->context = context;
(*matcher)->attributes = hashMap_create(driverMatcher_matchKeyHash, NULL, driverMatcher_matchKeyEquals, NULL);
arrayList_create(&(*matcher)->matches);
if(logHelper_create(context, &(*matcher)->loghelper) == CELIX_SUCCESS) {
logHelper_start((*matcher)->loghelper);
}
}
return status;
}
celix_status_t driverMatcher_destroy(driver_matcher_pt *matcher) {
arrayList_destroy((*matcher)->matches);
hash_map_iterator_pt iter = hashMapIterator_create((*matcher)->attributes);
while (hashMapIterator_hasNext(iter)) {
array_list_pt list = hashMapIterator_nextValue(iter);
if (list != NULL) {
arrayList_destroy(list);
}
}
hashMapIterator_destroy(iter);
hashMap_destroy((*matcher)->attributes, false, false);
logHelper_stop((*matcher)->loghelper);
logHelper_destroy(&(*matcher)->loghelper);
free(*matcher);
return CELIX_SUCCESS;
}
celix_status_t driverMatcher_add(driver_matcher_pt matcher, int matchValue, driver_attributes_pt attributes) {
celix_status_t status = CELIX_SUCCESS;
array_list_pt da = NULL;
status = driverMatcher_get(matcher, matchValue, &da);
if (status == CELIX_SUCCESS) {
arrayList_add(da, attributes);
match_pt match = NULL;
match = calloc(1, sizeof(*match));
if (!match) {
status = CELIX_ENOMEM;
} else {
match->matchValue = matchValue;
match->reference = NULL;
driverAttributes_getReference(attributes, &match->reference);
arrayList_add(matcher->matches, match);
}
}
return status;
}
celix_status_t driverMatcher_get(driver_matcher_pt matcher, int key, array_list_pt *attributes) {
celix_status_t status = CELIX_SUCCESS;
match_key_t matchKeyS = calloc(1, sizeof(*matchKeyS));
matchKeyS->matchValue = key;
*attributes = hashMap_get(matcher->attributes, matchKeyS);
if (*attributes == NULL) {
arrayList_create(attributes);
match_key_t matchKey = calloc(1, sizeof(*matchKey));
matchKey->matchValue = key;
hashMap_put(matcher->attributes, matchKey, *attributes);
}
return status;
}
celix_status_t driverMatcher_getBestMatch(driver_matcher_pt matcher, service_reference_pt reference, match_pt *match) {
celix_status_t status = CELIX_SUCCESS;
if (*match != NULL) {
status = CELIX_ILLEGAL_ARGUMENT;
} else {
service_reference_pt selectorRef = NULL;
status = bundleContext_getServiceReference(matcher->context, OSGI_DEVICEACCESS_DRIVER_SELECTOR_SERVICE_NAME, &selectorRef);
if (status == CELIX_SUCCESS) {
int index = -1;
if (selectorRef != NULL) {
driver_selector_service_pt selector = NULL;
status = bundleContext_getService(matcher->context, selectorRef, (void **) &selector);
if (status == CELIX_SUCCESS) {
if (selector != NULL) {
int size = -1;
status = selector->driverSelector_select(selector->selector, reference, matcher->matches, &index);
if (status == CELIX_SUCCESS) {
size = arrayList_size(matcher->matches);
if (index != -1 && index >= 0 && index < size) {
*match = arrayList_get(matcher->matches, index);
}
}
}
}
}
if (status == CELIX_SUCCESS && *match == NULL) {
status = driverMatcher_getBestMatchInternal(matcher, match);
}
}
}
return status;
}
celix_status_t driverMatcher_getBestMatchInternal(driver_matcher_pt matcher, match_pt *match) {
celix_status_t status = CELIX_SUCCESS;
if (!hashMap_isEmpty(matcher->attributes)) {
match_key_t matchKey = NULL;
hash_map_iterator_pt iter = hashMapIterator_create(matcher->attributes);
while (hashMapIterator_hasNext(iter)) {
hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
match_key_t key = hashMapEntry_getKey(entry);
if (matchKey == NULL || matchKey->matchValue < key->matchValue) {
matchKey = key;
}
}
hashMapIterator_destroy(iter);
array_list_pt das = hashMap_get(matcher->attributes, matchKey);
service_reference_pt best = NULL;
int i;
for (i = 0; i < arrayList_size(das); i++) {
driver_attributes_pt attributes = arrayList_get(das, i);
service_reference_pt reference = NULL;
celix_status_t substatus = driverAttributes_getReference(attributes, &reference);
if (substatus == CELIX_SUCCESS) {
if (best != NULL) {
char *rank1Str, *rank2Str;
int rank1, rank2;
rank1Str = "0";
rank2Str = "0";
logHelper_log(matcher->loghelper, OSGI_LOGSERVICE_DEBUG, "DRIVER_MATCHER: Compare ranking");
serviceReference_getProperty(reference, (char *) OSGI_FRAMEWORK_SERVICE_RANKING, &rank1Str);
serviceReference_getProperty(reference, (char *) OSGI_FRAMEWORK_SERVICE_RANKING, &rank2Str);
rank1 = atoi(rank1Str);
rank2 = atoi(rank2Str);
if (rank1 != rank2) {
if (rank1 > rank2) {
best = reference;
}
} else {
char *id1Str, *id2Str;
long id1, id2;
id1Str = NULL;
id2Str = NULL;
logHelper_log(matcher->loghelper, OSGI_LOGSERVICE_DEBUG, "DRIVER_MATCHER: Compare id's");
serviceReference_getProperty(reference, (char *) OSGI_FRAMEWORK_SERVICE_ID, &id1Str);
serviceReference_getProperty(reference, (char *) OSGI_FRAMEWORK_SERVICE_ID, &id2Str);
id1 = atol(id1Str);
id2 = atol(id2Str);
if (id1 < id2) {
best = reference;
}
}
} else {
best = reference;
}
}
}
*match = calloc(1, sizeof(**match));
if (!*match) {
status = CELIX_ENOMEM;
} else {
(*match)->matchValue = matchKey->matchValue;
(*match)->reference = best;
}
}
return status;
}