/*********************************************************************************** * * Copyright (c) 2014 Kamil Baczkowicz * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Eclipse Distribution License v1.0 which accompany this distribution. * * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * * The Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * * Kamil Baczkowicz - initial API and implementation and/or initial documentation * */ package pl.baczkowicz.mqttspy.utils; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import org.eclipse.paho.client.mqttv3.MqttTopic; import pl.baczkowicz.mqttspy.common.generated.ProtocolVersionEnum; import pl.baczkowicz.spy.exceptions.SpyException; /** * MQTT utilities. */ public class MqttUtils { /** TCP prefix. */ public final static String TCP_PREFIX = "tcp://"; /** SSL prefix. */ public final static String SSL_PREFIX = "ssl://"; /** WebSocket prefix. */ public final static String WS_PREFIX = "ws://"; /** Secure WebSocket prefix. */ public final static String SWS_PREFIX = "wss://"; /** Multi-level MQTT topic wildcard. */ public static final String MULTI_LEVEL_WILDCARD = "#"; /** Single-level MQTT topic wildcard. */ public static final String SINGLE_LEVEL_WILDCARD = "+"; /** MQTT topic level delimiter. */ public static final String TOPIC_DELIMITER = "/"; /** Max client length for MQTT 3.1. */ public static final int MAX_CLIENT_LENGTH_FOR_3_1 = 23; /** Client ID timestamp delimiter. */ private static final String CLIENT_ID_TIMESTAMP_DELIMITER = "_"; /** Client ID timestamp format. */ private static final String CLIENT_ID_TIMESTAMP_FORMAT = "HHmmssSSS"; /** Client ID timestamp SDF. */ private static final SimpleDateFormat CLIENT_ID_SDF = new SimpleDateFormat(CLIENT_ID_TIMESTAMP_FORMAT); /** * Removes last topic delimiter if present. * * @param topic Topic to remove the delimiter from * * @return Topic with removed delimiter */ public static String removeLastDelimiter(String topic) { if (topic.endsWith(TOPIC_DELIMITER)) { topic = topic.substring(0, topic.length() - TOPIC_DELIMITER.length()); } return topic; } /** * Generate client ID with timestamp. * * @param clientId The client ID to use as source * * @return The generated client ID */ public static String generateClientIdWithTimestamp(final String clientId, final ProtocolVersionEnum protocol) { final int addedLength = CLIENT_ID_TIMESTAMP_FORMAT.length() + CLIENT_ID_TIMESTAMP_DELIMITER.length(); final int index = clientId.lastIndexOf(CLIENT_ID_TIMESTAMP_DELIMITER); String newClientId = clientId; // for e.g. k-01; index = 1; added length = 3; length == 4 if (index >= 0 && (index + addedLength == newClientId.length())) { newClientId = newClientId.substring(0, index); } if (limitClientId(protocol) && newClientId.length() + addedLength > MAX_CLIENT_LENGTH_FOR_3_1) { newClientId = newClientId.substring(0, MAX_CLIENT_LENGTH_FOR_3_1 - addedLength); } newClientId = newClientId + CLIENT_ID_TIMESTAMP_DELIMITER + CLIENT_ID_SDF.format(new Date()); return newClientId; } public static boolean limitClientId(final ProtocolVersionEnum protocol) { if (ProtocolVersionEnum.MQTT_3_1.equals(protocol) || ProtocolVersionEnum.MQTT_DEFAULT.equals(protocol)) { return true; } return false; } /** * Completes the server URI with the TCP prefix if not present. * * @param brokerAddress The broker URL to complete * * @return Complete URL */ public static String getCompleteServerURI(final String brokerAddress, final boolean sslEnabled, final boolean websocket) { String serverURI = brokerAddress.replaceAll(TCP_PREFIX, "").replaceAll(SSL_PREFIX, "").replaceAll(WS_PREFIX, "").replaceAll(SWS_PREFIX, ""); if (sslEnabled && websocket) { serverURI = SWS_PREFIX + serverURI; } else if (sslEnabled && !websocket) { serverURI = SSL_PREFIX + serverURI; } else if (!sslEnabled && websocket) { serverURI = WS_PREFIX + serverURI; } else { serverURI = TCP_PREFIX + serverURI; } return serverURI; } public static boolean recordTopic(final String newTopic, final List<String> topics) { final boolean contains = topics.contains(newTopic); if (!contains) { topics.add(newTopic); return true; } return false; } public static void validateTopic(final String topic) throws SpyException { try { MqttTopic.validate(topic, true); } catch (Exception e) { throw new SpyException(e.getMessage(), e); } } }