Creating your first MQ Telemetry Transport publisher application using Java

The steps to create an MQTT client application are described in tutorial fashion. Each line of code is explained. At the end of the task, you will have created an MQTT publisher. You can browse the publications using WebSphere® MQ Explorer.

Before you begin

Install the WebSphere MQ Telemetry feature on a server that has IBM® WebSphere MQ Version 7.1 or later installed.

The client application uses the com.ibm.mq.micro.client.mqttv3 package in the IBM WebSphere MQ Telemetry Software Development Toolkit (SDK). The SDK is part of the IBM WebSphere MQ Telemetry installation. The client connects to the IBM WebSphere MQ Telemetry feature to exchange messages with IBM WebSphere MQ.

You must also install the telemetry updates for IBM WebSphere MQ Explorer Version 7.1 to administer IBM WebSphere MQ Telemetry. The updates are part of the IBM WebSphere MQ Telemetry installation.

An MQTT client, running on Java SE, requires version 6.0 of Java SE, or later. IBM Java SE v6.0 is part of the IBM WebSphere MQ Version 7.1 installation. It is located at WebSphere MQ installation directory\java\jre

About this task

The example is a publish application, PubSync. PubSync publishes Hello World on the topic MQTT Examples, and waits for confirmation that the publication has been delivered to the queue manager.

By setting up a durable subscription to MQTT Examples you can check that the application works.

The procedure uses Eclipse to develop, build, and run the client. You can download Eclipse from the Eclipse project website at www.eclipse.org.

To create the application, you can create the Java files, and compile and run them by using the command line.

In a new directory, create the directory path .\com\ibm\mq\id. Create two Java files, Example.java and PubSync.java. Copy the code from Example code into the Java files.

Compile the Java code using the command,
javac -cp jar_dir\com.mq.micro.client.mqttv3.jar 
       com.ibm.mq.id.PubSync.java com.ibm.mq.id.Example.java
Run PubSync using the command,
java -cp jar_dir\com.mq.micro.client.mqttv3.jar  
      com.ibm.mq.id.PubSync

Procedure

  1. Create a Java project in Eclipse.
    1. File > New > Java project and type a project name. Click Next.

      Check the JRE is at the correct or later version. Java SE must be at 6.0 or later.

    2. On the Java Settings page, click Libraries > Add External Jars...
    3. Browse to the directory where you have installed the WebSphere MQ Telemetry SDK folder to. Locate the SDK\clients\java folder and select the all the .jar files > > Open > Finish.
  2. Install the MQTT client Javadoc.

    With the MQTT client Javadoc installed, the Java editor provides assistance with the MQTT v3 classes.

    1. In your Java project, open Package Explorer > Referenced Libraries. Right click com.ibm.micro.client.mqttv3.jar > Properties.
    2. In the Properties navigator click Javadoc Location.
    3. In the Javadoc Location page click Javadoc URL > Browse... and find the WMQ Installation directory\mqxr\SDK\clients\java\doc\javadoc folder > OK.
    4. Click Validate... > OK

      You are prompted to open a browser to view the documentation.

  3. Create the class, PubSync, using the Java Class wizard.
    1. Right-click the Java project you have created > New > Class.
    2. Type the package name, com.ibm.mq.id
    3. Type the class name, PubSync
    4. Check the method stub box, public static void main(String [] args)
  4. Create a file, Example.java in the package com.ibm.mq.id. Copy the code in Figure 3 into the file.

    All the parameters used in the examples are set as properties. You can override the values by changing the defaults in Example.java, or by supplying the properties as options on the Java command line using the -D parameter:

    Read syntax diagramSkip visual syntax diagram -Dproperty name=string" string"

    The client identifier used in this example, and the Creating an asynchronous publisher for MQ Telemetry Transport using Java examples, is a user name suffixed by a random string.

  5. Follow the steps to create the code, or copy the code from Figure 2.

    The steps that follow explain the code in Pubsync.java.

  6. Create a try-catch block.
        try { ...
         } catch (Exception e) {
          e.printStackTrace();
        }
    

    The MQTT client throws MqttException, MqttPersistenceException or MqttSecurityException. MqttPersistenceException and MqttSecurityException are subclasses of MqttException.

    Use the MqttException.getReasonCode method to find out the reason for the exception. If a MqttPersistenceException or MqttSecurityException is thrown, use the getCause method to return the underlying throwable exception.

  7. Create a new MqttClient instance.
    MqttClient client = new MqttClient(Example.TCPAddress, Example.clientId);

    Provide the client with a server address, which is used later to connect to WebSphere MQ. Set the client identifier to name the client.

    • Optionally, you can provide an implementation of the MqttClientPersistence interface to replace the default implementation. The default MqttPersistence implementation stores QoS 1 and 2 messages awaiting delivery as files; see Message persistence in MQTT clients.
    • The default IBM WebSphere MQ TCP/IP port for MQTT is 1883. For SSL, it is 8883. In the example, the default address is set to tcp://localhost:1883.
    • Typically, it is important to be able to identify a specific physical client using the client identifier. The client identifier must be unique across all clients connect to a server; see Client identifier. Using the same client identifier as a previous instance indicates the present instance is an instance of the same client. If you duplicate a client identifier in two running clients, an exception is thrown in both clients, and one client terminates.
    • The length of the client identifier is limited to 23 bytes. An exception is thrown, if the length is exceeded. The client identifier must contain only characters permitted in a queue manager name; for example, no hyphens or spaces.
    • Until you call the MqttClient.connect method, no message processing takes place.
    Use the client object to publish and subscribe topics and recover information about publications that have not been delivered yet.
  8. Create a topic to publish on.
     MqttTopic topic = client.getTopic(Example.topicString);

    A topic string is limited to 64 K bytes, which exceeds the maximum length of an IBM WebSphere MQ topic string. Otherwise, a topic string follows the same rules as WebSphere MQ topic strings; see Topic strings. The example sets the topic string MQTT Examples.

  9. Create a publication message.
    MqttMessage message = new MqttMessage(Example.publication.getBytes());

    The string "Hello World" is converted to a byte array and used to create an MqttMessage.

    • An MQTT message payload is always a byte array. The getBytes method converts a string object to UTF-8. The MqttMessage has a convenience toString method to return the message payload as a string. It is equivalent to new string(message.getPayload)
    • A publication message is sent to the queue manager with an RFH2 header, and the message data is sent as a jms-bytes message.
    • The message object has quality of service and retained attributes. The quality of service (QoS) determines how reliably the message is transferred between the MQTT client and the queue manager; see Qualities of service provided by an MQTT client. The retained attribute controls if a publication is stored by the queue manager for future subscribers. If a publication is not retained, it is sent only to current subscribers; see Retained publications and MQTT clients. The default MqttMessage settings are, Messages are delivered at least once, and are not retained.
  10. Connect to the server.
    client.connect();
    The example connects to the server using the default connection options. Once you connect, you can start publishing. The default connection options are:
    • A small "keep-alive" message is sent every 15 seconds to prevent the TCP/IP connection from being closed.
    • The session is started without checking for the completion of previous publications.
    • The interval between trying to send a message again is 15 seconds.
    • No last will and testament message is created for the connection.
    • The standard SocketFactory is used to create the connection.
    Change the connection options by creating a ConnectionOptions object and passing it as an additional parameter to client.connect.
  11. Publish.
    MqttDeliveryToken token = topic.publish(message);

    The example sends the "Hello World" publication on the topic "MQTT Examples" to the queue manager.

    • When the publish method returns, the message is safely transferred to the MQTT client, but not yet transferred to the server. If the message has QoS 1 or 2, then the message is stored locally, in case the client fails before delivery is completed.
    • publish returns a delivery token, which is used to check whether an acknowledgment has been received from the server yet.
  12. Wait for acknowledgment from the server.
    token.waitForCompletion(Example.timeout);
    The PubSync example waits for an acknowledgment from the server, which confirms the message has been delivered.
  13. Disconnect the client from the server.
    client.disconnect();

    The client disconnects from the server and waits for any MqttCallback methods that are running to finish. It then waits for up to 30 seconds to finish any remaining work. You can specify a quiesce timeout as an additional parameter.

  14. Save changes to PubSync.java and Example.Java

    Eclipse automatically compiles the Java. You are now ready to see the results by running the program.

Results

To see the publications using WebSphere MQ, create a topic, a queue, and a durable subscription, all called "MQTTExampleTopic" using the script in Figure 1. Run the client to publish on the MQTT Examples topic, and then run the sample program amqsbcg to browse the publications on the MQTTExamples queue.
  1. Start a queue manager, and start its telemetry (MQXR) service running. Make sure the TCP/IP address and port configured for the telemetry channel match the values you use in the MQTT application.
  2. Configure a durable subscription by creating the mqttexamples.txt command script, and running it using runmqsc:
    Figure 1. mqttExampleTopic.txt
    DEFINE TOPIC('MQTTExampleTopic') TOPICSTR('MQTT Example') REPLACE
    DEFINE QLOCAL('MQTTExampleQueue') REPLACE
    DEFINE SUB('MQTTExampleSub') DEST('MQTTExampleQueue') TOPICOBJ('MQTTExampleTopic') REPLACE
    To run the script on Windows, type the command:
    runmqsc queue manager name < mqttExampleTopic.txt
  3. Run the client as a Java application from within Eclipse, or by running Java in a command window:
    java -cp jar_dir\com.mq.micro.client.mqttv3.jar  
          com.ibm.mq.id.classname.class
    Note: The command window must be open in the directory containing the path, com\ibm\mq\id.
  4. Either browse the results using WebSphere MQ Explorer, or run the command:
    amqsbcg MQTTExampleQueue queue manager name

Example code

PubSync.java is a full listing of the code described in Procedure. Modify the Example class in Figure 3 to override the default parameters used in PubSync.java.

Figure 2. PubSync.java
package com.ibm.mq.id;
import com.ibm.micro.client.mqttv3.*;
public class PubSync {
  public static void main(String[] args) {
    try {
      MqttClient client = new MqttClient(Example.TCPAddress, Example.clientId);
      MqttTopic topic = client.getTopic(Example.topicString);
      MqttMessage message = new MqttMessage(Example.publication.getBytes());
      message.setQos(Example.QoS);
      client.connect();
      System.out.println("Waiting for up to " + Example.sleepTimeout / 1000
          + " seconds for publication of \"" + message.toString()
          + "\" with QoS = " + message.getQos());
      System.out.println("On topic \"" + topic.getName()
          + "\" for client instance: \"" + client.getClientId()
          + "\" on address " + client.getServerURI() + "\"");
      MqttDeliveryToken token = topic.publish(message);
      token.waitForCompletion(Example.sleepTimeout);
      System.out.println("Delivery token \"" + token.hashCode()
          + "\" has been received: " + token.isComplete());
      client.disconnect();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
Figure 3. Example.java
package com.ibm.mq.id;
import java.util.Properties;
import java.util.UUID;
public final class Example {
  public static final String          TCPAddress = 
    System.getProperty("TCPAddress", "tcp://localhost:1883");
  public static final String          SSLAddress = 
    System.getProperty("SSLAddress", "ssl://localhost:8883");
  public static final String            username =
    System.getProperty("username", System.getProperty("user.name"));
  public static final char []           password = 
    System.getProperty("password", "Password").toCharArray();
  public static String                  clientId = 
  String.format("%-23.23s", username  + "_" + 
    System.getProperty("clientId", 
    (UUID.randomUUID().toString())).trim()).replace('-', '_');
  public static final String         topicString = 
    System.getProperty("topicString", "MQTT Example");
  public static final String         publication = 
    System.getProperty("publication", "Hello World " + 
  String.format("%tc", System.currentTimeMillis()));
  public static final int         quiesceTimeout = 
    Integer.parseInt(System.getProperty("timeout", "10000"));
  public static final int           sleepTimeout = 
    Integer.parseInt(System.getProperty("timeout", "10000"));
  public static final boolean       cleanSession = 
    Boolean.parseBoolean(System.getProperty("cleanSession", "false"));
  public static final int                    QoS = 
    Integer.parseInt(System.getProperty("QoS", "1"));
  public static final boolean           retained = 
    Boolean.parseBoolean(System.getProperty("retained", "false"));
  public static final Properties getSSLSettings() {
    final Properties properties = new Properties();
    properties.setProperty("com.ibm.ssl.keyStore", 
        "C:\\IBM\\MQ\\Data\\ClientKeyStore.jks");
    properties.setProperty("com.ibm.ssl.keyStoreType", 
        "JKS");
    properties.setProperty("com.ibm.ssl.keyStorePassword", 
        "password");
    properties.setProperty("com.ibm.ssl.trustStore", 
        "C:\\IBM\\MQ\\Data\\ClientTrustStore.jks");
    properties.setProperty("com.ibm.ssl.trustStoreType", 
        "JKS");
    properties.setProperty("com.ibm.ssl.trustStorePassword", 
        "password");
    return properties;
  }
}