Hello World!

7 Minute Read

Your first Solace app

Hello and welcome to your first Solace app tutorial. Appropriately, we'll be looking at the sample called "HelloWorld". At first glance, this application might seem longer than the first Java/Python/etc. program you might have ever written. E.g.:

public static void main(String... args) {
    System.out.println("Hello world!");
}

However, as you can tell from this Wikipedia article, there are many different types of "Hello World" programs. Rather than trying to do the bare minimum to produce some visual output, this Solace Hello World will demonstrate some very fundamental and basic features of Solace APIs and pub/sub messaging, and teach some best practices:

  • Publish and Subscribe: most Solace applications do both
  • Dynamic topics: topics are hierarchical and descriptive, not static
  • Wildcard subscriptions: attract multiple topics via a single subscription
  • Asynchronous messaging: use of callback handlers
  • Connection lifecycle management: connect once, and stay online for the lifetime of the app

This Hello World sample application will connect to a Solace PubSub+ Event Broker, and publish/subscribe in a loop. Let's begin!

Assumptions

This tutorial assumes the following:

  • You are familiar with Solace core concepts.

  • You have access to Solace messaging with the following configuration details:

    • Connectivity information for a Solace message-VPN
    • Enabled client username and password

One simple way to get access to Solace messaging quickly is to create a messaging service in Solace Cloud as outlined here. You can find other ways to get access to Solace messaging below.

Get Solace Messaging

This tutorial requires access Solace PubSub+ messaging and requires that you know several connectivity properties about your Solace messaging. Specifically you need to know the following:

Resources Value Description
Host String This is the address clients use when connecting to the PubSub+ messaging to send and receive messages. (Format: DNS_NAME:Port or IP:Port)
Message VPN String The PubSub+ message router Message VPN that this client should connect to.
Client Username String The client username. (See Notes below)
Client Password String The client password. (See Notes below)

There are several ways you can get access to PubSub+ Messaging and find these required properties.

Option 1: Use PubSub+ Cloud

  • Follow these instructions to quickly spin up a cloud-based PubSub+ messaging service for your applications.

  • The messaging connectivity information is found in the service details in the connectivity tab (shown below). You will need:

    • Host:Port (use the SMF URI)
    • Message VPN
    • Client Username
    • Client Password

Screenshot: Messaging Connectivity Information

Option 2: Start a PubSub+ Software

  • Follow these instructions to start the PubSub+ Software in leading Clouds, Container Platforms or Hypervisors. The tutorials outline where to download and how to install the PubSub+ Software.

  • The messaging connectivity information are the following:

    • Host: <public_ip> (IP address assigned to the VMR in tutorial instructions)

    • Message VPN: default

    • Client Username: sampleUser (can be any value)

    • Client Password: samplePassword (can be any value)

      Note: By default, the PubSub+ Software "default" message VPN has authentication disabled.

Option 3: Get access to a PubSub+ Appliance

  • Contact your PubSub+ appliance administrators and obtain the following:

    • A PubSub+ Message-VPN where you can produce and consume direct and persistent messages
    • The host name or IP address of the Solace appliance hosting your Message-VPN
    • A username and password to access the Solace appliance

Source Code

The full source code for this sample is available in the SolaceSamples GitHub repo.

Details on how to clone, build, and run the samples are all in the README.md file in the repo.

1. Command line arguments

The first couple lines of the program simply read connection parameters from the console:

    /** Simple application for doing pub/sub. */
    public static void main(String... args) throws IOException {
        if (args.length < 3) {  // Check command line arguments
            System.out.printf("Usage: %s <host:port> <message-vpn> <client-username> [password]%n", SAMPLE_NAME);
            System.out.printf("  e.g. %s localhost default default%n%n", SAMPLE_NAME);
            System.exit(-1);
        }

Specifically, for Solace Native (SMF) APIs, we need to know:

  • Broker / host IP address or hostname
    • E.g. localhost, 192.168.42.35, mr-abc123.messaging.solace.cloud
  • Message VPN: a virtual partition of a single broker, how Solace supports multitenancy
    • E.g. default, lab-vpn, cloud-demo-singapore
  • Username
    • E.g. default, testuser, solace-cloud-client
  • Password (optional)
    • This is for basic authentication, and would be different if using certificates or single-sign-on

2. Enter your name

This part is certainly not required in production applications, but allows Hello World to easily build a dynamic topic based on this input. It is also useful if running multiple instances of this application, to see them "talking" to each other, as we'll see later.

        // User prompt, what is your name??, to use in the topic
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String uniqueName = "";
        while (uniqueName.isEmpty()) {
            System.out.printf("Hello! Enter your name, or a unique word: ");
            uniqueName = reader.readLine().trim().replaceAll("\\s+", "_");  // clean up whitespace
        }

3. Connect to the Broker

The next few lines of Hello World initialize the connection parameters, as well as a few other properties that might be useful, and connects to the broker.

        final Properties properties = new Properties();
        properties.setProperty(TransportLayerProperties.HOST, args[0]);          // host:port
        properties.setProperty(ServiceProperties.VPN_NAME,  args[1]);     // message-vpn
        properties.setProperty(AuthenticationProperties.SCHEME_BASIC_USER_NAME, args[2]);      // client-username
        if (args.length > 3) {
            properties.setProperty(AuthenticationProperties.SCHEME_BASIC_PASSWORD, args[3]);  // client-password
        }
        properties.setProperty(ServiceProperties.RECEIVER_DIRECT_SUBSCRIPTION_REAPPLY, "true");  // subscribe Direct subs after reconnect

        final MessagingService messagingService = MessagingService.builder(ConfigurationProfile.V1)
                .fromProperties(properties).build().connect();  // blocking connect to the broker

4. Setup Producer

The "producer" or publisher in Solace APIs is the component that sends messages to the Solace broker. The producer can be configured to send both Direct and Guaranteed messages on the same session, as well as transactions and other qualities-of-service.

        // create and start the publisher 
        final DirectMessagePublisher publisher = messagingService.createDirectMessagePublisherBuilder()
                .onBackPressureWait(1).build().start();

The producer configuration options varies from API to API. For example, in JCSMP, you specify two callback handlers: these are mostly used for Guaranteed messaging applications, which we'll see later. As our Hello World app uses only Direct messaging, these are not as useful, but still need to be configured regardless. In Python or the PubSub+ Messaging API for Java, Direct publishers do not have to configure this.

5. Set Up Consumer

The next part of the sample sets up the ability to receive messages from the broker asynchronously - that is: the application does not have to poll the broker for the next message.

        // create and start the subscriber
        final DirectMessageReceiver receiver = messagingService.createDirectMessageReceiverBuilder()
                .withSubscriptions(TopicSubscription.of(TOPIC_PREFIX + "*/hello/>")).build().start();
        final MessageHandler messageHandler = (inboundMessage) -> {
            System.out.printf("vvv RECEIVED A MESSAGE vvv%n%s===%n",inboundMessage.dump());  // just print
        };
        receiver.receiveAsync(messageHandler);

As you can see, the "on receive" or "on message" callback does not do very much in this simple application, it simply outputs the message to the screen, and continues.

6. Add Direct message subscriptions

To receive messages from the broker, you have to tell it what you want to receive. To receive messages via Direct messaging, you add a (topic) subscription:

        // create and start the subscriber
        final DirectMessageReceiver receiver = messagingService.createDirectMessageReceiverBuilder()
                .withSubscriptions(TopicSubscription.of(TOPIC_PREFIX + "*/hello/>")).build().start();
        final MessageHandler messageHandler = (inboundMessage) -> {
            System.out.printf("vvv RECEIVED A MESSAGE vvv%n%s===%n",inboundMessage.dump());  // just print
        };
        receiver.receiveAsync(messageHandler);

Notice a few things:

  • The topic subscription is hierarchical: there are "/" characters between levels
  • The use of "*" and ">" wildcard characters in the subscription
  • Direct subscription (not using Guaranteed delivery yet)

These wildcards are called single-level and multi-level wildcards respectively. The "*" will match anything up to the next /, including the empty-string; for the multi-level, as long as the message's first part of the topic matches the subscription to that point, the ">" wildcard will match any remaining (one-or-more) levels. See here for more details on topics and on wildcards.

So, our Hello World app is adding a subscription: solace/samples/*/hello/>

After adding the only one subscription (you can add as many as you'd like, within the limits of the broker), start the Consumer object which tells the broker the API is ready to start to receive messages.

7. Publish and receive messages

Now we are ready to send some messages, and the subscription will allow us to receive those messages back. So in a loop, wait for some user input, and publish a message every 5 seconds:

        OutboundMessageBuilder messageBuilder = messagingService.messageBuilder();
        while (System.in.available() == 0 && !isShutdown) {  // loop now, just use main thread
            try {
                Thread.sleep(5000);  // take a pause
                // payload is our "hello world" message from you!
                OutboundMessage message = messageBuilder.build(String.format("Hello World from %s!",uniqueName));
                // make a dynamic topic: solace/samples/java/hello/[uniqueName]
                String topicString = TOPIC_PREFIX + API.toLowerCase() + "/hello/" + uniqueName.toLowerCase();
                System.out.printf(">> Calling send() on %s%n",topicString);
                publisher.publish(message, Topic.of(topicString));
            } catch (RuntimeException e) {
                System.out.printf("### Exception caught during producer.send(): %s%n",e);
                isShutdown = true;
            } catch (InterruptedException e) {
                // Thread.sleep() interrupted... probably getting shut down
            }
        }

Note that we specify the payload each loop (could be a text String, or a binary byte[] payload, etc.), as well as define what the message's published topic is. Recall: topics are not configured in the Solace broker, they are metadata of the message, and a pattern matching (via subscriptions) is done on each received message.

8. Run it again!

Running this application once by itself is ok to ensure you have broker connectivity, but event-driven technologies like Solace are all about decoupled distributed architectures: you need multiple applications to communicate asynchronously. So split your terminal, or get a second screen, and try running it again.

Note that you could run a different language for your 2nd instance, or even another protocol that Solace supports (e.g. REST, MQTT, AMQP 1.0). Just ensure your topics match the subscriptions.

Screenshot: Python HelloWorld app talking to the Java JCSMP HelloWorld app

Here is the Python HelloWorld app talking to the Java JCSMP HelloWorld app. Both are subscribed using wildcards, one subscription each, and they will match topics published by other API flavours: note the published topic for each is different (more for demonstration purposes than anything).

9. What's Next?

Got a handle on how a basic Solace native app sends and receives messages? Wondering what the next step is?

  • Higher performance publish-subscribe using Direct messages
  • Message payload transformation using Processor pattern
  • Request-Reply using blocking call (not everything needs to be asynchronous)
  • Guaranteed messaging publish-subscribe