|
| 1 | +--- |
| 2 | +title: Create an Application for Sending and Receiving Messages using Java based client |
| 3 | +description: Develop and deploy a basic Java based messaging application for sending and receiving messages to a queue. |
| 4 | +time: 45 |
| 5 | +auto_validation: true |
| 6 | +tags: [ tutorial>intermediate, topic>java, products>sap-business-technology-platform, tutorial>license] |
| 7 | +primary_tag: products>sap-event-mesh |
| 8 | +--- |
| 9 | + |
| 10 | +## Prerequisites |
| 11 | +- Installed Java 8 -> [Java download](https://www.java.com/en/download/) |
| 12 | +- Installed Maven 3.x -> [Maven download](https://maven.apache.org/download.cgi) |
| 13 | +- Installed Git -> [Git download](https://git-scm.com/downloads) |
| 14 | +- Follow [Create Instance of SAP Event Mesh Service](cp-enterprisemessaging-instance-create) and follow [Create Queues and Queue Subscriptions for Event Mesh](cp-enterprisemessaging-queue-queuesubscription) to create a queue in an instance of Event Mesh. |
| 15 | +- Follow [Install the Cloud Foundry Command Line Interface(CLI)](cp-cf-download-cli) to download and work with CLI. |
| 16 | + |
| 17 | +## Recommended |
| 18 | +- Installed IDE of choice (e.g. [Visual Studio](https://code.visualstudio.com/) with installed [Java language support](https://marketplace.visualstudio.com/items?itemName=redhat.java) plug in) |
| 19 | + |
| 20 | +## Details |
| 21 | +### You will learn |
| 22 | + - How to create a basic messaging client application with Java, using combinations of vanilla Java, Spring, and JMS for sending messages to a queue |
| 23 | + - How to deploy this application to the SAP Event Mesh and test it |
| 24 | + |
| 25 | + |
| 26 | +--- |
| 27 | + |
| 28 | +[ACCORDION-BEGIN [Step 1: ](Setup the environment)] |
| 29 | + |
| 30 | + |
| 31 | +| Application | Scenario Description |
| 32 | +| :----------------------------------- | :----------------------------------------------------------------- |
| 33 | +| emjapi-samples-jms-p2p | This sample demonstrates how messages can be sent |
| 34 | +| (Point to Point communication) | and received from an application deployed on SAP Business Technology Platform. |
| 35 | +| | Therefore the messaging sample provides a Spring |
| 36 | +| | Boot based application which provides REST |
| 37 | +| | endpoints for sending and receiving messages via a |
| 38 | +| | queue (or queues) of choice. The REST endpoints |
| 39 | +| | are provided via the `MessagingServiceRestController`. |
| 40 | + |
| 41 | + |
| 42 | +| Application | Scenario Description |
| 43 | +| :----------------------------------- | :----------------------------------------------------------------- |
| 44 | +| emjapi-samples-jms-pubsub | This sample demonstrates how messages can be sent and |
| 45 | +| (Publish & Subscribe) | received to a topic from an application deployed on SAP Business Technology Platform. |
| 46 | +| | This messaging sample provides a Spring Boot |
| 47 | +| | based application which provides REST endpoints for sending |
| 48 | +| | and receiving messages via a topic of choice. It also |
| 49 | +| | offers a REST endpoint to receive a message from a queue. |
| 50 | +| | The REST endpoints are provided via the |
| 51 | +| | `MessagingServiceRestController`. |
| 52 | + |
| 53 | +To download and install the samples, just clone the repository via: |
| 54 | + [git clone](https://github.com/SAP/enterprise-messaging-client-java-samples) |
| 55 | + |
| 56 | +This downloads both the scenarios to your local IDE and the structure is as follows: |
| 57 | +  |
| 58 | + |
| 59 | +The downloaded project has all the dependencies and required client files for both scenarios mentioned above. |
| 60 | +The Event Mesh service descriptor is `/config/em-config-default.json`. Detailed information on different parameters of the |
| 61 | +descriptor can be found in [Create Instance of SAP Event Mesh](cp-enterprisemessaging-instance-create). |
| 62 | + |
| 63 | +Replace the content in the json file with the content of the descriptor in the service instance you have created. |
| 64 | + |
| 65 | +[DONE] |
| 66 | +[ACCORDION-END] |
| 67 | + |
| 68 | +[ACCORDION-BEGIN [Step 2: ](Understand the dependencies)] |
| 69 | +To be able to build, deploy and run the Java message client, ensure the following dependencies are mentioned in the pom.xml. |
| 70 | + |
| 71 | +- enterprise-messaging spring service connector that provides the `MessagingService` |
| 72 | +- enterprise-messaging core that creates the connection factory |
| 73 | +- enterprise-messaging JMS extension that provides the `MessagingServiceJmsConnectionFactory` |
| 74 | + |
| 75 | +```POM.XML |
| 76 | +<dependency> |
| 77 | + <groupId>com.sap.cloud.servicesdk.xbem</groupId> |
| 78 | + <artifactId>emjapi-connector-sap-cp</artifactId> |
| 79 | + <version>${version.xbem.client}</version> |
| 80 | +</dependency> |
| 81 | + |
| 82 | +<dependency> |
| 83 | + <groupId>com.sap.cloud.servicesdk.xbem</groupId> |
| 84 | + <artifactId>emjapi-core</artifactId> |
| 85 | + <version>${version.xbem.client}</version> |
| 86 | +</dependency> |
| 87 | + |
| 88 | +<dependency> |
| 89 | + <groupId>com.sap.cloud.servicesdk.xbem</groupId> |
| 90 | + <artifactId>emjapi-extension-sap-cp-jms</artifactId> |
| 91 | + <version>${version.xbem.client}</version> |
| 92 | +</dependency> |
| 93 | + |
| 94 | +``` |
| 95 | + |
| 96 | +[VALIDATE_1] |
| 97 | +[ACCORDION-END] |
| 98 | + |
| 99 | +[ACCORDION-BEGIN [Step 3: ](Code Snippets - common for both examples)] |
| 100 | + |
| 101 | +Open the manifest.yml file for the projects and make changes to the following parameters: |
| 102 | + - applications: |
| 103 | + `-` name: *<<Customized name of choice. Should be unique for a space of SCP>>* |
| 104 | + - services: |
| 105 | + `-` *<<name of the SAP Event Mesh instance>>* |
| 106 | + |
| 107 | + |
| 108 | +- Get the `MessagingService` |
| 109 | + |
| 110 | +``` |
| 111 | +ServiceConnectorConfig config = null; // currently there are no configurations for the MessagingServiceFactory supported |
| 112 | +Cloud cloud = new CloudFactory().getCloud(); |
| 113 | +// get a messaging service factory via the service connector |
| 114 | +MessagingService messagingService = cloud.getSingletonServiceConnector(MessagingService.class, config); |
| 115 | +
|
| 116 | +``` |
| 117 | + |
| 118 | +- Create a `MessagingServiceFactory` object with the help of `MessagingServiceFactoryCreator` and get a `MessagingServiceJmsConnectionFactory`. |
| 119 | +The Connection Factory can be configured with the `MessagingServiceJmsSettings`. In case the reconnection feature is not needed and an individual |
| 120 | +connection mechanism (for example, through a connection cache) is used these settings can be skipped. The connection factory can be built with `messagingServiceFactory.createConnectionFactory(MessagingServiceJmsConnectionFactory.class,settings)`. |
| 121 | + |
| 122 | +``` |
| 123 | +MessagingServiceJmsSettings settings = new MessagingServiceJmsSettings(); // settings are preset with default values (see JavaDoc) |
| 124 | +settings.setMaxReconnectAttempts(5); // use -1 for unlimited attempts |
| 125 | +settings.setInitialReconnectDelay(3000); |
| 126 | +settings.setReconnectDelay(3000); |
| 127 | +MessagingServiceFactory messagingServiceFactory = MessagingServiceFactoryCreator.createFactory(messagingService); |
| 128 | +MessagingServiceJmsConnectionFactory connectionFactory = messagingServiceFactory.createConnectionFactory(MessagingServiceJmsConnectionFactory.class, settings) |
| 129 | +
|
| 130 | +``` |
| 131 | +- Create a connection and a session |
| 132 | + |
| 133 | +``` |
| 134 | +Connection connection = connectionFactory.createConnection(); |
| 135 | +Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)); |
| 136 | +``` |
| 137 | + |
| 138 | +[DONE] |
| 139 | +[ACCORDION-END] |
| 140 | + |
| 141 | +[ACCORDION-BEGIN [Step 4: ](Code Snippets - Point to Point communication)] |
| 142 | +### Sending |
| 143 | + |
| 144 | +Open the `MessagingServiceRestController.java` source code. Change the value of `QUEUE_PATH` based on the values of the instance you created. |
| 145 | + |
| 146 | + `private static final String QUEUE_PATH = "queue/{queueName}";` |
| 147 | + |
| 148 | +For sending messages a Connection and a Session are required first. Note that those resources must be closed if they are not needed anymore. As those objects |
| 149 | +are implementing the `autoclosable` interface they will be closed automatically after the try-catch-block. Now a `BytesMessage` can be created. In the next |
| 150 | +steps a queue is bound to a producer. The queue must be created on the broker first (via for example, the UI or MM API). Note that the prefix "queue:" is |
| 151 | +mandatory. Finally, the message can be sent to the queue. |
| 152 | + |
| 153 | +``` |
| 154 | +try ( |
| 155 | + Connection connection = connectionFactory.createConnection(); |
| 156 | + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)) { |
| 157 | + connection.start(); |
| 158 | + BytesMessage byteMessage = session.createBytesMessage(); |
| 159 | + byteMessage.writeBytes(message.getBytes()); |
| 160 | + Queue queue = session.createQueue("queue:" + "<queue-name>"); // even though the JMS API is "createQueue" the queue will not be created on the message broker |
| 161 | + MessageProducer producer = session.createProducer(queue); |
| 162 | + producer.send(byteMessage); |
| 163 | +} catch (JMSException e) { |
| 164 | + LOG.error("Could not send message={}.", message, e); |
| 165 | +} |
| 166 | +``` |
| 167 | +### Receiving |
| 168 | +In this example a consumer is listening to a queue. Again a Connection and a Session are required. Note that those resources must be closed if they are not |
| 169 | +needed anymore. First a queue with the mandatory prefix "queue:" is bound to a consumer. Since the messages are sent as a `ByteMassage`, the message needs to be |
| 170 | +converted to say a String. |
| 171 | +``` |
| 172 | +try (Connection connection = connectionFactory.createConnection();Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)) { |
| 173 | + connection.start(); |
| 174 | + Queue queue = session.createQueue(QUEUE_PREFIX + queueName); // see comments above |
| 175 | + MessageConsumer consumer = session.createConsumer(queue); |
| 176 | + BytesMessage message = (BytesMessage) consumer.receive(); // Blocking call. Define a timeout or use a Message Listener |
| 177 | + byte[] byteData = new byte[(int) message.getBodyLength()]; |
| 178 | + message.readBytes(byteData); |
| 179 | +} catch (JMSException e) { |
| 180 | + LOG.error("Could not receive message.", e); |
| 181 | +} |
| 182 | +
|
| 183 | +``` |
| 184 | + |
| 185 | +[DONE] |
| 186 | +[ACCORDION-END] |
| 187 | + |
| 188 | +[ACCORDION-BEGIN [Step 5: ](Code Snippets - Publish & Subscribe)] |
| 189 | + |
| 190 | +Open the `MessageingServiceRestController.java` source code. Change the value of `TOPIC_PATH` & `QUEUE_PATH` based on the values of the instance you created. |
| 191 | + |
| 192 | + `private static final String TOPIC_PATH = "topic/{topicName}"; |
| 193 | + private static final String QUEUE_PATH = "queue/{queueName}";` |
| 194 | + |
| 195 | +### Sending |
| 196 | +For sending messages a Connection and a Session are required first. Note that those resources must be closed if they are not needed anymore. As those objects are |
| 197 | +implementing the `autoclosable` interface they will be closed automatically after the try-catch-block. Now a `BytesMessage` can be created. In the next steps, |
| 198 | +a topic is bound (not created) to a producer. Note, that the prefix "topic:" is mandatory. Finally, the message can be sent to the topic. |
| 199 | +``` |
| 200 | +try ( |
| 201 | + Connection connection = connectionFactory.createConnection(); |
| 202 | + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)) { |
| 203 | + connection.start(); |
| 204 | + Topic topic = session.createTopic("topic:" + "<topic-name>"); |
| 205 | + BytesMessage byteMessage = session.createBytesMessage(); |
| 206 | + byteMessage.writeBytes(message.getBytes()); |
| 207 | + MessageProducer producer = session.createProducer(topic); |
| 208 | + producer.send(byteMessage); |
| 209 | +} catch (JMSException e) { |
| 210 | + LOG.error("Could not send message={}.", message, e); |
| 211 | +} |
| 212 | +``` |
| 213 | +### Receiving |
| 214 | +Currently, direct topic subscription is *not supported for the default plan*. In this example, a consumer is subscribed to a specific topic. Again a Connection |
| 215 | +and a Session are needed. Note that those resources must be closed if they are not needed anymore. First a topic (not created) with the mandatory prefix "topic:" |
| 216 | +is bound to consumer. Since the messages are sent as a `ByteMessage` the message needs to be converted to say a String |
| 217 | + |
| 218 | +``` |
| 219 | +try ( |
| 220 | + Connection connection = connectionFactory.createConnection(); |
| 221 | + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)) { |
| 222 | + connection.start(); |
| 223 | + Topic topic = session.createTopic(TOPIC_PREFIX + topicName); |
| 224 | + MessageConsumer consumer = session.createConsumer(topic); |
| 225 | + // Blocking call. Define a timeout or use a Message Listener |
| 226 | + BytesMessage message = (BytesMessage) consumer.receive(); |
| 227 | + byte[] byteData = new byte[(int) message.getBodyLength()]; |
| 228 | + message.readBytes(byteData); |
| 229 | +} catch (JMSException e) { |
| 230 | + LOG.error("Could not receive message.", e); |
| 231 | +} |
| 232 | +``` |
| 233 | + |
| 234 | +[DONE] |
| 235 | +[ACCORDION-END] |
| 236 | + |
| 237 | +[ACCORDION-BEGIN [Step 6: ](Build & Deploy)] |
| 238 | +- Build the project with maven (`maven clean install`) |
| 239 | +- Push it to Cloud Foundry via `cf push` using CLI from the folder where the executable is available. |
| 240 | +- After successful deployment, follow [Send and Receive Test Event Mesh](cp-enterprisemessaging-test-queue-sendreceive) to test sending and receiving of message using the Java client. |
| 241 | + |
| 242 | +[VALIDATE_2] |
| 243 | +[ACCORDION-END] |
| 244 | + |
| 245 | + |
| 246 | +--- |
0 commit comments