All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.azure.sdk.iot.service.registry.RegistryClient Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) Microsoft. All rights reserved.
 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
 */

package com.microsoft.azure.sdk.iot.service.registry;

import com.azure.core.credential.AzureSasCredential;
import com.azure.core.credential.TokenCredential;
import com.google.gson.Gson;
import com.microsoft.azure.sdk.iot.service.auth.IotHubConnectionString;
import com.microsoft.azure.sdk.iot.service.auth.IotHubConnectionStringBuilder;
import com.microsoft.azure.sdk.iot.service.auth.IotHubServiceSasToken;
import com.microsoft.azure.sdk.iot.service.auth.TokenCredentialCache;
import com.microsoft.azure.sdk.iot.service.exceptions.IotHubException;
import com.microsoft.azure.sdk.iot.service.exceptions.IotHubExceptionManager;
import com.microsoft.azure.sdk.iot.service.registry.serializers.JobPropertiesParser;
import com.microsoft.azure.sdk.iot.service.registry.serializers.RegistryIdentityParser;
import com.microsoft.azure.sdk.iot.service.registry.serializers.RegistryStatisticsParser;
import com.microsoft.azure.sdk.iot.service.transport.TransportUtils;
import com.microsoft.azure.sdk.iot.service.transport.http.HttpMethod;
import com.microsoft.azure.sdk.iot.service.transport.http.HttpRequest;
import com.microsoft.azure.sdk.iot.service.transport.http.HttpResponse;
import com.microsoft.azure.sdk.iot.service.twin.TwinClient;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.Proxy;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Use the RegistryClient to manage the identity registry in IoT hubs.
 * To access twins, use the {@link TwinClient}.
 */
@Slf4j
public final class RegistryClient
{
    private final String hostName;
    private TokenCredentialCache credentialCache;
    private AzureSasCredential azureSasCredential;
    private IotHubConnectionString iotHubConnectionString;

    private final RegistryClientOptions options;

    /**
     * Constructor to create instance from connection string
     *
     * @param connectionString The iot hub connection string
     */
    public RegistryClient(String connectionString)
    {
        this(connectionString, RegistryClientOptions.builder().build());
    }

    /**
     * Constructor to create instance from connection string
     *
     * @param connectionString The iot hub connection string
     * @param options The connection options to use when connecting to the service.
     */
    public RegistryClient(String connectionString, RegistryClientOptions options)
    {
        if (connectionString == null || connectionString.isEmpty())
        {
            throw new IllegalArgumentException("The provided connection string cannot be null or empty");
        }

        if (options == null)
        {
            throw new IllegalArgumentException("RegistryClientOptions cannot be null for this constructor");
        }

        this.iotHubConnectionString =
                IotHubConnectionStringBuilder.createIotHubConnectionString(connectionString);

        this.hostName = iotHubConnectionString.getHostName();
        this.options = options;
        commonConstructorSetup();
    }

    /**
     * Create a new RegistryClient instance.
     *
     * @param hostName The hostname of your IoT Hub instance (For instance, "your-iot-hub.azure-devices.net")
     * @param credential The custom {@link TokenCredential} that will provide authentication tokens to
     *                                    this library when they are needed. The provided tokens must be Json Web Tokens.
     */
    public RegistryClient(String hostName, TokenCredential credential)
    {
        this(hostName, credential, RegistryClientOptions.builder().build());
    }

    /**
     * Create a new RegistryClient instance.
     *
     * @param hostName The hostname of your IoT Hub instance (For instance, "your-iot-hub.azure-devices.net")
     * @param credential The custom {@link TokenCredential} that will provide authentication tokens to
     *                                    this library when they are needed. The provided tokens must be Json Web Tokens.
     * @param options The connection options to use when connecting to the service.
     */
    public RegistryClient(String hostName, TokenCredential credential, RegistryClientOptions options)
    {
        Objects.requireNonNull(credential, "credential cannot be null");
        Objects.requireNonNull(options, "options cannot be null");
        if (hostName == null || hostName.isEmpty())
        {
            throw new IllegalArgumentException("hostName cannot be null or empty");
        }

        this.options = options;
        this.credentialCache = new TokenCredentialCache(credential);
        this.hostName = hostName;
        commonConstructorSetup();
    }

    /**
     * Create a new RegistryClient instance.
     *
     * @param hostName The hostname of your IoT Hub instance (For instance, "your-iot-hub.azure-devices.net")
     * @param azureSasCredential The SAS token provider that will be used for authentication.
     */
    public RegistryClient(String hostName, AzureSasCredential azureSasCredential)
    {
        this(hostName, azureSasCredential, RegistryClientOptions.builder().build());
    }

    /**
     * Create a new RegistryClient instance.
     *
     * @param hostName The hostname of your IoT Hub instance (For instance, "your-iot-hub.azure-devices.net")
     * @param azureSasCredential The SAS token provider that will be used for authentication.
     * @param options The connection options to use when connecting to the service.
     */
    public RegistryClient(String hostName, AzureSasCredential azureSasCredential, RegistryClientOptions options)
    {
        Objects.requireNonNull(azureSasCredential, "azureSasCredential cannot be null");
        Objects.requireNonNull(options, "options cannot be null");
        if (hostName == null || hostName.isEmpty())
        {
            throw new IllegalArgumentException("hostName cannot be null or empty");
        }

        this.options = options;
        this.azureSasCredential = azureSasCredential;
        this.hostName = hostName;
        commonConstructorSetup();
    }

    private static void commonConstructorSetup()
    {
        log.debug("Initialized a RegistryClient instance client using SDK version {}", TransportUtils.serviceVersion);
    }

    /**
     * Add device using the given Device object
     * Return with the response device object from IotHub
     *
     * @param device The device object to add
     * @return The future object for the requested operation
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    public Device addDevice(Device device) throws IOException, IotHubException
    {
        if (device == null)
        {
            throw new IllegalArgumentException("device cannot be null");
        }

        String deviceJson = device.toRegistryIdentityParser().toJson();

        URL url = IotHubConnectionString.getUrlDevice(this.hostName, device.getDeviceId());
        HttpRequest request = createRequest(url, HttpMethod.PUT, deviceJson.getBytes(StandardCharsets.UTF_8));

        HttpResponse response = request.send();

        IotHubExceptionManager.httpResponseVerification(response);

        String bodyStr = new String(response.getBody(), StandardCharsets.UTF_8);

        return new Device(new RegistryIdentityParser(bodyStr));
    }

    /**
     * Get device data by device Id from IotHub
     *
     * @param deviceId The id of requested device
     * @return The device object of requested device
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    public Device getDevice(String deviceId) throws IOException, IotHubException
    {
        if (deviceId == null || deviceId.isEmpty())
        {
            throw new IllegalArgumentException("deviceId cannot be null or empty");
        }

        URL url = IotHubConnectionString.getUrlDevice(this.hostName, deviceId);

        HttpRequest request = createRequest(url, HttpMethod.GET, new byte[0]);

        HttpResponse response = request.send();

        IotHubExceptionManager.httpResponseVerification(response);

        String bodyStr = new String(response.getBody(), StandardCharsets.UTF_8);

        return new Device(new RegistryIdentityParser(bodyStr));
    }

    /**
     * Update device not forced
     *
     * @param device The device object containing updated data
     * @return The updated device object
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    public Device updateDevice(Device device) throws IOException, IotHubException
    {
        if (device == null)
        {
            throw new IllegalArgumentException("device cannot be null");
        }

        URL url = IotHubConnectionString.getUrlDevice(this.hostName, device.getDeviceId());
        HttpRequest request = createRequest(url, HttpMethod.PUT, device.toRegistryIdentityParser().toJson().getBytes(StandardCharsets.UTF_8));

        request.setHeaderField("If-Match", "*");

        HttpResponse response = request.send();

        IotHubExceptionManager.httpResponseVerification(response);

        String bodyStr = new String(response.getBody(), StandardCharsets.UTF_8);

        return new Device(new RegistryIdentityParser(bodyStr));
    }

    /**
     * Remove device
     *
     * @param deviceId The device name to remove
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    public void removeDevice(String deviceId) throws IOException, IotHubException
    {
        removeDeviceOperation(deviceId, "*");
    }

    /**
     * Remove device
     *
     * @param device The device name to remove
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    public void removeDevice(Device device) throws IOException, IotHubException
    {
        if (device == null)
        {
            throw new IllegalArgumentException("device cannot be null or empty");
        }

        removeDeviceOperation(device.getDeviceId(), device.getETag());
    }

    /**
     * send remove device request and verify response
     *
     * @param deviceId The device name to remove
     * @param etag The etag associated with the device to remove
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    private void removeDeviceOperation(String deviceId, String etag) throws IOException, IotHubException
    {
        if (deviceId == null || deviceId.isEmpty())
        {
            throw new IllegalArgumentException("deviceId cannot be null or empty");
        }

        if (etag == null || etag.isEmpty())
        {
            throw new IllegalArgumentException("etag cannot be null or empty");
        }

        URL url = IotHubConnectionString.getUrlDevice(this.hostName, deviceId);

        HttpRequest request = createRequest(url, HttpMethod.DELETE, new byte[0]);
        request.setHeaderField("If-Match", etag);

        HttpResponse response = request.send();

        IotHubExceptionManager.httpResponseVerification(response);
    }

    /**
     * Get device statistics
     *
     * @return RegistryStatistics object containing the requested data
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    public RegistryStatistics getStatistics() throws IOException, IotHubException
    {
        URL url = IotHubConnectionString.getUrlDeviceStatistics(this.hostName);

        HttpRequest request = createRequest(url, HttpMethod.GET, new byte[0]);

        HttpResponse response = request.send();

        IotHubExceptionManager.httpResponseVerification(response);

        String bodyStr = new String(response.getBody(), StandardCharsets.UTF_8);
        return new RegistryStatistics(new RegistryStatisticsParser(bodyStr));
    }

    /**
     * Add module using the given Module object
     * Return with the response module object from IotHub
     *
     * @param module The module object to add
     * @return The module object for the requested operation
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    public Module addModule(Module module) throws IOException, IotHubException
    {
        if (module == null)
        {
            throw new IllegalArgumentException("module cannot be null");
        }

        String moduleJson = module.toRegistryIdentityParser().toJson();

        URL url = IotHubConnectionString.getUrlModule(this.hostName, module.getDeviceId(), module.getId());

        HttpRequest request = createRequest(url, HttpMethod.PUT, moduleJson.getBytes(StandardCharsets.UTF_8));

        HttpResponse response = request.send();

        IotHubExceptionManager.httpResponseVerification(response);

        String bodyStr = new String(response.getBody(), StandardCharsets.UTF_8);

        return new Module(new RegistryIdentityParser(bodyStr));
    }

    /**
     * Get module data by device Id and module Id from IotHub
     *
     * @param deviceId The id of requested device
     * @param moduleId The id of requested module
     * @return The module object of requested module on the specific device
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    public Module getModule(String deviceId, String moduleId) throws IOException, IotHubException
    {
        if (deviceId == null || deviceId.isEmpty())
        {
            throw new IllegalArgumentException("deviceId cannot be null or empty");
        }

        if (moduleId == null || moduleId.isEmpty())
        {
            throw new IllegalArgumentException("moduleId cannot be null or empty");
        }

        URL url = IotHubConnectionString.getUrlModule(this.hostName, deviceId, moduleId);

        HttpRequest request = createRequest(url, HttpMethod.GET, new byte[0]);

        HttpResponse response = request.send();

        IotHubExceptionManager.httpResponseVerification(response);

        String bodyStr = new String(response.getBody(), StandardCharsets.UTF_8);

        return new Module(new RegistryIdentityParser(bodyStr));
    }

    /**
     * Get modules data by device Id from IotHub
     *
     * @param deviceId The id of requested device
     * @return The module objects on the specific device
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    public List getModulesOnDevice(String deviceId) throws IOException, IotHubException
    {
        if (deviceId == null || deviceId.isEmpty())
        {
            throw new IllegalArgumentException("deviceId cannot be null or empty");
        }

        URL url = IotHubConnectionString.getUrlModulesOnDevice(this.hostName, deviceId);

        HttpRequest request = createRequest(url, HttpMethod.GET, new byte[0]);

        HttpResponse response = request.send();

        IotHubExceptionManager.httpResponseVerification(response);

        String bodyStr = new String(response.getBody(), StandardCharsets.UTF_8);

        Gson gson = new Gson();
        RegistryIdentityParser[] registryIdentityParsers = gson.fromJson(bodyStr, RegistryIdentityParser[].class);

        List moduleList = new ArrayList<>();
        for (int i = 0; i < registryIdentityParsers.length; i++)
        {
            moduleList.add(new Module(registryIdentityParsers[i]));
        }

        return moduleList;
    }

    /**
     * Update module not forced
     *
     * @param module The module object containing updated data
     * @return The updated module object
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    public Module updateModule(Module module) throws IOException, IotHubException
    {
        if (module == null)
        {
            throw new IllegalArgumentException("module cannot be null");
        }

        URL url = IotHubConnectionString.getUrlModule(this.hostName, module.getDeviceId(), module.getId());

        HttpRequest request = createRequest(url, HttpMethod.PUT, module.toRegistryIdentityParser().toJson().getBytes(StandardCharsets.UTF_8));
        request.setHeaderField("If-Match", "*");

        HttpResponse response = request.send();

        IotHubExceptionManager.httpResponseVerification(response);

        String bodyStr = new String(response.getBody(), StandardCharsets.UTF_8);

        return new Module(new RegistryIdentityParser(bodyStr));
    }

    /**
     * Remove module
     *
     * @param deviceId The device name associated with the module to be removed
     * @param moduleId The module name to be removed
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    public void removeModule(String deviceId, String moduleId) throws IOException, IotHubException
    {
        removeModuleOperation(deviceId, moduleId, "*");
    }

    /**
     * Remove module
     *
     * @param module The module to be removed
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    public void removeModule(Module module) throws IOException, IotHubException
    {
        if (module == null)
        {
            throw new IllegalArgumentException("module cannot be null or empty");
        }

        removeModuleOperation(module.getDeviceId(), module.getId(), module.getETag());
    }

    /**
     * Send remove module request and verify response
     *
     * @param deviceId The device name associated with the module to be removed
     * @param moduleId The module name to be removed
     * @param etag The etag of the module to be removed, "*" as wildcard.
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    private void removeModuleOperation(String deviceId, String moduleId, String etag)
            throws IOException, IotHubException
    {
        if (deviceId == null || deviceId.isEmpty())
        {
            throw new IllegalArgumentException("deviceId cannot be null or empty");
        }

        if (moduleId == null || moduleId.isEmpty())
        {
            throw new IllegalArgumentException("moduleId cannot be null or empty");
        }

        if (etag == null || etag.isEmpty())
        {
            throw new IllegalArgumentException("etag cannot be null or empty");
        }

        URL url = IotHubConnectionString.getUrlModule(this.hostName, deviceId, moduleId);

        HttpRequest request = createRequest(url, HttpMethod.DELETE, new byte[0]);
        request.setHeaderField("If-Match", etag);

        HttpResponse response = request.send();

        IotHubExceptionManager.httpResponseVerification(response);
    }

    /**
     * Create a bulk export job.
     *
     * @param exportBlobContainerUri URI containing SAS token to a blob container where export data will be placed
     * @param excludeKeys Whether the devices keys should be excluded from the exported data or not
     *
     * @return A RegistryJob object for the newly created bulk export job
     *
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    public RegistryJob exportDevices(String exportBlobContainerUri, boolean excludeKeys) throws IOException, IotHubException
    {
        if (exportBlobContainerUri == null)
        {
            throw new IllegalArgumentException("Export blob uri cannot be null");
        }

        URL url = IotHubConnectionString.getUrlCreateExportImportJob(this.hostName);

        String jobPropertiesJson = createExportJobPropertiesJson(exportBlobContainerUri, excludeKeys);
        HttpRequest request = createRequest(url, HttpMethod.POST, jobPropertiesJson.getBytes(StandardCharsets.UTF_8));

        HttpResponse response = request.send();

        return processJobResponse(response);
    }

    /**
     * Create a bulk export job.
     *
     * @param exportDevicesParameters A RegistryJob object containing input parameters for export Devices job
     *                                This API also supports identity based storage authentication, identity authentication
     *                                support is currently available in limited regions. If a user wishes to try it out,
     *                                they will need to set an Environment Variable of "EnabledStorageIdentity" and set it to "1"
     *                                otherwise default key based authentication is used for storage
     *                                 More details here 
     *
     * @return A RegistryJob object for the newly created bulk export job
     *
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    public RegistryJob exportDevices(RegistryJob exportDevicesParameters) throws IOException, IotHubException
    {
        URL url = IotHubConnectionString.getUrlCreateExportImportJob(this.hostName);

        exportDevicesParameters.setType(RegistryJob.JobType.EXPORT);
        String jobPropertiesJson = exportDevicesParameters.toJobPropertiesParser().toJson();
        HttpRequest request = createRequest(url, HttpMethod.POST, jobPropertiesJson.getBytes(StandardCharsets.UTF_8));

        HttpResponse response = request.send();

        return processJobResponse(response);
    }

    /**
     * Create a bulk import job.
     *
     * @param importBlobContainerUri URI containing SAS token to a blob container that contains registry data to sync
     * @param outputBlobContainerUri URI containing SAS token to a blob container where the result of the bulk import operation will be placed
     *
     * @return A RegistryJob object for the newly created bulk import job
     *
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    public RegistryJob importDevices(String importBlobContainerUri, String outputBlobContainerUri) throws IOException, IotHubException
    {
        if (importBlobContainerUri == null || outputBlobContainerUri == null)
        {
            throw new IllegalArgumentException("Import blob uri or output blob uri cannot be null");
        }

        URL url = IotHubConnectionString.getUrlCreateExportImportJob(this.hostName);

        String jobPropertiesJson = createImportJobPropertiesJson(importBlobContainerUri, outputBlobContainerUri);
        HttpRequest request = createRequest(url, HttpMethod.POST, jobPropertiesJson.getBytes(StandardCharsets.UTF_8));

        HttpResponse response = request.send();

        return processJobResponse(response);
    }

    /**
     * Create a bulk import job.
     *
     * @param importDevicesParameters A RegistryJob object containing input parameters for import Devices job
     *                                This API also supports identity based storage authentication, identity authentication
     *                                support is currently available in limited regions. If a user wishes to try it out,
     *                                they will need to set an Environment Variable of "EnabledStorageIdentity" and set it to "1"
     *                                otherwise default key based authentication is used for storage
     *                                 More details here 
     *
     * @return A RegistryJob object for the newly created bulk import job
     *
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    public RegistryJob importDevices(RegistryJob importDevicesParameters) throws IOException, IotHubException
    {
        URL url = IotHubConnectionString.getUrlCreateExportImportJob(this.hostName);

        importDevicesParameters.setType(RegistryJob.JobType.IMPORT);
        String jobPropertiesJson = importDevicesParameters.toJobPropertiesParser().toJson();
        HttpRequest request = createRequest(url, HttpMethod.POST, jobPropertiesJson.getBytes(StandardCharsets.UTF_8));

        HttpResponse response = request.send();

        return processJobResponse(response);
    }

    /**
     * Get the properties of an existing job.
     *
     * @param jobId The id of the import/export job to be retrieved.
     *
     * @return A RegistryJob object for the requested job id
     *
     * @throws IOException This exception is thrown if the IO operation failed
     * @throws IotHubException This exception is thrown if the response verification failed
     */
    public RegistryJob getJob(String jobId) throws IOException, IotHubException
    {
        if (jobId == null)
        {
            throw new IllegalArgumentException("importExportJobId cannot be null");
        }

        URL url = IotHubConnectionString.getUrlImportExportJob(this.hostName, jobId);

        HttpRequest request = createRequest(url, HttpMethod.GET, new byte[0]);

        HttpResponse response = request.send();

        return processJobResponse(response);
    }

    private RegistryJob processJobResponse(HttpResponse response) throws IotHubException
    {
        String bodyStr = new String(response.getBody(), StandardCharsets.UTF_8);
        return new RegistryJob(new JobPropertiesParser(bodyStr));
    }

    private String createExportJobPropertiesJson(String exportBlobContainerUri, boolean excludeKeysInExport)
    {
        RegistryJob jobProperties = new RegistryJob();
        jobProperties.setType(RegistryJob.JobType.EXPORT);
        jobProperties.setOutputBlobContainerUri(exportBlobContainerUri);
        jobProperties.setExcludeKeysInExport(excludeKeysInExport);
        return jobProperties.toJobPropertiesParser().toJson();
    }

    private String createImportJobPropertiesJson(String importBlobContainerUri, String outputBlobContainerUri)
    {
        RegistryJob jobProperties = new RegistryJob();
        jobProperties.setType(RegistryJob.JobType.IMPORT);
        jobProperties.setInputBlobContainerUri(importBlobContainerUri);
        jobProperties.setOutputBlobContainerUri(outputBlobContainerUri);
        return jobProperties.toJobPropertiesParser().toJson();
    }

    private HttpRequest createRequest(URL url, HttpMethod method, byte[] payload) throws IOException
    {
        Proxy proxy = null;
        if (this.options.getProxyOptions() != null)
        {
            proxy = this.options.getProxyOptions().getProxy();
        }

        HttpRequest request = new HttpRequest(url, method, payload, getAuthenticationToken(), proxy);
        request.setReadTimeoutSeconds(options.getHttpReadTimeoutSeconds());
        request.setConnectTimeoutSeconds(options.getHttpConnectTimeoutSeconds());
        return request;
    }

    private String getAuthenticationToken()
    {
        // Three different constructor types for this class, and each type provides either a TokenCredential implementation,
        // an AzureSasCredential instance, or just the connection string. The sas token can be retrieved from the non-null
        // one of the three options.
        if (this.credentialCache != null)
        {
            return this.credentialCache.getTokenString();
        }
        else if (this.azureSasCredential != null)
        {
            return this.azureSasCredential.getSignature();
        }

        return new IotHubServiceSasToken(iotHubConnectionString).toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy