Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

break(iot-dev): Rework thrown exceptions, add new device reconnection sample #1502

Merged
merged 26 commits into from
Mar 30, 2022
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
008fb2a
So far. Needs thorough javadocs
timtay-microsoft Mar 28, 2022
c97a458
fixup
timtay-microsoft Mar 28, 2022
0722fb2
fixup
timtay-microsoft Mar 28, 2022
d6ceb2e
jackson
timtay-microsoft Mar 29, 2022
e5de4e5
fixup
timtay-microsoft Mar 29, 2022
f17eee5
databind
timtay-microsoft Mar 29, 2022
488e4fa
fixup
timtay-microsoft Mar 29, 2022
2138291
fixup
timtay-microsoft Mar 29, 2022
8c4e36c
fixup
timtay-microsoft Mar 29, 2022
9ecc2da
fixup
timtay-microsoft Mar 29, 2022
8021062
fixup
timtay-microsoft Mar 29, 2022
53e87e7
fixup
timtay-microsoft Mar 29, 2022
c56faba
more javadoc fixes
timtay-microsoft Mar 29, 2022
5371933
fix unit test
timtay-microsoft Mar 29, 2022
92bb519
Update device/iot-device-client/src/main/java/com/microsoft/azure/sdk…
timtay-microsoft Mar 29, 2022
9cfbd50
Update device/iot-device-client/src/main/java/com/microsoft/azure/sdk…
timtay-microsoft Mar 29, 2022
b0002ad
cr comment
timtay-microsoft Mar 29, 2022
4df4986
cr comments
timtay-microsoft Mar 29, 2022
43267b8
Update device/iot-device-client/src/main/java/com/microsoft/azure/sdk…
timtay-microsoft Mar 29, 2022
c599be8
quotaExceededException
timtay-microsoft Mar 29, 2022
0fa6a2a
Merge branch 'timtay/exceptions2' of https://github.com/Azure/azure-i…
timtay-microsoft Mar 29, 2022
2202dea
batch messaging only over HTTPS
timtay-microsoft Mar 29, 2022
2402ba7
javadocs
timtay-microsoft Mar 29, 2022
3aae880
delete unused enum
timtay-microsoft Mar 29, 2022
b9777a0
sample shift to overwrite existing reconnection sample
timtay-microsoft Mar 30, 2022
94f4288
fix warnings
timtay-microsoft Mar 30, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
azabbasi marked this conversation as resolved.
Show resolved Hide resolved
{
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)
timtay-microsoft marked this conversation as resolved.
Show resolved Hide resolved
{
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