Refactored the disconenct and clean of session to use new ClientSession

This commit is contained in:
andsel
2015-11-08 18:42:03 +01:00
parent 635c87389d
commit 19dac6e32b
21 changed files with 239 additions and 264 deletions
@@ -15,18 +15,21 @@
*/
package org.eclipse.moquette.server;
import org.eclipse.moquette.server.config.IConfig;
import java.io.File;
import java.util.Properties;
import static org.eclipse.moquette.commons.Constants.DEFAULT_MOQUETTE_STORE_MAP_DB_FILENAME;
import static org.eclipse.moquette.commons.Constants.PERSISTENT_STORE_PROPERTY_NAME;
import static org.junit.Assert.assertFalse;
/**
* Used to carry integration configurations.
*
* Created by andrea on 4/7/15.
*/
class IntegrationUtils {
public class IntegrationUtils {
static String localMapDBPath() {
String currentDir = System.getProperty("user.dir");
return currentDir + File.separator + DEFAULT_MOQUETTE_STORE_MAP_DB_FILENAME;
@@ -37,4 +40,19 @@ class IntegrationUtils {
testProperties.put(PERSISTENT_STORE_PROPERTY_NAME, IntegrationUtils.localMapDBPath());
return testProperties;
}
public static void cleanPersistenceFile(IConfig config) {
String fileName = config.getProperty(PERSISTENT_STORE_PROPERTY_NAME);
cleanPersistenceFile(fileName);
}
public static void cleanPersistenceFile(String fileName) {
File dbFile = new File(fileName);
if (dbFile.exists()) {
dbFile.delete();
new File(fileName + ".p").delete();
new File(fileName + ".t").delete();
}
assertFalse(dbFile.exists());
}
}
@@ -62,9 +62,6 @@ public class ServerIntegrationFuseTest {
@After
public void tearDown() throws Exception {
// if (m_mqtt.isConnected()) {
// m_mqtt.disconnect();
// }
if (m_subscriber != null) {
m_subscriber.disconnect();
}
@@ -74,10 +71,7 @@ public class ServerIntegrationFuseTest {
}
m_server.stopServer();
File dbFile = new File(m_config.getProperty(PERSISTENT_STORE_PROPERTY_NAME));
if (dbFile.exists()) {
dbFile.delete();
}
IntegrationUtils.cleanPersistenceFile(m_config);
}
@Test
@@ -30,7 +30,6 @@ import java.io.File;
import java.io.IOException;
import java.util.Properties;
import static org.eclipse.moquette.commons.Constants.*;
import static org.junit.Assert.*;
public class ServerIntegrationPahoTest {
@@ -83,11 +82,7 @@ public class ServerIntegrationPahoTest {
private void stopServer() {
m_server.stopServer();
File dbFile = new File(m_config.getProperty(PERSISTENT_STORE_PROPERTY_NAME));
if (dbFile.exists()) {
dbFile.delete();
}
assertFalse(dbFile.exists());
IntegrationUtils.cleanPersistenceFile(m_config);
}
@Test
@@ -159,7 +154,7 @@ public class ServerIntegrationPahoTest {
m_client.connect();
m_client.publish("/topic", "Test my payload".getBytes(), 0, false);
assertNull(m_callback.getMessage(false));
assertEquals("Test my payload", new String(m_callback.getMessage(false).getPayload()));
}
@Test
@@ -265,7 +260,7 @@ public class ServerIntegrationPahoTest {
assertEquals("Hello MQTT", m_callback.getMessage(true).toString());
}
@Test
public void checkReceivePublishedMessage_after_a_reconnect_with_notCleanSession() throws Exception {
LOG.info("*** checkReceivePublishedMessage_after_a_reconnect_with_notCleanSession ***");
@@ -274,19 +269,19 @@ public class ServerIntegrationPahoTest {
m_client.connect(options);
m_client.subscribe("/topic", 1);
m_client.disconnect();
m_client.connect(options);
m_client.subscribe("/topic", 1);
//publish a QoS 1 message another client publish a message on the topic
publishFromAnotherClient("/topic", "Hello MQTT".getBytes(), 1);
publishFromAnotherClient("/topic", "Hello MQTT".getBytes(), 1);
//Verify that after a reconnection the client receive the message
MqttMessage message = m_callback.getMessage(true);
assertNotNull(message);
assertEquals("Hello MQTT", message.toString());
}
private void publishFromAnotherClient(String topic, byte[] payload, int qos) throws Exception {
IMqttClient anotherClient = new MqttClient("tcp://localhost:1883", "TestClientPUB", s_pubDataStore);
anotherClient.connect();
@@ -307,7 +302,7 @@ public class ServerIntegrationPahoTest {
publishFromAnotherClient("/topic", "Hello MQTT".getBytes(), 2);
m_callback.reinit();
m_client.connect(options);
MqttMessage message = m_callback.getMessage(true);
assertEquals("Hello MQTT", message.toString());
assertEquals(2, message.getQos());
@@ -326,13 +321,13 @@ public class ServerIntegrationPahoTest {
publishFromAnotherClient("/topic", "Hello MQTT".getBytes(), 2);
m_callback.reinit();
m_client.connect(options);
assertNotNull(m_callback);
MqttMessage message = m_callback.getMessage(true);
assertNotNull(message);
assertEquals("Hello MQTT", message.toString());
}
@Test
public void avoidMultipleNotificationsAfterMultipleReconnection_cleanSessionFalseQoS1() throws Exception {
LOG.info("*** avoidMultipleNotificationsAfterMultipleReconnection_cleanSessionFalseQoS1, issue #16 ***");
@@ -341,20 +336,20 @@ public class ServerIntegrationPahoTest {
m_client.connect(options);
m_client.subscribe("/topic", 1);
m_client.disconnect();
publishFromAnotherClient("/topic", "Hello MQTT 1".getBytes(), 1);
m_callback.reinit();
m_client.connect(options);
assertNotNull(m_callback);
MqttMessage message = m_callback.getMessage(true);
assertNotNull(message);
assertEquals("Hello MQTT 1", message.toString());
m_client.disconnect();
//publish other message
publishFromAnotherClient("/topic", "Hello MQTT 2".getBytes(), 1);
//reconnect the second time
m_callback.reinit();
m_client.connect(options);
@@ -34,7 +34,6 @@ import java.io.File;
import java.io.IOException;
import java.util.Properties;
import static org.eclipse.moquette.commons.Constants.PERSISTENT_STORE_PROPERTY_NAME;
import static org.junit.Assert.assertEquals;
/**
@@ -78,8 +77,6 @@ public class ServerIntegrationQoSValidationTest {
m_subscriber.connect();
m_publisher = new MqttClient("tcp://localhost:1883", "Publisher", s_pubDataStore);
// m_callback = new TestCallback();
// m_subscriber.setCallback(m_callback);
m_publisher.connect();
}
@@ -94,10 +91,7 @@ public class ServerIntegrationQoSValidationTest {
}
m_server.stopServer();
File dbFile = new File(m_config.getProperty(PERSISTENT_STORE_PROPERTY_NAME));
if (dbFile.exists()) {
dbFile.delete();
}
IntegrationUtils.cleanPersistenceFile(m_config);
}
@Test
@@ -66,10 +66,7 @@ public class ServerIntegrationWebSocketTest {
client.stop();
m_server.stopServer();
File dbFile = new File(m_config.getProperty(PERSISTENT_STORE_PROPERTY_NAME));
if (dbFile.exists()) {
dbFile.delete();
}
IntegrationUtils.cleanPersistenceFile(m_config);
}
@Test
@@ -73,10 +73,7 @@ public class ServerLowlevelMessagesIntegrationTests {
Thread.sleep(300); //to let the close event pass before server stop event
m_server.stopServer();
LOG.debug("After asked server to stop");
File dbFile = new File(m_config.getProperty(PERSISTENT_STORE_PROPERTY_NAME));
if (dbFile.exists()) {
dbFile.delete();
}
IntegrationUtils.cleanPersistenceFile(m_config);
}
@Test
@@ -21,15 +21,9 @@ import org.fusesource.mqtt.client.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import static org.eclipse.moquette.commons.Constants.PERSISTENT_STORE_PROPERTY_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@@ -38,8 +32,7 @@ import static org.junit.Assert.assertNull;
* @author andrea
*/
public class ServerRestartIntegrationTest {
private static Logger LOG = LoggerFactory.getLogger(ServerRestartIntegrationTest.class);
Server m_server;
MQTT m_mqtt;
BlockingConnection m_subscriber;
@@ -74,10 +67,7 @@ public class ServerRestartIntegrationTest {
}
m_server.stopServer();
File dbFile = new File(m_config.getProperty(PERSISTENT_STORE_PROPERTY_NAME));
if (dbFile.exists()) {
dbFile.delete();
}
IntegrationUtils.cleanPersistenceFile(m_config);
}
@@ -93,11 +83,8 @@ public class ServerRestartIntegrationTest {
//shutdown the server
m_server.stopServer();
File dbFile = new File(m_config.getProperty(PERSISTENT_STORE_PROPERTY_NAME));
if (dbFile.exists()) {
dbFile.delete();
}
IntegrationUtils.cleanPersistenceFile(m_config);
//restart the server
m_server.startServer(IntegrationUtils.prepareTestPropeties());
@@ -38,7 +38,7 @@ class TestCallback implements MqttCallback {
throw new IllegalStateException("Elapsed the timeout to get the result");
}
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
e.printStackTrace();
}
return m_message;
}
@@ -47,7 +47,7 @@ class TestCallback implements MqttCallback {
try {
m_latch.await(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
e.printStackTrace();
}
return m_topic;
}
@@ -59,7 +59,6 @@ class TestCallback implements MqttCallback {
}
public void connectionLost(Throwable cause) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void messageArrived(String topic, MqttMessage message) throws Exception {
@@ -69,6 +68,5 @@ class TestCallback implements MqttCallback {
}
public void deliveryComplete(IMqttDeliveryToken token) {
//To change body of implemented methods use File | Settings | File Templates.
}
}
@@ -18,11 +18,11 @@ package org.eclipse.moquette.spi.impl;
import java.nio.ByteBuffer;
import java.util.*;
import jdk.nashorn.internal.objects.NativeJava;
import org.eclipse.moquette.spi.ClientSession;
import org.eclipse.moquette.spi.IMatchingCondition;
import org.eclipse.moquette.spi.IMessagesStore;
import org.eclipse.moquette.spi.impl.events.PublishEvent;
import org.eclipse.moquette.spi.persistence.MemorySessionStore;
import org.eclipse.moquette.spi.impl.subscriptions.Subscription;
import org.eclipse.moquette.proto.messages.AbstractMessage;
@@ -211,12 +211,22 @@ public class MemoryStorageService implements IMessagesStore, ISessionsStore {
}
@Override
public ClientSession createNewSession(String clientID) {
return m_sessionsStore.createNewSession(clientID);
public ClientSession createNewSession(String clientID, boolean cleanSession) {
return m_sessionsStore.createNewSession(clientID, cleanSession);
}
@Override
public ClientSession sessionForClient(String clientID) {
return m_sessionsStore.sessionForClient(clientID);
}
@Override
public void activate(String clientID) {
m_sessionsStore.activate(clientID);
}
@Override
public void deactivate(String clientID) {
m_sessionsStore.deactivate(clientID);
}
}
@@ -27,6 +27,7 @@ import org.eclipse.moquette.spi.IMatchingCondition;
import org.eclipse.moquette.spi.IMessagesStore;
import org.eclipse.moquette.spi.ISessionsStore;
import org.eclipse.moquette.spi.impl.events.PublishEvent;
import org.eclipse.moquette.spi.persistence.MemorySessionStore;
import org.eclipse.moquette.spi.impl.security.PermitAllAuthorizator;
import org.eclipse.moquette.spi.impl.subscriptions.Subscription;
import org.eclipse.moquette.spi.impl.subscriptions.SubscriptionsStore;
@@ -117,6 +118,7 @@ public class ProtocolProcessorTest {
ConnectMessage connectMessage = new ConnectMessage();
connectMessage.setProtocolVersion((byte) 3);
connectMessage.setClientID(FAKE_CLIENT_ID);
m_sessionStore.createNewSession(FAKE_CLIENT_ID, false);
connectMessage.setCleanSession(subscription.isCleanSession());
m_processor.processConnect(m_session, connectMessage);
@@ -207,7 +209,7 @@ public class ProtocolProcessorTest {
msg.addSubscription(new SubscribeMessage.Couple(AbstractMessage.QOSType.MOST_ONE.byteValue(), FAKE_TOPIC));
m_session.setAttribute(NettyChannel.ATTR_KEY_CLIENTID, FAKE_CLIENT_ID);
m_session.setAttribute(NettyChannel.ATTR_KEY_CLEANSESSION, false);
m_sessionStore.createNewSession(FAKE_CLIENT_ID);
m_sessionStore.createNewSession(FAKE_CLIENT_ID, false);
m_processor.processSubscribe(m_session, msg/*, FAKE_CLIENT_ID, false*/);
//Verify
@@ -222,7 +224,7 @@ public class ProtocolProcessorTest {
msg.addSubscription(new SubscribeMessage.Couple(AbstractMessage.QOSType.MOST_ONE.byteValue(), FAKE_TOPIC));
m_session.setAttribute(NettyChannel.ATTR_KEY_CLIENTID, FAKE_CLIENT_ID);
m_session.setAttribute(NettyChannel.ATTR_KEY_CLEANSESSION, false);
m_sessionStore.createNewSession(FAKE_CLIENT_ID);
m_sessionStore.createNewSession(FAKE_CLIENT_ID, false);
assertEquals(0, subscriptions.size());
m_processor.processSubscribe(m_session, msg);
@@ -243,7 +245,7 @@ public class ProtocolProcessorTest {
msg.addSubscription(new SubscribeMessage.Couple(AbstractMessage.QOSType.MOST_ONE.byteValue(), BAD_FORMATTED_TOPIC));
m_session.setAttribute(NettyChannel.ATTR_KEY_CLIENTID, FAKE_CLIENT_ID);
m_session.setAttribute(NettyChannel.ATTR_KEY_CLEANSESSION, false);
m_sessionStore.createNewSession(FAKE_CLIENT_ID);
m_sessionStore.createNewSession(FAKE_CLIENT_ID, false);
assertEquals(0, subscriptions.size());
//Exercise
@@ -279,7 +281,7 @@ public class ProtocolProcessorTest {
@Test
public void testPublishOfRetainedMessage_afterNewSubscription() throws Exception {
final CountDownLatch publishRecvSignal = new CountDownLatch(1);
/*ServerChannel */m_session = new DummyChannel() {
m_session = new DummyChannel() {
@Override
public void write(Object value) {
try {
@@ -370,10 +372,12 @@ public class ProtocolProcessorTest {
}
@Test
public void publishNoPublishToInactiveSubscriptions() {
public void publishNoPublishToInactiveSession() {
//create an inactive session for Subscriber
m_sessionStore.createNewSession("Subscriber", false).deactivate();
SubscriptionsStore mockedSubscriptions = mock(SubscriptionsStore.class);
Subscription inactiveSub = new Subscription("Subscriber", "/topic", QOSType.LEAST_ONE, false);
inactiveSub.setActive(false);
List<Subscription> inactiveSubscriptions = Arrays.asList(inactiveSub);
when(mockedSubscriptions.matches(eq("/topic"))).thenReturn(inactiveSubscriptions);
m_processor = new ProtocolProcessor();
@@ -396,14 +400,16 @@ public class ProtocolProcessorTest {
@Test
public void publishToAnInactiveSubscriptionsCleanSession() {
//create an inactive session for Subscriber
m_sessionStore.createNewSession("Subscriber", false).deactivate();
SubscriptionsStore mockedSubscriptions = mock(SubscriptionsStore.class);
Subscription inactiveSub = new Subscription("Subscriber", "/topic", QOSType.LEAST_ONE, true);
inactiveSub.setActive(false);
List<Subscription> inactiveSubscriptions = Arrays.asList(inactiveSub);
when(mockedSubscriptions.matches(eq("/topic"))).thenReturn(inactiveSubscriptions);
m_processor = new ProtocolProcessor();
m_processor.init(mockedSubscriptions, m_storageService, m_sessionStore, null, true, new PermitAllAuthorizator(), NO_OBSERVERS_INTERCEPTOR);
m_processor.init(mockedSubscriptions, m_storageService, m_sessionStore, null, true, new PermitAllAuthorizator(),
NO_OBSERVERS_INTERCEPTOR);
//Exercise
ByteBuffer buffer = ByteBuffer.allocate(5).put("Hello".getBytes());
PublishMessage msg = new PublishMessage();
@@ -463,11 +469,14 @@ public class ProtocolProcessorTest {
ByteBuffer payload = ByteBuffer.wrap("Hello world MQTT!!".getBytes());
PublishEvent forwardPublish = new PublishEvent("a/b", QOSType.EXACTLY_ONCE, payload, true, "Publisher", 1);
IMessagesStore memoryMessageStore = new MemoryStorageService();
ISessionsStore sessionsStore = new MemorySessionStore(memoryMessageStore);
sessionsStore.createNewSession("Sub A", false).activate();
sessionsStore.createNewSession("Sub B", false).activate();
Subscription subQos1 = new Subscription("Sub A", "a/b", QOSType.LEAST_ONE, false);
Subscription subQos2 = new Subscription("Sub B", "a/+", QOSType.EXACTLY_ONCE, false);
SubscriptionsStore subscriptions = new SubscriptionsStore();
subscriptions.init(new MemorySessionStore(memoryMessageStore));
subscriptions.init(sessionsStore);
subscriptions.add(subQos1);
subscriptions.add(subQos2);
@@ -479,7 +488,7 @@ public class ProtocolProcessorTest {
publishedForwarded.add(new PublishEvent(topic, qos, message, retained, clientId, messageID));
}
};
processor.init(subscriptions, memoryMessageStore, null, null, true, null, NO_OBSERVERS_INTERCEPTOR);
processor.init(subscriptions, memoryMessageStore, sessionsStore, null, true, null, NO_OBSERVERS_INTERCEPTOR);
//Exercise
processor.forward2Subscribers(forwardPublish);
@@ -58,11 +58,6 @@ public class SubscriptionsStoreTest {
assertEqualsSeq(asArray(Token.EMPTY, Token.EMPTY), tokens);
}
// @Test(expected = ParseException.class)
// public void testSplitTopicTwinsSlashAvoided() throws ParseException {
// store.parseTopic("/finance//stock/ibm");
// }
@Test
public void testParseTopicMultiValid() throws ParseException {
List<Token> tokens = store.parseTopic("finance/stock/#");
@@ -355,8 +350,8 @@ public class SubscriptionsStoreTest {
//subscribe a not active clientID1 to /topic
Subscription slashSub = new Subscription("FAKE_CLI_ID_1", "/topic", AbstractMessage.QOSType.MOST_ONE, false);
aStore.add(slashSub);
aStore.deactivate(slashSub.getClientId());
memStore.createNewSession("FAKE_CLI_ID_1", true).deactivate();
//subscribe an active clientID2 to /topic
Subscription slashSub2 = new Subscription("FAKE_CLI_ID_2", "/topic", AbstractMessage.QOSType.MOST_ONE, false);
aStore.add(slashSub2);
@@ -16,8 +16,8 @@
package org.eclipse.moquette.spi.persistence;
import org.eclipse.moquette.proto.messages.AbstractMessage;
import org.eclipse.moquette.server.IntegrationUtils;
import org.eclipse.moquette.spi.impl.subscriptions.Subscription;
import org.eclipse.moquette.spi.persistence.MapDBPersistentStore;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -36,12 +36,10 @@ import static org.junit.Assert.*;
public class MapDBPersistentStoreTest {
MapDBPersistentStore m_storageService;
@Before
public void setUp() throws Exception {
File dbFile = new File(DEFAULT_PERSISTENT_PATH);
assertFalse(String.format("The DB storage file %s already exists", DEFAULT_PERSISTENT_PATH), dbFile.exists());
IntegrationUtils.cleanPersistenceFile(DEFAULT_PERSISTENT_PATH);
m_storageService = new MapDBPersistentStore(DEFAULT_PERSISTENT_PATH);
m_storageService.initStore();
}
@@ -51,12 +49,8 @@ public class MapDBPersistentStoreTest {
if (m_storageService != null) {
m_storageService.close();
}
File dbFile = new File(DEFAULT_PERSISTENT_PATH);
if (dbFile.exists()) {
assertTrue("Error deleting the moquette db file " + DEFAULT_PERSISTENT_PATH, dbFile.delete());
}
assertFalse(dbFile.exists());
IntegrationUtils.cleanPersistenceFile(DEFAULT_PERSISTENT_PATH);
}
@Test
@@ -13,12 +13,13 @@
*
* You may elect to redistribute this code under either of these licenses.
*/
package org.eclipse.moquette.spi.impl;
package org.eclipse.moquette.spi.persistence;
import org.eclipse.moquette.spi.ClientSession;
import org.eclipse.moquette.spi.IMessagesStore;
import org.eclipse.moquette.spi.ISessionsStore;
import org.eclipse.moquette.spi.impl.subscriptions.Subscription;
import static org.eclipse.moquette.spi.persistence.MapDBPersistentStore.PersistentSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -33,6 +34,8 @@ public class MemorySessionStore implements ISessionsStore {
private Map<String, Set<Subscription>> m_persistentSubscriptions = new HashMap<>();
private Map<String, PersistentSession> m_persistentSessions = new HashMap<>();
private final IMessagesStore m_messagesStore;
public MemorySessionStore(IMessagesStore messagesStore) {
@@ -90,24 +93,30 @@ public class MemorySessionStore implements ISessionsStore {
}
@Override
public ClientSession createNewSession(String clientID) {
public ClientSession createNewSession(String clientID, boolean cleanSession) {
LOG.debug("createNewSession for client <{}>", clientID);
if (m_persistentSubscriptions.containsKey(clientID)) {
if (m_persistentSessions.containsKey(clientID)) {
LOG.error("already exists a session for client <{}>, bad condition", clientID);
throw new IllegalArgumentException("Can't create a session with the ID of an already existing" + clientID);
}
LOG.debug("clientID {} is a newcome, creating it's empty subscriptions set", clientID);
m_persistentSubscriptions.put(clientID, new HashSet<Subscription>());
return new ClientSession(clientID, m_messagesStore, this);
m_persistentSessions.put(clientID, new PersistentSession(cleanSession, false));
return new ClientSession(clientID, m_messagesStore, this, cleanSession);
}
@Override
public ClientSession sessionForClient(String clientID) {
if (!m_persistentSubscriptions.containsKey(clientID)) {
if (!m_persistentSessions.containsKey(clientID)) {
return null;
}
return new ClientSession(clientID, m_messagesStore, this);
PersistentSession storedSession = m_persistentSessions.get(clientID);
ClientSession clientSession = new ClientSession(clientID, m_messagesStore, this, storedSession.cleanSession);
if (storedSession.active) {
clientSession.activate();
}
return clientSession;
}
@Override
@@ -118,4 +127,23 @@ public class MemorySessionStore implements ISessionsStore {
}
return allSubscriptions;
}
@Override
public void activate(String clientID) {
activationHelper(clientID, true);
}
@Override
public void deactivate(String clientID) {
activationHelper(clientID, false);
}
private void activationHelper(String clientID, boolean activation) {
PersistentSession storedSession = m_persistentSessions.get(clientID);
if (storedSession == null) {
throw new IllegalStateException((activation ? "activating" : "deactivating") + " a session never stored/created, clientID <"+ clientID + ">", null);
}
PersistentSession newStoredSession = new PersistentSession(storedSession.cleanSession, activation);
m_persistentSessions.put(clientID, newStoredSession);
}
}