celix_status_t rsaShm_exportService()

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, &registration);
            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;
}