it.sysdata.mqtt.service.impl.MqttLocalServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for it.sysdata.mqtt.service.impl.MqttLocalServiceImpl.java

Source

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package it.sysdata.mqtt.service.impl;

import com.liferay.mail.service.MailServiceUtil;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.mail.MailMessage;
import com.liferay.portal.kernel.messaging.Message;
import com.liferay.portal.kernel.messaging.MessageBusUtil;
import com.liferay.portal.kernel.util.PrefsPropsUtil;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.util.PortalUtil;

import it.sysdata.mqtt.service.base.MqttLocalServiceBaseImpl;
import it.sysdata.mqtt.util.ConfigUtil;
import it.sysdata.mqtt.util.PortletPropsKeys;
import it.sysdata.mqtt.util.PortletPropsValues;

import java.io.PrintWriter;
import java.io.StringWriter;

import javax.mail.internet.InternetAddress;

import javax.portlet.PortletPreferences;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

/**
 * The implementation of the mqtt local service.
 *
 * <p>
 * All custom service methods should be put in this class. Whenever methods are added, rerun ServiceBuilder to copy their definitions into the {@link it.sysdata.mqtt.service.MqttLocalService} interface.
 *
 * <p>
 * This is a local service. Methods of this service will not have security checks based on the propagated JAAS credentials because this service can only be accessed from within the same VM.
 * </p>
 *
 * @author @baxtheman
 * @see it.sysdata.mqtt.service.base.MqttLocalServiceBaseImpl
 * @see it.sysdata.mqtt.service.MqttLocalServiceUtil
 */
public class MqttLocalServiceImpl extends MqttLocalServiceBaseImpl implements MqttCallback {

    @Override
    public void applySubscriptionsList() throws MqttException, SystemException {

        String[] subscriptions = PrefsPropsUtil.getStringArray(PortletPropsKeys.MQTT_SUBSCRIPTIONS_LIST,
                StringPool.NEW_LINE, PortletPropsValues.MQTT_SUBSCRIPTIONS_ARRAY);

        if (_getInstance().isConnected()) {
            String[] topics = ConfigUtil.properties2topic(subscriptions);

            int[] qos = ConfigUtil.properties2qos(subscriptions);

            for (int i = 0; i < topics.length; i++) {
                subscribe(topics[i], qos[i]);
            }
        }
    }

    @Override
    public boolean connect() throws MqttException, SystemException {

        try {
            disconnect();

            String username = PrefsPropsUtil.getString(PortletPropsKeys.MQTT_BROKER_USERNAME,
                    PortletPropsValues.MQTT_BROKER_USERNAME);

            String password = PrefsPropsUtil.getString(PortletPropsKeys.MQTT_BROKER_PASSWORD,
                    PortletPropsValues.MQTT_BROKER_PASSWORD);

            int keepalive = PrefsPropsUtil.getInteger(PortletPropsKeys.MQTT_BROKER_KEEPALIVE,
                    PortletPropsValues.MQTT_BROKER_KEEPALIVE);

            MqttClient client = _getInstance();

            MqttConnectOptions options = new MqttConnectOptions();

            options.setCleanSession(true);
            options.setKeepAliveInterval(keepalive);

            if (Validator.isNotNull(username)) {
                options.setUserName(username);
                options.setPassword(password.toCharArray());
            }

            IMqttToken token = client.connectWithResult(options);

            _log.info("connected: " + client.getServerURI());

            applySubscriptionsList();

            _noRetry();

            // send event to message bus

            _notifyEvent(client, "connect");
        } catch (MqttException e) {
            _log.error(e);

            throw e;
        }

        return isConnected();
    }

    @Override
    public void connectionLost(Throwable e) {

        _log.error(e);

        // send message bus event

        _notifyEvent(null, "connectionLost", e);

        // send email alert

        _notityMail("connectionLost", e);

        // clear instance

        _clearInstance();

        // setup retry connection

        _setupRetry(e);
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {

        // not yet useful
    }

    @Override
    public boolean disconnect() throws MqttException, SystemException {

        MqttClient client = _getInstance();

        if (client.isConnected()) {
            client.disconnectForcibly();

            _log.info("close " + client.getServerURI());
        }

        // send event to message bus

        _notifyEvent(client, "disconnect");

        // clear client object

        _clearInstance();

        return true;
    }

    @Override
    public String getServerConnected() throws MqttException, SystemException {

        return _getInstance().getServerURI();
    }

    @Override
    public boolean isConnected() {

        try {
            return _getInstance().isConnected();
        } catch (SystemException | MqttException e) {
            _log.warn(e);
        }

        return false;
    }

    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {

        Message mb = new Message();

        mb.put("topic", topic);
        mb.put("qos", message.getQos());
        mb.put("retained", message.isRetained());

        String payload = new String(message.getPayload());

        mb.setPayload(payload);

        MessageBusUtil.sendMessage(PortletPropsValues.MQTT_MESSAGES_DESTINATION, mb);

        boolean logInfo = PrefsPropsUtil.getBoolean(PortletPropsKeys.MQTT_EVENTS_LOGINFO,
                PortletPropsValues.MQTT_EVENTS_LOGINFO);

        if (logInfo) {
            _log.info(String.format("arrived [%s,%s,%s] %s", topic, message.getQos(),
                    message.isRetained() ? "R" : "", payload));
        }
    }

    @Override
    public void publish(String topic, byte[] payload, int qos) throws MqttException, SystemException {

        _getInstance().publish(topic, payload, qos, false);

        boolean logInfo = PrefsPropsUtil.getBoolean(PortletPropsKeys.MQTT_EVENTS_LOGINFO,
                PortletPropsValues.MQTT_EVENTS_LOGINFO);

        if (logInfo) {
            _log.info(String.format("send [%s,%s] %s", topic, qos, payload));
        }
    }

    @Override
    public void publish(String topic, String payload, int qos) throws MqttException, SystemException {

        publish(topic, payload.getBytes(), qos);
    }

    @Override
    public void resetSubscriptionsList() throws MqttException, SystemException {

        String[] subscriptions = PrefsPropsUtil.getStringArray(PortletPropsKeys.MQTT_SUBSCRIPTIONS_LIST,
                StringPool.NEW_LINE, PortletPropsValues.MQTT_SUBSCRIPTIONS_ARRAY);

        if (_getInstance().isConnected()) {
            String[] topics = ConfigUtil.properties2topic(subscriptions);

            _getInstance().unsubscribe(topics);
        }
    }

    @Override
    public void subscribe(String topic, int qos) throws MqttException, SystemException {

        _getInstance().subscribe(topic, qos);

        boolean logInfo = PrefsPropsUtil.getBoolean(PortletPropsKeys.MQTT_EVENTS_LOGINFO,
                PortletPropsValues.MQTT_EVENTS_LOGINFO);

        if (logInfo) {
            _log.info("subscribe " + topic);
        }
    }

    private void _clearInstance() {

        _mqttClient = null;
    }

    private synchronized MqttClient _getInstance() throws MqttException, SystemException {

        if (_mqttClient == null) {
            String serverURI = PrefsPropsUtil.getString(PortletPropsKeys.MQTT_BROKER_URL,
                    PortletPropsValues.MQTT_BROKER_URL);

            String clientID = PrefsPropsUtil.getString(PortletPropsKeys.MQTT_BROKER_CLIENTID,
                    PortletPropsValues.MQTT_BROKER_CLIENTID);

            MemoryPersistence persistence = new MemoryPersistence();

            _mqttClient = new MqttClient(serverURI, clientID, persistence);

            _mqttClient.setCallback(this);
        }

        return _mqttClient;
    }

    private void _noRetry() {

        try {
            PortletPreferences portletPreferences = PrefsPropsUtil.getPreferences();

            portletPreferences.setValue(PortletPropsKeys.MQTT_ERRORS_RETRY_CONNECT, String.valueOf(false));

            portletPreferences.store();
        } catch (Exception e1) {
            _log.error(e1);
        }
    }

    private void _notifyEvent(MqttClient client, String event, Throwable e) {

        Message mb = new Message();

        mb.put("event", event);

        if (client != null) {
            mb.put("brokerUrl", client.getServerURI());
        }

        if (e != null) {
            mb.put("error", e.getMessage());
        }

        MessageBusUtil.sendMessage(PortletPropsValues.MQTT_EVENTS_DESTINATION, mb);
    }

    private void _notifyEvent(MqttClient client, String event) {

        _notifyEvent(client, event, null);
    }

    private void _notityMail(String context, Throwable e) {

        try {
            String errorMailTo = PrefsPropsUtil.getString(PortletPropsKeys.MQTT_ERRORS_SEND_MAIL_TO,
                    PortletPropsValues.MQTT_ERRORS_SEND_MAIL_TO);

            if (Validator.isNotNull(errorMailTo)) {
                MailMessage mailMessage = new MailMessage();

                long companyId = PortalUtil.getDefaultCompanyId();

                String fromAddress = PrefsPropsUtil.getString(companyId, PropsKeys.ADMIN_EMAIL_FROM_ADDRESS);

                mailMessage.setHTMLFormat(false);
                mailMessage.setTo(new InternetAddress(errorMailTo));
                mailMessage.setSubject(String.format("%s Mqtt connector error", PortalUtil.getComputerName()));
                mailMessage.setFrom(new InternetAddress(fromAddress));

                StringWriter sw = new StringWriter();
                PrintWriter pw = new PrintWriter(sw);
                e.printStackTrace(pw);

                mailMessage.setBody(String.format("context: %s\nerror: %s\n stacktrace:%s\n", context,
                        e.getMessage(), sw.toString()));

                MailServiceUtil.sendEmail(mailMessage);
            }
        } catch (Exception e1) {
            _log.error(e1);
        }
    }

    private void _setupRetry(Throwable e) {

        try {
            PortletPreferences portletPreferences = PrefsPropsUtil.getPreferences();

            portletPreferences.setValue(PortletPropsKeys.MQTT_ERRORS_RETRY_CONNECT, String.valueOf(true));

            portletPreferences.store();
        } catch (Exception e1) {
            _log.error(e);
        }
    }

    private static MqttClient _mqttClient;

    private static Log _log = LogFactoryUtil.getLog(MqttLocalServiceImpl.class);
}