diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 7fc23a3830..523cb26d38 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -43,7 +43,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Configure pagefile - uses: al-cheb/configure-pagefile-action@v1.3 + uses: al-cheb/configure-pagefile-action@v1.4 with: minimum-size: 8GB maximum-size: 16GB diff --git a/pom.xml b/pom.xml index 8d0ff6336f..ad24fdd29f 100644 --- a/pom.xml +++ b/pom.xml @@ -68,10 +68,10 @@ UTF-8 UTF-8 1.8 - 2.0.10 + 2.0.12 4.11.0 2.2 - 5.10.1 + 5.10.2 8 8 @@ -81,7 +81,7 @@ 3.3.1 3.12.1 3.3.0 - 3.2.3 + 3.2.5 3.21.2 3.3.0 3.6.3 @@ -94,7 +94,7 @@ 3.5.0 3.4.2 3.0.0 - 3.10.2 + 3.11.0 3.3.0 1.2 8059 @@ -467,7 +467,7 @@ maven-plugin-plugin - 3.10.2 + 3.11.0 maven-install-plugin diff --git a/quickfixj-base/pom.xml b/quickfixj-base/pom.xml index 4c2a7eb601..8f17ef5af8 100644 --- a/quickfixj-base/pom.xml +++ b/quickfixj-base/pom.xml @@ -229,7 +229,7 @@ maven-jxr-plugin - 3.3.1 + 3.3.2 diff --git a/quickfixj-codegenerator/pom.xml b/quickfixj-codegenerator/pom.xml index 0bb96d8ca8..5cbee80d44 100644 --- a/quickfixj-codegenerator/pom.xml +++ b/quickfixj-codegenerator/pom.xml @@ -78,7 +78,10 @@ maven-plugin-plugin - 3.10.2 + 3.11.0 + + quickfixj-codegenerator + diff --git a/quickfixj-core/pom.xml b/quickfixj-core/pom.xml index b7aafd9eae..b07c0d3dc6 100644 --- a/quickfixj-core/pom.xml +++ b/quickfixj-core/pom.xml @@ -234,7 +234,7 @@ org.apache.maven.plugins maven-jxr-plugin - 3.3.1 + 3.3.2 diff --git a/quickfixj-core/src/main/java/quickfix/SessionSettings.java b/quickfixj-core/src/main/java/quickfix/SessionSettings.java index 3765c35c1f..de52063503 100644 --- a/quickfixj-core/src/main/java/quickfix/SessionSettings.java +++ b/quickfixj-core/src/main/java/quickfix/SessionSettings.java @@ -877,4 +877,22 @@ public static Set parseRemoteAddresses(String raw) { return result; } + public void removeSection(final SessionID sessionID) throws ConfigError { + Properties properties = getSessionProperties(sessionID); + + if (properties == null) { + throw new ConfigError("Session not found"); + } + sections.remove(sessionID); + } + + public void removeSection(final String propertyKey, final String propertyValue) throws ConfigError { + SessionID sessionIdToRemove = sections.entrySet().stream() + .filter(entry -> propertyValue.equals(entry.getValue().get(propertyKey))) + .map(Map.Entry::getKey) + .findFirst() + .orElseThrow(() -> new ConfigError("Session not found")); + + sections.remove(sessionIdToRemove); + } } diff --git a/quickfixj-core/src/test/java/quickfix/JdbcLogTest.java b/quickfixj-core/src/test/java/quickfix/JdbcLogTest.java index 189f9e1449..7436d7ca74 100644 --- a/quickfixj-core/src/test/java/quickfix/JdbcLogTest.java +++ b/quickfixj-core/src/test/java/quickfix/JdbcLogTest.java @@ -133,7 +133,6 @@ private void setUpJdbcLog(boolean filterHeartbeats, DataSource dataSource) throw if (filterHeartbeats) { settings.setBool(JdbcSetting.SETTING_JDBC_LOG_HEARTBEATS, false); } - settings.setString(sessionID, JdbcSetting.SETTING_JDBC_CONNECTION_TEST_QUERY, "SELECT COUNT(1) FROM INFORMATION_SCHEMA.SYSTEM_USERS WHERE 1 = 0;"); JdbcTestSupport.setHypersonicSettings(settings); initializeTableDefinitions(connection); logFactory = new JdbcLogFactory(settings); diff --git a/quickfixj-core/src/test/java/quickfix/JdbcTestSupport.java b/quickfixj-core/src/test/java/quickfix/JdbcTestSupport.java index a2f573f472..c29940bbb4 100644 --- a/quickfixj-core/src/test/java/quickfix/JdbcTestSupport.java +++ b/quickfixj-core/src/test/java/quickfix/JdbcTestSupport.java @@ -43,6 +43,8 @@ public static void setHypersonicSettings(SessionSettings settings) { settings.setString(JdbcSetting.SETTING_JDBC_CONNECTION_URL, HSQL_CONNECTION_URL); settings.setString(JdbcSetting.SETTING_JDBC_USER, HSQL_USER); settings.setString(JdbcSetting.SETTING_JDBC_PASSWORD, ""); + // HSQL doesn't support JDBC4 which means that test query has to be supplied to HikariCP + settings.setString(JdbcSetting.SETTING_JDBC_CONNECTION_TEST_QUERY, "SELECT COUNT(1) FROM INFORMATION_SCHEMA.SYSTEM_USERS WHERE 1 = 0;"); } public static Connection getConnection() throws ClassNotFoundException, SQLException { diff --git a/quickfixj-core/src/test/java/quickfix/SessionSettingsTest.java b/quickfixj-core/src/test/java/quickfix/SessionSettingsTest.java index 2de5d1ad10..19f468b85a 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionSettingsTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionSettingsTest.java @@ -31,6 +31,7 @@ import java.util.Iterator; import java.util.Properties; import java.util.Set; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.HashMap; @@ -610,6 +611,51 @@ public void testConcurrentAccess() throws ConfigError, InterruptedException { assertTrue(testHasPassed.get()); } + @Test + public void testRemoveSectionBySessionID() throws ConfigError { + final Map defaultSettings = createDefaultSettings(); + + final Map pricingSection = createPricingSection(); + final SessionID pricingSessionID = new SessionID("FIX.4.2:FOOBAR_PRICING->*"); + + final Map tradingSection = createTradingSection(); + final SessionID tradingSessionID = new SessionID("FIX.4.2:FOOBAR_TRADING->*"); + + final SessionSettings sessionSettings = new SessionSettings(); + sessionSettings.set(new Dictionary(null, defaultSettings)); + sessionSettings.set(pricingSessionID, new Dictionary("sessions", pricingSection)); + sessionSettings.set(tradingSessionID, new Dictionary("sessions", tradingSection)); + + while (sessionSettings.sectionIterator().hasNext()) { + SessionID sessionID = sessionSettings.sectionIterator().next(); + sessionSettings.removeSection(sessionID); + } + + assertFalse(sessionSettings.sectionIterator().hasNext()); + } + + @Test + public void testRemoveSectionByPropertyKey() throws ConfigError { + final Map defaultSettings = createDefaultSettings(); + + final Map tradingSection = createTradingSection(); + final SessionID tradingSessionID = new SessionID("FIX.4.2:FOOBAR_TRADING->*"); + + final SessionSettings sessionSettings = new SessionSettings(); + sessionSettings.set(new Dictionary(null, defaultSettings)); + sessionSettings.set(tradingSessionID, new Dictionary("sessions", tradingSection)); + + sessionSettings.removeSection("SocketAcceptPort", "7566"); + + Set expectedSessionIdSet = new HashSet<>(); + while (sessionSettings.sectionIterator().hasNext()) { + SessionID sessionID = sessionSettings.sectionIterator().next(); + expectedSessionIdSet.add(sessionID); + } + + assertFalse(expectedSessionIdSet.contains(tradingSessionID)); + } + private Map createTradingSection() { final Map tradingSection = new HashMap<>(); tradingSection.put("PersistMessages","Y"); diff --git a/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java b/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java index 6d31b9293f..3a9d8a8d58 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java @@ -23,19 +23,21 @@ import org.apache.mina.core.filterchain.IoFilterChain; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.ssl.SslFilter; -import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import quickfix.Acceptor; import quickfix.ApplicationAdapter; import quickfix.ConfigError; import quickfix.DefaultMessageFactory; import quickfix.FixVersions; +import quickfix.Initiator; import quickfix.MemoryStoreFactory; import quickfix.MessageFactory; import quickfix.MessageStoreFactory; import quickfix.RuntimeError; import quickfix.Session; +import quickfix.SessionFactory; import quickfix.SessionID; import quickfix.SessionSettings; import quickfix.ThreadedSocketAcceptor; @@ -552,6 +554,51 @@ public void shouldFailWhenUsingBadServerCertificate() throws Exception { } } + @Test + public void shouldConnectDifferentTypesOfSessions() throws Exception { + int sslPort = AvailablePortFinder.getNextAvailable(); + int nonSslPort = AvailablePortFinder.getNextAvailable(); + TestAcceptor acceptor = new TestAcceptor(createMixedSessionAcceptorSettings(sslPort, nonSslPort, "single-session/server.keystore")); + + try { + acceptor.start(); + + TestInitiator sslInitiator = new TestInitiator( + createInitiatorSettings("single-session/client.keystore", "single-session/client.truststore", + CIPHER_SUITES_TLS, "TLSv1.2", "ZULU_SSL", "ALFA_SSL", Integer.toString(sslPort), "JKS", "JKS")); + + TestInitiator nonSslInitiator = new TestInitiator(createInitiatorSettings("ZULU_NON_SSL", "ALFA_NON_SSL", nonSslPort)); + + try { + sslInitiator.start(); + nonSslInitiator.start(); + + sslInitiator.assertNoSslExceptionThrown(); + sslInitiator.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU_SSL", "ALFA_SSL")); + sslInitiator.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU_SSL", "ALFA_SSL"), + new BigInteger("1448538842")); + + acceptor.assertNoSslExceptionThrown(); + acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA_SSL", "ZULU_SSL")); + acceptor.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA_SSL", "ZULU_SSL")); + + nonSslInitiator.assertNoSslExceptionThrown(); + nonSslInitiator.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU_NON_SSL", "ALFA_NON_SSL")); + nonSslInitiator.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU_NON_SSL", "ALFA_NON_SSL")); + + acceptor.assertNoSslExceptionThrown(); + acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA_NON_SSL", "ZULU_NON_SSL")); + acceptor.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA_NON_SSL", "ZULU_NON_SSL")); + + } finally { + sslInitiator.stop(); + nonSslInitiator.stop(); + } + } finally { + acceptor.stop(); + } + } + static abstract class TestConnector { private static final Logger LOGGER = LoggerFactory.getLogger(TestConnector.class); private static final int TIMEOUT_SECONDS = 5; @@ -744,24 +791,53 @@ public SessionConnector createConnector(SessionSettings sessionSettings) throws return new ThreadedSocketInitiator(new ApplicationAdapter(), messageStoreFactory, sessionSettings, messageFactory); } + } + /** + * Creates acceptor settings that contains two sessions. One with SSL support, one without. + */ + private SessionSettings createMixedSessionAcceptorSettings(int sslPort, int nonSslPort, String keyStoreName) { + HashMap defaults = new HashMap<>(); + defaults.put(SessionFactory.SETTING_CONNECTION_TYPE, "acceptor"); + defaults.put(Session.SETTING_START_TIME, "00:00:00"); + defaults.put(Session.SETTING_END_TIME, "00:00:00"); + defaults.put(Session.SETTING_HEARTBTINT, "30"); + + SessionSettings sessionSettings = new SessionSettings(); + sessionSettings.set(defaults); + + SessionID sslSession = new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA_SSL", "ZULU_SSL"); + sessionSettings.setString(sslSession, "BeginString", FixVersions.BEGINSTRING_FIX44); + sessionSettings.setString(sslSession, "DataDictionary", "FIX44.xml"); + sessionSettings.setString(sslSession, "TargetCompID", "ZULU_SSL"); + sessionSettings.setString(sslSession, "SenderCompID", "ALFA_SSL"); + sessionSettings.setString(sslSession, SSLSupport.SETTING_USE_SSL, "Y"); + sessionSettings.setString(sslSession, SSLSupport.SETTING_KEY_STORE_NAME, keyStoreName); + sessionSettings.setString(sslSession, SSLSupport.SETTING_KEY_STORE_PWD, "password"); + sessionSettings.setString(sslSession, SSLSupport.SETTING_NEED_CLIENT_AUTH, "N"); + sessionSettings.setString(sslSession, "SocketAcceptPort", Integer.toString(sslPort)); + + SessionID nonSslSession = new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA_NON_SSL", "ZULU_NON_SSL"); + sessionSettings.setString(nonSslSession, "BeginString", FixVersions.BEGINSTRING_FIX44); + sessionSettings.setString(nonSslSession, "DataDictionary", "FIX44.xml"); + sessionSettings.setString(nonSslSession, "TargetCompID", "ZULU_NON_SSL"); + sessionSettings.setString(nonSslSession, "SenderCompID", "ALFA_NON_SSL"); + sessionSettings.setString(nonSslSession, "SocketAcceptPort", Integer.toString(nonSslPort)); + + return sessionSettings; } private SessionSettings createMultiSessionAcceptorSettings(String keyStoreName, boolean needClientAuth, String[] trustStoreNames, String cipherSuites, String protocols) { HashMap defaults = new HashMap<>(); - defaults.put("ConnectionType", "acceptor"); - defaults.put("SocketConnectProtocol", ProtocolFactory.getTypeString(ProtocolFactory.SOCKET)); + defaults.put(SessionFactory.SETTING_CONNECTION_TYPE, "acceptor"); defaults.put(SSLSupport.SETTING_USE_SSL, "Y"); defaults.put(SSLSupport.SETTING_KEY_STORE_NAME, keyStoreName); defaults.put(SSLSupport.SETTING_KEY_STORE_PWD, "password"); - defaults.put(SSLSupport.SETTING_NEED_CLIENT_AUTH, needClientAuth ? "Y" : "N"); - defaults.put("SocketAcceptHost", "localhost"); - defaults.put("StartTime", "00:00:00"); - defaults.put("EndTime", "00:00:00"); - defaults.put("HeartBtInt", "30"); - defaults.put("ReconnectInterval", "2"); + defaults.put(Session.SETTING_START_TIME, "00:00:00"); + defaults.put(Session.SETTING_END_TIME, "00:00:00"); + defaults.put(Session.SETTING_HEARTBTINT, "30"); if (cipherSuites != null) { defaults.put(SSLSupport.SETTING_CIPHER_SUITES, cipherSuites); @@ -791,8 +867,7 @@ private SessionSettings createMultiSessionAcceptorSettings(String keyStoreName, private SessionSettings createAcceptorSettings(String keyStoreName, boolean needClientAuth, String trustStoreName, String cipherSuites, String protocols, String keyStoreType, String trustStoreType, int port) { HashMap defaults = new HashMap<>(); - defaults.put("ConnectionType", "acceptor"); - defaults.put("SocketConnectProtocol", ProtocolFactory.getTypeString(ProtocolFactory.SOCKET)); + defaults.put(SessionFactory.SETTING_CONNECTION_TYPE, "acceptor"); defaults.put(SSLSupport.SETTING_USE_SSL, "Y"); defaults.put(SSLSupport.SETTING_KEY_STORE_NAME, keyStoreName); defaults.put(SSLSupport.SETTING_KEY_STORE_PWD, "password"); @@ -811,12 +886,10 @@ private SessionSettings createAcceptorSettings(String keyStoreName, boolean need } defaults.put(SSLSupport.SETTING_NEED_CLIENT_AUTH, needClientAuth ? "Y" : "N"); - defaults.put("SocketAcceptHost", "localhost"); - defaults.put("SocketAcceptPort", Integer.toString(port)); - defaults.put("StartTime", "00:00:00"); - defaults.put("EndTime", "00:00:00"); - defaults.put("HeartBtInt", "30"); - defaults.put("ReconnectInterval", "2"); + defaults.put(Acceptor.SETTING_SOCKET_ACCEPT_PORT, Integer.toString(port)); + defaults.put(Session.SETTING_START_TIME, "00:00:00"); + defaults.put(Session.SETTING_END_TIME, "00:00:00"); + defaults.put(Session.SETTING_HEARTBTINT, "30"); if (cipherSuites != null) { defaults.put(SSLSupport.SETTING_CIPHER_SUITES, cipherSuites); @@ -848,8 +921,8 @@ private SessionSettings createInitiatorSettings(String keyStoreName, String trus String protocols, String senderId, String targetId, String port, String keyStoreType, String trustStoreType, String endpointIdentificationAlgorithm) { HashMap defaults = new HashMap<>(); - defaults.put("ConnectionType", "initiator"); - defaults.put("SocketConnectProtocol", ProtocolFactory.getTypeString(ProtocolFactory.SOCKET)); + defaults.put(SessionFactory.SETTING_CONNECTION_TYPE, "initiator"); + defaults.put(Initiator.SETTING_SOCKET_CONNECT_PROTOCOL, ProtocolFactory.getTypeString(ProtocolFactory.SOCKET)); defaults.put(SSLSupport.SETTING_USE_SSL, "Y"); defaults.put(SSLSupport.SETTING_KEY_STORE_NAME, keyStoreName); defaults.put(SSLSupport.SETTING_KEY_STORE_PWD, "password"); @@ -867,12 +940,12 @@ private SessionSettings createInitiatorSettings(String keyStoreName, String trus } } - defaults.put("SocketConnectHost", "localhost"); - defaults.put("SocketConnectPort", port); - defaults.put("StartTime", "00:00:00"); - defaults.put("EndTime", "00:00:00"); - defaults.put("HeartBtInt", "30"); - defaults.put("ReconnectInterval", "2"); + defaults.put(Initiator.SETTING_SOCKET_CONNECT_HOST, "localhost"); + defaults.put(Initiator.SETTING_SOCKET_CONNECT_PORT, port); + defaults.put(Initiator.SETTING_RECONNECT_INTERVAL, "2"); + defaults.put(Session.SETTING_START_TIME, "00:00:00"); + defaults.put(Session.SETTING_END_TIME, "00:00:00"); + defaults.put(Session.SETTING_HEARTBTINT, "30"); if (cipherSuites != null) { defaults.put(SSLSupport.SETTING_CIPHER_SUITES, cipherSuites); @@ -897,4 +970,27 @@ private SessionSettings createInitiatorSettings(String keyStoreName, String trus return sessionSettings; } + + private SessionSettings createInitiatorSettings(String senderId, String targetId, int port) { + HashMap defaults = new HashMap<>(); + defaults.put(SessionFactory.SETTING_CONNECTION_TYPE, "initiator"); + defaults.put(Initiator.SETTING_SOCKET_CONNECT_PROTOCOL, ProtocolFactory.getTypeString(ProtocolFactory.SOCKET)); + defaults.put(Initiator.SETTING_SOCKET_CONNECT_HOST, "localhost"); + defaults.put(Initiator.SETTING_SOCKET_CONNECT_PORT, Integer.toString(port)); + defaults.put(Initiator.SETTING_RECONNECT_INTERVAL, "2"); + defaults.put(Session.SETTING_START_TIME, "00:00:00"); + defaults.put(Session.SETTING_END_TIME, "00:00:00"); + defaults.put(Session.SETTING_HEARTBTINT, "30"); + + SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX44, senderId, targetId); + + SessionSettings sessionSettings = new SessionSettings(); + sessionSettings.set(defaults); + sessionSettings.setString(sessionID, "BeginString", FixVersions.BEGINSTRING_FIX44); + sessionSettings.setString(sessionID, "DataDictionary", "FIX44.xml"); + sessionSettings.setString(sessionID, "SenderCompID", senderId); + sessionSettings.setString(sessionID, "TargetCompID", targetId); + + return sessionSettings; + } }