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

com.microsoft.azure.sdk.iot.service.twin.TwinClient 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.twin;

import com.azure.core.credential.AzureSasCredential;
import com.azure.core.credential.TokenCredential;
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.query.QueryClient;
import com.microsoft.azure.sdk.iot.service.query.QueryClientOptions;
import com.microsoft.azure.sdk.iot.service.query.QueryPageOptions;
import com.microsoft.azure.sdk.iot.service.query.TwinQueryResponse;
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 lombok.extern.slf4j.Slf4j;

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

import static com.microsoft.azure.sdk.iot.service.transport.http.HttpRequest.IF_MATCH;
import static com.microsoft.azure.sdk.iot.service.transport.http.HttpRequest.REQUEST_ID;

/**
 * Use the TwinClient class to manage the device twins in IoT hubs.
 */
@Slf4j
public final class TwinClient
{
    private int requestId = 0;

    private final TwinClientOptions options;
    private final String hostName;
    private TokenCredentialCache credentialCache;
    private AzureSasCredential azureSasCredential;
    private IotHubConnectionString iotHubConnectionString;

    // keep a queryClient within this client so that twins can be queried
    private final QueryClient queryClient;

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

    /**
     * Constructor to create instance from connection string.
     *
     * @param connectionString The iot hub connection string.
     * @param options the configurable options for each operation on this client. May not be null.
     */
    public TwinClient(String connectionString, TwinClientOptions options)
    {
        if (connectionString == null || connectionString.isEmpty())
        {
            throw new IllegalArgumentException("connectionString cannot be null or empty.");
        }

        this.options = options;
        this.iotHubConnectionString = IotHubConnectionStringBuilder.createIotHubConnectionString(connectionString);
        this.hostName = this.iotHubConnectionString.getHostName();
        commonConstructorSetup();

        QueryClientOptions queryClientOptions =
            QueryClientOptions.builder()
                .httpReadTimeoutSeconds(options.getHttpReadTimeoutSeconds())
                .httpConnectTimeoutSeconds(options.getHttpConnectTimeoutSeconds())
                .proxyOptions(options.getProxyOptions())
                .build();

        this.queryClient = new QueryClient(connectionString, queryClientOptions);
    }

    /**
     * Create a new TwinClient 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 TwinClient(String hostName, TokenCredential credential)
    {
        this(hostName, credential, TwinClientOptions.builder().build());
    }

    /**
     * Create a new TwinClient 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 TwinClient(String hostName, TokenCredential credential, TwinClientOptions options)
    {
        Objects.requireNonNull(credential, "TokenCredential 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();

        QueryClientOptions queryClientOptions =
            QueryClientOptions.builder()
                .httpReadTimeoutSeconds(options.getHttpReadTimeoutSeconds())
                .httpConnectTimeoutSeconds(options.getHttpConnectTimeoutSeconds())
                .proxyOptions(options.getProxyOptions())
                .build();

        this.queryClient = new QueryClient(hostName, credential, queryClientOptions);
    }

    /**
     * Create a new TwinClient 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 TwinClient(String hostName, AzureSasCredential azureSasCredential)
    {
        this(hostName, azureSasCredential, TwinClientOptions.builder().build());
    }

    /**
     * Create a new TwinClient 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 TwinClient(String hostName, AzureSasCredential azureSasCredential, TwinClientOptions 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();

        QueryClientOptions queryClientOptions =
            QueryClientOptions.builder()
                .httpReadTimeoutSeconds(options.getHttpReadTimeoutSeconds())
                .httpConnectTimeoutSeconds(options.getHttpConnectTimeoutSeconds())
                .proxyOptions(options.getProxyOptions())
                .build();

        this.queryClient = new QueryClient(hostName, azureSasCredential, queryClientOptions);
    }

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

    /**
     * This method retrieves device twin for the specified device.
     *
     * @param deviceId The id of the device whose twin will be retrieved.
     * @throws IOException This exception is thrown if the IO operation failed.
     * @throws IotHubException This exception is thrown if the response verification failed.
     * @return The retrieved twin object for the specified device.
     */
    public Twin get(String deviceId) throws IotHubException, IOException
    {
        if (deviceId == null || deviceId.isEmpty())
        {
            throw new IllegalArgumentException("DeviceId must not be null or empty");
        }

        return get(IotHubConnectionString.getUrlTwin(this.hostName, deviceId));
    }

    /**
     * This method retrieves device twin for the specified device.
     *
     * @param deviceId The id of the device whose twin will be retrieved.
     * @param moduleId The id of the module on the device whose twin will be retrieved.
     * @throws IOException This exception is thrown if the IO operation failed.
     * @throws IotHubException This exception is thrown if the response verification failed.
     * @return The retrieved twin object for the specified module on the specified device.
     */
    public Twin get(String deviceId, String moduleId) throws IotHubException, IOException
    {
        if (deviceId == null || deviceId.isEmpty())
        {
            throw new IllegalArgumentException("DeviceId must not be null or empty");
        }

        return get(IotHubConnectionString.getUrlModuleTwin(this.hostName, deviceId, moduleId));
    }

    private Twin get(URL url) throws IotHubException, IOException
    {
        HttpRequest httpRequest = createRequest(url, HttpMethod.GET, new byte[0]);
        HttpResponse response = httpRequest.send();
        String twinString = new String(response.getBody(), StandardCharsets.UTF_8);
        return Twin.fromJson(twinString);
    }

    /**
     * This method patches the twin for the specified device.
     * 

See PATCH for * more details.

* * @param twin The twin to be patched. To delete a particular property, set the value to null. * @throws IOException This exception is thrown if the IO operation failed. * @throws IotHubException This exception is thrown if the response verification failed. */ public Twin patch(Twin twin) throws IotHubException, IOException { return patch(twin, null); } /** * This method patches the twin for the specified device. *

See PATCH for * more details.

* * @param twin The twin to be patched. To delete a particular property, set the value to null. * @param ifMatch the string representing a ETag for the device twin, as per RFC7232. If null, no if-match header * will be sent as a part of this request and it will be executed unconditionally. * @throws IOException This exception is thrown if the IO operation failed. * @throws IotHubException This exception is thrown if the response verification failed. */ public Twin patch(Twin twin, String ifMatch) throws IotHubException, IOException { if (twin == null || twin.getDeviceId() == null || twin.getDeviceId().length() == 0) { throw new IllegalArgumentException("Instantiate a twin and set device Id to be used."); } if ((twin.getDesiredProperties() == null || twin.getDesiredProperties().isEmpty()) && (twin.getTags() == null || twin.getTags().isEmpty())) { throw new IllegalArgumentException("Set either desired properties or tags for the device to be updated."); } URL url; if ((twin.getModuleId() == null) || twin.getModuleId().length() == 0) { url = IotHubConnectionString.getUrlTwin(this.hostName, twin.getDeviceId()); } else { url = IotHubConnectionString.getUrlModuleTwin(this.hostName, twin.getDeviceId(), twin.getModuleId()); } TwinState twinState = new TwinState(twin.getTags(), twin.getDesiredProperties(), null); String twinJson = twinState.toJsonElement().toString(); HttpRequest httpRequest = createRequest(url, HttpMethod.PATCH, twinJson.getBytes(StandardCharsets.UTF_8)); if (ifMatch != null) { httpRequest.setHeaderField(IF_MATCH, ifMatch); } // no need to return http response since method returns void HttpResponse httpResponse = httpRequest.send(); String twinString = new String(httpResponse.getBody(), StandardCharsets.UTF_8); return Twin.fromJson(twinString); } /** * Replace the full twin for a given device or module with the provided twin. * * @param twin The twin object to replace the current twin object. * @throws IotHubException If any an IoT hub level exception is thrown. For instance, * if the sendHttpRequest is unauthorized, a exception that extends IotHubException will be thrown. * @throws IOException If the sendHttpRequest failed to send to IoT hub. * @return The Twin object's current state returned from the service after the replace operation. */ public Twin replace(Twin twin) throws IotHubException, IOException { return replace(twin, null); } /** * Replace the full twin for a given device or module with the provided twin. * * @param twin The twin object to replace the current twin object. * @param ifMatch the string representing a ETag for the device twin, as per RFC7232. If null, no if-match header * will be sent as a part of this request and it will be executed unconditionally. * @throws IotHubException If any an IoT hub level exception is thrown. For instance, * if the sendHttpRequest is unauthorized, an exception that extends IotHubException will be thrown. * @throws IOException If the sendHttpRequest failed to send to IoT hub. * @return The Twin object's current state returned from the service after the replace operation. */ public Twin replace(Twin twin, String ifMatch) throws IotHubException, IOException { if (twin == null || twin.getDeviceId() == null || twin.getDeviceId().length() == 0) { throw new IllegalArgumentException("Instantiate a device and set device Id to be used."); } URL url; if (twin.getModuleId() == null || twin.getModuleId().length() == 0) { url = IotHubConnectionString.getUrlTwin(this.hostName, twin.getDeviceId()); } else { url = IotHubConnectionString.getUrlModuleTwin(this.hostName, twin.getDeviceId(), twin.getModuleId()); } TwinState twinState = new TwinState(twin.getTags(), twin.getDesiredProperties(), null); String twinJson = twinState.toJsonElement().toString(); HttpRequest httpRequest = createRequest(url, HttpMethod.PUT, twinJson.getBytes(StandardCharsets.UTF_8)); if (ifMatch != null) { httpRequest.setHeaderField(IF_MATCH, ifMatch); } HttpResponse httpResponse = httpRequest.send(); String twinString = new String(httpResponse.getBody(), StandardCharsets.UTF_8); return Twin.fromJson(twinString); } /** * Query from your IoT Hub's set of Twins. * * @param query The IoT Hub query for selecting which twins to getJob. * @return The pageable set of Twins that were queried. * @throws IOException If IoT Hub cannot be reached due to network level issues. * @throws IotHubException If the request fails for non-network level issues such as an incorrectly formatted query. * @see IoT Hub query language */ public TwinQueryResponse query(String query) throws IOException, IotHubException { return this.queryClient.queryTwins(query); } /** * Query from your IoT Hub's set of Twins. * * @param query The IoT Hub query for selecting which twins to getJob. * @param options The optional parameters used to decide how the query's results are returned. May not be null. * @return The pageable set of Twins that were queried. * @throws IOException If IoT Hub cannot be reached due to network level issues. * @throws IotHubException If the request fails for non-network level issues such as an incorrectly formatted query. * @see IoT Hub query language */ public TwinQueryResponse query(String query, QueryPageOptions options) throws IOException, IotHubException { return this.queryClient.queryTwins(query, options); } 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()); request.setHeaderField(REQUEST_ID, String.valueOf(requestId++)); 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