in bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_impl.c [284:418]
celix_status_t rsaShm_exportService(rsa_shm_t *admin, char *serviceId,
celix_properties_t *properties, celix_array_list_t **registrationsOut) {
celix_status_t status = CELIX_SUCCESS;
if (admin == NULL || serviceId == NULL || registrationsOut == NULL) {
return CELIX_ILLEGAL_ARGUMENT;
}
celix_autoptr(celix_array_list_t) references = NULL;
service_reference_pt reference = NULL;
char filter[32] = {0};// It is longer than the size of "service.id" + serviceId
snprintf(filter, sizeof(filter), "(%s=%s)", (char *) CELIX_FRAMEWORK_SERVICE_ID, serviceId);
status = bundleContext_getServiceReferences(admin->context, NULL, filter, &references);
if (status != CELIX_SUCCESS) {
celix_logHelper_error(admin->logHelper,"Error getting reference for service id %s.", serviceId);
return status;
}
//We get reference with serviceId, so the size of references must be less than or equal to 1.
if (celix_arrayList_size(references) == 1) {
reference = celix_arrayList_get(references, 0);
}
if (reference == NULL) {
celix_logHelper_error(admin->logHelper, "Expect a exactly one reference for service id %s. Got %i", serviceId, celix_arrayList_size(references));
return CELIX_ILLEGAL_STATE;
}
celix_auto(celix_service_ref_guard_t) ref = celix_ServiceRefGuard_init(admin->context, reference);
celix_autoptr(celix_properties_t) exportedProperties = celix_properties_create();
if (exportedProperties == NULL) {
celix_logHelper_error(admin->logHelper, "Error creating exported properties.");
return CELIX_ENOMEM;
}
unsigned int propertySize = 0;
char **keys = NULL;
serviceReference_getPropertyKeys(reference, &keys, &propertySize);
for (int i = 0; i < propertySize; i++) {
char *key = keys[i];
const char *value = NULL;
if (serviceReference_getProperty(reference, key, &value) == CELIX_SUCCESS) {
celix_properties_set(exportedProperties, key, value);
}
}
free(keys);
//Property in the additional properties overrides the Service Reference properties
if (properties != NULL) {
rsaShm_overlayProperties(properties,exportedProperties);
}
celix_autoptr(celix_array_list_t) registrations = NULL;
if (rsaShm_isConfigTypeMatched(exportedProperties)) {
const char *exportsProp = celix_properties_get(exportedProperties, (char *) CELIX_RSA_SERVICE_EXPORTED_INTERFACES, NULL);
const char *providedProp = celix_properties_get(exportedProperties, (char *) CELIX_FRAMEWORK_SERVICE_NAME, NULL);
if (exportsProp == NULL || providedProp == NULL) {
celix_logHelper_error(admin->logHelper, "Error exporting service %s. Missing property %s or %s.", serviceId, CELIX_RSA_SERVICE_EXPORTED_INTERFACES, CELIX_FRAMEWORK_SERVICE_NAME);
return CELIX_ILLEGAL_STATE;
}
celix_autofree char *exports = celix_utils_trim(exportsProp);
celix_autofree char *provided = celix_utils_trim(providedProp);
if (exports == NULL || provided == NULL) {
celix_logHelper_error(admin->logHelper, "Failed to trim exported interface.");
return CELIX_ENOMEM;
}
celix_logHelper_info(admin->logHelper, "Export services (%s)", exports);
celix_autoptr(celix_array_list_t) interfaces = celix_arrayList_create();
celix_autoptr(celix_array_list_t) proInterfaces = celix_arrayList_create();
registrations = celix_arrayList_create();
// Parse export interfaces for export service.
if (strcmp(exports, "*") == 0) {
char *provided_save_ptr = NULL;
char *interface = strtok_r(provided, ",", &provided_save_ptr);
while (interface != NULL) {
celix_arrayList_add(interfaces, celix_utils_trimInPlace(interface));
interface = strtok_r(NULL, ",", &provided_save_ptr);
}
} else {
char *provided_save_ptr = NULL;
char *pinterface = strtok_r(provided, ",", &provided_save_ptr);
while (pinterface != NULL) {
celix_arrayList_add(proInterfaces, celix_utils_trimInPlace(pinterface));
pinterface = strtok_r(NULL, ",", &provided_save_ptr);
}
char *exports_save_ptr = NULL;
char *einterface = strtok_r(exports, ",", &exports_save_ptr);
while (einterface != NULL) {
einterface = celix_utils_trimInPlace(einterface);
for (int i = 0; i < celix_arrayList_size(proInterfaces); ++i) {
if (strcmp(celix_arrayList_get(proInterfaces, i), einterface) == 0) {
celix_arrayList_add(interfaces, einterface);
break;
}
}
einterface = strtok_r(NULL, ",", &exports_save_ptr);
}
}
// Create export registrations for its interfaces.
size_t interfaceNum = celix_arrayList_size(interfaces);
for (int iter = 0; iter < interfaceNum; iter++) {
char *interface = celix_arrayList_get(interfaces, iter);
celix_autoptr(endpoint_description_t) endpointDescription = NULL;
export_registration_t *registration = NULL;
int ret = CELIX_SUCCESS;
ret = rsaShm_createEndpointDescription(admin,
exportedProperties, interface, &endpointDescription);
if (ret != CELIX_SUCCESS) {
continue;
}
ret = exportRegistration_create(admin->context, admin->logHelper,
reference, endpointDescription, ®istration);
if (ret == CELIX_SUCCESS) {
celix_arrayList_add(registrations, registration);
}
}
}
//We return a empty list of registrations if Remote Service Admin does not recognize any of the configuration types.
celix_array_list_t *newRegistrations = celix_arrayList_create();
int regSize = registrations != NULL ? celix_arrayList_size(registrations) : 0;
if (regSize > 0) {
for (int i = 0; i < regSize; ++i) {
celix_arrayList_add(newRegistrations, celix_arrayList_get(registrations, i));
}
celix_auto(celix_mutex_lock_guard_t) lock = celixMutexLockGuard_init(&admin->exportedServicesLock);
celix_longHashMap_put(admin->exportedServices, atol(serviceId), celix_steal_ptr(registrations));
}
*registrationsOut = newRegistrations;
return CELIX_SUCCESS;
}