com.solace.samples.cloudfoundry.javaapp.controller.SolaceController.java Source code

Java tutorial

Introduction

Here is the source code for com.solace.samples.cloudfoundry.javaapp.controller.SolaceController.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package com.solace.samples.cloudfoundry.javaapp.controller;

import com.solace.samples.cloudfoundry.javaapp.model.SimpleMessage;
import com.solace.samples.cloudfoundry.javaapp.model.SimpleSubscription;
import com.solacesystems.jcsmp.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PostConstruct;
import java.util.concurrent.atomic.AtomicInteger;

@RestController
public class SolaceController {

    private static final Log logger = LogFactory.getLog(SolaceController.class);

    private JCSMPSession session;
    private XMLMessageProducer producer;
    private TextMessage lastReceivedMessage;

    // Stats
    private final AtomicInteger numMessagesReceived = new AtomicInteger();
    private final AtomicInteger numMessagesSent = new AtomicInteger();

    private class SimplePublisherEventHandler implements JCSMPStreamingPublishEventHandler {
        @Override
        public void responseReceived(String messageID) {
            logger.info("Producer received response for msg: " + messageID);
        }

        @Override
        public void handleError(String messageID, JCSMPException e, long timestamp) {
            logger.error("Producer received error for msg: " + messageID + " - " + timestamp, e);
        }

    }

    private class SimpleMessageListener implements XMLMessageListener {

        @Override
        public void onReceive(BytesXMLMessage receivedMessage) {

            numMessagesReceived.incrementAndGet();

            if (receivedMessage instanceof TextMessage) {
                lastReceivedMessage = (TextMessage) receivedMessage;
                logger.info("Received message : " + lastReceivedMessage.getText());
            } else {
                logger.error("Received message that was not a TextMessage: " + receivedMessage.dump());
            }
        }

        @Override
        public void onException(JCSMPException e) {
            logger.error("Consumer received exception: %s%n", e);
        }
    }

    @PostConstruct
    public void init() {

        // Connect to Solace
        logger.info("************* Init Called ************");

        String vcapServices = System.getenv("VCAP_SERVICES");
        logger.info(vcapServices);

        // Need to parse the Solace HOST from VCAP Services
        if (vcapServices == null || vcapServices.equals("") || vcapServices.equals("{}")) {
            logger.error("The VCAP_SERVICES variable wasn't set in the environment. Aborting connection.");
            logger.info("************* Aborting Solace initialization!! ************");
            return;
        }

        JSONObject vcapServicesJson = new JSONObject(vcapServices);

        JSONArray solMessagingArray = vcapServicesJson.getJSONArray("solace-messaging");

        if (solMessagingArray == null) {
            logger.error("Did not find Solace provided messaging service \"solace-messaging\"");
            logger.info("************* Aborting Solace initialization!! ************");
            return;
        }

        logger.info("Number of provided bindings: " + solMessagingArray.length());

        // Get the first Solace credentials from the array
        JSONObject solaceCredentials = null;
        if (solMessagingArray.length() > 0) {
            solaceCredentials = solMessagingArray.getJSONObject(0);
            if (solaceCredentials != null) {
                solaceCredentials = solaceCredentials.getJSONObject("credentials");
            }
        }

        if (solaceCredentials == null) {
            logger.error("Did not find Solace messaging service credentials");
            logger.info("************* Aborting Solace initialization!! ************");
            return;
        }

        logger.info("Solace client initializing and using Credentials: " + solaceCredentials.toString(2));

        final JCSMPProperties properties = new JCSMPProperties();

        // The host property is in a json array. Two hosts are provided in a
        // High Availability environment,
        // one for the primary router and one for the backup.
        JSONArray hostsArray = solaceCredentials.getJSONArray("smfHosts");

        // Make a host list (for HA and non HA)
        String host = "";
        for (int i = 0; i < hostsArray.length(); i++) {
            String newHostEntry = hostsArray.getString(i);
            if (i > 0)
                host += ",";

            host += newHostEntry;
        }

        logger.info("Using host " + host);
        properties.setProperty(JCSMPProperties.HOST, host);

        // Must be using HA to have more than 1 host.
        if (hostsArray.length() > 1) {

            // A Sample for High Availability automatic reconnects.
            JCSMPChannelProperties channelProperties = (JCSMPChannelProperties) properties
                    .getProperty(JCSMPProperties.CLIENT_CHANNEL_PROPERTIES);
            channelProperties.setConnectRetries(1);
            channelProperties.setReconnectRetries(5);
            channelProperties.setReconnectRetryWaitInMillis(3000);
            channelProperties.setConnectRetriesPerHost(20);
        }

        properties.setProperty(JCSMPProperties.VPN_NAME, solaceCredentials.getString("msgVpnName"));
        properties.setProperty(JCSMPProperties.USERNAME, solaceCredentials.getString("clientUsername"));
        properties.setProperty(JCSMPProperties.PASSWORD, solaceCredentials.getString("clientPassword"));

        try {
            session = JCSMPFactory.onlyInstance().createSession(properties);
            session.connect();
        } catch (Exception e) {
            logger.error("Error connecting and setting up session.", e);
            logger.info("************* Aborting Solace initialization!! ************");
            return;
        }

        try {
            final XMLMessageConsumer cons = session.getMessageConsumer(new SimpleMessageListener());
            cons.start();

            producer = session.getMessageProducer(new SimplePublisherEventHandler());

            logger.info("************* Solace initialized correctly!! ************");
        } catch (Exception e) {
            logger.error("Error creating the consumer and producer.", e);
        }
    }

    @RequestMapping(value = "/message", method = RequestMethod.POST)
    public ResponseEntity<String> sendMessage(@RequestBody SimpleMessage message) {

        if (session == null || session.isClosed()) {
            logger.error("Session was null or closed, Could not send message");
            return new ResponseEntity<>("{'description': 'Somehow the session is not connected, please see logs'}",
                    HttpStatus.BAD_REQUEST);
        }

        logger.info("Sending message on topic: " + message.getTopic() + " with body: " + message.getBody());

        final Topic topic = JCSMPFactory.onlyInstance().createTopic(message.getTopic());
        TextMessage msg = JCSMPFactory.onlyInstance().createMessage(TextMessage.class);
        msg.setText(message.getBody());
        try {
            producer.send(msg, topic);
            numMessagesSent.incrementAndGet();

        } catch (JCSMPException e) {
            logger.error("Sending message failed.", e);
            return new ResponseEntity<>("{'description': '" + e.getMessage() + "'}", HttpStatus.BAD_REQUEST);
        }
        return new ResponseEntity<>("{}", HttpStatus.OK);
    }

    @RequestMapping(value = "/message", method = RequestMethod.GET)
    public ResponseEntity<SimpleMessage> getLastMessageReceived() {

        if (lastReceivedMessage != null) {
            logger.info("Sending the lastReceivedMessage");

            // Return the last received message if it exists.
            SimpleMessage receivedMessage = new SimpleMessage();

            receivedMessage.setTopic(lastReceivedMessage.getDestination().getName());
            receivedMessage.setBody(lastReceivedMessage.getText());
            return new ResponseEntity<>(receivedMessage, HttpStatus.OK);
        } else {
            logger.info("Sorry did not find a lastReceivedMessage");
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }

    }

    @RequestMapping(value = "/subscription", method = RequestMethod.POST)
    public ResponseEntity<String> addSubscription(@RequestBody SimpleSubscription subscription) {
        String subscriptionTopic = subscription.getSubscription();
        logger.info("Adding a subscription to topic: " + subscriptionTopic);

        final Topic topic = JCSMPFactory.onlyInstance().createTopic(subscriptionTopic);
        try {
            boolean waitForConfirm = true;
            session.addSubscription(topic, waitForConfirm);
        } catch (JCSMPException e) {
            logger.error("Adding a subscription failed.", e);
            return new ResponseEntity<>("{'description': '" + e.getMessage() + "'}", HttpStatus.BAD_REQUEST);
        }
        logger.info("Finished Adding a subscription to topic: " + subscriptionTopic);
        return new ResponseEntity<>("{}", HttpStatus.OK);
    }

    @RequestMapping(value = "/subscription", method = RequestMethod.DELETE)
    public ResponseEntity<String> deleteSubscription(@RequestBody SimpleSubscription subscription) {
        String subscriptionTopic = subscription.getSubscription();
        final Topic topic = JCSMPFactory.onlyInstance().createTopic(subscriptionTopic);
        logger.info("Deleting a subscription to topic: " + subscriptionTopic);

        try {
            boolean waitForConfirm = true;
            session.removeSubscription(topic, waitForConfirm);
        } catch (JCSMPException e) {
            logger.error("Deleting a subscription failed.", e);
            return new ResponseEntity<>("{'description': '" + e.getMessage() + "'}", HttpStatus.BAD_REQUEST);
        }
        logger.info("Finished Deleting a subscription to topic: " + subscriptionTopic);
        return new ResponseEntity<>("{}", HttpStatus.OK);
    }

    @RequestMapping(value = "/status", method = RequestMethod.GET)
    public ResponseEntity<String> getStatus() {

        logger.info("Received request for getStatus");

        JSONObject statusJson = new JSONObject();
        statusJson.put("numMsgsSent", numMessagesSent.get());
        statusJson.put("numMsgsReceived", numMessagesReceived.get());
        return new ResponseEntity<>(statusJson.toString(), HttpStatus.OK);
    }

    @RequestMapping(value = "/status", method = RequestMethod.DELETE)
    public ResponseEntity<String> resetStats() {
        numMessagesReceived.set(0);
        numMessagesSent.set(0);
        lastReceivedMessage = null;
        return new ResponseEntity<>("{}", HttpStatus.OK);
    }

}