Skip to content

Commit

Permalink
break(iot-dev): Rework thrown exceptions, refactor device reconnectio…
Browse files Browse the repository at this point in the history
…n sample (#1502)
  • Loading branch information
timtay-microsoft authored Mar 30, 2022
1 parent 801f3c8 commit 04b0a74
Show file tree
Hide file tree
Showing 245 changed files with 2,023 additions and 2,311 deletions.
120 changes: 61 additions & 59 deletions SDK v2 migration guide.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import java.util.List;

/**
* Used to construct batch messages to be sent to the IoT Hub {@link com.microsoft.azure.sdk.iot.device.InternalClient#sendEventAsync(List, IotHubEventCallback, Object)}
* Used to construct batch messages to be sent to the IoT Hub {@link com.microsoft.azure.sdk.iot.device.InternalClient#sendEventsAsync(List, MessagesSentCallback, Object)}
*/
public class BatchMessage extends Message
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package com.microsoft.azure.sdk.iot.device;

import com.microsoft.azure.sdk.iot.device.transport.ExponentialBackoffWithJitter;
import com.microsoft.azure.sdk.iot.device.transport.NoRetry;
import com.microsoft.azure.sdk.iot.device.twin.Pair;
import com.microsoft.azure.sdk.iot.device.auth.*;
import com.microsoft.azure.sdk.iot.device.transport.RetryPolicy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

package com.microsoft.azure.sdk.iot.device;

import com.microsoft.azure.sdk.iot.device.exceptions.TransportException;
import com.microsoft.azure.sdk.iot.device.exceptions.IotHubClientException;

/**
* This interface has a number of call backs to notify when a message is in a specific part of the {@link com.microsoft.azure.sdk.iot.device.transport.IotHubTransport} lifecycle.
Expand Down Expand Up @@ -36,7 +36,7 @@ public interface CorrelatingMessageCallback
* @param callbackContext The context sent with the message.
* @param e The exception given by the transport. If there are no errors this will be {@code null}.
*/
void onRequestAcknowledged(Message message, Object callbackContext, TransportException e);
void onRequestAcknowledged(Message message, Object callbackContext, IotHubClientException e);

/**
* Called when a response to the sent message has been sent by IoT hub and has been receieved by the transport.
Expand All @@ -45,7 +45,7 @@ public interface CorrelatingMessageCallback
* @param callbackContext The context sent with the message.
* @param e The exception given by the transport. If there are no errors this will be {@code null}.
*/
void onResponseReceived(Message message, Object callbackContext, TransportException e);
void onResponseReceived(Message message, Object callbackContext, IotHubClientException e);

/**
* Called when a response to the message has been sent by IoT hub and has been acknowledged by the transport.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

package com.microsoft.azure.sdk.iot.device;

import com.microsoft.azure.sdk.iot.device.exceptions.IotHubClientException;
import com.microsoft.azure.sdk.iot.device.transport.RetryPolicy;
import com.microsoft.azure.sdk.iot.device.transport.TransportUtils;
import com.microsoft.azure.sdk.iot.device.transport.https.HttpsTransportManager;
import com.microsoft.azure.sdk.iot.provisioning.security.SecurityProvider;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.URISyntaxException;

/**
* <p>
Expand Down Expand Up @@ -154,8 +154,6 @@ public DeviceClient(String uri, String deviceId, SecurityProvider securityProvid
*
* @throws IllegalArgumentException if the callback is {@code null} but a context is
* passed in.
* @throws IllegalStateException if the callback is set after the client is
* closed.
*/
public DeviceClient setMessageCallback(MessageCallback callback, Object context) throws IllegalArgumentException
{
Expand Down Expand Up @@ -184,9 +182,10 @@ private void commonConstructorVerifications() throws UnsupportedOperationExcepti
* it fails. Both the operation timeout set in {@link #setOperationTimeout(long)} and the retry policy set in
* {{@link #setRetryPolicy(RetryPolicy)}} will be respected while retrying to open the connection.
*
* @throws IOException if a connection to an IoT hub cannot be established.
* @throws IotHubClientException if a connection to an IoT hub cannot be established or if the connection can be
* established but the service rejects it for any reason.
*/
public void open(boolean withRetry) throws IOException
public void open(boolean withRetry) throws IotHubClientException
{
if (this.deviceClientType == DeviceClientType.USE_MULTIPLEXING_CLIENT)
{
Expand Down Expand Up @@ -233,9 +232,9 @@ public void close()
* Get a file upload SAS URI which the Azure Storage SDK can use to upload a file to blob for this device. See <a href="https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-file-upload#initialize-a-file-upload">this documentation</a> for more details.
* @param request The request details for getting the SAS URI, including the destination blob name.
* @return The file upload details to be used with the Azure Storage SDK in order to upload a file from this device.
* @throws IOException If this HTTPS request fails to send.
* @throws IotHubClientException If this HTTPS request fails to send or if the service rejects the request for any reason.
*/
public FileUploadSasUriResponse getFileUploadSasUri(FileUploadSasUriRequest request) throws IOException
public FileUploadSasUriResponse getFileUploadSasUri(FileUploadSasUriRequest request) throws IotHubClientException
{
if (this.fileUpload == null)
{
Expand All @@ -248,9 +247,9 @@ public FileUploadSasUriResponse getFileUploadSasUri(FileUploadSasUriRequest requ
/**
* Notify IoT hub that a file upload has been completed, successfully or otherwise. See <a href="https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-file-upload#notify-iot-hub-of-a-completed-file-upload">this documentation</a> for more details.
* @param notification The notification details, including if the file upload succeeded.
* @throws IOException If this HTTPS request fails to send.
* @throws IotHubClientException If this HTTPS request fails to send or if the service rejects the request for any reason.
*/
public void completeFileUpload(FileUploadCompletionNotification notification) throws IOException
public void completeFileUpload(FileUploadCompletionNotification notification) throws IotHubClientException
{
if (this.fileUpload == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@

package com.microsoft.azure.sdk.iot.device;

import com.microsoft.azure.sdk.iot.device.exceptions.DeviceClientException;
import com.microsoft.azure.sdk.iot.device.exceptions.MultiplexingClientException;
import com.microsoft.azure.sdk.iot.device.exceptions.TransportException;
import com.microsoft.azure.sdk.iot.device.exceptions.IotHubClientException;
import com.microsoft.azure.sdk.iot.device.transport.*;
import lombok.extern.slf4j.Slf4j;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
Expand Down Expand Up @@ -90,10 +87,8 @@ final class DeviceIO implements IotHubConnectionStatusChangeCallback
/**
* Starts asynchronously sending and receiving messages from an IoT Hub. If
* the client is already open, the function shall do nothing.
*
* @throws IOException if a connection to an IoT Hub cannot be established.
*/
void open(boolean withRetry) throws IOException
void open(boolean withRetry) throws IotHubClientException
{
synchronized (this.stateLock)
{
Expand All @@ -106,43 +101,19 @@ void open(boolean withRetry) throws IOException
{
this.transport.open(withRetry);
}
catch (DeviceClientException e)
catch (TransportException e)
{
throw new IOException("Could not open the connection", e);
throw e.toIotHubClientException();
}
}
}

// Functionally the same as "open()", but without wrapping any thrown TransportException into an IOException
void openWithoutWrappingException(boolean withRetry) throws TransportException
{
try
{
open(withRetry);
}
catch (IOException e)
{
// We did this silly thing in the DeviceClient to work around the fact that we can't throw TransportExceptions
// directly in methods like deviceClient.open() because the open API existed before the TransportException did.
// To get around it, we just nested the meaningful exception into an IOException. The multiplexing client doesn't
// have to do the same thing though, so this code un-nests the exception when possible.
Throwable cause = e.getCause();
if (cause instanceof TransportException)
{
throw (TransportException) cause;
}

// should never happen. Open only throws IOExceptions with an inner exception of type TransportException
throw new IllegalStateException("Encountered a wrapped IOException with no inner transport exception", e);
}
}

void registerMultiplexedDeviceClient(List<ClientConfiguration> configs, long timeoutMilliseconds) throws InterruptedException, MultiplexingClientException
void registerMultiplexedDeviceClient(List<ClientConfiguration> configs, long timeoutMilliseconds) throws InterruptedException, IotHubClientException
{
this.transport.registerMultiplexedDeviceClient(configs, timeoutMilliseconds);
}

void unregisterMultiplexedDeviceClient(List<ClientConfiguration> configs, long timeoutMilliseconds) throws InterruptedException, MultiplexingClientException
void unregisterMultiplexedDeviceClient(List<ClientConfiguration> configs, long timeoutMilliseconds) throws InterruptedException, IotHubClientException
{
this.transport.unregisterMultiplexedDeviceClient(configs, timeoutMilliseconds);
}
Expand Down Expand Up @@ -253,7 +224,7 @@ void close()
* @throws IllegalStateException if the client has not been opened yet or is already closed.
*/
void sendEventAsync(Message message,
IotHubEventCallback callback,
MessageSentCallback callback,
Object callbackContext,
String deviceId)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

package com.microsoft.azure.sdk.iot.device;

import com.microsoft.azure.sdk.iot.device.exceptions.IotHubServiceException;
import com.microsoft.azure.sdk.iot.device.exceptions.IotHubClientException;
import com.microsoft.azure.sdk.iot.device.transport.IotHubTransportMessage;
import com.microsoft.azure.sdk.iot.device.transport.https.HttpsMethod;
import com.microsoft.azure.sdk.iot.device.transport.https.HttpsResponse;
Expand All @@ -27,50 +27,59 @@ final class FileUpload
httpsTransportManager.open();
}

FileUploadSasUriResponse getFileUploadSasUri(FileUploadSasUriRequest request) throws IOException
FileUploadSasUriResponse getFileUploadSasUri(FileUploadSasUriRequest request) throws IotHubClientException
{
IotHubTransportMessage message = new IotHubTransportMessage(request.toJson());
message.setIotHubMethod(HttpsMethod.POST);

HttpsResponse responseMessage = httpsTransportManager.getFileUploadSasUri(message);
try
{
HttpsResponse responseMessage = httpsTransportManager.getFileUploadSasUri(message);
String responseMessagePayload = validateServiceStatusCode(responseMessage);

String responseMessagePayload = validateServiceStatusCode(responseMessage, "Failed to get the file upload SAS URI");
if (responseMessagePayload == null || responseMessagePayload.isEmpty())
{
throw new IotHubClientException(IotHubStatusCode.ERROR, "SAS URI response message had no payload");
}

if (responseMessagePayload == null || responseMessagePayload.isEmpty())
return new FileUploadSasUriResponse(responseMessagePayload);
}
catch (IOException e)
{
throw new IOException("Sas URI response message had no payload");
throw new IotHubClientException(IotHubStatusCode.IO_ERROR, "Failed to get file upload SAS URI", e);
}

return new FileUploadSasUriResponse(responseMessagePayload);
}

void sendNotification(FileUploadCompletionNotification fileUploadStatusParser) throws IOException
void sendNotification(FileUploadCompletionNotification fileUploadStatusParser) throws IotHubClientException
{
IotHubTransportMessage message = new IotHubTransportMessage(fileUploadStatusParser.toJson());
message.setIotHubMethod(HttpsMethod.POST);

HttpsResponse responseMessage = httpsTransportManager.sendFileUploadNotification(message);

validateServiceStatusCode(responseMessage, "Failed to complete the file upload notification");
try
{
HttpsResponse responseMessage = httpsTransportManager.sendFileUploadNotification(message);
validateServiceStatusCode(responseMessage);
}
catch (IOException e)
{
throw new IotHubClientException(IotHubStatusCode.IO_ERROR, "Failed to send file upload completion notification", e);
}
}

private String validateServiceStatusCode(HttpsResponse responseMessage, String errorMessage) throws IOException
private String validateServiceStatusCode(HttpsResponse responseMessage) throws IotHubClientException
{
String responseMessagePayload = null;
if (responseMessage.getBody() != null && responseMessage.getBody().length > 0)
{
responseMessagePayload = new String(responseMessage.getBody(), DEFAULT_IOTHUB_MESSAGE_CHARSET);
}

IotHubServiceException serviceException =
IotHubStatusCode.getConnectionStatusException(
IotHubStatusCode.getIotHubStatusCode(responseMessage.getStatus()),
responseMessagePayload);
IotHubStatusCode statusCode = IotHubStatusCode.getIotHubStatusCode(responseMessage.getStatus());

// serviceException is only not null if the provided status code was a non-successful status code like 400, 429, 500, etc.
if (serviceException != null)
if (!IotHubStatusCode.isSuccessful(statusCode))
{
throw new IOException(errorMessage, serviceException);
throw new IotHubClientException(statusCode, responseMessagePayload);
}

return responseMessagePayload;
Expand Down
Loading

0 comments on commit 04b0a74

Please sign in to comment.