keystore.load(file, password)
.
*
* @param hostName AWS IoT endpoint to connect to
* @param keyStore The Java keystore to use. Assumed to be loaded with certificates and keys
* @param certificateAlias The alias of the certificate and key to use with the builder.
* @param certificatePassword The password of the certificate and key to use with the builder.
* @return A new AwsIotMqtt5ClientBuilder
*/
public static AwsIotMqtt5ClientBuilder newDirectMqttBuilderWithJavaKeystore(
String hostName, java.security.KeyStore keyStore, String certificateAlias, String certificatePassword) {
TlsContextOptions options = TlsContextOptions.createWithMtlsJavaKeystore(keyStore, certificateAlias, certificatePassword);
AwsIotMqtt5ClientBuilder builder = new AwsIotMqtt5ClientBuilder(hostName, DEFAULT_DIRECT_MQTT_PORT, options);
options.close();
if (TlsContextOptions.isAlpnSupported()) {
builder.configTls.withAlpnList("x-amzn-mqtt-ca");
}
return builder;
}
/**
* Creates a new MQTT5 client builder with default TLS options. This requires setting all connection details manually.
* Default port to direct MQTT.
*
* @param hostName - AWS IoT endpoint to connect to
* @return - A new AwsIotMqtt5ClientBuilder
*/
public static AwsIotMqtt5ClientBuilder newMqttBuilder(String hostName) {
TlsContextOptions options = TlsContextOptions.createDefaultClient();
AwsIotMqtt5ClientBuilder builder = new AwsIotMqtt5ClientBuilder(hostName, DEFAULT_DIRECT_MQTT_PORT, options);
options.close();
if (TlsContextOptions.isAlpnSupported()) {
builder.configTls.withAlpnList("x-amzn-mqtt-ca");
}
return builder;
}
/**
* Creates a new MQTT5 client builder using a MqttConnectionConfig.
*
* This does NOT support all MqttConnectionConfig options and will throw
* an exception should it encounter options it does not support.
*
* Known unsupported options/cases:
* - Custom Authorizer: Will not be properly detected nor setup *
- Websockets: Is not supported and will throw an exception *
- Will Message: Is not supported and will throw an exception *
- All Callbacks: Connection callbacks are not supported and will be ignored
*
* @param mqtt311Config The MqttConnectionConfig to create a MQTT5 client builder from
* @param tlsOptions The TLS options to use alongside the MqttConnectionConfig
* @return A new AwsIotMqtt5ClientBuilder
* @throws Exception If an unsupported option is passed
*/
public static AwsIotMqtt5ClientBuilder newMqttBuilderFromMqtt311ConnectionConfig(MqttConnectionConfig mqtt311Config, TlsContextOptions tlsOptions) throws Exception {
if (mqtt311Config.getEndpoint() == null) {
throw new Exception("MQTT311 to MQTT5 builder requires MQTT311 to have a endpoint set");
}
if (tlsOptions == null) {
throw new Exception("MQTT311 to MQTT5 builder requires MQTT311 to TLS options passed");
}
AwsIotMqtt5ClientBuilder builder = new AwsIotMqtt5ClientBuilder(mqtt311Config.getEndpoint(), (long)mqtt311Config.getPort(), tlsOptions);
if (tlsOptions.isAlpnSupported()) {
builder.configTls.withAlpnList("x-amzn-mqtt-ca");
}
if (mqtt311Config.getUseWebsockets() == true) {
throw new Exception("MQTT311 to MQTT5 builder does not support MQTT311 websockets");
}
if (mqtt311Config.getWillMessage() != null) {
throw new Exception("MQTT311 to MQTT5 builder does not support MQTT311 Will messages");
}
ConnectPacketBuilder connectPacket = new ConnectPacketBuilder();
if (mqtt311Config.getClientId() != null) {
connectPacket.withClientId(mqtt311Config.getClientId());
}
connectPacket.withKeepAliveIntervalSeconds((long)mqtt311Config.getKeepAliveSecs());
if (mqtt311Config.getUsername() != null) {
connectPacket.withUsername(mqtt311Config.getUsername());
}
if (mqtt311Config.getPassword() != null) {
connectPacket.withPassword(mqtt311Config.getPassword().getBytes());
}
builder.withConnectProperties(connectPacket);
builder.withHttpProxyOptions(mqtt311Config.getHttpProxyOptions());
builder.withMaxReconnectDelayMs(mqtt311Config.getMaxReconnectTimeoutSecs() * 1000); // Seconds to milliseconds
builder.withMinReconnectDelayMs(mqtt311Config.getMinReconnectTimeoutSecs() * 1000); // Seconds to milliseconds
builder.withPingTimeoutMs((long)mqtt311Config.getPingTimeoutMs());
builder.withAckTimeoutSeconds((long)mqtt311Config.getProtocolOperationTimeoutMs() * 1000); // Seconds to milliseconds
builder.withSocketOptions(mqtt311Config.getSocketOptions());
return builder;
}
/* Instance methods for various config overrides */
/**
* Overrides the default system trust store.
*
* @param caDirPath - Only used on Unix-style systems where all trust anchors are
* stored in a directory (e.g. /etc/ssl/certs).
* @param caFilePath - Single file containing all trust CAs, in PEM format.
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withCertificateAuthorityFromPath(String caDirPath, String caFilePath) {
this.configTls.overrideDefaultTrustStoreFromPath(caDirPath, caFilePath);
return this;
}
/**
* Overrides the default trust store.
*
* @param caRoot - Buffer containing all trust CAs, in PEM format.
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withCertificateAuthority(String caRoot) {
this.configTls.overrideDefaultTrustStore(caRoot);
return this;
}
/**
* Overrides the port to connect to on the IoT endpoint
*
* @param port - The port to connect to on the IoT endpoint. Usually 8883 for MQTT, or 443 for websockets
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withPort(Long port) {
this.config.withPort(port);
return this;
}
/**
* Overrides all configurable options with respect to the CONNECT packet sent by the client, including the will.
* These connect properties will be used for every connection attempt made by the client. Custom authentication
* configuration will override the username and password values in this configuration.
*
* @param connectPacket - All configurable options with respect to the CONNECT packet sent by the client
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withConnectProperties(ConnectPacketBuilder connectPacket) {
this.configConnect = connectPacket;
return this;
}
/**
* Overrides how the MQTT5 client should behave with respect to MQTT sessions.
*
* @param sessionBehavior - How the MQTT5 client should behave with respect to MQTT sessions.
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withSessionBehavior(Mqtt5ClientOptions.ClientSessionBehavior sessionBehavior) {
this.config.withSessionBehavior(sessionBehavior);
return this;
}
/**
* Overrides how the reconnect delay is modified in order to smooth out the distribution of reconnect attempt
* time points for a large set of reconnecting clients.
*
* @param jitterMode - Controls how the reconnect delay is modified in order to smooth out the distribution
* of reconnect attempt time points for a large set of reconnecting clients.
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withRetryJitterMode(JitterMode jitterMode) {
this.config.withRetryJitterMode(jitterMode);
return this;
}
/**
* Overrides the minimum amount of time to wait to reconnect after a disconnect. Exponential back-off is
* performed with controllable jitter after each connection failure.
*
* @param minReconnectDelayMs - Minimum amount of time to wait to reconnect after a disconnect.
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withMinReconnectDelayMs(Long minReconnectDelayMs) {
this.config.withMinReconnectDelayMs(minReconnectDelayMs);
return this;
}
/**
* Overrides the maximum amount of time to wait to reconnect after a disconnect. Exponential back-off is
* performed with controllable jitter after each connection failure.
*
* @param maxReconnectDelayMs - Maximum amount of time to wait to reconnect after a disconnect.
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withMaxReconnectDelayMs(Long maxReconnectDelayMs) {
this.config.withMaxReconnectDelayMs(maxReconnectDelayMs);
return this;
}
/**
* Overrides the amount of time that must elapse with an established connection before the reconnect delay is
* reset to the minimum. This helps alleviate bandwidth-waste in fast reconnect cycles due to permission
* failures on operations.
*
* @param minConnectedTimeToResetReconnectDelayMs - The amount of time that must elapse with an established
* connection before the reconnect delay is reset to the minimum.
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withMinConnectedTimeToResetReconnectDelayMs(Long minConnectedTimeToResetReconnectDelayMs) {
this.config.withMinConnectedTimeToResetReconnectDelayMs(minConnectedTimeToResetReconnectDelayMs);
return this;
}
/**
* Overrides the time interval to wait after sending a CONNECT request for a CONNACK to arrive. If one does not
* arrive, the connection will be shut down.
*
* @param connackTimeoutMs - The time interval to wait after sending a CONNECT request for a CONNACK to arrive.
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withConnackTimeoutMs(Long connackTimeoutMs) {
this.config.withConnackTimeoutMs(connackTimeoutMs);
return this;
}
/**
* Overrides how disconnects affect the queued and in-progress operations tracked by the client. Also controls
* how new operations are handled while the client is not connected. In particular, if the client is not connected,
* then any operation that would be failed on disconnect (according to these rules) will also be rejected.
*
* @param offlineQueueBehavior - How disconnects affect the queued and in-progress operations tracked by the client.
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withOfflineQueueBehavior(Mqtt5ClientOptions.ClientOfflineQueueBehavior offlineQueueBehavior) {
this.config.withOfflineQueueBehavior(offlineQueueBehavior);
return this;
}
/**
* Overrides the time interval to wait after sending a PINGREQ for a PINGRESP to arrive. If one does not arrive,
* the client will close the current connection.
*
* @param pingTimeoutMs - The time interval to wait after sending a PINGREQ for a PINGRESP to arrive.
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withPingTimeoutMs(Long pingTimeoutMs) {
this.config.withPingTimeoutMs(pingTimeoutMs);
return this;
}
/**
* Overrides the time interval to wait for an ack after sending a QoS 1+ PUBLISH, SUBSCRIBE, or UNSUBSCRIBE before
* failing the operation. Defaults to no timeout.
*
* @param ackTimeoutSeconds - the time interval to wait for an ack after sending a QoS 1+ PUBLISH, SUBSCRIBE,
* or UNSUBSCRIBE before failing the operation
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withAckTimeoutSeconds(Long ackTimeoutSeconds) {
this.config.withAckTimeoutSeconds(ackTimeoutSeconds);
return this;
}
/**
* Overrides the socket properties of the underlying MQTT connections made by the client. Leave undefined to use
* defaults (no TCP keep alive, 10 second socket timeout).
*
* @param socketOptions - The socket properties of the underlying MQTT connections made by the client
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withSocketOptions(SocketOptions socketOptions) {
this.config.withSocketOptions(socketOptions);
return this;
}
/**
* Overrides (tunneling) HTTP proxy usage when establishing MQTT connections.
*
* @param httpProxyOptions - HTTP proxy options to use when establishing MQTT connections.
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withHttpProxyOptions(HttpProxyOptions httpProxyOptions) {
this.config.withHttpProxyOptions(httpProxyOptions);
return this;
}
/**
* Overrides additional controls for client behavior with respect to operation validation and flow control; these
* checks go beyond the base MQTT5 spec to respect limits of specific MQTT brokers.
*
* @param extendedValidationAndFlowControlOptions - additional controls for client behavior with respect to operation
* validation and flow control
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withExtendedValidationAndFlowControlOptions(Mqtt5ClientOptions.ExtendedValidationAndFlowControlOptions extendedValidationAndFlowControlOptions) {
this.config.withExtendedValidationAndFlowControlOptions(extendedValidationAndFlowControlOptions);
return this;
}
/**
* Sets the LifeCycleEvents that will be called by the client when receives a life cycle events. Examples of
* life cycle events are: Connection success, connection failure, disconnection, etc.
*
* @param lifecycleEvents - The LifeCycleEvents to be called
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withLifeCycleEvents(Mqtt5ClientOptions.LifecycleEvents lifecycleEvents) {
this.config.withLifecycleEvents(lifecycleEvents);
return this;
}
/**
* Sets the PublishEvents that will be called by the client when it receives a publish packet.
*
* @param publishEvents The PublishEvents to be called
* @return - The AwsIotMqtt5ClientBuilder
*/
public AwsIotMqtt5ClientBuilder withPublishEvents(Mqtt5ClientOptions.PublishEvents publishEvents) {
this.config.withPublishEvents(publishEvents);
return this;
}
/**
* Constructs an MQTT5 client object configured with the options set.
* @return A MQTT5ClientOptions
*/
public Mqtt5Client build() {
if (this.configTls == null) {
this.configTls = TlsContextOptions.createDefaultClient();
addReferenceTo(this.configTls);
this.configTls.close();
}
TlsContext tlsContext = new TlsContext(this.configTls);
this.config.withTlsContext(tlsContext);
addReferenceTo(tlsContext);
tlsContext.close();
try {
this.configConnect.withUsername(buildMqtt5FinalUsername(this.configCustomAuth));
if (this.configCustomAuth != null) {
if (this.configCustomAuth.password != null) {
this.configConnect.withPassword(this.configCustomAuth.password);
}
}
} catch (Exception ex) {
System.out.println("Error - exception occurred while building MQTT5 client options builder: " + ex.toString());
ex.printStackTrace();
return null;
}
this.config.withConnectOptions(this.configConnect.build());
Mqtt5Client returnClient = new Mqtt5Client(this.config.build());
// Keep a reference to the TLS configuration so any possible Websockets-related CrtResources are kept alive
returnClient.addReferenceTo(this.configTls);
return returnClient;
}
/* Helper functions and structs */
/**
* Websocket-specific MQTT5 connection AWS IoT configuration options
*/
public static final class WebsocketSigv4Config {
/**
* Sources the AWS Credentials used to sign the websocket connection handshake. If not provided,
* the default credentials provider chain is used.
*/
public CredentialsProvider credentialsProvider;
/**
* The AWS region the websocket connection is being established in. Must match the region embedded in the
* endpoint. If not provided, pattern-matching logic is used to extract the region from the endpoint.
* Use this option if the pattern-matching logic has not yet been updated to handle new endpoint formats.
*/
public String region;
}
/**
* Attempts to determine the AWS region associated with an endpoint.
* Will throw an exception if it cannot find the region.
*
* @param endpoint - The endpoint to compute the region for.
* @return The region associated with the endpoint.
* @throws Exception When AWS region cannot be extracted from endpoint.
*/
public static String extractRegionFromEndpoint(String endpoint) throws Exception {
Pattern regexPattern = Pattern.compile("^[\\w\\-]+\\.[\\w\\-]+\\.([\\w+\\-]+)\\.");
Matcher regexMatcher = regexPattern.matcher(endpoint);
try {
if (regexMatcher.find()) {
String result = regexMatcher.group(1);
if (result != null) {
return result;
}
}
} catch (Exception ex) {
throw new Exception("AWS region could not be extracted from endpoint. Use 'region' property on WebsocketConfig to set manually.");
}
throw new Exception("AWS region could not be extracted from endpoint. Use 'region' property on WebsocketConfig to set manually.");
}
/**
* Configuration options specific to
* AWS IoT Core custom authentication
* features. For clients constructed by an AwsIotMqtt5ClientBuilder, all parameters associated
* with AWS IoT custom authentication are passed via the username and password properties in the CONNECT packet.
*/
public static final class MqttConnectCustomAuthConfig {
/**
* Name of the custom authorizer to use.
*
* Required if the endpoint does not have a default custom authorizer associated with it.
* It is strongly suggested to URL-encode this value; the SDK will not do so for you.
*/
public String authorizerName;
/**
* The username to use with the custom authorizer. Query-string elements of this property value will be unioned
* with the query-string elements implied by other properties in this object.
*
* For example, if you set this to:
*
* {@literal MyUsername?someKey=someValue}
*
* and use authorizerName to specify the authorizer, the final username would look like:
*
* {@literal MyUsername?someKey=someValue&x-amz-customauthorizer-name=
*/
public String username;
/**
* The password to use with the custom authorizer. Becomes the MQTT5 CONNECT packet's password property.
* AWS IoT Core will base64 encode this binary data before passing it to the authorizer's lambda function.
*/
public byte[] password;
/**
* Key used to extract the custom authorizer token from MQTT username query-string properties.
*
* Required if the custom authorizer has signing enabled. It is strongly suggested to URL-encode this value; the
* SDK will not do so for you.
*/
public String tokenKeyName;
/**
* An opaque token value. This value must be signed by the private key associated with the custom authorizer and
* the result placed in the tokenSignature property.
*
* Required if the custom authorizer has signing enabled.
*/
public String tokenValue;
/**
* The digital signature of the token value in the tokenValue property. The signature must be based on
* the private key associated with the custom authorizer. The signature must be base64 encoded.
*
* Required if the custom authorizer has signing enabled. It is strongly suggested to URL-encode this value; the
* SDK will not do so for you.
*/
public String tokenSignature;
}
/**
* Adds a username parameter to the given list. Will only add to the list if the paramValue is not null.
* Always adds both values in pair. Set the key to null if you need to only add a single value.
*
* @param paramList The parameter list to use
* @param paramName The new parameter name
* @param paramValue The new parameter value
*/
private void addToUsernameParam(List?
or &
to append the strings together.
*
* Note: The paramList is expected to have either zero elements or an even amount. Will throw if uneven.
* Will correctly handle if the parameter name is null but the parameter value is not null.
*
* @param paramList The parameter list to use for creating the username.
* @return A string formatted from the parameter list.
* @throws Exception When parameters cannot be added to username due to parameters list being uneven
*/
private String formUsernameFromParam(List