Messaging Service

The PubSub+ Messaging API for Java provides the MessagingService interface, which allows you to connect to an event broker. The MessagingService interface handles all the functionality for interacting with a PubSub+ event broker. To create a MessagingService object, you must first configure a Properties object with the information required to establish a connection to the event broker, including the host details and the authentication scheme.

To ensure backwards compatibility with future versions of the API, you must pass a Configuration Profile as a parameter when you create the MessagingService object.

Creating a Properties Object

Properties (SolaceProperties interface) object can have a number of properties, however at least one property object must have a SolaceProperties.TransportLayerProperties.HOST and a SolaceProperties.TransportLayerProperties.VPN configured and passed to a MessagingService.builder() to configure the connection to the event broker. There are five categories of properties that can be configured in a Properties object.

  • ServiceProperties(required for the VPN property)
  • TransportLayerProperties (required for the HOST property )
  • AuthenticationProperties
  • ClientProperties
  • TransportLayerSecurityProperties

For more information, see the PubSub+ Messaging API for Java reference.

An example of a Properties object for a basic connection can be seen below. After you create a Properties object, you can use setter methods to configure the connection. In the following example, the fields have been hard-coded as string values for readability. In your own code, change these values as required based on your event broker.

import com.solace.messaging.MessagingService;
import com.solace.messaging.config.SolaceConstants.AuthenticationConstants;
import com.solace.messaging.config.SolaceProperties.AuthenticationProperties;
import com.solace.messaging.config.SolaceProperties.TransportLayerProperties;
import com.solace.messaging.config.profile.ConfigurationProfile;
import java.util.Properties;
...
...
...						
final Properties properties = new Properties();
properties.setProperty(TransportLayerProperties.HOST, "host");
properties.setProperty(ServiceProperties.VPN_NAME,  "vpn");
properties.setProperty(AuthenticationProperties.SCHEME_BASIC_USER_NAME, "userName");
properties.setProperty(AuthenticationProperties.SCHEME_BASIC_PASSWORD, "password");
properties.setProperty(ServiceProperties.RECEIVER_DIRECT_SUBSCRIPTION_REAPPLY, "true");

Alternatively if you're running samples, the configuration you want to use can be passed into the client application via the command line using the args[]array in the main method or loaded using a properties file. The following sample code shows how you can create a Properties object and load its values using a properties file. For a comprehensive list of the constant field values, see AuthenticationProperties.

/* Creating a Properties object and setting its values using a FileInputStream file reader */
try (InputStream input = new FileInputStream("path/to/properties/file")) {
    Properties properties = new Properties();
    properties.load(input);
} catch (IOException e) {
    e.printStackTrace();
}    

End-to-End Payload Compression

The PubSub+ Java API can perform end-to-end payload compression to allow for:

  • faster message throughput

  • reduced bandwidth usage

  • improved performance in your applications

While end-to-end payload compression creates more work for individual PubSub+ APIs, it enables faster aggregate rates of message publishing and message receiving. The PubSub+ event broker offers transport message compression that compresses the entire message, see Streaming Compressed Connections. However, when you send and receive large messages, compressing the entire message creates a lot of work for the event broker, which can result in slower throughput. If your application needs to send and receive large messages, we recommend you use end-to-end payload compression to improve performance.

  1. Considerations When Compressing Message Payloads

  2. Compressing Message Payloads in the PubSub+ Java API

Considerations When Compressing Message Payloads

The following sections explain what you should be aware of when you compress message payloads with the PubSub+ Messaging APIs.

Use only one form of message compression

We recommend you only use one form of compression, either Streaming Compressed Connections through the event broker or end-to-end payload compression through the APIs. Compressing the same message multiple times can waste resources and usually does not result in smaller message sizes.

Do not use end-to-end payload compression with small messages

End-to-end payload compression works best with messages that are a few megabytes in size. Solace does not recommend using message payload compression with small messages, because end-to-end payload compression can actually increase the size of small messages.

Upgrade your publisher and receiver applications

Receiver applications automatically decompress any compressed message payloads only if the API supports message payload compression and is updated to the minimum supported version. If your receiver application does not support message payload compression, this can cause potential errors or exceptions. Make sure you update your publisher and receiver applications to the minimum supported versions for payload compression. For version support information, see Feature Support in PubSub+ Messaging APIs.

End-to-end payload compression limitations

End-to-end payload compression does not currently support PubSub+ Cache.

End-to-end payload compression is not compatible with:

  • SolCache

  • Non-SMF protocols, such as AMQP, HTTP, Kafka and MQTT

If your applications use any of the above, we recommend you do not use end-to-end payload compression.

Compressing Message Payloads in the PubSub+ Java API

Your publisher application can compress the payload of any message before you publish it. To compress a message payload, you must set PAYLOAD_COMPRESSION_LEVEL, which tells the API you want end-to-end payload compression enabled. The payload compression level property can be set to an integer from 0-9:

  • 0—Payload compression is disabled. This is the default setting.

  • 1 - 9—Payload compression is enabled. 1 is the lowest level of compression with the fastest data throughput, and 9 is the highest level of compression with the slowest data throughput.

Your payload compression level should be adjusted according to your network and performance requirements. The following code snippet shows how to set PAYLOAD_COMPRESSION_LEVEL in a broker properties dictionary:

Properties properties = new Properties();
// Payload compression enabled with max compression:
properties.setProperty(SolaceProperties.ServiceProperties.PAYLOAD_COMPRESSION_LEVEL, "9");

Establishing a Connection to an Event Broker

When the necessary properties have been set and stored in a Properties object, you can call MessagingService.build() to create a MessagingService object. The MessagingService object allows the API to establish a connection to the event broker. The following is a list of commonly used methods to create the necessary MessagingService object using the MessagingServiceClientBuilder interface and establish a connection to the event broker:

  • builder(ConfigurationProfile activeProfile)
  • withAuthenticationStrategy(AuthenticationStrategy authenticationProvider)
  • fromProperties(Properties properties)
  • build()

For more information, see the PubSub+ Messaging API for Java reference.

After you create the MessagingService object, you call the connect() method.

The following sample code shows how to create a simple MessagingService object that connects to an event broker:

final MessagingService messagingService = MessagingService.builder(ConfigurationProfile.V1)
    .fromProperties(properties)    // Enables property based configuration, required to set host and VPN properties
                                   // withAuthenticationStrategy() can be called here to use one of the strategies listed below
    .build()                       // Returns a MessagingService object based on the provided configuration
    .connect();                    // A synchronous connection is established with an event broker.

Using Transport Layer Security

Transport Layer Security (TLS) allows for encrypted authentication and data transmission between the PubSub+ Java API and a PubSub+ event broker. The PubSub+ Java API supports Transport Layer Security versions: TLS 1.0, TLS 1.1, and TLS 1.2 . The recommended version to use is the most recent version of TLS. Secure Socket Layer (SSL) protocol, version 3 (SSLv3) is also supported. We don't recommend that you use SSL unless it's required for backwards compatibility.

You can use TransportSecurityStrategy.TLS.create() to configure the TLS connection properties, such as the Java Key Store (JKS) to use, or whether to disable certificate validation. When you use TLS, you must always use secure TCP  protocol (tcps or https) in setting the TransportLayerProperties.HOST property for your connection, for example:

properties.setProperty(TransportLayerProperties.HOST, "tcps://my-host-connection.messaging.solace.cloud:11111");

The following sample code shows the recommended security setup for client applications when you use TLS:

/* An entry point to create a service builder using a configuration profile (V1 sets it to default values). */
MessagingService.builder(ConfigurationProfile.V1)
    .withTransportSecurityStrategy(
        TLS.create()                                      // Creates a new transport security layer instance(required). Can configure or override authentication manually.
        .withCertificateHostValidation()                  // Configures transport layer security (TLS) to validate the host against one from a server certificate.
        .withCertificateValidation("changeme", false)     // changeme is the default truststore password, ignoreExpiration is set to false which rejects expired certificates
        .withExcludedProtocols(SecureProtocols.TLSv1_1, SecureProtocols.TLSv1, SecureProtocols.SSLv3)   // Excludes dated SSL protocols 
    .withAuthenticationStrategy(                          // Enables/overrides the existing authentication strategy with AuthenticationStrategy.
        ClientCertificateAuthentication         
        .of(myKeystoreUrl, myKeystorePassword)            // A factory method that creates an instance to be used for Client Certificate Authentication. 
            )
    .build()                                         
    .connect(); 

There are also a number of methods that you may find useful to configure the TLS connection using TransportSecurityStrategy.TLS. Here are three methods commonly used to configure the TLS connection:

  • withCipherSuites()—The list of cipher suites used when negotiating the TLS connection can be configured. You can configure the Java API to limit it to use a set of stronger ciphers and to help guarantee a more secure connection between the client applications and event brokers.

    Cipher suites are a useful method of encrypting communication through a TLS handshake and offer improved security between applications connected through the event broker. For a more detailed explanation and a list of supported cipher suites see Cipher Suites.

    The following code sample shows how to use the withCipherSuites() method:

    /* An entry point to create a service builder using a configuration profile (V1 sets it to default values). */
    MessagingService.builder(ConfigurationProfile.V1)
        .withTransportSecurityStrategy(TLS.create()      // Creates a new transport security layer instance(required). Can configure or override authentication manually.
        .withCipherSuites("CipherSuite1,                 // A comma separated list of cipher suites in order of preference used for SecureSocket Layer (SSL) connections.
                            CipherSuite2")               // Cipher suites can be specified using their JSSE name or openSSL name.
            )
        .withAuthenticationStrategy(                     // Enables/overrides the existing authentication strategy with AuthenticationStrategy.
            ClientCertificateAuthentication         
            .of(myKeystoreUrl, myKeystorePassword)       // A factory method that creates an instance to be used for Client Certificate Authentication. 
            )
        .build()        // Returns a PubSub+ MessagingService object based on the provided configuration and number of authentication parameters.
        .connect();     // A synchronous connection is established with a PubSub+ event broker.            

  • withExcludedProtocols()—You may not want to use specific protocols to connect with microservices. For example, you may not want to use legacy protocols. Use this method to specify the Secure Socket Layer (SSL) and Transport Layer Security (TLS) protocols not to use. Here is sample code that shows you how to exclude a specific protocol:

    /* An entry point to create a service builder using a configuration profile (V1 sets it to default values). */
    MessagingService.builder(ConfigurationProfile.V1)
        .withTransportSecurityStrategy(
            TLS.create()       // Creates a transport security layer instance. You can configure or override authentication manually.
            .withExcludedProtocols(TransportSecurityStrategy.TLS.SecureProtocols.TLS1.1)  // Excludes TLS1.1 from accessing micro service.
            )
        .withAuthenticationStrategy(               // Enables or overrides the existing authentication strategy with AuthenticationStrategy.
            ClientCertificateAuthentication          
            .of(myKeystoreUrl, myKeystorePassword) // A factory method that creates a new instance to be used for Client Certificate Authentication. 
            )
        .build()        // Returns a MessagingService object based on the provided configuration and number of authentication parameters.
        .connect();     // A synchronous connection is established with an event broker.            

  • withoutCertificateValidation()—This method configures your TLS connection not to validate server certificates.

    Only use this method in development environments. We recommend that you never use this method in production environments because it creates a security vulnerability.

    The following sample code shows how to use the withoutCertificateValidation() method:

    /* An entry point to create a service builder using a configuration profile (V1 sets it to default values). */
    MessagingService.builder(ConfigurationProfile.V1)
        .withTransportSecurityStrategy(
            TLS.create()                      // Creates a transport security layer instance. Can configure or override authentication manually.
            .withoutCertificateValidation()   // Configures transport layer security (TLS) to not validate server certificates.
            )
        .withAuthenticationStrategy(                 // Enables/overrides the existing authentication strategy with AuthenticationStrategy.
            ClientCertificateAuthentication          // Configures transport layer security (TLS) not to validate server certificates.
            .of(myKeystoreUrl, myKeystorePassword)   // A factory method that creates an instance to be used for Client Certificate Authentication. 
            )
        .build()        // Returns a MessagingService object based on the provided configuration and number of authentication parameters.
        .connect();     // A synchronous connection is established with an event broker.            

You can also configure the aspects of the TLS connection using TransportLayerSecurityProperties and the Properties object. The TLS connection can be configured using various fields found in SolaceProperties.TransportLayerSecurityProperties. We recommend that you use the default settings (set to true and enabled) to ensure secure connections for the following properties:

  • CERT_REJECT_EXPIRED
  • CERT_VALIDATE_USERNAME
  • CERT_VALIDATED

For more information about the object, methods, and properties, see the PubSub+ Messaging API for Java reference.

For details about creating a Properties object and establishing a connection to the broker via the MessagingService object, see Creating a Properties Object .

Using Websockets

The PubSub+ Java API supports the use of WebSockets, which allows data transmission that can bypass typical barriers like firewalls and proxies. WebSockets allow your applications to connect over ports 80 (HTTP) and 443 (HTTPS). Because these ports are usually open in most firewall configurations, WebSockets can establish connections without requiring additional port openings or configurations. To use Websockets, use one of the following prefixes in your HOST URL property:

  • ws: or ws://—Use WebSockets for unsecured communication between your application and the event broker.
  • wss: or wss://—Use a TLS/SSL channel over WebSockets for secure communication between your application and the event broker.

The following sample code shows how to set an example WebSocket HOST property:

final Properties properties = new Properties();
properties.setProperty(TransportLayerProperties.HOST, "wss://my-websocket.example:443");

Authentication

The PubSub+ Java API supports a number of authentication schemes (or strategies). that you can choose from. The scheme that you choose may depend on the credentials that the connecting client is required to provide. You can use one of the following authentication schemes:

Basic Authentication

Basic authentication is the default client authentication scheme which allows a client to authenticate with an event broker using a client username and password. To specify basic authentication, create an instance of a MessagingService object and specify the following as the parameter for the withAuthenticationStrategy() method:

  • BasicUserNamePassword
    • of(String userName, String password)

For details about object and method, see the PubSub+ Messaging API for Java reference.

The following sample code shows how to use basic authentication:

final String username = "solace01";
final String password = "12345678";
            
/* An entry point to create a service builder using ConfigurationProfile (see section below on ConfigurationProfile). */
final MessagingService messagingService = MessagingService.builder(ConfigurationProfile.V1)
    .withAuthenticationStrategy(BasicUserNamePassword      // Overrides/Enables the existing authentication strategy with strategy passed into parameter.
    .of(username,password))    // Creates an instance of BasicUserNamePassword.                     
    .build()                
    .connect();                

For details about creating a Properties object and establishing a connection to the broker via the MessagingService object, see Creating a Properties Object .

Kerberos Authentication

The PubSub+ Java API provides support for Kerberos Authentication. Connecting using this method requires both a valid jaas login configuration file, as well as a valid Kerboros configuration file. Call the withAuthenticationStrategy() method and pass the following object and methods as the parameters:

  • Kerboros
    • of(String jaasLoginContextName, String kerberosPrincipalInstanceName)
    • withUserName(String userName)
    • withMutualAuthentication()
    • withReloadableJaasConfiguration()

For details about object and methods, see the PubSub+ Messaging API for Java reference.

The following sample code shows how to use Kerboros for authentication and requires that you create these files as shown in the examples from the Solace Developer Hub:

  • jaas.conf for the login configuration file
  • krb5.conf for the Kerberos configuration file
final String kerberosPrincipalInstanceName = "solace01";
final String jaasLoginContextName = "SolaceGSS";           // jaasLoginContextName correlates to the entry in resources/jaas.conf file.
final String myUserNameOnBroker = "myUserNameOnBroker";    // myUserNameOnBroker should be setup on a broker, enable mutual authentication and JAAS config file reloading.

//An entry point to create a service builder using a configuration profile (V1 sets it to default values)
MessagingService.builder(ConfigurationProfile.V1)
    .fromProperties(serviceConfiguration)                           //Uses authentication properties passed in through command line or hard-coded into program.
    .withAuthenticationStrategy(                                    //Enables or overrides the existing authentication strategy with AuthenticationStrategy.
        Kerberos
        .of(kerberosPrincipalInstanceName, jaasLoginContextName)    // Creates an instance of Kerboros. 
        .withUserName(myUserNameOnBroker)                           // A factory method to configure non default user name when using Kerberos. 
        .withMutualAuthentication()                                 // A factory method to configure mutual authentication when using Kerberos.
        .withReloadableJaasConfiguration())                         // A factory method to configure reloading behavior of a (jaas.conf) file.
    .build()                                                        
    .connect();                                                  

For details about creating a Properties object and establishing a connection to the broker via the MessagingService object, see Creating a Properties Object .

Client Certificate Authentication

To use the Client certificate authentication scheme, the following steps are required:

  1. You must configure the host event broker to use TLS connections (see Using Transport Layer Security).

  2. Your application must connect to the broker using TLS.

  3. You must enable Client certificate verification on the Message VPN that the application uses to connect.

  4. In your client application, the client-side certificate must be present in a keystore file and you configure the certificate using the ClientCertificateAuthentication.of(String keystoreURL, String keystorePassword) method.

For details about object and method, see the PubSub+ Messaging API for Java reference.

The following sample code shows how to configure client certificate authentication:

MessagingService.builder(ConfigurationProfile.V1)
    .withTransportSecurityStrategy(TLS.create())    // Creates a new transport security layer instance(required). Can configure or override authentication manually.
    .withAuthenticationStrategy(                    // Enables/overrides the existing authentication strategy with AuthenticationStrategy.
        ClientCertificateAuthentication
        .of(myKeystoreUrl, myKeystorePassword)      // A factory method that creates an instance to be used for Client Certificate Authentication. 
        )
    .build()                                       
    .connect();                                   

For details about creating a Properties object and establishing a connection to the broker via the MessagingService object, see Creating a Properties Object .

OAuth 2.0 Authentication

The OAuth authentication scheme allows a client application to use the OAuth mechanism to authenticate its connection with an event broker. To use OAuth 2.0 authentication, configure the host event broker to use TLS connections (see Using Transport Layer Security) and ensure your application connects to the event broker using TLS. For more information see OAuth Authentication.

PubSub+ event brokers support the following OAuth authentication mechanisms:

The PubSub+ Java API supports different fields that can be sent to the event broker:

  • accessToken—a String for applications to make requests for data access

    and/or

    idToken—a String for Open ID Connect (OIDC) connections

  • issuerIdentifier—(Optional) a String to identify the appropriate OAuth profile configuration

OAuth authentication requires an accessToken, an idToken, or both to be enabled using these methods from the AuthenticationStrategy.OAuth2:

  • of(String token)
    • the idToken or accessToken can be used for this method
  • of(String accessToken, String idToken)
    • if you are use both tokens, the accessToken must be the first parameter
  • withIssuerIdentifier(String issuerIdentifier)
    • an optional Authorization Server Issuer Identifier

For details about the object and methods, refer to the PubSub+ Messaging API for Java reference.

OAuth 2.0

OAuth2.0 is an open standard for access delegation and authorization. It is commonly used as a mechanism to grant websites or applications access to users' information on other websites without giving them access to sensitive credentials. The OAuth authentication scheme allows access through the use of tokens issued to third-party clients by an authorization server that provides access to Message VPNs on PubSub+ event brokers. For more information, see OAuth Authentication.

  • (Mandatory) An access token as defined in OAuth. Access tokens are issued by the authorization server after successfully authenticating the user and obtaining their consent. The access token is the artifact that allows an OAuth client application to access the user's resource. The issuerIdentifier claim in the token, if present, is used to identify which OAuth profile the event broker will use for token validation. If no profile with a matching issuer is found, the default profile is used.

  • (Optionally) An Authorization Server Issuer Identifier (issuerIdentifier). If provided, this parameter must match the issuer of an OAuth profile on the event broker. That profile will be used for token validation, rather than the profile with the issuer provided in the token’s iss claim, if any, or the default profile configured on the event broker.

The following sample code shows how to use OAuth2 authentication with the issue:

/* Configure service access to use OAuth 2 authentication with an access token and an optional issuer identifier. */
MessagingService.builder(ConfigurationProfile.V1)
    // Configures service with an accessToken and an issuerIdentifier:
    .withAuthenticationStrategy(OAuth2.of(accessToken).withIssuerIdentifier(issuerIdentifier)) 
    .build()                                
    .connect(); 

OpenID Connect

The event broker is configured for OpenID Connect authentication (oauth-role is set to client), you must provide the following properties for the event broker to authenticate the client application:

  • Open ID Connect Token: (Required) Defined by the OpenID Connect (OIDC), OIDC tokens are an extension to OAuth2.0. ID tokens are issued by the authorization server and contain claims that carry information about the user. An ID token is an artifact that proves that the user has been authenticated. The issuerIdentifier claim in the token is used to identify which OAuth profile the event broker will use for token validation. If no profile with a matching issuer is found, the default profile is used.

  • Access token: (Optional) This access token is an optional access that your organization may require that the event broker uses to determine the authorizations available to the authenticated client application.

/* Configure service access to use a OpenID Connect authentication with an ID token and an optional access token. */
MessagingService.builder(ConfigurationProfile.V1)
    .withAuthenticationStrategy(OAuth2.of(accessToken,idToken))    // Configures service with an accessToken and an idToken. 
    .build()                                                        
    .connect();                                                   

Required Event Broker Configurations

For a client application to use an OAuth authentication scheme, a Message VPN OAuth profile must be configured for the host event broker and OAuth authentication must be configured and enabled for any Message VPNs to which a client connects. For more information, see OAuth Authentication.

Refreshing Expired OAuth Tokens

By default, event brokers disconnect clients when their tokens expire (see Disconnect on Token Expiration). When a client session is disconnected, the client application tries to reconnect a number of times using the same OAuth token based on the RECONNECTION_ATTEMPTS property. If the connection can't be reestablished due to token expiration, the client application must recreate the session with all its subscriptions.

To update the OAuth token, use the updateProperty(String, Object) method, which allows you to set a modifable service property after the creation of the MessagingService object. The first parameter is one of the following strings and the second parameter is the token:

  • SolaceProperties.AuthenticationProperties.SCHEME_OAUTH2_ACCESS_TOKEN to update an expired access token
  • SolaceProperties.AuthenticationProperties.SCHEME_OAUTH2_OIDC_ID_TOKEN to update an expired ID token

Modifiable service properties may not update immediately and may require the next reconnection attempt to update.

Refreshing the expired token can happen while:

  • the client application is connected. In this case, the client contacts the authentication server to refresh the token and modifies the session to use the updated token the next time the API connects to the event broker.

  • the client application is reconnecting. The reconnecting event includes a diagnostic subCode. If this subCode is Login Failure, this may indicate that your token has expired. In this case, the API tries to reconnect (using the expired token). The client then contacts the authentication server to refresh the token and modifies the session to use the updated token the next time the API attempts to reconnect to the event broker.

In general, it is better if the client application is aware of potential token expiry and refreshes the token before it expires.

When the client application's session is reconnected, the Java API re-applies the client application's direct subscriptions. If there is a change in the ACLs as a result of the refreshed token, the subscriptions may be rejected by the event broker.

Configuration Profiles

To ensure that your application remains compatible with future versions of this API, you must pass a predefined Configuration Profile enumeration (as ConfigurationProfile.V1) to the MessagingService.builder() method. The V1 (Version 1) refers to the currently available configuration profile.

The following sample code shows how to configure your application for backwards compatibility using the configuration profile:

final MessagingService messagingService = MessagingService.builder(ConfigurationProfile.V1)
    .fromProperties(properties)     // Uses authentication properties passed in through command line or hard-coded into program.
    .build()                  
    .connect();