In another post, we described a feature for conditional pub/sub message delivery using SQL selectors. With that (selector) approach, the publisher must attach headers to the message and the subscriber uses an SQL-based condition that references header names and values. In addition to selectors, Backendless supports another type of conditional delivery – subtopics.
Consider the following example:
A message with an announcement from Microsoft is published to the topic stocks.nasdaq.msft. Another message from IBM is published to stocks.nyse.ibm. Suppose a subscriber wants to receive all messages related to stock announcements. In this case, they subscribe to the stocks.* subtopic.
Another subscriber is interested in all Nasdaq announcements. That subscriber subscribes to the stocks.nasdaq.* subtopic. Finally, to receive Microsoft announcements, a subscriber would use the stocks.nasdaq.msft subtopic. As you can see, Backendless uses the federated subtopic structure for message filtering/delivery.
The sample below shows how to use subtopics in the Backendless messaging API:
Asynchronous API sample (Android and Plain Java):
AsyncCallback<MessageStatus> publishCallback = new AsyncCallback<MessageStatus>() { @Override public void handleResponse( MessageStatus messageStatus ) { System.out.println( "Message published - " + messageStatus.getMessageId() ); } @Override public void handleFault( BackendlessFault backendlessFault ) { System.out.println( "Server reported an error " + backendlessFault.getMessage() ); } }; while( true ) { // ********************************************************************************************************* // publish message 1 to subtopic "news.dallas.sports" // ********************************************************************************************************* NewsMessage newsMessage1 = new NewsMessage(); newsMessage1.teaser = "Dallas Cowboys project tab in Frisco: $168 million and climbing"; newsMessage1.details = "The price tag for the publicly owned portion of Dallas Cowboys development in Frisco has hit $168 million and continues to grow as the project takes shape"; newsMessage1.newsURL = "http://friscoblog.dallasnews.com/2015/03/dallas-cowboys-project-tab-in-frisco-168-million-and-climbing.html/"; PublishOptions publishOptions1 = new PublishOptions(); publishOptions1.setSubtopic( "news.dallas.sports" ); Backendless.Messaging.publish( "MyAppChannel", newsMessage1, publishOptions1, publishCallback ); // ********************************************************************************************************* // publish message 2 to subtopic "news.us.technology" // ********************************************************************************************************* NewsMessage newsMessage = new NewsMessage(); newsMessage.teaser = "Magic Leap Demo Flaunts Augmented Reality"; newsMessage.details = "In the latest \"OMG, I want one!\" news, startup Magic Leap on Thursday teased its advanced augmented reality tech"; newsMessage.newsURL = "http://www.pcmag.com/article2/0,2817,2478526,00.asp"; PublishOptions publishOptions2 = new PublishOptions(); publishOptions2.setSubtopic( "news.us.technology" ); Backendless.Messaging.publish( "MyAppChannel", newsMessage, publishOptions2, publishCallback ); Thread.sleep( 500 ); }
Synchronous API sample (Plain Java only):
while( true ) { // ********************************************************************************************************* // publish message 1 to subtopic "news.dallas.sports" // ********************************************************************************************************* NewsMessage newsMessage1 = new NewsMessage(); newsMessage1.teaser = "Dallas Cowboys project tab in Frisco: $168 million and climbing"; newsMessage1.details = "The price tag for the publicly owned portion of Dallas Cowboys development in Frisco has hit $168 million and continues to grow as the project takes shape"; newsMessage1.newsURL = "http://friscoblog.dallasnews.com/2015/03/dallas-cowboys-project-tab-in-frisco-168-million-and-climbing.html/"; PublishOptions publishOptions1 = new PublishOptions(); publishOptions1.setSubtopic( "news.dallas.sports" ); MessageStatus messageStatus = Backendless.Messaging.publish( "MyAppChannel", newsMessage1, publishOptions1 ); System.out.println( "Message published - " + messageStatus.getMessageId() ); // ********************************************************************************************************* // publish message 2 to subtopic "news.us.technology" // ********************************************************************************************************* NewsMessage newsMessage = new NewsMessage(); newsMessage.teaser = "Magic Leap Demo Flaunts Augmented Reality"; newsMessage.details = "In the latest \"OMG, I want one!\" news, startup Magic Leap on Thursday teased its advanced augmented reality tech"; newsMessage.newsURL = "http://www.pcmag.com/article2/0,2817,2478526,00.asp"; PublishOptions publishOptions2 = new PublishOptions(); publishOptions2.setSubtopic( "news.us.technology" ); messageStatus = Backendless.Messaging.publish( "MyAppChannel", newsMessage, publishOptions2 ); System.out.println( "Message published - " + messageStatus.getMessageId() ); Thread.sleep( 500 ); }
The code above publishes two messages to the news.dallas.sports and news.us.technology topics. Also, notice the published message is a custom strongly-typed object (as opposed to a primitive data type or a string). The code below subscribes to receive messages published to the news.* subtopic.
When you run that code, it will receive both messages from the publisher. However, if you modify the subscriber to receive messages from the news.us.* subtopic, it will receive only one of them (repeatedly, though, as the messages are published in a loop):
AsyncCallback<List<Message>> subscriptionResponder = new AsyncCallback<List<Message>>() { @Override public void handleResponse( List<Message> messages ) { Iterator<Message> messageIterator = messages.iterator(); while( messageIterator.hasNext() ) { Message message = messageIterator.next(); NewsMessage newsMessage = (NewsMessage) message.getData(); System.out.println( String.format( "Received message - %s\n\tHeadline - %s\n\tDetails - %s\n\tURL - %s", message.getMessageId(), newsMessage.teaser, newsMessage.details, newsMessage.newsURL ) ); } } @Override public void handleFault( BackendlessFault backendlessFault ) { System.out.println( "Server reported an error " + backendlessFault.getMessage() ); } }; SubscriptionOptions subscriptionOptions = new SubscriptionOptions(); subscriptionOptions.setSubtopic( "news.*" ); Backendless.Messaging.subscribe( "MyAppChannel", subscriptionResponder, subscriptionOptions );
Enjoy!