From 0eb3359059d3551dde588f3cff6c836119141cf6 Mon Sep 17 00:00:00 2001 From: charlesbr1 Date: Wed, 29 Jul 2015 23:40:09 -0500 Subject: [PATCH 001/165] Allocations optimization Set the log session id prefix in the logger appender, instead of building a new string on each message --- .../src/main/java/quickfix/SLF4JLog.java | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/SLF4JLog.java b/quickfixj-core/src/main/java/quickfix/SLF4JLog.java index 33fa52cd9..58c1a0798 100644 --- a/quickfixj-core/src/main/java/quickfix/SLF4JLog.java +++ b/quickfixj-core/src/main/java/quickfix/SLF4JLog.java @@ -47,26 +47,24 @@ public class SLF4JLog extends AbstractLog { private final Logger outgoingMsgLog; - private final String logPrefix; - private final String callerFQCN; public SLF4JLog(SessionID sessionID, String eventCategory, String errorEventCategory, - String incomingMsgCategory, String outgoingMsgCategory, boolean prependSessionID, - boolean logHeartbeats, String inCallerFQCN) { + String incomingMsgCategory, String outgoingMsgCategory, boolean prependSessionID, + boolean logHeartbeats, String inCallerFQCN) { setLogHeartbeats(logHeartbeats); - logPrefix = prependSessionID ? (sessionID + ": ") : null; - eventLog = getLogger(sessionID, eventCategory, DEFAULT_EVENT_CATEGORY); - errorEventLog = getLogger(sessionID, errorEventCategory, DEFAULT_ERROR_EVENT_CATEGORY); - incomingMsgLog = getLogger(sessionID, incomingMsgCategory, DEFAULT_INCOMING_MSG_CATEGORY); - outgoingMsgLog = getLogger(sessionID, outgoingMsgCategory, DEFAULT_OUTGOING_MSG_CATEGORY); + String logPrefix = prependSessionID ? (sessionID + ": ") : ""; + eventLog = getLogger(sessionID, eventCategory, DEFAULT_EVENT_CATEGORY, logPrefix); + errorEventLog = getLogger(sessionID, errorEventCategory, DEFAULT_ERROR_EVENT_CATEGORY, logPrefix); + incomingMsgLog = getLogger(sessionID, incomingMsgCategory, DEFAULT_INCOMING_MSG_CATEGORY, logPrefix); + outgoingMsgLog = getLogger(sessionID, outgoingMsgCategory, DEFAULT_OUTGOING_MSG_CATEGORY, logPrefix); callerFQCN = inCallerFQCN; } - private Logger getLogger(SessionID sessionID, String category, String defaultCategory) { - return LoggerFactory.getLogger(category != null + private Logger getLogger(SessionID sessionID, String category, String defaultCategory, String logPrefix) { + return LoggerFactory.getLogger((category != null ? substituteVariables(sessionID, category) - : defaultCategory); + : defaultCategory) + logPrefix); } private static final String FIX_MAJOR_VERSION_VAR = "\\$\\{fixMajorVersion}"; @@ -134,23 +132,23 @@ protected void logOutgoing(String message) { */ protected void log(org.slf4j.Logger log, String text) { if (log.isInfoEnabled()) { - final String message = logPrefix != null ? (logPrefix + text) : text; if (log instanceof LocationAwareLogger) { final LocationAwareLogger la = (LocationAwareLogger) log; - la.log(null, callerFQCN, LocationAwareLogger.INFO_INT, message, null, null); + la.log(null, callerFQCN, LocationAwareLogger.INFO_INT, text, null, null); } else { - log.info(message); + log.info(text); } } } protected void logError(org.slf4j.Logger log, String text) { - final String message = logPrefix != null ? (logPrefix + text) : text; - log.error(message); + log.error(text); } + private final String clearString = "Log clear operation is not supported: " + getClass().getName(); + public void clear() { - onEvent("Log clear operation is not supported: " + getClass().getName()); + onEvent(clearString); } } From 130a52073fa8bd57a2d93b66466ab36f6c56c15d Mon Sep 17 00:00:00 2001 From: charlesbr1 Date: Fri, 31 Jul 2015 12:39:57 -0500 Subject: [PATCH 002/165] Create NumbersCache.java A cache of strings for frequently used integers --- .../src/main/java/quickfix/NumbersCache.java | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 quickfixj-core/src/main/java/quickfix/NumbersCache.java diff --git a/quickfixj-core/src/main/java/quickfix/NumbersCache.java b/quickfixj-core/src/main/java/quickfix/NumbersCache.java new file mode 100644 index 000000000..a3c72707a --- /dev/null +++ b/quickfixj-core/src/main/java/quickfix/NumbersCache.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) quickfixengine.org All rights reserved. + * + * This file is part of the QuickFIX FIX Engine + * + * This file may be distributed under the terms of the quickfixengine.org + * license as defined by quickfixengine.org and appearing in the file + * LICENSE included in the packaging of this file. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING + * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * See http://www.quickfixengine.org/LICENSE for licensing information. + * + * Contact ask@quickfixengine.org if any conditions of this licensing + * are not clear to you. + ******************************************************************************/ + +package quickfix; + +import java.util.ArrayList; + +/** + * A cache for commonly used string representing numbers. + * Hold values from 0 to 999999 and from 1000 to 200 000 000 by step of 1000 + */ +public final class NumbersCache { + + private static final int littleNumbersLength = 1000000; + private static final int bigNumbersLength = 200000; + private static final int bigNumbersOffset = 1000; + private static final int bigNumbersMax = bigNumbersLength * bigNumbersOffset; + + public static final ArrayList littleNumbers; + public static final ArrayList bigNumbers; + + static { + littleNumbers = new ArrayList(littleNumbersLength); + bigNumbers = new ArrayList(bigNumbersLength); + for (int i = 0; i < littleNumbersLength; i++) + littleNumbers.add(Integer.toString(i)); + for (long i = 0; i < bigNumbersLength;) + bigNumbers.add(Long.toString(++i * bigNumbersOffset)); + + } + + /** + * Get the string representing the given number + * + * @param i the long to convert + * @return the String representing the long + */ + public static String get(long i) { + if (i < littleNumbersLength) + return littleNumbers.get((int)i); + if (i <= bigNumbersMax && i % bigNumbersOffset == 0) + return bigNumbers.get((int)(i/bigNumbersOffset)-1); + return String.valueOf(i); + } + + /** + * Get the string representing the given double if it's an integer + * + * @param d the double to convert + * @return the String representing the double or null if the double is not an integer + */ + public static String get(double d) { + long l = (long)d; + if (d == (double)l) + return get(l); + return null; + } +} From 8a1cfb78666a5f601c311931410781163a336058 Mon Sep 17 00:00:00 2001 From: charlesbr1 Date: Fri, 31 Jul 2015 12:41:39 -0500 Subject: [PATCH 003/165] Allocations optimization Put the string builder used in toString method in a thread local in order to reuse it. Calculate the message length & checksum after the message is built, this avoid to compute the message multiple time and to iterate over each field. If the charset used to send message is not string equivalent to the jvm one, this optimization is not active. --- .../src/main/java/quickfix/Message.java | 137 ++++++++++++++++-- 1 file changed, 127 insertions(+), 10 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/Message.java b/quickfixj-core/src/main/java/quickfix/Message.java index 7ed213419..6054f77ca 100644 --- a/quickfixj-core/src/main/java/quickfix/Message.java +++ b/quickfixj-core/src/main/java/quickfix/Message.java @@ -129,6 +129,21 @@ private Object cloneTo(Message message) { return message; } + private static final class Context { + private final BodyLength bodyLength = new BodyLength(100); + private final CheckSum checkSum = new CheckSum("000"); + private final StringBuilder stringBuilder = new StringBuilder(1024); + } + + private static final ThreadLocal stringContexts = new ThreadLocal() { + @Override + protected Context initialValue() { + return new Context(); + } + }; + + private static final boolean isStringEquivalent = CharsetSupport.isStringEquivalent(CharsetSupport.getCharsetInstance()); + /** * Do not call this method concurrently while modifying the contents of the message. * This is likely to produce unexpected results or will fail with a ConcurrentModificationException @@ -136,16 +151,118 @@ private Object cloneTo(Message message) { */ @Override public String toString() { - final int bodyLength = bodyLength(); - header.setInt(BodyLength.FIELD, bodyLength); - trailer.setString(CheckSum.FIELD, checksum()); - - final StringBuilder sb = new StringBuilder(bodyLength); - header.calculateString(sb, null, null); - calculateString(sb, null, null); - trailer.calculateString(sb, null, null); - - return sb.toString(); + Context context = stringContexts.get(); + if(isStringEquivalent) { // length & checksum can easily be calculated after message is built + header.setField(context.bodyLength); + trailer.setField(context.checkSum); + } else { + header.setInt(BodyLength.FIELD, bodyLength()); + trailer.setString(CheckSum.FIELD, checksum()); + } + StringBuilder stringBuilder = context.stringBuilder; + try { + header.calculateString(stringBuilder, null, null); + calculateString(stringBuilder, null, null); + trailer.calculateString(stringBuilder, null, null); + if(isStringEquivalent) { + setBodyLength(stringBuilder); + setChecksum(stringBuilder); + } + return stringBuilder.toString(); + } finally { + stringBuilder.setLength(0); + } + } + + private static final String beginStringField = String.valueOf(BeginString.FIELD); + private static final String separatorFix = String.valueOf('\001'); + private static final String bodyLengthField = separatorFix + String.valueOf(BodyLength.FIELD) + '='; + private static final String checkSumField = separatorFix + String.valueOf(CheckSum.FIELD) + '='; + + private static void setBodyLength(StringBuilder stringBuilder) { + int index = indexOf(stringBuilder, beginStringField, 0); + if(index != 0) + throw new IllegalArgumentException("Malformed FIX message"); + int bodyLengthIndex = getIndex(stringBuilder, bodyLengthField, 0); + index = getIndex(stringBuilder, separatorFix, bodyLengthIndex + 1); + int checkSumIndex = lastIndexOf(stringBuilder, checkSumField); + if(checkSumIndex < 0) + throw new IllegalArgumentException("Malformed FIX message"); + int length = checkSumIndex - index; + bodyLengthIndex += bodyLengthField.length(); + stringBuilder.replace(bodyLengthIndex, bodyLengthIndex + 3, NumbersCache.get(length)); + } + + private static void setChecksum(StringBuilder stringBuilder) { + int checkSumIndex = lastIndexOf(stringBuilder, checkSumField); + int checkSum = 0; + for(int i = checkSumIndex; i-- != 0;) + checkSum += stringBuilder.charAt(i); + String checkSumValue = NumbersCache.get((checkSum + 1) % 256); + checkSumIndex += checkSumField.length(); + stringBuilder.replace(checkSumIndex + (3 - checkSumValue.length()), checkSumIndex + 3, checkSumValue); + } + + private static int getIndex(StringBuilder stringBuilder, String value, int fromIndex) { + int index = indexOf(stringBuilder, value, fromIndex); + if(index < 0) + throw new IllegalArgumentException("Malformed FIX message"); + return index; + } + + // return index of a string in a stringbuilder without performing allocations + private static int indexOf(StringBuilder source, String target, int fromIndex) { + if (fromIndex >= source.length()) + return (target.length() == 0 ? source.length() : -1); + if (fromIndex < 0) + fromIndex = 0; + if (target.length() == 0) + return fromIndex; + char first = target.charAt(0); + int max = source.length() - target.length(); + for (int i = fromIndex; i <= max; i++) { + if (source.charAt(i) != first) + while (++i <= max && source.charAt(i) != first); + if (i <= max) { + int j = i + 1; + int end = j + target.length() - 1; + for (int k = 1; j < end && source.charAt(j) + == target.charAt(k); j++, k++); + if (j == end) + return i; + } + } + return -1; + } + + // return last index of a string in a stringbuilder without performing allocations + static int lastIndexOf(StringBuilder source, String target) { + int rightIndex = source.length() - target.length(); + int fromIndex = source.length(); + if (fromIndex > rightIndex) + fromIndex = rightIndex; + if (target.length() == 0) + return fromIndex; + int strLastIndex = target.length() - 1; + char strLastChar = target.charAt(strLastIndex); + int min = target.length() - 1; + int i = min + fromIndex; + startSearchForLastChar: + while (true) { + while (i >= min && source.charAt(i) != strLastChar) + i--; + if (i < min) + return -1; + int j = i - 1; + int start = j - (target.length() - 1); + int k = strLastIndex - 1; + while (j > start) + if (source.charAt(j--) != target.charAt(k--)) { + i--; + continue startSearchForLastChar; + } + return start + 1; + } } public int bodyLength() { From c961fea7ec5dd99ca08579f1afc6c74a557cbad0 Mon Sep 17 00:00:00 2001 From: Knut Arild Erstad Date: Fri, 10 Jun 2016 12:41:11 +0200 Subject: [PATCH 004/165] Update FileLog.java Fixes thread race condition regression in http://www.quickfixj.org/jira/browse/QFJ-318. 1.4.0 seems to be the last released version with this fix. See also: https://sourceforge.net/p/quickfixj/code/826/ --- quickfixj-core/src/main/java/quickfix/FileLog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickfixj-core/src/main/java/quickfix/FileLog.java b/quickfixj-core/src/main/java/quickfix/FileLog.java index de2a06454..a83f1a8a3 100644 --- a/quickfixj-core/src/main/java/quickfix/FileLog.java +++ b/quickfixj-core/src/main/java/quickfix/FileLog.java @@ -90,7 +90,7 @@ protected void logOutgoing(String message) { writeMessage(messages, message, false); } - private void writeMessage(FileOutputStream stream, String message, boolean forceTimestamp) { + private synchronized void writeMessage(FileOutputStream stream, String message, boolean forceTimestamp) { try { if (forceTimestamp || includeTimestampForMessages) { writeTimeStamp(stream); From 090cee48c5b306832ea4e46679b5a56db653f750 Mon Sep 17 00:00:00 2001 From: Knut Arild Erstad Date: Thu, 22 Sep 2016 02:45:00 +0200 Subject: [PATCH 005/165] Update FileLog.java --- .../src/main/java/quickfix/FileLog.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/FileLog.java b/quickfixj-core/src/main/java/quickfix/FileLog.java index a83f1a8a3..d75270016 100644 --- a/quickfixj-core/src/main/java/quickfix/FileLog.java +++ b/quickfixj-core/src/main/java/quickfix/FileLog.java @@ -90,16 +90,18 @@ protected void logOutgoing(String message) { writeMessage(messages, message, false); } - private synchronized void writeMessage(FileOutputStream stream, String message, boolean forceTimestamp) { + private void writeMessage(FileOutputStream stream, String message, boolean forceTimestamp) { try { - if (forceTimestamp || includeTimestampForMessages) { - writeTimeStamp(stream); - } - stream.write(message.getBytes(CharsetSupport.getCharset())); - stream.write('\n'); - stream.flush(); - if (syncAfterWrite) { - stream.getFD().sync(); + synchronized(stream) { + if (forceTimestamp || includeTimestampForMessages) { + writeTimeStamp(stream); + } + stream.write(message.getBytes(CharsetSupport.getCharset())); + stream.write('\n'); + stream.flush(); + if (syncAfterWrite) { + stream.getFD().sync(); + } } } catch (IOException e) { // QFJ-459: no point trying to log the error in the file if we had an IOException From 629b801446431f06e0426aebcf669a2eca341a69 Mon Sep 17 00:00:00 2001 From: Guido Medina Date: Fri, 21 Oct 2016 11:12:38 +0100 Subject: [PATCH 006/165] QFJ-906: Source code language level set to JDK 7. --- .../quickfixj/codegenerator/GenerateMojo.java | 5 +- .../codegenerator/MessageCodeGenerator.java | 43 +++++---- .../jmx/mbean/connector/ConnectorAdmin.java | 34 ++++---- .../mbean/connector/SocketAcceptorAdmin.java | 24 +++-- .../mbean/connector/SocketInitiatorAdmin.java | 17 ++-- .../jmx/mbean/session/SessionAdmin.java | 15 +++- .../jmx/mbean/session/SessionJmxExporter.java | 24 +++-- .../mbean/session/SessionSettingsAdmin.java | 17 ++-- .../jmx/openmbean/CompositeDataFactory.java | 7 +- .../jmx/openmbean/CompositeTypeFactory.java | 9 +- .../jmx/openmbean/TabularDataAdapter.java | 15 ++-- .../src/main/java/quickfix/Acceptor.java | 8 +- .../main/java/quickfix/CachedFileStore.java | 42 ++++----- .../src/main/java/quickfix/Connector.java | 2 +- .../main/java/quickfix/DataDictionary.java | 70 ++++++++------- .../DefaultDataDictionaryProvider.java | 11 ++- .../java/quickfix/DefaultMessageFactory.java | 14 ++- .../java/quickfix/DefaultSessionFactory.java | 10 +-- .../src/main/java/quickfix/Dictionary.java | 4 +- .../src/main/java/quickfix/FieldMap.java | 31 ++++--- .../src/main/java/quickfix/FileStore.java | 39 +++------ .../src/main/java/quickfix/FileUtil.java | 3 - .../src/main/java/quickfix/FixVersions.java | 20 ++--- .../src/main/java/quickfix/Initiator.java | 12 +-- .../src/main/java/quickfix/JdbcLog.java | 18 ++-- .../src/main/java/quickfix/JdbcUtil.java | 23 ++--- .../main/java/quickfix/ListenerSupport.java | 2 +- .../src/main/java/quickfix/MemoryStore.java | 6 +- .../src/main/java/quickfix/Message.java | 28 +++--- .../main/java/quickfix/MessageCracker.java | 8 +- .../main/java/quickfix/MessageFactory.java | 2 +- .../main/java/quickfix/ScreenLogFactory.java | 4 +- .../src/main/java/quickfix/Session.java | 82 +++++++++-------- .../main/java/quickfix/SessionFactory.java | 8 +- .../quickfix/SessionRejectReasonText.java | 6 +- .../main/java/quickfix/SessionSettings.java | 17 ++-- .../src/main/java/quickfix/SessionState.java | 2 +- .../field/converter/DoubleConverter.java | 8 +- .../field/converter/UtcDateOnlyConverter.java | 6 +- .../field/converter/UtcTimeOnlyConverter.java | 6 +- .../converter/UtcTimestampConverter.java | 12 +-- .../quickfix/mina/EventHandlingStrategy.java | 4 +- .../java/quickfix/mina/NetworkingOptions.java | 13 ++- .../java/quickfix/mina/SessionConnector.java | 33 ++++--- .../SingleThreadedEventHandlingStrategy.java | 10 ++- ...ThreadPerSessionEventHandlingStrategy.java | 12 ++- .../mina/acceptor/AbstractSocketAcceptor.java | 32 ++++--- .../initiator/AbstractSocketInitiator.java | 25 +++--- .../mina/message/FIXMessageDecoder.java | 29 +++---- .../quickfix/mina/ssl/SSLContextFactory.java | 22 +++-- .../java/quickfix/mina/ssl/SSLSupport.java | 12 ++- .../jmx/mbean/session/SessionAdminTest.java | 8 +- .../quickfix/AbstractMessageStoreTest.java | 8 +- .../src/test/java/quickfix/FieldTest.java | 17 ++-- .../src/test/java/quickfix/FileStoreTest.java | 2 +- .../src/test/java/quickfix/JdbcStoreTest.java | 27 +++--- .../src/test/java/quickfix/LoginTestCase.java | 8 +- .../src/test/java/quickfix/MessageTest.java | 45 +++++----- .../test/java/quickfix/MultiAcceptorTest.java | 16 ++-- .../src/test/java/quickfix/SLF4JLogTest.java | 15 ++-- .../test/java/quickfix/SerializationTest.java | 51 ++++------- .../SessionDisconnectConcurrentlyTest.java | 22 +++-- .../src/test/java/quickfix/SessionTest.java | 64 +++++++------- .../java/quickfix/SocketAcceptorTest.java | 26 +++--- .../java/quickfix/SocketInitiatorTest.java | 31 ++++--- .../java/quickfix/UnitTestApplication.java | 14 +-- .../quickfix/mina/SessionConnectorTest.java | 24 ++--- ...ngleThreadedEventHandlingStrategyTest.java | 19 ++-- .../mina/acceptor/AcceptorIoHandlerTest.java | 29 +++---- .../DynamicAcceptorSessionProviderTest.java | 33 ++++--- .../mina/message/FIXMessageDecoderTest.java | 29 +++---- .../message/ProtocolDecoderOutputForTest.java | 6 +- .../quickfix/mina/ssl/SSLAndNonSSLTest.java | 19 ++-- .../quickfix/mina/ssl/SSLCertificateTest.java | 26 +++--- .../quickfix/mina/ssl/SecureSocketTest.java | 12 ++- .../test/acceptance/ATMessageCracker.java | 14 ++- .../quickfix/test/acceptance/ATServer.java | 36 ++++---- .../test/acceptance/AcceptanceTestSuite.java | 36 ++++---- .../test/acceptance/ExpectMessageStep.java | 20 ++--- .../test/acceptance/TestConnection.java | 37 ++++---- .../acceptance/resynch/ResynchTestClient.java | 13 ++- .../acceptance/resynch/ResynchTestServer.java | 15 ++-- .../acceptance/timer/TimerTestClient.java | 13 ++- .../acceptance/timer/TimerTestServer.java | 14 ++- quickfixj-dictgenerator/pom.xml | 13 +-- .../org/quickfixj/dictgenerator/Field.java | 2 +- .../quickfixj/dictgenerator/Generator.java | 8 +- .../org/quickfixj/dictgenerator/Message.java | 2 +- .../quickfixj/dictgenerator/Repository.java | 16 ++-- .../examples/banzai/BanzaiApplication.java | 87 +++++++++++-------- .../examples/banzai/ExecutionTableModel.java | 11 ++- .../quickfix/examples/banzai/OrderSide.java | 2 +- .../quickfix/examples/banzai/OrderTIF.java | 2 +- .../examples/banzai/OrderTableModel.java | 9 +- .../quickfix/examples/banzai/OrderType.java | 2 +- .../quickfix/examples/banzai/TwoWayMap.java | 4 +- .../examples/executor/Application.java | 13 ++- .../quickfix/examples/executor/Executor.java | 38 ++++---- .../examples/ordermatch/Application.java | 6 +- .../quickfix/examples/ordermatch/Main.java | 26 +++--- .../quickfix/examples/ordermatch/Market.java | 10 +-- .../examples/ordermatch/OrderMatcher.java | 2 +- 102 files changed, 928 insertions(+), 980 deletions(-) diff --git a/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/GenerateMojo.java b/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/GenerateMojo.java index 6788cf195..d39c0234d 100644 --- a/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/GenerateMojo.java +++ b/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/GenerateMojo.java @@ -19,12 +19,13 @@ package org.quickfixj.codegenerator; -import java.io.File; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.FileUtils; +import java.io.File; + /** * A mojo that uses the quickfix code generator to generate * Java source files from a QuickFIX Dictionary. @@ -137,8 +138,6 @@ public void execute() throws MojoExecutionException { task.setOrderedFields(orderedFields); task.setDecimalGenerated(decimal); generator.generate(task); - } catch (Exception e) { - throw new MojoExecutionException("QuickFIX code generator execution failed", e); } catch (Throwable t) { throw new MojoExecutionException("QuickFIX code generator execution failed", t); } diff --git a/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/MessageCodeGenerator.java b/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/MessageCodeGenerator.java index d6787fde6..3d0403d19 100644 --- a/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/MessageCodeGenerator.java +++ b/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/MessageCodeGenerator.java @@ -19,17 +19,10 @@ package org.quickfixj.codegenerator; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -42,11 +35,17 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * Generates Message and Field related code for the various FIX versions. @@ -84,7 +83,7 @@ private void generateMessageBaseClass(Task task) throws ParserConfigurationException, SAXException, IOException, TransformerFactoryConfigurationError, TransformerException { logInfo(task.getName() + ": generating message base class"); - Map parameters = new HashMap(); + Map parameters = new HashMap<>(); parameters.put(XSLPARAM_SERIAL_UID, SERIAL_UID_STR); generateClassCode(task, "Message", parameters); } @@ -107,7 +106,7 @@ private void generateClassCode(Task task, String className, Map TransformerException { logDebug("generating " + className + " for " + task.getName()); if (parameters == null) { - parameters = new HashMap(); + parameters = new HashMap<>(); } parameters.put("messagePackage", task.getMessagePackage()); parameters.put("fieldPackage", task.getFieldPackage()); @@ -131,7 +130,7 @@ private void generateFieldClasses(Task task) throws ParserConfigurationException String outputFile = outputDirectory + fieldName + ".java"; if (!new File(outputFile).exists()) { logDebug("field: " + fieldName); - Map parameters = new HashMap(); + Map parameters = new HashMap<>(); parameters.put("fieldName", fieldName); parameters.put("fieldPackage", task.getFieldPackage()); if (task.isDecimalGenerated()) { @@ -159,7 +158,7 @@ private void generateMessageSubclasses(Task task) throws ParserConfigurationExce Transformer transformer = createTransformer(task, "MessageSubclass.xsl"); for (String messageName : messageNames) { logDebug("generating message class: " + messageName); - Map parameters = new HashMap(); + Map parameters = new HashMap<>(); parameters.put("itemName", messageName); parameters.put(XSLPARAM_SERIAL_UID, SERIAL_UID_STR); parameters.put("orderedFields", Boolean.toString(task.isOrderedFields())); @@ -185,7 +184,7 @@ private void generateComponentClasses(Task task) throws ParserConfigurationExcep Transformer transformer = createTransformer(task, "MessageSubclass.xsl"); for (String componentName : componentNames) { logDebug("generating component class: " + componentName); - Map parameters = new HashMap(); + Map parameters = new HashMap<>(); parameters.put("itemName", componentName); parameters.put("baseClass", "quickfix.MessageComponent"); parameters.put("subpackage", ".component"); @@ -212,7 +211,7 @@ private Transformer createTransformer(Task task, String xsltFile) return transformerFactory.newTransformer(styleSource); } - private final Map specificationCache = new HashMap(); + private final Map specificationCache = new HashMap<>(); private Document getSpecification(Task task) throws ParserConfigurationException, SAXException, IOException { diff --git a/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/connector/ConnectorAdmin.java b/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/connector/ConnectorAdmin.java index 110218662..ec26da147 100644 --- a/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/connector/ConnectorAdmin.java +++ b/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/connector/ConnectorAdmin.java @@ -17,20 +17,6 @@ package org.quickfixj.jmx.mbean.connector; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.List; - -import javax.management.MBeanRegistration; -import javax.management.MBeanServer; -import javax.management.ObjectName; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; - import org.quickfixj.QFJException; import org.quickfixj.jmx.JmxExporter; import org.quickfixj.jmx.mbean.JmxSupport; @@ -38,7 +24,6 @@ import org.quickfixj.jmx.openmbean.TabularDataAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.Acceptor; import quickfix.Connector; import quickfix.Initiator; @@ -47,6 +32,19 @@ import quickfix.SessionSettings; import quickfix.mina.SessionConnector; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.TabularData; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; + abstract class ConnectorAdmin implements ConnectorAdminMBean, MBeanRegistration { private final Logger log = LoggerFactory.getLogger(getClass()); @@ -64,7 +62,7 @@ abstract class ConnectorAdmin implements ConnectorAdminMBean, MBeanRegistration private final ObjectName connectorName; - private final List sessionNames = new ArrayList(); + private final List sessionNames = new ArrayList<>(); private final SessionSettings settings; @@ -118,7 +116,7 @@ public String getRemoteAddress() { } public TabularData getSessions() throws IOException { - List sessions = new ArrayList(); + List sessions = new ArrayList<>(); for (SessionID sessionID : connector.getSessions()) { Session session = Session.lookupSession(sessionID); sessions.add(new ConnectorSession(session, sessionExporter.getSessionName(sessionID))); @@ -131,7 +129,7 @@ public TabularData getSessions() throws IOException { } public TabularData getLoggedOnSessions() throws OpenDataException { - List names = new ArrayList(); + List names = new ArrayList<>(); for (SessionID sessionID : connector.getSessions()) { Session session = Session.lookupSession(sessionID); if (session.isLoggedOn()) { diff --git a/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/connector/SocketAcceptorAdmin.java b/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/connector/SocketAcceptorAdmin.java index 41d9b2411..19a066c6b 100644 --- a/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/connector/SocketAcceptorAdmin.java +++ b/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/connector/SocketAcceptorAdmin.java @@ -17,25 +17,23 @@ package org.quickfixj.jmx.mbean.connector; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.management.ObjectName; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; - import org.quickfixj.jmx.JmxExporter; import org.quickfixj.jmx.mbean.JmxSupport; import org.quickfixj.jmx.mbean.session.SessionJmxExporter; import org.quickfixj.jmx.openmbean.TabularDataAdapter; - import quickfix.SessionID; import quickfix.mina.acceptor.AbstractSocketAcceptor; +import javax.management.ObjectName; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.TabularData; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + /** * Implementation of the socket acceptor management interface. */ @@ -85,7 +83,7 @@ public ObjectName getSessionName() { } public TabularData getAcceptorAddresses() throws IOException { - List rows = new ArrayList(); + List rows = new ArrayList<>(); for (Map.Entry entry : acceptor.getAcceptorAddresses().entrySet()) { SessionID sessionID = entry.getKey(); SocketAddress address = entry.getValue(); diff --git a/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/connector/SocketInitiatorAdmin.java b/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/connector/SocketInitiatorAdmin.java index cf63af778..590e6dfa9 100644 --- a/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/connector/SocketInitiatorAdmin.java +++ b/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/connector/SocketInitiatorAdmin.java @@ -17,20 +17,17 @@ package org.quickfixj.jmx.mbean.connector; -import java.io.IOException; -import java.util.ArrayList; - -import javax.management.ObjectName; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; - import org.quickfixj.jmx.JmxExporter; import org.quickfixj.jmx.mbean.JmxSupport; import org.quickfixj.jmx.mbean.session.SessionJmxExporter; import org.quickfixj.jmx.openmbean.TabularDataAdapter; - import quickfix.mina.initiator.AbstractSocketInitiator; -import quickfix.mina.initiator.IoSessionInitiator; + +import javax.management.ObjectName; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.TabularData; +import java.io.IOException; +import java.util.ArrayList; class SocketInitiatorAdmin extends ConnectorAdmin implements SocketInitiatorAdminMBean { @@ -47,7 +44,7 @@ protected SocketInitiatorAdmin(JmxExporter jmxExporter, AbstractSocketInitiator public TabularData getEndpoints() throws IOException { try { return tabularDataAdapter.fromBeanList("Endpoints", "Endpoint", "sessionID", - new ArrayList(initiator.getInitiators())); + new ArrayList<>(initiator.getInitiators())); } catch (OpenDataException e) { throw JmxSupport.toIOException(e); } diff --git a/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/session/SessionAdmin.java b/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/session/SessionAdmin.java index 3a1ac52b2..e6c3810a0 100644 --- a/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/session/SessionAdmin.java +++ b/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/session/SessionAdmin.java @@ -20,13 +20,20 @@ import org.quickfixj.QFJException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import quickfix.*; +import quickfix.Message; +import quickfix.Session; +import quickfix.SessionID; +import quickfix.SessionNotFound; +import quickfix.SessionStateListener; import quickfix.field.MsgType; import quickfix.field.NewSeqNo; import quickfix.field.converter.UtcTimestampConverter; -import javax.management.*; - +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.ObjectName; import java.io.IOException; import java.util.ArrayList; @@ -167,7 +174,7 @@ public int getNextTargetMsgSeqNum() throws IOException { * @see quickfix.jmx.SessionMBean#getMessages(int, int) */ public String[] getMessages(int startSequence, int endSequence) throws IOException { - ArrayList messages = new ArrayList(); + ArrayList messages = new ArrayList<>(); session.getStore().get(startSequence, endSequence, messages); return messages.toArray(new String[messages.size()]); } diff --git a/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/session/SessionJmxExporter.java b/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/session/SessionJmxExporter.java index e5e7acdd3..c341752a4 100644 --- a/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/session/SessionJmxExporter.java +++ b/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/session/SessionJmxExporter.java @@ -17,26 +17,24 @@ package org.quickfixj.jmx.mbean.session; -import static quickfix.SessionID.NOT_SET; - -import java.util.HashMap; -import java.util.Map; -import java.util.TreeMap; - -import javax.management.JMException; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; - import org.quickfixj.jmx.JmxExporter; import org.quickfixj.jmx.mbean.ObjectNameFactory; - import quickfix.ConfigError; import quickfix.Session; import quickfix.SessionID; import quickfix.SessionSettings; +import javax.management.JMException; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +import static quickfix.SessionID.NOT_SET; + public class SessionJmxExporter { - private final Map sessionObjectNames = new HashMap(); + private final Map sessionObjectNames = new HashMap<>(); public ObjectName register(JmxExporter jmxExporter, Session session, ObjectName connectorName, SessionSettings settings) throws JMException, ConfigError { @@ -60,7 +58,7 @@ public ObjectName getSessionName(SessionID sessionID) { } public ObjectName createSessionName(SessionID sessionID) throws MalformedObjectNameException { - TreeMap properties = new TreeMap(); + TreeMap properties = new TreeMap<>(); properties.put("type", "Session"); ObjectNameFactory nameFactory = new ObjectNameFactory(); nameFactory.addProperty("type", "Session"); diff --git a/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/session/SessionSettingsAdmin.java b/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/session/SessionSettingsAdmin.java index 4099f08af..ffc516d94 100644 --- a/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/session/SessionSettingsAdmin.java +++ b/quickfixj-core/src/main/java/org/quickfixj/jmx/mbean/session/SessionSettingsAdmin.java @@ -17,10 +17,9 @@ package org.quickfixj.jmx.mbean.session; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Properties; +import quickfix.ConfigError; +import quickfix.SessionID; +import quickfix.SessionSettings; import javax.management.Attribute; import javax.management.AttributeList; @@ -31,10 +30,10 @@ import javax.management.MBeanException; import javax.management.MBeanInfo; import javax.management.ReflectionException; - -import quickfix.ConfigError; -import quickfix.SessionID; -import quickfix.SessionSettings; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; /** * This is a read-only view of a sessions settings. @@ -68,7 +67,7 @@ public AttributeList getAttributes(String[] attributeNames) { } public MBeanInfo getMBeanInfo() { - List attributeInfos = new ArrayList(); + List attributeInfos = new ArrayList<>(); for (Map.Entry entry : settings.entrySet()) { String name = (String) entry.getKey(); attributeInfos.add(new MBeanAttributeInfo(name, "Setting for " + name, entry.getValue().getClass().getName(), true, false, diff --git a/quickfixj-core/src/main/java/org/quickfixj/jmx/openmbean/CompositeDataFactory.java b/quickfixj-core/src/main/java/org/quickfixj/jmx/openmbean/CompositeDataFactory.java index 0085ce7f1..e95c068b3 100644 --- a/quickfixj-core/src/main/java/org/quickfixj/jmx/openmbean/CompositeDataFactory.java +++ b/quickfixj-core/src/main/java/org/quickfixj/jmx/openmbean/CompositeDataFactory.java @@ -17,17 +17,16 @@ package org.quickfixj.jmx.openmbean; -import java.util.ArrayList; - import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenDataException; +import java.util.ArrayList; public class CompositeDataFactory { private final CompositeType compositeType; - private final ArrayList itemNames = new ArrayList(); - private final ArrayList itemValues = new ArrayList(); + private final ArrayList itemNames = new ArrayList<>(); + private final ArrayList itemValues = new ArrayList<>(); public CompositeDataFactory(CompositeType compositeType) { this.compositeType = compositeType; diff --git a/quickfixj-core/src/main/java/org/quickfixj/jmx/openmbean/CompositeTypeFactory.java b/quickfixj-core/src/main/java/org/quickfixj/jmx/openmbean/CompositeTypeFactory.java index 5f1bb8ca8..f7ceff2de 100644 --- a/quickfixj-core/src/main/java/org/quickfixj/jmx/openmbean/CompositeTypeFactory.java +++ b/quickfixj-core/src/main/java/org/quickfixj/jmx/openmbean/CompositeTypeFactory.java @@ -17,11 +17,10 @@ package org.quickfixj.jmx.openmbean; -import java.util.ArrayList; - import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenDataException; import javax.management.openmbean.OpenType; +import java.util.ArrayList; // NOTE: Do not parameterize OpenType for Java6 since it will // be incompatible with Java 5 @@ -29,11 +28,11 @@ public class CompositeTypeFactory { private final String name; private final String description; - private final ArrayList itemNames = new ArrayList(); - private final ArrayList itemDescriptions = new ArrayList(); + private final ArrayList itemNames = new ArrayList<>(); + private final ArrayList itemDescriptions = new ArrayList<>(); @SuppressWarnings("rawtypes") // Java 5/6 incompatibility - private final ArrayList itemTypes = new ArrayList(); + private final ArrayList itemTypes = new ArrayList<>(); public CompositeTypeFactory(String name, String description) { this.name = name; diff --git a/quickfixj-core/src/main/java/org/quickfixj/jmx/openmbean/TabularDataAdapter.java b/quickfixj-core/src/main/java/org/quickfixj/jmx/openmbean/TabularDataAdapter.java index 615822770..0e02d321f 100644 --- a/quickfixj-core/src/main/java/org/quickfixj/jmx/openmbean/TabularDataAdapter.java +++ b/quickfixj-core/src/main/java/org/quickfixj/jmx/openmbean/TabularDataAdapter.java @@ -17,19 +17,18 @@ package org.quickfixj.jmx.openmbean; -import java.beans.BeanInfo; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenDataException; import javax.management.openmbean.SimpleType; import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; public class TabularDataAdapter { @@ -113,7 +112,7 @@ public TabularData fromBeanList(String tableTypeName, String rowTypeName, String TabularData table; try { CompositeTypeFactory rowTypeFactory = new CompositeTypeFactory(rowTypeName, rowTypeName); - List indexNames = new ArrayList(); + List indexNames = new ArrayList<>(); indexNames.add(keyProperty); rowTypeFactory.defineItem(formatHeader(keyProperty), SimpleType.STRING); for (Object bean : beans) { diff --git a/quickfixj-core/src/main/java/quickfix/Acceptor.java b/quickfixj-core/src/main/java/quickfix/Acceptor.java index 7e1e22f4a..9a35dd9f2 100644 --- a/quickfixj-core/src/main/java/quickfix/Acceptor.java +++ b/quickfixj-core/src/main/java/quickfix/Acceptor.java @@ -27,20 +27,20 @@ public interface Acceptor extends Connector { /** * Acceptor setting specifying the socket protocol used to accept connections. */ - public static final String SETTING_SOCKET_ACCEPT_PROTOCOL = "SocketAcceptProtocol"; + String SETTING_SOCKET_ACCEPT_PROTOCOL = "SocketAcceptProtocol"; /** * Acceptor setting specifying port for accepting FIX client connections. */ - public static final String SETTING_SOCKET_ACCEPT_PORT = "SocketAcceptPort"; + String SETTING_SOCKET_ACCEPT_PORT = "SocketAcceptPort"; /** * Acceptor setting specifying local IP interface address for accepting connections. */ - public static final String SETTING_SOCKET_ACCEPT_ADDRESS = "SocketAcceptAddress"; + String SETTING_SOCKET_ACCEPT_ADDRESS = "SocketAcceptAddress"; /** * Acceptor setting specifying local IP interface address for accepting connections. */ - public static final String SETTING_ACCEPTOR_TEMPLATE = "AcceptorTemplate"; + String SETTING_ACCEPTOR_TEMPLATE = "AcceptorTemplate"; } diff --git a/quickfixj-core/src/main/java/quickfix/CachedFileStore.java b/quickfixj-core/src/main/java/quickfix/CachedFileStore.java index faa01aa71..2254fcd6c 100644 --- a/quickfixj-core/src/main/java/quickfix/CachedFileStore.java +++ b/quickfixj-core/src/main/java/quickfix/CachedFileStore.java @@ -19,6 +19,11 @@ package quickfix; +import org.quickfixj.CharsetSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import quickfix.field.converter.UtcTimestampConverter; + import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; @@ -39,12 +44,6 @@ import java.util.Set; import java.util.TreeMap; -import org.quickfixj.CharsetSupport; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import quickfix.field.converter.UtcTimestampConverter; - /** * File store implementation. THIS CLASS IS PUBLIC ONLY TO MAINTAIN COMPATIBILITY WITH THE QUICKFIX JNI. IT SHOULD ONLY * BE CREATED USING A FACTORY. @@ -134,16 +133,13 @@ private void initializeCache() throws IOException { private void initializeSessionCreateTime() throws IOException { final File sessionTimeFile = new File(sessionFileName); if (sessionTimeFile.exists() && sessionTimeFile.length() > 0) { - final DataInputStream sessionTimeInput = new DataInputStream(new BufferedInputStream( - new FileInputStream(sessionTimeFile))); - try { + try (DataInputStream sessionTimeInput = new DataInputStream(new BufferedInputStream( + new FileInputStream(sessionTimeFile)))) { final Calendar c = SystemTime.getUtcCalendar(UtcTimestampConverter .convert(sessionTimeInput.readUTF())); cache.setCreationTime(c); } catch (final Exception e) { throw new IOException(e.getMessage()); - } finally { - sessionTimeInput.close(); } } else { storeSessionTimeStamp(); @@ -151,14 +147,11 @@ private void initializeSessionCreateTime() throws IOException { } private void storeSessionTimeStamp() throws IOException { - final DataOutputStream sessionTimeOutput = new DataOutputStream(new BufferedOutputStream( - new FileOutputStream(sessionFileName, false))); - try { + try (DataOutputStream sessionTimeOutput = new DataOutputStream(new BufferedOutputStream( + new FileOutputStream(sessionFileName, false)))) { final Date date = SystemTime.getDate(); cache.setCreationTime(SystemTime.getUtcCalendar(date)); sessionTimeOutput.writeUTF(UtcTimestampConverter.convert(date, true)); - } finally { - sessionTimeOutput.close(); } } @@ -187,17 +180,14 @@ private void initializeSequenceNumbers() throws IOException { private void initializeMessageIndex() throws IOException { final File headerFile = new File(headerFileName); if (headerFile.exists()) { - final DataInputStream headerDataInputStream = new DataInputStream( - new BufferedInputStream(new FileInputStream(headerFile))); - try { + try (DataInputStream headerDataInputStream = new DataInputStream( + new BufferedInputStream(new FileInputStream(headerFile)))) { while (headerDataInputStream.available() > 0) { final int sequenceNumber = headerDataInputStream.readInt(); final long offset = headerDataInputStream.readLong(); final int size = headerDataInputStream.readInt(); - messageIndex.put((long) sequenceNumber, new long[] { offset, size }); + messageIndex.put((long) sequenceNumber, new long[]{offset, size}); } - } finally { - headerDataInputStream.close(); } } headerFileOutputStream = new FileOutputStream(headerFileName, true); @@ -331,7 +321,7 @@ private String read(long offset, long size) throws IOException { } private Collection getMessage(long startSequence, long endSequence) throws IOException { - final Collection messages = new ArrayList(); + final Collection messages = new ArrayList<>(); final List offsetAndSizes = messageIndex.get(startSequence, endSequence); for (final long[] offsetAndSize : offsetAndSizes) { @@ -407,7 +397,7 @@ public void reset() throws IOException { */ private class CachedHashMap implements Map { - private final TreeMap cacheIndex = new TreeMap(); + private final TreeMap cacheIndex = new TreeMap<>(); private int currentSize; @@ -510,7 +500,7 @@ private long[] seekMessageIndex(final long index) { } private List seekMessageIndex(final long startSequence, final long endSequence) { - final TreeMap indexPerSequenceNumber = new TreeMap(); + final TreeMap indexPerSequenceNumber = new TreeMap<>(); final File headerFile = new File(headerFileName); if (headerFile.exists()) { DataInputStream headerDataInputStream = null; @@ -538,7 +528,7 @@ private List seekMessageIndex(final long startSequence, final long endSe } } } - return new ArrayList(indexPerSequenceNumber.values()); + return new ArrayList<>(indexPerSequenceNumber.values()); } public List get(final long startSequence, final long endSequence) { diff --git a/quickfixj-core/src/main/java/quickfix/Connector.java b/quickfixj-core/src/main/java/quickfix/Connector.java index 852973591..8efcc876e 100644 --- a/quickfixj-core/src/main/java/quickfix/Connector.java +++ b/quickfixj-core/src/main/java/quickfix/Connector.java @@ -46,7 +46,7 @@ public interface Connector { * * @param force don't wait for logout before disconnect. */ - public void stop(boolean force); + void stop(boolean force); /** * Start accepting connections. This method blocks until stop is called from diff --git a/quickfixj-core/src/main/java/quickfix/DataDictionary.java b/quickfixj-core/src/main/java/quickfix/DataDictionary.java index bb36d9e54..92e6d42fe 100644 --- a/quickfixj-core/src/main/java/quickfix/DataDictionary.java +++ b/quickfixj-core/src/main/java/quickfix/DataDictionary.java @@ -19,31 +19,11 @@ package quickfix; -import static quickfix.FileUtil.Location.CLASSLOADER_RESOURCE; -import static quickfix.FileUtil.Location.CONTEXT_RESOURCE; -import static quickfix.FileUtil.Location.FILESYSTEM; -import static quickfix.FileUtil.Location.URL; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; - import quickfix.field.BeginString; import quickfix.field.MsgType; import quickfix.field.SessionRejectReason; @@ -55,6 +35,24 @@ import quickfix.field.converter.UtcTimeOnlyConverter; import quickfix.field.converter.UtcTimestampConverter; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static quickfix.FileUtil.Location.CLASSLOADER_RESOURCE; +import static quickfix.FileUtil.Location.CONTEXT_RESOURCE; +import static quickfix.FileUtil.Location.FILESYSTEM; +import static quickfix.FileUtil.Location.URL; + /** * Provide the message metadata for various versions of FIX. */ @@ -76,19 +74,19 @@ public class DataDictionary { private boolean checkUnorderedGroupFields = true; private boolean allowUnknownMessageFields = false; private String beginString; - private final Map> messageFields = new HashMap>(); - private final Map> requiredFields = new HashMap>(); - private final Set messages = new HashSet(); - private final Map messageCategory = new HashMap(); - private final Map messageTypeForName = new HashMap(); - private final LinkedHashSet fields = new LinkedHashSet(); - private final Map fieldTypes = new HashMap(); - private final Map> fieldValues = new HashMap>(); - private final Map fieldNames = new HashMap(); - private final Map names = new HashMap(); - private final Map valueNames = new HashMap(); - private final Map groups = new HashMap(); - private final Map components = new HashMap(); + private final Map> messageFields = new HashMap<>(); + private final Map> requiredFields = new HashMap<>(); + private final Set messages = new HashSet<>(); + private final Map messageCategory = new HashMap<>(); + private final Map messageTypeForName = new HashMap<>(); + private final LinkedHashSet fields = new LinkedHashSet<>(); + private final Map fieldTypes = new HashMap<>(); + private final Map> fieldValues = new HashMap<>(); + private final Map fieldNames = new HashMap<>(); + private final Map names = new HashMap<>(); + private final Map valueNames = new HashMap<>(); + private final Map groups = new HashMap<>(); + private final Map components = new HashMap<>(); private DataDictionary() { } @@ -247,7 +245,7 @@ public boolean isAppMessage(String msgType) { private void addMsgField(String msgType, int field) { Set fields = messageFields.get(msgType); if (fields == null) { - fields = new HashSet(); + fields = new HashSet<>(); messageFields.put(msgType, fields); } fields.add(field); @@ -303,7 +301,7 @@ public int getFieldTag(String name) { private void addRequiredField(String msgType, int field) { Set fields = requiredFields.get(msgType); if (fields == null) { - fields = new HashSet(); + fields = new HashSet<>(); requiredFields.put(msgType, fields); } fields.add(field); @@ -344,7 +342,7 @@ public boolean isRequiredTrailerField(int field) { private void addFieldValue(int field, String value) { Set values = fieldValues.get(field); if (values == null) { - values = new HashSet(); + values = new HashSet<>(); fieldValues.put(field, values); } values.add(value); diff --git a/quickfixj-core/src/main/java/quickfix/DefaultDataDictionaryProvider.java b/quickfixj-core/src/main/java/quickfix/DefaultDataDictionaryProvider.java index 3af287101..78991dfab 100644 --- a/quickfixj-core/src/main/java/quickfix/DefaultDataDictionaryProvider.java +++ b/quickfixj-core/src/main/java/quickfix/DefaultDataDictionaryProvider.java @@ -19,18 +19,17 @@ package quickfix; -import static quickfix.MessageUtils.*; +import org.quickfixj.QFJException; +import quickfix.field.ApplVerID; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import org.quickfixj.QFJException; - -import quickfix.field.ApplVerID; +import static quickfix.MessageUtils.toBeginString; public class DefaultDataDictionaryProvider implements DataDictionaryProvider { - private final Map transportDictionaries = new ConcurrentHashMap(); - private final Map applicationDictionaries = new ConcurrentHashMap(); + private final Map transportDictionaries = new ConcurrentHashMap<>(); + private final Map applicationDictionaries = new ConcurrentHashMap<>(); private final boolean findDataDictionaries; public DefaultDataDictionaryProvider() { diff --git a/quickfixj-core/src/main/java/quickfix/DefaultMessageFactory.java b/quickfixj-core/src/main/java/quickfix/DefaultMessageFactory.java index f942e0c50..60a3dfbf2 100644 --- a/quickfixj-core/src/main/java/quickfix/DefaultMessageFactory.java +++ b/quickfixj-core/src/main/java/quickfix/DefaultMessageFactory.java @@ -19,18 +19,26 @@ package quickfix; -import static quickfix.FixVersions.*; import quickfix.field.MsgType; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import static quickfix.FixVersions.BEGINSTRING_FIX40; +import static quickfix.FixVersions.BEGINSTRING_FIX41; +import static quickfix.FixVersions.BEGINSTRING_FIX42; +import static quickfix.FixVersions.BEGINSTRING_FIX43; +import static quickfix.FixVersions.BEGINSTRING_FIX44; +import static quickfix.FixVersions.BEGINSTRING_FIXT11; +import static quickfix.FixVersions.FIX50; +import static quickfix.FixVersions.FIX50SP1; +import static quickfix.FixVersions.FIX50SP2; + /** * The default factory for creating FIX message instances. */ public class DefaultMessageFactory implements MessageFactory { - private final Map messageFactories - = new ConcurrentHashMap(); + private final Map messageFactories = new ConcurrentHashMap<>(); /** * Constructs a DefaultMessageFactory, which dynamically loads and delegates to diff --git a/quickfixj-core/src/main/java/quickfix/DefaultSessionFactory.java b/quickfixj-core/src/main/java/quickfix/DefaultSessionFactory.java index 50943cbb3..e7c66ab7f 100644 --- a/quickfixj-core/src/main/java/quickfix/DefaultSessionFactory.java +++ b/quickfixj-core/src/main/java/quickfix/DefaultSessionFactory.java @@ -19,22 +19,22 @@ package quickfix; +import quickfix.field.ApplVerID; +import quickfix.field.DefaultApplVerID; + import java.net.InetAddress; import java.util.Enumeration; -import java.util.Hashtable; import java.util.Map; import java.util.Properties; import java.util.Set; - -import quickfix.field.ApplVerID; -import quickfix.field.DefaultApplVerID; +import java.util.concurrent.ConcurrentHashMap; /** * Factory for creating sessions. Used by the communications code (acceptors, * initiators) for creating sessions. */ public class DefaultSessionFactory implements SessionFactory { - private static final Map dictionaryCache = new Hashtable(); + private static final Map dictionaryCache = new ConcurrentHashMap<>(); private final Application application; private final MessageStoreFactory messageStoreFactory; private final LogFactory logFactory; diff --git a/quickfixj-core/src/main/java/quickfix/Dictionary.java b/quickfixj-core/src/main/java/quickfix/Dictionary.java index 3d3310d9e..ab7989b42 100644 --- a/quickfixj-core/src/main/java/quickfix/Dictionary.java +++ b/quickfixj-core/src/main/java/quickfix/Dictionary.java @@ -29,13 +29,13 @@ */ public class Dictionary { private String name; - private final HashMap data = new HashMap(); + private final HashMap data = new HashMap<>(); public Dictionary() { } public Dictionary(String name) { - this(name, new HashMap()); + this(name, new HashMap<>()); } public Dictionary(Dictionary dictionary) { diff --git a/quickfixj-core/src/main/java/quickfix/FieldMap.java b/quickfixj-core/src/main/java/quickfix/FieldMap.java index 4d26a1406..bbbf988ed 100644 --- a/quickfixj-core/src/main/java/quickfix/FieldMap.java +++ b/quickfixj-core/src/main/java/quickfix/FieldMap.java @@ -19,17 +19,6 @@ package quickfix; -import java.io.Serializable; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.TreeMap; - import quickfix.field.BeginString; import quickfix.field.BodyLength; import quickfix.field.CheckSum; @@ -43,6 +32,17 @@ import quickfix.field.converter.UtcTimeOnlyConverter; import quickfix.field.converter.UtcTimestampConverter; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; + /** * Field container used by messages, groups, and composites. */ @@ -54,7 +54,7 @@ public abstract class FieldMap implements Serializable { private final TreeMap> fields; - private final TreeMap> groups = new TreeMap>(); + private final TreeMap> groups = new TreeMap<>(); /** * Constructs a FieldMap with the given field order. @@ -64,8 +64,7 @@ public abstract class FieldMap implements Serializable { */ protected FieldMap(int[] fieldOrder) { this.fieldOrder = fieldOrder; - fields = new TreeMap>( - fieldOrder != null ? new FieldOrderComparator() : null); + fields = new TreeMap<>(fieldOrder != null ? new FieldOrderComparator() : null); } protected FieldMap() { @@ -412,7 +411,7 @@ protected void initializeFrom(FieldMap source) { fields.clear(); fields.putAll(source.fields); for (Entry> entry : source.groups.entrySet()) { - final List clones = new ArrayList(); + final List clones = new ArrayList<>(); for (final Group group : entry.getValue()) { final Group clone = new Group(group.getFieldTag(), group.delim(), group.getFieldOrder()); @@ -572,7 +571,7 @@ protected void setGroupCount(int countTag, int groupSize) { public List getGroups(int field) { List groupList = groups.get(field); if (groupList == null) { - groupList = new ArrayList(); + groupList = new ArrayList<>(); groups.put(field, groupList); } return groupList; diff --git a/quickfixj-core/src/main/java/quickfix/FileStore.java b/quickfixj-core/src/main/java/quickfix/FileStore.java index b965d05ac..325db55b8 100644 --- a/quickfixj-core/src/main/java/quickfix/FileStore.java +++ b/quickfixj-core/src/main/java/quickfix/FileStore.java @@ -19,6 +19,9 @@ package quickfix; +import org.quickfixj.CharsetSupport; +import quickfix.field.converter.UtcTimestampConverter; + import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.Closeable; @@ -37,10 +40,6 @@ import java.util.Set; import java.util.TreeMap; -import org.quickfixj.CharsetSupport; - -import quickfix.field.converter.UtcTimestampConverter; - /** * File store implementation. THIS CLASS IS PUBLIC ONLY TO MAINTAIN * COMPATIBILITY WITH THE QUICKFIX JNI. IT SHOULD ONLY BE CREATED USING A @@ -124,16 +123,13 @@ private void initializeCache() throws IOException { private void initializeSessionCreateTime() throws IOException { final File sessionTimeFile = new File(sessionFileName); if (sessionTimeFile.exists() && sessionTimeFile.length() > 0) { - final DataInputStream sessionTimeInput = new DataInputStream(new BufferedInputStream( - new FileInputStream(sessionTimeFile))); - try { + try (DataInputStream sessionTimeInput = new DataInputStream(new BufferedInputStream( + new FileInputStream(sessionTimeFile)))) { final Calendar c = SystemTime.getUtcCalendar(UtcTimestampConverter .convert(sessionTimeInput.readUTF())); cache.setCreationTime(c); } catch (final Exception e) { throw new IOException(e.getMessage()); - } finally { - sessionTimeInput.close(); } } else { storeSessionTimeStamp(); @@ -141,14 +137,11 @@ private void initializeSessionCreateTime() throws IOException { } private void storeSessionTimeStamp() throws IOException { - final DataOutputStream sessionTimeOutput = new DataOutputStream(new BufferedOutputStream( - new FileOutputStream(sessionFileName, false))); - try { + try (DataOutputStream sessionTimeOutput = new DataOutputStream(new BufferedOutputStream( + new FileOutputStream(sessionFileName, false)))) { final Date date = SystemTime.getDate(); cache.setCreationTime(SystemTime.getUtcCalendar(date)); sessionTimeOutput.writeUTF(UtcTimestampConverter.convert(date, true)); - } finally { - sessionTimeOutput.close(); } } @@ -180,17 +173,14 @@ private void initializeMessageIndex() throws IOException { messageIndex.clear(); final File headerFile = new File(headerFileName); if (headerFile.exists()) { - final DataInputStream headerDataInputStream = new DataInputStream( - new BufferedInputStream(new FileInputStream(headerFile))); - try { + try (DataInputStream headerDataInputStream = new DataInputStream( + new BufferedInputStream(new FileInputStream(headerFile)))) { while (headerDataInputStream.available() > 0) { final int sequenceNumber = headerDataInputStream.readInt(); final long offset = headerDataInputStream.readLong(); final int size = headerDataInputStream.readInt(); updateMessageIndex(sequenceNumber, offset, size); } - } finally { - headerDataInputStream.close(); } } } @@ -303,9 +293,9 @@ public void incrNextTargetMsgSeqNum() throws IOException { @Override public void get(int startSequence, int endSequence, Collection messages) throws IOException { - final Set uncachedOffsetMsgIds = new HashSet(); + final Set uncachedOffsetMsgIds = new HashSet<>(); // Use a treemap to make sure the messages are sorted by sequence num - final TreeMap messagesFound = new TreeMap(); + final TreeMap messagesFound = new TreeMap<>(); for (int i = startSequence; i <= endSequence; i++) { final String message = getMessage(i); if (message != null) { @@ -318,9 +308,8 @@ public void get(int startSequence, int endSequence, Collection messages) if (!uncachedOffsetMsgIds.isEmpty()) { // parse the header file to find missing messages final File headerFile = new File(headerFileName); - final DataInputStream headerDataInputStream = new DataInputStream( - new BufferedInputStream(new FileInputStream(headerFile))); - try { + try (DataInputStream headerDataInputStream = new DataInputStream( + new BufferedInputStream(new FileInputStream(headerFile)))) { while (!uncachedOffsetMsgIds.isEmpty() && headerDataInputStream.available() > 0) { final int sequenceNumber = headerDataInputStream.readInt(); final long offset = headerDataInputStream.readLong(); @@ -330,8 +319,6 @@ public void get(int startSequence, int endSequence, Collection messages) messagesFound.put(sequenceNumber, message); } } - } finally { - headerDataInputStream.close(); } } diff --git a/quickfixj-core/src/main/java/quickfix/FileUtil.java b/quickfixj-core/src/main/java/quickfix/FileUtil.java index e732ee562..c8159f778 100644 --- a/quickfixj-core/src/main/java/quickfix/FileUtil.java +++ b/quickfixj-core/src/main/java/quickfix/FileUtil.java @@ -24,7 +24,6 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.net.MalformedURLException; import java.net.URL; public class FileUtil { @@ -143,8 +142,6 @@ public static InputStream open(Class clazz, String name, Location... location case URL: try { in = new URL(name).openStream(); - } catch (MalformedURLException e) { - // ignore } catch (IOException e) { // ignore } diff --git a/quickfixj-core/src/main/java/quickfix/FixVersions.java b/quickfixj-core/src/main/java/quickfix/FixVersions.java index 16503b6e1..7cb7f9818 100644 --- a/quickfixj-core/src/main/java/quickfix/FixVersions.java +++ b/quickfixj-core/src/main/java/quickfix/FixVersions.java @@ -23,21 +23,21 @@ * Constants containing the BeginString field values for various FIX versions. */ public interface FixVersions { - public static final String BEGINSTRING_FIX40 = "FIX.4.0"; - public static final String BEGINSTRING_FIX41 = "FIX.4.1"; - public static final String BEGINSTRING_FIX42 = "FIX.4.2"; - public static final String BEGINSTRING_FIX43 = "FIX.4.3"; - public static final String BEGINSTRING_FIX44 = "FIX.4.4"; + String BEGINSTRING_FIX40 = "FIX.4.0"; + String BEGINSTRING_FIX41 = "FIX.4.1"; + String BEGINSTRING_FIX42 = "FIX.4.2"; + String BEGINSTRING_FIX43 = "FIX.4.3"; + String BEGINSTRING_FIX44 = "FIX.4.4"; /** * FIX 5.0 does not have a begin string. */ - public static final String FIX50 = "FIX.5.0"; - public static final String FIX50SP1 = "FIX.5.0SP1"; - public static final String FIX50SP2 = "FIX.5.0SP2"; + String FIX50 = "FIX.5.0"; + String FIX50SP1 = "FIX.5.0SP1"; + String FIX50SP2 = "FIX.5.0SP2"; // FIXT.x.x support - public static final String FIXT_SESSION_PREFIX = "FIXT."; - public static final String BEGINSTRING_FIXT11 = FIXT_SESSION_PREFIX + "1.1"; + String FIXT_SESSION_PREFIX = "FIXT."; + String BEGINSTRING_FIXT11 = FIXT_SESSION_PREFIX + "1.1"; } diff --git a/quickfixj-core/src/main/java/quickfix/Initiator.java b/quickfixj-core/src/main/java/quickfix/Initiator.java index 21899c60a..7dcab3020 100644 --- a/quickfixj-core/src/main/java/quickfix/Initiator.java +++ b/quickfixj-core/src/main/java/quickfix/Initiator.java @@ -30,12 +30,12 @@ public interface Initiator extends Connector { * * @see quickfix.SessionFactory#SETTING_CONNECTION_TYPE */ - public static final String SETTING_RECONNECT_INTERVAL = "ReconnectInterval"; + String SETTING_RECONNECT_INTERVAL = "ReconnectInterval"; /** * Initiator setting for connection protocol (defaults to "tcp"). */ - public static final String SETTING_SOCKET_CONNECT_PROTOCOL = "SocketConnectProtocol"; + String SETTING_SOCKET_CONNECT_PROTOCOL = "SocketConnectProtocol"; /** * Initiator setting for connection host. Only valid when session connection @@ -43,7 +43,7 @@ public interface Initiator extends Connector { * * @see quickfix.SessionFactory#SETTING_CONNECTION_TYPE */ - public static final String SETTING_SOCKET_CONNECT_HOST = "SocketConnectHost"; + String SETTING_SOCKET_CONNECT_HOST = "SocketConnectHost"; /** * Initiator setting for connection port. Only valid when session connection @@ -51,7 +51,7 @@ public interface Initiator extends Connector { * * @see quickfix.SessionFactory#SETTING_CONNECTION_TYPE */ - public static final String SETTING_SOCKET_CONNECT_PORT = "SocketConnectPort"; + String SETTING_SOCKET_CONNECT_PORT = "SocketConnectPort"; /** * Initiator setting for local/bind host. Only valid when session connection @@ -59,7 +59,7 @@ public interface Initiator extends Connector { * * @see quickfix.SessionFactory#SETTING_CONNECTION_TYPE */ - public static final String SETTING_SOCKET_LOCAL_HOST = "SocketLocalHost"; + String SETTING_SOCKET_LOCAL_HOST = "SocketLocalHost"; /** * Initiator setting for local/bind port. Only valid when session connection @@ -67,5 +67,5 @@ public interface Initiator extends Connector { * * @see quickfix.SessionFactory#SETTING_CONNECTION_TYPE */ - public static final String SETTING_SOCKET_LOCAL_PORT = "SocketLocalPort"; + String SETTING_SOCKET_LOCAL_PORT = "SocketLocalPort"; } diff --git a/quickfixj-core/src/main/java/quickfix/JdbcLog.java b/quickfixj-core/src/main/java/quickfix/JdbcLog.java index 2dfefcda6..8ccf5cdb0 100644 --- a/quickfixj-core/src/main/java/quickfix/JdbcLog.java +++ b/quickfixj-core/src/main/java/quickfix/JdbcLog.java @@ -19,9 +19,7 @@ package quickfix; -import static quickfix.JdbcSetting.*; -import static quickfix.JdbcUtil.*; - +import javax.sql.DataSource; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; @@ -29,7 +27,15 @@ import java.util.HashMap; import java.util.Map; -import javax.sql.DataSource; +import static quickfix.JdbcSetting.SETTING_JDBC_LOG_HEARTBEATS; +import static quickfix.JdbcSetting.SETTING_JDBC_SESSION_ID_DEFAULT_PROPERTY_VALUE; +import static quickfix.JdbcSetting.SETTING_LOG_EVENT_TABLE; +import static quickfix.JdbcSetting.SETTING_LOG_INCOMING_TABLE; +import static quickfix.JdbcSetting.SETTING_LOG_OUTGOING_TABLE; +import static quickfix.JdbcUtil.determineSessionIdSupport; +import static quickfix.JdbcUtil.getIDColumns; +import static quickfix.JdbcUtil.getIDPlaceholders; +import static quickfix.JdbcUtil.getIDWhereClause; class JdbcLog extends AbstractLog { private static final String DEFAULT_MESSAGES_LOG_TABLE = "messages_log"; @@ -45,8 +51,8 @@ class JdbcLog extends AbstractLog { private Throwable recursiveException = null; - private final Map insertItemSqlCache = new HashMap(); - private final Map deleteItemsSqlCache = new HashMap(); + private final Map insertItemSqlCache = new HashMap<>(); + private final Map deleteItemsSqlCache = new HashMap<>(); public JdbcLog(SessionSettings settings, SessionID sessionID, DataSource ds) throws SQLException, ClassNotFoundException, ConfigError, FieldConvertError { diff --git a/quickfixj-core/src/main/java/quickfix/JdbcUtil.java b/quickfixj-core/src/main/java/quickfix/JdbcUtil.java index bd8f24b3f..5ce513fe5 100644 --- a/quickfixj-core/src/main/java/quickfix/JdbcUtil.java +++ b/quickfixj-core/src/main/java/quickfix/JdbcUtil.java @@ -19,6 +19,11 @@ package quickfix; +import org.logicalcobwebs.proxool.ProxoolDataSource; + +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; @@ -27,17 +32,11 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import javax.naming.InitialContext; -import javax.naming.NamingException; -import javax.sql.DataSource; - -import org.logicalcobwebs.proxool.ProxoolDataSource; - class JdbcUtil { static final String CONNECTION_POOL_ALIAS = "quickfixj"; - private static final Map dataSources = new ConcurrentHashMap(); + private static final Map dataSources = new ConcurrentHashMap<>(); private static int dataSourceCounter = 1; static DataSource getDataSource(SessionSettings settings, SessionID sessionID) @@ -146,24 +145,18 @@ static void close(SessionID sessionID, ResultSet rs) { } static boolean determineSessionIdSupport(DataSource dataSource, String tableName) throws SQLException { - Connection connection = dataSource.getConnection(); - try { + try (Connection connection = dataSource.getConnection()) { DatabaseMetaData metaData = connection.getMetaData(); String columnName = "sendersubid"; return isColumn(metaData, tableName.toUpperCase(), columnName.toUpperCase()) || isColumn(metaData, tableName, columnName); - } finally { - connection.close(); } } private static boolean isColumn(DatabaseMetaData metaData, String tableName, String columnName) throws SQLException { - ResultSet columns = metaData.getColumns(null, null, tableName, columnName); - try { + try (ResultSet columns = metaData.getColumns(null, null, tableName, columnName)) { return columns.next(); - } finally { - columns.close(); } } diff --git a/quickfixj-core/src/main/java/quickfix/ListenerSupport.java b/quickfixj-core/src/main/java/quickfix/ListenerSupport.java index 99041a21e..56146e1d6 100644 --- a/quickfixj-core/src/main/java/quickfix/ListenerSupport.java +++ b/quickfixj-core/src/main/java/quickfix/ListenerSupport.java @@ -26,7 +26,7 @@ import java.util.concurrent.CopyOnWriteArrayList; public class ListenerSupport { - private final List listeners = new CopyOnWriteArrayList(); + private final List listeners = new CopyOnWriteArrayList<>(); private final Object multicaster; public ListenerSupport(Class listenerClass) { diff --git a/quickfixj-core/src/main/java/quickfix/MemoryStore.java b/quickfixj-core/src/main/java/quickfix/MemoryStore.java index 553e3d6dc..fb3d1e49c 100644 --- a/quickfixj-core/src/main/java/quickfix/MemoryStore.java +++ b/quickfixj-core/src/main/java/quickfix/MemoryStore.java @@ -19,21 +19,21 @@ package quickfix; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.HashMap; -import org.slf4j.LoggerFactory; - /** * In-memory message store implementation. * * @see quickfix.MemoryStoreFactory */ public class MemoryStore implements MessageStore { - private final HashMap messages = new HashMap(); + private final HashMap messages = new HashMap<>(); private int nextSenderMsgSeqNum; private int nextTargetMsgSeqNum; private SessionID sessionID; diff --git a/quickfixj-core/src/main/java/quickfix/Message.java b/quickfixj-core/src/main/java/quickfix/Message.java index d39e8592b..32bea95b0 100644 --- a/quickfixj-core/src/main/java/quickfix/Message.java +++ b/quickfixj-core/src/main/java/quickfix/Message.java @@ -19,23 +19,10 @@ package quickfix; -import java.io.ByteArrayOutputStream; -import java.text.DecimalFormat; -import java.util.Iterator; -import java.util.List; - -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - import org.quickfixj.CharsetSupport; import org.w3c.dom.CDATASection; import org.w3c.dom.Document; import org.w3c.dom.Element; - import quickfix.field.ApplVerID; import quickfix.field.BeginString; import quickfix.field.BodyLength; @@ -70,6 +57,17 @@ import quickfix.field.XmlData; import quickfix.field.XmlDataLen; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.ByteArrayOutputStream; +import java.text.DecimalFormat; +import java.util.Iterator; +import java.util.List; + /** * Represents a FIX message. */ @@ -115,9 +113,7 @@ public Object clone() { try { final Message message = getClass().newInstance(); return cloneTo(message); - } catch (final InstantiationException e) { - throw new RuntimeException(e); - } catch (final IllegalAccessException e) { + } catch (final InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } } diff --git a/quickfixj-core/src/main/java/quickfix/MessageCracker.java b/quickfixj-core/src/main/java/quickfix/MessageCracker.java index 3874d6ea0..28b65dac1 100644 --- a/quickfixj-core/src/main/java/quickfix/MessageCracker.java +++ b/quickfixj-core/src/main/java/quickfix/MessageCracker.java @@ -34,7 +34,7 @@ * type-safe onMessage methods. */ public class MessageCracker { - private final Map, Invoker> invokers = new HashMap, Invoker>(); + private final Map, Invoker> invokers = new HashMap<>(); @Target({ ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @@ -128,11 +128,7 @@ public void crack(quickfix.Message message, SessionID sessionID) throws Unsuppor } catch (InvocationTargetException ite) { try { throw ite.getTargetException(); - } catch (UnsupportedMessageType e) { - throw e; - } catch (FieldNotFound e) { - throw e; - } catch (IncorrectTagValue e) { + } catch (UnsupportedMessageType | IncorrectTagValue | FieldNotFound e) { throw e; } catch (Throwable t) { propagate(t); diff --git a/quickfixj-core/src/main/java/quickfix/MessageFactory.java b/quickfixj-core/src/main/java/quickfix/MessageFactory.java index eb90d23f3..9cf30a1da 100644 --- a/quickfixj-core/src/main/java/quickfix/MessageFactory.java +++ b/quickfixj-core/src/main/java/quickfix/MessageFactory.java @@ -50,5 +50,5 @@ public interface MessageFactory { * @param correspondingFieldID the fieldID of the field in the group * @return group, or null if the group can't be created. */ - public Group create(String beginString, String msgType, int correspondingFieldID); + Group create(String beginString, String msgType, int correspondingFieldID); } diff --git a/quickfixj-core/src/main/java/quickfix/ScreenLogFactory.java b/quickfixj-core/src/main/java/quickfix/ScreenLogFactory.java index e2b8dec63..ce0a36933 100644 --- a/quickfixj-core/src/main/java/quickfix/ScreenLogFactory.java +++ b/quickfixj-core/src/main/java/quickfix/ScreenLogFactory.java @@ -126,9 +126,7 @@ public Log create(SessionID sessionID) { includeMillis = getBooleanSetting(sessionID, ScreenLogFactory.SETTING_INCLUDE_MILLIS_IN_TIMESTAMP, false); return new ScreenLog(incoming, outgoing, events, heartBeats, includeMillis, sessionID, System.out); - } catch (FieldConvertError e) { - throw new RuntimeError(e); - } catch (ConfigError e) { + } catch (FieldConvertError | ConfigError e) { throw new RuntimeError(e); } } diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index b30c87652..43622135a 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -19,23 +19,8 @@ package quickfix; -import static quickfix.LogUtil.logThrowable; - -import java.io.Closeable; -import java.io.IOException; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.Message.Header; import quickfix.SessionState.ResendRange; import quickfix.field.ApplVerID; @@ -71,6 +56,20 @@ import quickfix.field.Text; import quickfix.mina.EventHandlingStrategy; +import java.io.Closeable; +import java.io.IOException; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import static quickfix.LogUtil.logThrowable; + /** * The Session is the primary FIX abstraction for message communication. *

@@ -344,7 +343,7 @@ public class Session implements Closeable { public static final String SETTING_MAX_SCHEDULED_WRITE_REQUESTS = "MaxScheduledWriteRequests"; - private static final ConcurrentMap sessions = new ConcurrentHashMap(); + private static final ConcurrentMap sessions = new ConcurrentHashMap<>(); private final Application application; private final SessionID sessionID; @@ -397,7 +396,7 @@ public class Session implements Closeable { private final SessionStateListener stateListener = (SessionStateListener) stateListeners .getMulticaster(); - private final AtomicReference targetDefaultApplVerID = new AtomicReference(); + private final AtomicReference targetDefaultApplVerID = new AtomicReference<>(); private final DefaultApplVerID senderDefaultApplVerID; private boolean validateSequenceNumbers = true; private boolean validateIncomingMessage = true; @@ -975,25 +974,34 @@ private void next(Message message, boolean isProcessingQueuedMessages) throws Fi } } - if (msgType.equals(MsgType.LOGON)) { - nextLogon(message); - } else if (msgType.equals(MsgType.HEARTBEAT)) { - nextHeartBeat(message); - } else if (msgType.equals(MsgType.TEST_REQUEST)) { - nextTestRequest(message); - } else if (msgType.equals(MsgType.SEQUENCE_RESET)) { - nextSequenceReset(message); - } else if (msgType.equals(MsgType.LOGOUT)) { - nextLogout(message); - } else if (msgType.equals(MsgType.RESEND_REQUEST)) { - nextResendRequest(message); - } else if (msgType.equals(MsgType.REJECT)) { - nextReject(message); - } else { - if (!verify(message)) { - return; - } - state.incrNextTargetMsgSeqNum(); + switch (msgType) { + case MsgType.LOGON: + nextLogon(message); + break; + case MsgType.HEARTBEAT: + nextHeartBeat(message); + break; + case MsgType.TEST_REQUEST: + nextTestRequest(message); + break; + case MsgType.SEQUENCE_RESET: + nextSequenceReset(message); + break; + case MsgType.LOGOUT: + nextLogout(message); + break; + case MsgType.RESEND_REQUEST: + nextResendRequest(message); + break; + case MsgType.REJECT: + nextReject(message); + break; + default: + if (!verify(message)) { + return; + } + state.incrNextTargetMsgSeqNum(); + break; } } catch (final FieldException e) { getLog().onErrorEvent("Rejecting invalid message: " + e + ": " + message); @@ -2143,7 +2151,7 @@ private void nextLogon(Message logon) throws FieldNotFound, RejectLogon, Incorre private void resendMessages(Message receivedMessage, int beginSeqNo, int endSeqNo) throws IOException, InvalidMessage, FieldNotFound { - final ArrayList messages = new ArrayList(); + final ArrayList messages = new ArrayList<>(); try { state.get(beginSeqNo, endSeqNo, messages); } catch (final IOException e) { diff --git a/quickfixj-core/src/main/java/quickfix/SessionFactory.java b/quickfixj-core/src/main/java/quickfix/SessionFactory.java index 98d6e8ec5..234f26836 100644 --- a/quickfixj-core/src/main/java/quickfix/SessionFactory.java +++ b/quickfixj-core/src/main/java/quickfix/SessionFactory.java @@ -28,17 +28,17 @@ public interface SessionFactory { * Specifies the connection type for a session. Valid values are "initiator" * and "acceptor". */ - public static final String SETTING_CONNECTION_TYPE = "ConnectionType"; + String SETTING_CONNECTION_TYPE = "ConnectionType"; /** * Instructs the connection-related code to continue if there is an error * creating or initializing a session. In other words, one bad session won't * stop the initialization of other sessions. */ - public static final String SETTING_CONTINUE_INIT_ON_ERROR = "ContinueInitializationOnError"; + String SETTING_CONTINUE_INIT_ON_ERROR = "ContinueInitializationOnError"; - public static final String ACCEPTOR_CONNECTION_TYPE = "acceptor"; - public static final String INITIATOR_CONNECTION_TYPE = "initiator"; + String ACCEPTOR_CONNECTION_TYPE = "acceptor"; + String INITIATOR_CONNECTION_TYPE = "initiator"; Session create(SessionID sessionID, SessionSettings settings) throws ConfigError; diff --git a/quickfixj-core/src/main/java/quickfix/SessionRejectReasonText.java b/quickfixj-core/src/main/java/quickfix/SessionRejectReasonText.java index f790f6b28..39cbe1bf4 100644 --- a/quickfixj-core/src/main/java/quickfix/SessionRejectReasonText.java +++ b/quickfixj-core/src/main/java/quickfix/SessionRejectReasonText.java @@ -19,12 +19,12 @@ package quickfix; -import java.util.HashMap; - import quickfix.field.SessionRejectReason; +import java.util.HashMap; + class SessionRejectReasonText extends SessionRejectReason { - private static final HashMap rejectReasonText = new HashMap(); + private static final HashMap rejectReasonText = new HashMap<>(); static { rejectReasonText.put(INVALID_TAG_NUMBER, "Invalid tag number"); diff --git a/quickfixj-core/src/main/java/quickfix/SessionSettings.java b/quickfixj-core/src/main/java/quickfix/SessionSettings.java index 0b68e3f66..68d86b6a3 100644 --- a/quickfixj-core/src/main/java/quickfix/SessionSettings.java +++ b/quickfixj-core/src/main/java/quickfix/SessionSettings.java @@ -19,6 +19,10 @@ package quickfix; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import quickfix.field.converter.BooleanConverter; + import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; @@ -42,11 +46,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import quickfix.field.converter.BooleanConverter; - /** * Settings for sessions. Settings are grouped by FIX version and target company * ID. There is also a default settings section that is inherited by the @@ -373,10 +372,10 @@ public void setBool(SessionID sessionID, String key, boolean value) { getOrCreateSessionProperties(sessionID).setProperty(key, BooleanConverter.convert(value)); } - private final HashMap sections = new HashMap(); + private final HashMap sections = new HashMap<>(); public Iterator sectionIterator() { - final HashSet nondefaultSessions = new HashSet(sections.keySet()); + final HashSet nondefaultSessions = new HashSet<>(sections.keySet()); nondefaultSessions.remove(DEFAULT_SESSION_ID); return nondefaultSessions.iterator(); } @@ -729,7 +728,7 @@ public static int[] parseSettingReconnectInterval(String raw) { } final String multiplierCharacter = raw.contains("*") ? "\\*" : "x"; final String[] data = raw.split(";"); - final List result = new ArrayList(); + final List result = new ArrayList<>(); for (final String multi : data) { final String[] timesSec = multi.split(multiplierCharacter); int times; @@ -767,7 +766,7 @@ public static Set parseRemoteAddresses(String raw) { return null; } final String[] data = raw.split(","); - final Set result = new HashSet(); + final Set result = new HashSet<>(); for (final String multi : data) { try { result.add(InetAddress.getByName(multi)); diff --git a/quickfixj-core/src/main/java/quickfix/SessionState.java b/quickfixj-core/src/main/java/quickfix/SessionState.java index c0f11fae7..ef666c852 100644 --- a/quickfixj-core/src/main/java/quickfix/SessionState.java +++ b/quickfixj-core/src/main/java/quickfix/SessionState.java @@ -72,7 +72,7 @@ public final class SessionState { private final AtomicInteger nextExpectedMsgSeqNum = new AtomicInteger(0); // The messageQueue should be accessed from a single thread - private final Map messageQueue = new LinkedHashMap(); + private final Map messageQueue = new LinkedHashMap<>(); public SessionState(Object lock, Log log, int heartBeatInterval, boolean initiator, MessageStore messageStore, double testRequestDelayMultiplier) { diff --git a/quickfixj-core/src/main/java/quickfix/field/converter/DoubleConverter.java b/quickfixj-core/src/main/java/quickfix/field/converter/DoubleConverter.java index f3bc31a1d..fa9bdecd2 100644 --- a/quickfixj-core/src/main/java/quickfix/field/converter/DoubleConverter.java +++ b/quickfixj-core/src/main/java/quickfix/field/converter/DoubleConverter.java @@ -19,21 +19,21 @@ package quickfix.field.converter; +import quickfix.FieldConvertError; +import quickfix.RuntimeError; + import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; -import quickfix.FieldConvertError; -import quickfix.RuntimeError; - /** * Converts between a double and a String. */ public class DoubleConverter { private static final Pattern DECIMAL_PATTERN = Pattern.compile("-?\\d*(\\.\\d*)?"); - private static final ThreadLocal THREAD_DECIMAL_FORMATS = new ThreadLocal(); + private static final ThreadLocal THREAD_DECIMAL_FORMATS = new ThreadLocal<>(); /** * Converts a double to a string with no padding. diff --git a/quickfixj-core/src/main/java/quickfix/field/converter/UtcDateOnlyConverter.java b/quickfixj-core/src/main/java/quickfix/field/converter/UtcDateOnlyConverter.java index 593bad044..8617f4933 100644 --- a/quickfixj-core/src/main/java/quickfix/field/converter/UtcDateOnlyConverter.java +++ b/quickfixj-core/src/main/java/quickfix/field/converter/UtcDateOnlyConverter.java @@ -19,19 +19,19 @@ package quickfix.field.converter; +import quickfix.FieldConvertError; + import java.text.DateFormat; import java.text.ParseException; import java.util.Date; -import quickfix.FieldConvertError; - /** * Convert between a date and a String */ public class UtcDateOnlyConverter extends AbstractDateTimeConverter { // SimpleDateFormats are not thread safe. A thread local is being // used to maintain high concurrency among multiple session threads - private static final ThreadLocal utcDateConverter = new ThreadLocal(); + private static final ThreadLocal utcDateConverter = new ThreadLocal<>(); private final DateFormat dateFormat = createDateFormat("yyyyMMdd"); /** diff --git a/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimeOnlyConverter.java b/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimeOnlyConverter.java index 797bb36e2..4c280ef3c 100644 --- a/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimeOnlyConverter.java +++ b/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimeOnlyConverter.java @@ -19,19 +19,19 @@ package quickfix.field.converter; +import quickfix.FieldConvertError; + import java.text.DateFormat; import java.text.ParseException; import java.util.Date; -import quickfix.FieldConvertError; - /** * Convert between a time and a String. */ public class UtcTimeOnlyConverter extends AbstractDateTimeConverter { // SimpleDateFormats are not thread safe. A thread local is being // used to maintain high concurrency among multiple session threads - private static final ThreadLocal utcTimeConverter = new ThreadLocal(); + private static final ThreadLocal utcTimeConverter = new ThreadLocal<>(); private final DateFormat utcTimeFormat = createDateFormat("HH:mm:ss"); private final DateFormat utcTimeFormatMillis = createDateFormat("HH:mm:ss.SSS"); diff --git a/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimestampConverter.java b/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimestampConverter.java index 8b2cfcc91..09b98e1e7 100644 --- a/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimestampConverter.java +++ b/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimestampConverter.java @@ -19,24 +19,24 @@ package quickfix.field.converter; +import quickfix.FieldConvertError; +import quickfix.SystemTime; + import java.text.DateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; -import java.util.concurrent.*; - -import quickfix.FieldConvertError; -import quickfix.SystemTime; +import java.util.concurrent.ConcurrentHashMap; /** * Convert between a timestamp and a String. A timestamp includes both a date * and a time. */ public class UtcTimestampConverter extends AbstractDateTimeConverter { - private static final ThreadLocal utcTimestampConverter = new ThreadLocal(); + private static final ThreadLocal utcTimestampConverter = new ThreadLocal<>(); private final DateFormat utcTimestampFormat = createDateFormat("yyyyMMdd-HH:mm:ss"); private final DateFormat utcTimestampFormatMillis = createDateFormat("yyyyMMdd-HH:mm:ss.SSS"); - private final static ConcurrentHashMap dateCache = new ConcurrentHashMap(); + private final static ConcurrentHashMap dateCache = new ConcurrentHashMap<>(); /** * Convert a timestamp (represented as a Date) to a String. diff --git a/quickfixj-core/src/main/java/quickfix/mina/EventHandlingStrategy.java b/quickfixj-core/src/main/java/quickfix/mina/EventHandlingStrategy.java index c5149f843..1b2b50e81 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/EventHandlingStrategy.java +++ b/quickfixj-core/src/main/java/quickfix/mina/EventHandlingStrategy.java @@ -33,10 +33,10 @@ public interface EventHandlingStrategy { * Constant indicating how long we wait for an incoming message. After * thread has been asked to stop, it can take up to this long to terminate. */ - static final long THREAD_WAIT_FOR_MESSAGE_MS = 250; + long THREAD_WAIT_FOR_MESSAGE_MS = 250; // will be put to the eventQueue to signal a disconnection - public static final Message END_OF_STREAM = new Message(); + Message END_OF_STREAM = new Message(); void onMessage(Session quickfixSession, Message message); diff --git a/quickfixj-core/src/main/java/quickfix/mina/NetworkingOptions.java b/quickfixj-core/src/main/java/quickfix/mina/NetworkingOptions.java index 7d9b33aba..b335c43ba 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/NetworkingOptions.java +++ b/quickfixj-core/src/main/java/quickfix/mina/NetworkingOptions.java @@ -19,21 +19,20 @@ package quickfix.mina; -import java.net.SocketException; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - import org.apache.mina.core.session.IoSession; import org.apache.mina.core.session.IoSessionConfig; import org.apache.mina.transport.socket.SocketSessionConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.FieldConvertError; import quickfix.field.converter.BooleanConverter; import quickfix.field.converter.IntConverter; +import java.net.SocketException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + /** * This class holds the QFJ settings information related to networking options. */ @@ -65,7 +64,7 @@ public class NetworkingOptions { public static final String IPTOC_RELIABILITY = "IPTOS_RELIABILITY"; public static final String IPTOC_THROUGHPUT = "IPTOS_THROUGHPUT"; public static final String IPTOC_LOWDELAY = "IPTOS_LOWDELAY"; - public static final Map trafficClasses = new HashMap(); + public static final Map trafficClasses = new HashMap<>(); static { trafficClasses.put(IPTOC_LOWCOST, 0x02); diff --git a/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java b/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java index d09bf79c8..12713f87c 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java +++ b/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java @@ -19,6 +19,19 @@ package quickfix.mina; +import org.apache.mina.core.filterchain.IoFilterChainBuilder; +import org.apache.mina.core.session.IoSession; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import quickfix.ConfigError; +import quickfix.Connector; +import quickfix.FieldConvertError; +import quickfix.Session; +import quickfix.SessionFactory; +import quickfix.SessionID; +import quickfix.SessionSettings; +import quickfix.field.converter.IntConverter; + import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.IOException; @@ -35,20 +48,6 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; -import org.apache.mina.core.filterchain.IoFilterChainBuilder; -import org.apache.mina.core.session.IoSession; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import quickfix.ConfigError; -import quickfix.Connector; -import quickfix.FieldConvertError; -import quickfix.Session; -import quickfix.SessionFactory; -import quickfix.SessionID; -import quickfix.SessionSettings; -import quickfix.field.converter.IntConverter; - /** * An abstract base class for acceptors and initiators. Provides support for common functionality and also serves as an * abstraction where the code doesn't need to make the acceptor/initiator distinction. @@ -98,7 +97,7 @@ protected void setSessions(Map sessions) { * @see quickfix.Session */ public List getManagedSessions() { - return new ArrayList(sessions.values()); + return new ArrayList<>(sessions.values()); } /** @@ -118,7 +117,7 @@ protected Map getSessionMap() { * @return list of session identifiers */ public ArrayList getSessions() { - return new ArrayList(sessions.keySet()); + return new ArrayList<>(sessions.keySet()); } public void addDynamicSession(Session inSession) { @@ -168,7 +167,7 @@ public boolean isLoggedOn() { } private Set getLoggedOnSessions() { - Set loggedOnSessions = new HashSet(sessions.size()); + Set loggedOnSessions = new HashSet<>(sessions.size()); for (Session session : sessions.values()) { if (session.isLoggedOn()) { loggedOnSessions.add(session); diff --git a/quickfixj-core/src/main/java/quickfix/mina/SingleThreadedEventHandlingStrategy.java b/quickfixj-core/src/main/java/quickfix/mina/SingleThreadedEventHandlingStrategy.java index 1f46fa3a1..ff3ca6732 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/SingleThreadedEventHandlingStrategy.java +++ b/quickfixj-core/src/main/java/quickfix/mina/SingleThreadedEventHandlingStrategy.java @@ -20,7 +20,11 @@ package quickfix.mina; -import quickfix.*; +import quickfix.LogUtil; +import quickfix.Message; +import quickfix.Session; +import quickfix.SessionID; +import quickfix.SystemTime; import java.util.ArrayList; import java.util.List; @@ -41,7 +45,7 @@ public class SingleThreadedEventHandlingStrategy implements EventHandlingStrateg public SingleThreadedEventHandlingStrategy(SessionConnector connector, int queueCapacity) { sessionConnector = connector; - eventQueue = new LinkedBlockingQueue(queueCapacity); + eventQueue = new LinkedBlockingQueue<>(queueCapacity); } @Override @@ -67,7 +71,7 @@ public void block() { synchronized (this) { if (isStopped) { if (!eventQueue.isEmpty()) { - final List tempList = new ArrayList(); + final List tempList = new ArrayList<>(); eventQueue.drainTo(tempList); for (SessionMessageEvent event : tempList) { event.processMessage(); diff --git a/quickfixj-core/src/main/java/quickfix/mina/ThreadPerSessionEventHandlingStrategy.java b/quickfixj-core/src/main/java/quickfix/mina/ThreadPerSessionEventHandlingStrategy.java index 06cb4b9ea..0b0489703 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/ThreadPerSessionEventHandlingStrategy.java +++ b/quickfixj-core/src/main/java/quickfix/mina/ThreadPerSessionEventHandlingStrategy.java @@ -29,14 +29,18 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; -import java.util.concurrent.*; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; /** * Processes messages in a session-specific thread. */ public class ThreadPerSessionEventHandlingStrategy implements EventHandlingStrategy { - private final ConcurrentMap dispatchers = new ConcurrentHashMap(); + private final ConcurrentMap dispatchers = new ConcurrentHashMap<>(); private final SessionConnector sessionConnector; private final int queueCapacity; @@ -110,7 +114,7 @@ protected class MessageDispatchingThread extends Thread { private MessageDispatchingThread(Session session, int queueCapacity) { super("QF/J Session dispatcher: " + session.getSessionID()); quickfixSession = session; - messages = new LinkedBlockingQueue(queueCapacity); + messages = new LinkedBlockingQueue<>(queueCapacity); } public void enqueue(Message message) { @@ -151,7 +155,7 @@ public void run() { } } if (!messages.isEmpty()) { - final List tempList = new ArrayList(); + final List tempList = new ArrayList<>(); messages.drainTo(tempList); for (Message message : tempList) { try { diff --git a/quickfixj-core/src/main/java/quickfix/mina/acceptor/AbstractSocketAcceptor.java b/quickfixj-core/src/main/java/quickfix/mina/acceptor/AbstractSocketAcceptor.java index 4cd799504..fcee034a4 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/acceptor/AbstractSocketAcceptor.java +++ b/quickfixj-core/src/main/java/quickfix/mina/acceptor/AbstractSocketAcceptor.java @@ -19,21 +19,10 @@ package quickfix.mina.acceptor; -import java.net.SocketAddress; -import java.security.GeneralSecurityException; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import javax.net.ssl.SSLContext; - import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.buffer.SimpleBufferAllocator; import org.apache.mina.core.service.IoAcceptor; import org.apache.mina.filter.codec.ProtocolCodecFilter; - import quickfix.Acceptor; import quickfix.Application; import quickfix.ConfigError; @@ -59,14 +48,23 @@ import quickfix.mina.ssl.SSLFilter; import quickfix.mina.ssl.SSLSupport; +import javax.net.ssl.SSLContext; +import java.net.SocketAddress; +import java.security.GeneralSecurityException; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + /** * Abstract base class for socket acceptors. */ public abstract class AbstractSocketAcceptor extends SessionConnector implements Acceptor { - private final Map sessionProviders = new HashMap(); + private final Map sessionProviders = new HashMap<>(); private final SessionFactory sessionFactory; - private final Map socketDescriptorForAddress = new HashMap(); - private final Map ioAcceptors = new HashMap(); + private final Map socketDescriptorForAddress = new HashMap<>(); + private final Map ioAcceptors = new HashMap<>(); protected AbstractSocketAcceptor(SessionSettings settings, SessionFactory sessionFactory) throws ConfigError { @@ -221,7 +219,7 @@ private boolean equals(Object object1, Object object2) { } private void createSessions(SessionSettings settings) throws ConfigError, FieldConvertError { - HashMap allSessions = new HashMap(); + HashMap allSessions = new HashMap<>(); for (Iterator i = settings.sectionIterator(); i.hasNext();) { SessionID sessionID = i.next(); String connectionType = settings.getString(sessionID, @@ -265,7 +263,7 @@ private static class AcceptorSocketDescriptor { private final SocketAddress address; private final boolean useSSL; private final SSLConfig sslConfig; - private final Map acceptedSessions = new HashMap(); + private final Map acceptedSessions = new HashMap<>(); public AcceptorSocketDescriptor(SocketAddress address, boolean useSSL, SSLConfig sslConfig) { this.address = address; @@ -299,7 +297,7 @@ public Collection getEndpoints() { } public Map getAcceptorAddresses() { - Map sessionIdToAddressMap = new HashMap(); + Map sessionIdToAddressMap = new HashMap<>(); for (AcceptorSocketDescriptor descriptor : socketDescriptorForAddress.values()) { for (SessionID sessionID : descriptor.getAcceptedSessions().keySet()) { sessionIdToAddressMap.put(sessionID, descriptor.getAddress()); diff --git a/quickfixj-core/src/main/java/quickfix/mina/initiator/AbstractSocketInitiator.java b/quickfixj-core/src/main/java/quickfix/mina/initiator/AbstractSocketInitiator.java index f5f0f5933..10e02a579 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/initiator/AbstractSocketInitiator.java +++ b/quickfixj-core/src/main/java/quickfix/mina/initiator/AbstractSocketInitiator.java @@ -19,20 +19,10 @@ package quickfix.mina.initiator; -import java.net.SocketAddress; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.buffer.SimpleBufferAllocator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.Application; import quickfix.ConfigError; import quickfix.DefaultSessionFactory; @@ -53,13 +43,22 @@ import quickfix.mina.ssl.SSLConfig; import quickfix.mina.ssl.SSLSupport; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + /** * Abstract base class for socket initiators. */ public abstract class AbstractSocketInitiator extends SessionConnector implements Initiator { protected final Logger log = LoggerFactory.getLogger(getClass()); - private final Set initiators = new HashSet(); + private final Set initiators = new HashSet<>(); protected AbstractSocketInitiator(Application application, MessageStoreFactory messageStoreFactory, SessionSettings settings, @@ -146,7 +145,7 @@ private void createSessions() throws ConfigError, FieldConvertError { continueInitOnError = settings.getBool(SessionFactory.SETTING_CONTINUE_INIT_ON_ERROR); } - final Map initiatorSessions = new HashMap(); + final Map initiatorSessions = new HashMap<>(); for (final Iterator i = settings.sectionIterator(); i.hasNext();) { final SessionID sessionID = i.next(); if (isInitiatorSession(sessionID)) { @@ -188,7 +187,7 @@ private int[] getReconnectIntervalInSeconds(SessionID sessionID) throws ConfigEr private SocketAddress[] getSocketAddresses(SessionID sessionID) throws ConfigError { final SessionSettings settings = getSettings(); - final ArrayList addresses = new ArrayList(); + final ArrayList addresses = new ArrayList<>(); for (int index = 0;; index++) { try { final String protocolKey = Initiator.SETTING_SOCKET_CONNECT_PROTOCOL diff --git a/quickfixj-core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java b/quickfixj-core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java index b7aa92356..f5888c9e4 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java +++ b/quickfixj-core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java @@ -19,18 +19,9 @@ package quickfix.mina.message; -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.io.UnsupportedEncodingException; -import java.nio.MappedByteBuffer; -import java.nio.channels.FileChannel; -import java.util.ArrayList; -import java.util.List; - import org.apache.mina.core.buffer.IoBuffer; -import org.apache.mina.core.session.IoSession; import org.apache.mina.core.filterchain.IoFilter; +import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecException; import org.apache.mina.filter.codec.ProtocolDecoderOutput; import org.apache.mina.filter.codec.demux.MessageDecoder; @@ -38,9 +29,17 @@ import org.quickfixj.CharsetSupport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.mina.CriticalProtocolCodecException; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.io.UnsupportedEncodingException; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.List; + /** * Detects and decodes FIX message strings in an incoming data stream. The * message string is then passed to MINA IO handlers for further processing. @@ -302,7 +301,7 @@ public interface MessageListener { * quickfix.mina.message.FIXMessageDecoder.MessageListener) */ public List extractMessages(File file) throws IOException, ProtocolCodecException { - final List messages = new ArrayList(); + final List messages = new ArrayList<>(); extractMessages(file, new MessageListener() { @Override public void onMessage(String message) { @@ -326,8 +325,7 @@ public void onMessage(String message) { public void extractMessages(File file, final MessageListener listener) throws IOException, ProtocolCodecException { // Set up a read-only memory-mapped file - RandomAccessFile fileIn = new RandomAccessFile(file, "r"); - try { + try (RandomAccessFile fileIn = new RandomAccessFile(file, "r")) { FileChannel readOnlyChannel = fileIn.getChannel(); MappedByteBuffer memoryMappedBuffer = readOnlyChannel.map(FileChannel.MapMode.READ_ONLY, 0, (int) readOnlyChannel.size()); @@ -336,13 +334,12 @@ public void extractMessages(File file, final MessageListener listener) throws IO public void write(Object message) { listener.onMessage((String) message); } + @Override public void flush(IoFilter.NextFilter nextFilter, IoSession ioSession) { // ignored } }); - } finally { - fileIn.close(); } } diff --git a/quickfixj-core/src/main/java/quickfix/mina/ssl/SSLContextFactory.java b/quickfixj-core/src/main/java/quickfix/mina/ssl/SSLContextFactory.java index 53d3aca48..f04f39376 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/ssl/SSLContextFactory.java +++ b/quickfixj-core/src/main/java/quickfix/mina/ssl/SSLContextFactory.java @@ -19,6 +19,15 @@ package quickfix.mina.ssl; +import org.apache.mina.filter.ssl.BogusTrustManagerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import quickfix.FileUtil; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; import java.io.IOException; import java.io.InputStream; import java.security.GeneralSecurityException; @@ -30,17 +39,6 @@ import java.util.HashMap; import java.util.Map; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; - -import org.apache.mina.filter.ssl.BogusTrustManagerFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import quickfix.FileUtil; - /** * SSL context factory that deals with various SSL configuration. * Caches the created SSL contexts for future reuse. @@ -48,7 +46,7 @@ public class SSLContextFactory { private static final Logger log = LoggerFactory.getLogger(SSLContextFactory.class); private static final String PROTOCOL = "TLS"; - private static final Map contextCache = new HashMap(); + private static final Map contextCache = new HashMap<>(); /** * Creates an {@link SSLContext} with a specified {@link SSLConfig} diff --git a/quickfixj-core/src/main/java/quickfix/mina/ssl/SSLSupport.java b/quickfixj-core/src/main/java/quickfix/mina/ssl/SSLSupport.java index d905eb7d8..c230930c4 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/ssl/SSLSupport.java +++ b/quickfixj-core/src/main/java/quickfix/mina/ssl/SSLSupport.java @@ -19,16 +19,15 @@ package quickfix.mina.ssl; -import java.io.IOException; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocket; - import quickfix.ConfigError; import quickfix.FieldConvertError; import quickfix.SessionID; import quickfix.SessionSettings; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import java.io.IOException; + public class SSLSupport { public static final String FILTER_NAME = "SslFilter"; public static final String SETTING_USE_SSL = "SocketUseSSL"; @@ -122,8 +121,7 @@ private static String getString(SessionSettings sessionSettings, SessionID sessi if (sessionSettings.isSetting(sessionID, key)) { try { propertyValue = sessionSettings.getString(sessionID, key); - } catch (ConfigError ignored) { - } catch (FieldConvertError ignored) { + } catch (ConfigError | FieldConvertError ignored) { } } return propertyValue; diff --git a/quickfixj-core/src/test/java/org/quickfixj/jmx/mbean/session/SessionAdminTest.java b/quickfixj-core/src/test/java/org/quickfixj/jmx/mbean/session/SessionAdminTest.java index 240cb5800..2352f6449 100644 --- a/quickfixj-core/src/test/java/org/quickfixj/jmx/mbean/session/SessionAdminTest.java +++ b/quickfixj-core/src/test/java/org/quickfixj/jmx/mbean/session/SessionAdminTest.java @@ -1,7 +1,11 @@ package org.quickfixj.jmx.mbean.session; import junit.framework.TestCase; -import quickfix.*; +import quickfix.Message; +import quickfix.Session; +import quickfix.SessionFactoryTestSupport; +import quickfix.SessionID; +import quickfix.SessionNotFound; import quickfix.field.NewSeqNo; import javax.management.ObjectName; @@ -24,7 +28,7 @@ public void testResetSequence() throws Exception { } private class MockSessionAdmin extends SessionAdmin { - final ArrayList sentMessages = new ArrayList(); + final ArrayList sentMessages = new ArrayList<>(); public MockSessionAdmin(Session session, ObjectName connectorName, ObjectName settingsName) { super(session, connectorName, settingsName); diff --git a/quickfixj-core/src/test/java/quickfix/AbstractMessageStoreTest.java b/quickfixj-core/src/test/java/quickfix/AbstractMessageStoreTest.java index be7e059ef..f4a54a73a 100644 --- a/quickfixj-core/src/test/java/quickfix/AbstractMessageStoreTest.java +++ b/quickfixj-core/src/test/java/quickfix/AbstractMessageStoreTest.java @@ -19,11 +19,11 @@ package quickfix; +import junit.framework.TestCase; + import java.io.IOException; import java.util.ArrayList; -import junit.framework.TestCase; - public abstract class AbstractMessageStoreTest extends TestCase { private SessionID sessionID; private MessageStore store; @@ -106,7 +106,7 @@ public void testMessageStorageMessages() throws Exception { store.refresh(); - final ArrayList messages = new ArrayList(); + final ArrayList messages = new ArrayList<>(); store.get(100, 115, messages); assertEquals("wrong # of messages", 2, messages.size()); assertEquals("wrong message", "\u00E4bcf\u00F6d\u00E7\u00E9", messages.get(0)); @@ -123,7 +123,7 @@ public void testMessageStorageOutOfSequence() throws Exception { store.refresh(); - final ArrayList messages = new ArrayList(); + final ArrayList messages = new ArrayList<>(); store.get(100, 115, messages); assertEquals("wrong # of messages", 2, messages.size()); assertEquals("wrong message", "message1", messages.get(0)); diff --git a/quickfixj-core/src/test/java/quickfix/FieldTest.java b/quickfixj-core/src/test/java/quickfix/FieldTest.java index 9eb1ef5d4..431894267 100644 --- a/quickfixj-core/src/test/java/quickfix/FieldTest.java +++ b/quickfixj-core/src/test/java/quickfix/FieldTest.java @@ -19,13 +19,6 @@ package quickfix; -import java.io.UnsupportedEncodingException; -import java.math.BigDecimal; -import java.util.Arrays; -import java.util.Date; - -import static junit.framework.Assert.assertTrue; -import static junit.framework.Assert.assertEquals; import org.junit.Test; import org.quickfixj.CharsetSupport; import quickfix.field.MDUpdateAction; @@ -34,6 +27,14 @@ import quickfix.field.TradeCondition; import quickfix.fix50.MarketDataIncrementalRefresh; +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Date; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + public class FieldTest { @Test @@ -48,7 +49,7 @@ public void testMessageSetGetString() { } private void testFieldCalcuations(String value, int checksum, int length) { - Field field = new Field(12, value); + Field field = new Field<>(12, value); field.setObject(value); assertEquals("12=" + value, field.toString()); assertEquals(checksum, field.getChecksum()); diff --git a/quickfixj-core/src/test/java/quickfix/FileStoreTest.java b/quickfixj-core/src/test/java/quickfix/FileStoreTest.java index 661833d20..3cfdc00a1 100644 --- a/quickfixj-core/src/test/java/quickfix/FileStoreTest.java +++ b/quickfixj-core/src/test/java/quickfix/FileStoreTest.java @@ -55,7 +55,7 @@ public void testMessageIndexReset() throws Exception { store.set(2, "MESSAGE"); - List messages = new ArrayList(); + List messages = new ArrayList<>(); store.get(1, 1, messages); assertEquals(0, messages.size()); diff --git a/quickfixj-core/src/test/java/quickfix/JdbcStoreTest.java b/quickfixj-core/src/test/java/quickfix/JdbcStoreTest.java index ccbfb3e3d..647e59522 100644 --- a/quickfixj-core/src/test/java/quickfix/JdbcStoreTest.java +++ b/quickfixj-core/src/test/java/quickfix/JdbcStoreTest.java @@ -19,6 +19,17 @@ package quickfix; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; +import java.io.IOException; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + import static quickfix.JdbcSetting.SETTING_JDBC_DS_NAME; import static quickfix.JdbcSetting.SETTING_JDBC_STORE_MESSAGES_TABLE_NAME; import static quickfix.JdbcSetting.SETTING_JDBC_STORE_SESSIONS_TABLE_NAME; @@ -30,18 +41,6 @@ import static quickfix.JdbcTestSupport.loadSQL; import static quickfix.JdbcUtil.close; -import java.io.IOException; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import javax.naming.Context; -import javax.naming.InitialContext; -import javax.naming.NamingException; -import javax.sql.DataSource; - public class JdbcStoreTest extends AbstractMessageStoreTest { private String initialContextFactory; @@ -114,7 +113,7 @@ public void testMessageStorageMessagesWithCustomMessagesTableName() throws Excep assertTrue("set failed", store.set(113, "message1")); assertTrue("set failed", store.set(120, "message3")); - ArrayList messages = new ArrayList(); + ArrayList messages = new ArrayList<>(); store.get(100, 115, messages); assertEquals("wrong # of messages", 2, messages.size()); assertEquals("wrong message", "message2", messages.get(0)); @@ -166,7 +165,7 @@ public void testMessageUpdate() throws Exception { assertTrue(store.set(1, "MESSAGE1")); assertTrue(store.set(1, "MESSAGE2")); - List messages = new ArrayList(); + List messages = new ArrayList<>(); store.get(1, 1, messages); assertEquals("MESSAGE2", messages.get(0)); } diff --git a/quickfixj-core/src/test/java/quickfix/LoginTestCase.java b/quickfixj-core/src/test/java/quickfix/LoginTestCase.java index 129b33245..f124e112c 100644 --- a/quickfixj-core/src/test/java/quickfix/LoginTestCase.java +++ b/quickfixj-core/src/test/java/quickfix/LoginTestCase.java @@ -19,13 +19,13 @@ package quickfix; -import static org.junit.Assert.*; -import static quickfix.FixVersions.*; - import java.util.HashMap; import java.util.Map; import java.util.concurrent.CountDownLatch; +import static org.junit.Assert.assertEquals; +import static quickfix.FixVersions.BEGINSTRING_FIX44; + public class LoginTestCase { public static void main(String[] args) { @@ -59,7 +59,7 @@ public void run() { private static SessionSettings createSettings(String senderCompID) { SessionSettings settings = new SessionSettings(); - Map defaults = new HashMap(); + Map defaults = new HashMap<>(); defaults.put("FileStorePath", "target/data/banzai"); defaults.put("ConnectionType", "initiator"); defaults.put("TargetCompID", "EXEC"); diff --git a/quickfixj-core/src/test/java/quickfix/MessageTest.java b/quickfixj-core/src/test/java/quickfix/MessageTest.java index 1562f0a35..803913b90 100644 --- a/quickfixj-core/src/test/java/quickfix/MessageTest.java +++ b/quickfixj-core/src/test/java/quickfix/MessageTest.java @@ -19,20 +19,7 @@ package quickfix; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.math.BigDecimal; -import java.util.Calendar; -import java.util.Date; -import java.util.TimeZone; - import org.junit.Test; - import org.quickfixj.CharsetSupport; import quickfix.field.Account; import quickfix.field.AllocAccount; @@ -109,6 +96,18 @@ import quickfix.fix44.component.Parties; import quickfix.fix50.MarketDataSnapshotFullRefresh; +import java.math.BigDecimal; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + public class MessageTest { @Test @@ -1414,14 +1413,18 @@ private void assertGroupContent(Message message, NewOrderSingle.NoAllocs numAllo } private void assertAllocation(String accountId, Object shares) { - if (accountId.equals("AllocACC1")) { - assertEquals("got shares: " + shares, 0, - new BigDecimal("1010.10").compareTo(new BigDecimal(shares.toString()))); - } else if (accountId.equals("AllocACC2")) { - assertEquals("got shares: " + shares, 0, - new BigDecimal("2020.20").compareTo(new BigDecimal(shares.toString()))); - } else { - fail("Unknown account"); + switch (accountId) { + case "AllocACC1": + assertEquals("got shares: " + shares, 0, + new BigDecimal("1010.10").compareTo(new BigDecimal(shares.toString()))); + break; + case "AllocACC2": + assertEquals("got shares: " + shares, 0, + new BigDecimal("2020.20").compareTo(new BigDecimal(shares.toString()))); + break; + default: + fail("Unknown account"); + break; } } diff --git a/quickfixj-core/src/test/java/quickfix/MultiAcceptorTest.java b/quickfixj-core/src/test/java/quickfix/MultiAcceptorTest.java index 5d78a109e..0a9eef396 100644 --- a/quickfixj-core/src/test/java/quickfix/MultiAcceptorTest.java +++ b/quickfixj-core/src/test/java/quickfix/MultiAcceptorTest.java @@ -19,19 +19,17 @@ package quickfix; -import java.util.HashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - import junit.framework.TestCase; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.field.TestReqID; import quickfix.fix42.TestRequest; import quickfix.mina.ProtocolFactory; +import java.util.HashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + public class MultiAcceptorTest extends TestCase { private final Logger log = LoggerFactory.getLogger(getClass()); private TestAcceptorApplication testAcceptorApplication; @@ -131,7 +129,7 @@ private SessionID getSessionIDForClient(int i) { } private static class TestAcceptorApplication extends ApplicationAdapter { - private final HashMap sessionMessages = new HashMap(); + private final HashMap sessionMessages = new HashMap<>(); private final CountDownLatch logonLatch; private CountDownLatch messageLatch; @@ -192,7 +190,7 @@ public void tearDown() { private Initiator createInitiator(boolean wrongPort) throws ConfigError { SessionSettings settings = new SessionSettings(); - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "initiator"); defaults.put("StartTime", "00:00:00"); defaults.put("EndTime", "00:00:00"); @@ -222,7 +220,7 @@ private void configureInitiatorForSession(SessionSettings settings, int i, int p private Acceptor createAcceptor() throws ConfigError { SessionSettings settings = new SessionSettings(); - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "acceptor"); defaults.put("StartTime", "00:00:00"); defaults.put("EndTime", "00:00:00"); diff --git a/quickfixj-core/src/test/java/quickfix/SLF4JLogTest.java b/quickfixj-core/src/test/java/quickfix/SLF4JLogTest.java index 61998c896..4df76477f 100644 --- a/quickfixj-core/src/test/java/quickfix/SLF4JLogTest.java +++ b/quickfixj-core/src/test/java/quickfix/SLF4JLogTest.java @@ -19,6 +19,10 @@ package quickfix; +import junit.framework.TestCase; +import org.slf4j.Marker; +import org.slf4j.spi.LocationAwareLogger; + import java.util.ArrayList; import java.util.Vector; import java.util.logging.Handler; @@ -26,11 +30,6 @@ import java.util.logging.LogRecord; import java.util.logging.Logger; -import junit.framework.TestCase; - -import org.slf4j.Marker; -import org.slf4j.spi.LocationAwareLogger; - public class SLF4JLogTest extends TestCase { public SLF4JLogTest(String name) { super(name); @@ -225,7 +224,7 @@ private TestHandler setUpLoggerForTest(String category) { } private class TestHandler extends java.util.logging.Handler { - public final ArrayList records = new ArrayList(); + public final ArrayList records = new ArrayList<>(); @Override public void close() throws SecurityException { @@ -259,8 +258,8 @@ protected void log(org.slf4j.Logger log, String text) { } private class MyLog4JLog extends DummySLF4JLogger implements LocationAwareLogger { - final Vector messages = new Vector(); - final Vector fqcns = new Vector(); + final Vector messages = new Vector<>(); + final Vector fqcns = new Vector<>(); public void log(Marker marker, String fqcn, int level, String message, Object[] params, Throwable t) { diff --git a/quickfixj-core/src/test/java/quickfix/SerializationTest.java b/quickfixj-core/src/test/java/quickfix/SerializationTest.java index 68b176ee8..6697cda9b 100644 --- a/quickfixj-core/src/test/java/quickfix/SerializationTest.java +++ b/quickfixj-core/src/test/java/quickfix/SerializationTest.java @@ -19,13 +19,20 @@ package quickfix; -import java.io.*; +import junit.framework.TestCase; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.regex.Pattern; -import junit.framework.TestCase; - public class SerializationTest extends TestCase { private final String[] srcDirs = { @@ -135,11 +142,7 @@ public static Message createTestMessage(String className, int maxGroupElts) { try { Class cl = Class.forName(className); res = createMessageWithDefaultValues(cl, maxGroupElts); - } catch (ClassNotFoundException e) { - fail(e.getMessage()); - } catch (InstantiationException e) { - fail(e.getMessage()); - } catch (IllegalAccessException e) { + } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) { fail(e.getMessage()); } return res; @@ -150,11 +153,7 @@ private static Object objectFromClassName(String className) { try { Class cl = Class.forName(className); res = cl.newInstance(); - } catch (ClassNotFoundException e) { - fail(e.getMessage()); - } catch (InstantiationException e) { - fail(e.getMessage()); - } catch (IllegalAccessException e) { + } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) { fail(e.getMessage()); } return res; @@ -171,9 +170,7 @@ private Object buildSerializedObject(Object sourceMsg) { ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); ObjectInputStream ins = new ObjectInputStream(in); res = ins.readObject(); - } catch (IOException e) { - fail(e.getMessage()); - } catch (ClassNotFoundException e) { + } catch (IOException | ClassNotFoundException e) { fail(e.getMessage()); } return res; @@ -181,7 +178,7 @@ private Object buildSerializedObject(Object sourceMsg) { private interface SerializationAssertion { - public void assertSerialization(String className); + void assertSerialization(String className); } private final class MessageSerializationAssertion implements SerializationAssertion { @@ -246,15 +243,7 @@ private static Message createMessageWithDefaultValues(Class cl, int maxGroupE Object[] args = new Object[1]; args[0] = g; addGroup.invoke(res, args); - } catch (SecurityException e) { - fail(e.getMessage()); - } catch (NoSuchMethodException e) { - fail(e.getMessage()); - } catch (IllegalArgumentException e) { - fail(e.getMessage()); - } catch (IllegalAccessException e) { - fail(e.getMessage()); - } catch (InvocationTargetException e) { + } catch (SecurityException | InvocationTargetException | IllegalAccessException | IllegalArgumentException | NoSuchMethodException e) { fail(e.getMessage()); } } @@ -284,15 +273,7 @@ private static FieldMap createFieldMapWithDefaultValues(Class cl) throws Inst Object[] args = new Object[1]; args[0] = f; setter.invoke(res, args); - } catch (SecurityException e) { - fail(e.getMessage()); - } catch (NoSuchMethodException e) { - fail(e.getMessage()); - } catch (IllegalArgumentException e) { - fail(e.getMessage()); - } catch (IllegalAccessException e) { - fail(e.getMessage()); - } catch (InvocationTargetException e) { + } catch (SecurityException | InvocationTargetException | IllegalAccessException | IllegalArgumentException | NoSuchMethodException e) { fail(e.getMessage()); } } diff --git a/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java b/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java index 016790187..4d1b0d74a 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java @@ -19,6 +19,12 @@ package quickfix; +import junit.framework.TestCase; +import org.junit.Test; +import quickfix.field.TestReqID; +import quickfix.fix42.TestRequest; +import quickfix.mina.ProtocolFactory; + import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; @@ -28,14 +34,6 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import junit.framework.TestCase; - -import org.junit.Test; - -import quickfix.field.TestReqID; -import quickfix.fix42.TestRequest; -import quickfix.mina.ProtocolFactory; - public class SessionDisconnectConcurrentlyTest extends TestCase { private TestAcceptorApplication testAcceptorApplication; @@ -87,7 +85,7 @@ private SessionID getSessionIDForClient(int i) { } private static class TestAcceptorApplication extends ApplicationAdapter { - private final HashMap sessionMessages = new HashMap(); + private final HashMap sessionMessages = new HashMap<>(); private final CountDownLatch logonLatch; private CountDownLatch messageLatch; @@ -144,7 +142,7 @@ public void tearDown() { private Initiator createInitiator() throws ConfigError { SessionSettings settings = new SessionSettings(); - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "initiator"); defaults.put("StartTime", "00:00:00"); defaults.put("EndTime", "00:00:00"); @@ -174,7 +172,7 @@ private void configureInitiatorForSession(SessionSettings settings, int i, int p private Acceptor createAcceptor() throws ConfigError { SessionSettings settings = new SessionSettings(); - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "acceptor"); defaults.put("StartTime", "00:00:00"); defaults.put("EndTime", "00:00:00"); @@ -216,7 +214,7 @@ public void run() { } public List getDeadlockedThreads() { - List deadlockedThreads = new ArrayList(); + List deadlockedThreads = new ArrayList<>(); if (null != threadIds) { for (long threadId : threadIds) { ThreadInfo threadInfo = bean.getThreadInfo(threadId); diff --git a/quickfixj-core/src/test/java/quickfix/SessionTest.java b/quickfixj-core/src/test/java/quickfix/SessionTest.java index 9ac707796..5025bd321 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionTest.java @@ -1,37 +1,8 @@ package quickfix; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.stub; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; -import static quickfix.SessionFactoryTestSupport.createSession; - -import java.io.BufferedOutputStream; -import java.io.Closeable; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.lang.reflect.Field; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; - import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; - import quickfix.field.ApplVerID; import quickfix.field.BeginSeqNo; import quickfix.field.BeginString; @@ -64,6 +35,34 @@ import quickfix.fix44.TestRequest; import quickfix.test.util.ReflectionUtil; +import java.io.BufferedOutputStream; +import java.io.Closeable; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.stub; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; +import static quickfix.SessionFactoryTestSupport.createSession; + /** * Note: most session tests are in the form of acceptance tests. */ @@ -811,16 +810,13 @@ private void setupFileStoreForQFJ357(final SessionID sessionID, final String prefix = FileUtil.fileAppendPath(fullPath, sessionName + "."); final String sessionFileName = prefix + "session"; - final DataOutputStream sessionTimeOutput = new DataOutputStream( + try (DataOutputStream sessionTimeOutput = new DataOutputStream( new BufferedOutputStream(new FileOutputStream(sessionFileName, - false))); - try { + false)))) { // removing the file does NOT trigger the reset in the Session // constructor, so we fake an outdated session sessionTimeOutput.writeUTF(UtcTimestampConverter.convert( new Date(0), true)); - } finally { - sessionTimeOutput.close(); } // delete files to have the message store reset seqNums to 1 diff --git a/quickfixj-core/src/test/java/quickfix/SocketAcceptorTest.java b/quickfixj-core/src/test/java/quickfix/SocketAcceptorTest.java index d52e1f216..dc7dadc3b 100644 --- a/quickfixj-core/src/test/java/quickfix/SocketAcceptorTest.java +++ b/quickfixj-core/src/test/java/quickfix/SocketAcceptorTest.java @@ -19,24 +19,24 @@ package quickfix; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import quickfix.mina.ProtocolFactory; +import quickfix.mina.SingleThreadedEventHandlingStrategy; + import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.util.HashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertNull; -import static junit.framework.Assert.assertTrue; -import static junit.framework.Assert.fail; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import quickfix.mina.ProtocolFactory; -import quickfix.mina.SingleThreadedEventHandlingStrategy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** * QFJ-643: Unable to restart a stopped acceptor (SocketAcceptor) @@ -179,7 +179,7 @@ private Acceptor createAcceptor(TestAcceptorApplication testAcceptorApplication) throws ConfigError { SessionSettings settings = new SessionSettings(); - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "acceptor"); defaults.put("StartTime", "00:00:00"); defaults.put("EndTime", "00:00:00"); @@ -196,7 +196,7 @@ private Acceptor createAcceptor(TestAcceptorApplication testAcceptorApplication) private Initiator createInitiator() throws ConfigError { SessionSettings settings = new SessionSettings(); - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "initiator"); defaults.put("StartTime", "00:00:00"); defaults.put("EndTime", "00:00:00"); diff --git a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java index 19044f044..f23723834 100644 --- a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java +++ b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java @@ -19,20 +19,6 @@ package quickfix; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadInfo; -import java.lang.management.ThreadMXBean; -import java.util.HashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - import org.apache.mina.core.filterchain.IoFilterAdapter; import org.apache.mina.core.filterchain.IoFilterChain; import org.apache.mina.core.filterchain.IoFilterChainBuilder; @@ -42,11 +28,24 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.mina.ProtocolFactory; import quickfix.mina.SingleThreadedEventHandlingStrategy; import quickfix.test.acceptance.ATServer; +import java.io.File; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.util.HashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + public class SocketInitiatorTest { private final Logger log = LoggerFactory.getLogger(getClass()); @@ -263,7 +262,7 @@ private void doTestOfRestart(SessionID clientSessionID, ClientApplication client private SessionSettings getClientSessionSettings(SessionID clientSessionID) { SessionSettings settings = new SessionSettings(); - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "initiator"); defaults.put("SocketConnectProtocol", ProtocolFactory.getTypeString(ProtocolFactory.SOCKET)); defaults.put("SocketConnectHost", "localhost"); diff --git a/quickfixj-core/src/test/java/quickfix/UnitTestApplication.java b/quickfixj-core/src/test/java/quickfix/UnitTestApplication.java index 735a2b534..034aa9689 100644 --- a/quickfixj-core/src/test/java/quickfix/UnitTestApplication.java +++ b/quickfixj-core/src/test/java/quickfix/UnitTestApplication.java @@ -23,13 +23,13 @@ import java.util.List; public class UnitTestApplication implements ApplicationExtended, SessionStateListener { - public final List fromAppMessages = new ArrayList(); - public final List toAppMessages = new ArrayList(); - public final List fromAdminMessages = new ArrayList(); - public final List toAdminMessages = new ArrayList(); - public final List logonSessions = new ArrayList(); - public final List logoutSessions = new ArrayList(); - public final List createSessions = new ArrayList(); + public final List fromAppMessages = new ArrayList<>(); + public final List toAppMessages = new ArrayList<>(); + public final List fromAdminMessages = new ArrayList<>(); + public final List toAdminMessages = new ArrayList<>(); + public final List logonSessions = new ArrayList<>(); + public final List logoutSessions = new ArrayList<>(); + public final List createSessions = new ArrayList<>(); public int sessionResets = 0; public boolean canLogon(SessionID sessionID) { diff --git a/quickfixj-core/src/test/java/quickfix/mina/SessionConnectorTest.java b/quickfixj-core/src/test/java/quickfix/mina/SessionConnectorTest.java index c89b77761..52413ce48 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/SessionConnectorTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/SessionConnectorTest.java @@ -19,15 +19,6 @@ package quickfix.mina; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import junit.framework.TestCase; import quickfix.Acceptor; import quickfix.ConfigError; @@ -43,8 +34,17 @@ import quickfix.SessionState; import quickfix.UnitTestApplication; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + public class SessionConnectorTest extends TestCase { - private final List propertyChangeEvents = new ArrayList(); + private final List propertyChangeEvents = new ArrayList<>(); public void testConnector() throws Exception { SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX40, "TW", "ISLD"); @@ -103,7 +103,7 @@ public void testOneSessionLoggedOnOneSessionNotLoggedOne() throws Exception { connector.addPropertyChangeListener(connectorListener); connector.removePropertyChangeListener(connectorListener); - Map sessions = new HashMap(); + Map sessions = new HashMap<>(); sessions.put(session1.getSessionID(), session1); connector.setSessions(sessions); @@ -159,7 +159,7 @@ public void testAddingRemovingDymaicSessions() throws Exception { connector.addDynamicSession(session2); assertEquals(2, connector.getManagedSessions().size()); // the list can be in arbitrary order so let's make sure that we get both - HashMap map = new HashMap(); + HashMap map = new HashMap<>(); for (Session s : connector.getManagedSessions()) { map.put(s.getSessionID(), s); } diff --git a/quickfixj-core/src/test/java/quickfix/mina/SingleThreadedEventHandlingStrategyTest.java b/quickfixj-core/src/test/java/quickfix/mina/SingleThreadedEventHandlingStrategyTest.java index 8f2b0f0d1..fe5b3e2de 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/SingleThreadedEventHandlingStrategyTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/SingleThreadedEventHandlingStrategyTest.java @@ -19,17 +19,9 @@ */ package quickfix.mina; -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadInfo; -import java.lang.management.ThreadMXBean; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CountDownLatch; - import org.junit.Assert; import org.junit.Test; import org.mockito.Mockito; - import quickfix.Application; import quickfix.ConfigError; import quickfix.DefaultMessageFactory; @@ -45,6 +37,13 @@ import quickfix.SocketInitiator; import quickfix.UnitTestApplication; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; + /** * * @author chrjohn @@ -255,7 +254,7 @@ public void run() { } private SocketAcceptor createAcceptor(int i) throws ConfigError { - Map acceptorProperties = new HashMap(); + Map acceptorProperties = new HashMap<>(); acceptorProperties.put("ConnectionType", "acceptor"); acceptorProperties.put("HeartBtInt", "5"); acceptorProperties.put("SocketAcceptHost", "localhost"); @@ -280,7 +279,7 @@ private SocketAcceptor createAcceptor(int i) throws ConfigError { } public SocketInitiator createInitiator(int i) throws ConfigError { - Map acceptorProperties = new HashMap(); + Map acceptorProperties = new HashMap<>(); acceptorProperties.put("ConnectionType", "initiator"); acceptorProperties.put("HeartBtInt", "5"); acceptorProperties.put("SocketConnectHost", "localhost"); diff --git a/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java b/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java index c4ed1ef8c..717c1a807 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java @@ -19,19 +19,8 @@ package quickfix.mina.acceptor; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.stub; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; - -import java.util.Date; -import java.util.HashMap; -import java.util.Properties; - import org.apache.mina.core.session.IoSession; import org.junit.Test; - import quickfix.FixVersions; import quickfix.Session; import quickfix.SessionFactoryTestSupport; @@ -51,6 +40,16 @@ import quickfix.mina.NetworkingOptions; import quickfix.mina.acceptor.AbstractSocketAcceptor.StaticAcceptorSessionProvider; +import java.util.Date; +import java.util.HashMap; +import java.util.Properties; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.stub; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + public class AcceptorIoHandlerTest { /** @@ -69,7 +68,7 @@ public void testFIXTLogonAndApplVerID() throws Exception { new UnitTestApplication(), false); stub(mockIoSession.getAttribute("QF_SESSION")).toReturn(null); // to create a new Session - final HashMap acceptorSessions = new HashMap(); + final HashMap acceptorSessions = new HashMap<>(); acceptorSessions.put(sessionID, session); final StaticAcceptorSessionProvider sessionProvider = createSessionProvider(acceptorSessions); @@ -96,7 +95,7 @@ public void testMessageBeforeLogon() throws Exception { EventHandlingStrategy mockEventHandlingStrategy = mock(EventHandlingStrategy.class); - HashMap acceptorSessions = new HashMap(); + HashMap acceptorSessions = new HashMap<>(); AcceptorIoHandler handler = new AcceptorIoHandler(createSessionProvider(acceptorSessions), new NetworkingOptions(new Properties()), mockEventHandlingStrategy); @@ -126,7 +125,7 @@ public void testMessageBeforeLogonWithBoundSession() throws Exception { logout.getHeader() .setString(TargetCompID.FIELD, qfSession.getSessionID().getTargetCompID()); - HashMap acceptorSessions = new HashMap(); + HashMap acceptorSessions = new HashMap<>(); AcceptorIoHandler handler = new AcceptorIoHandler(createSessionProvider(acceptorSessions), new NetworkingOptions(new Properties()), mockEventHandlingStrategy); @@ -156,7 +155,7 @@ public void testMessageBeforeLogonWithKnownButUnboundSession() throws Exception // Expect that onMessage will not be called //mockEventHandlingStrategy.onMessage(qfSession, logout); - HashMap acceptorSessions = new HashMap(); + HashMap acceptorSessions = new HashMap<>(); acceptorSessions.put(qfSession.getSessionID(), qfSession); AcceptorIoHandler handler = new AcceptorIoHandler(createSessionProvider(acceptorSessions), new NetworkingOptions(new Properties()), mockEventHandlingStrategy); diff --git a/quickfixj-core/src/test/java/quickfix/mina/acceptor/DynamicAcceptorSessionProviderTest.java b/quickfixj-core/src/test/java/quickfix/mina/acceptor/DynamicAcceptorSessionProviderTest.java index 4e0433f6a..8bbc8e1a8 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/acceptor/DynamicAcceptorSessionProviderTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/acceptor/DynamicAcceptorSessionProviderTest.java @@ -19,19 +19,30 @@ package quickfix.mina.acceptor; -import static quickfix.mina.acceptor.DynamicAcceptorSessionProvider.*; +import junit.framework.TestCase; +import org.quickfixj.QFJException; +import quickfix.Application; +import quickfix.ConfigError; +import quickfix.DefaultMessageFactory; +import quickfix.LogFactory; +import quickfix.MemoryStoreFactory; +import quickfix.MessageFactory; +import quickfix.MessageStoreFactory; +import quickfix.RuntimeError; +import quickfix.ScreenLogFactory; +import quickfix.Session; +import quickfix.SessionFactory; +import quickfix.SessionID; +import quickfix.SessionSettings; +import quickfix.UnitTestApplication; +import quickfix.mina.SessionConnector; import java.util.ArrayList; -import java.util.List; import java.util.HashMap; +import java.util.List; -import junit.framework.TestCase; - -import org.quickfixj.QFJException; - -import quickfix.*; -import quickfix.mina.acceptor.DynamicAcceptorSessionProvider.TemplateMapping; -import quickfix.mina.SessionConnector; +import static quickfix.mina.acceptor.DynamicAcceptorSessionProvider.TemplateMapping; +import static quickfix.mina.acceptor.DynamicAcceptorSessionProvider.WILDCARD; public class DynamicAcceptorSessionProviderTest extends TestCase { private DynamicAcceptorSessionProvider provider; @@ -45,7 +56,7 @@ public class DynamicAcceptorSessionProviderTest extends TestCase { @Override protected void setUp() throws Exception { settings = new SessionSettings(); - templateMappings = new ArrayList(); + templateMappings = new ArrayList<>(); application = new UnitTestApplication(); messageStoreFactory = new MemoryStoreFactory(); logFactory = new ScreenLogFactory(); @@ -152,7 +163,7 @@ public void testDynamicSessionIsAddedToSessionConnector() throws Exception { } private static class MySessionConnector extends SessionConnector { - private final HashMap sessions = new HashMap(); + private final HashMap sessions = new HashMap<>(); public MySessionConnector(SessionSettings settings, SessionFactory sessionFactory) throws ConfigError { super(settings, sessionFactory); diff --git a/quickfixj-core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java b/quickfixj-core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java index 5e0036578..5ecc0ff69 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java @@ -19,19 +19,6 @@ package quickfix.mina.message; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.List; - import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.filter.codec.ProtocolCodecException; import org.apache.mina.filter.codec.ProtocolDecoder; @@ -42,13 +29,25 @@ import org.junit.Before; import org.junit.Test; import org.quickfixj.CharsetSupport; - import quickfix.DataDictionaryTest; import quickfix.InvalidMessage; import quickfix.Message; import quickfix.field.Headline; import quickfix.mina.CriticalProtocolCodecException; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + public class FIXMessageDecoderTest { private FIXMessageDecoder decoder; private IoBuffer buffer; @@ -277,7 +276,7 @@ public void testMessageStreamingExtraction() throws Exception { File testFile = setUpTestFile(); FIXMessageDecoder decoder = new FIXMessageDecoder(); - final List messages = new ArrayList(); + final List messages = new ArrayList<>(); decoder.extractMessages(testFile, new FIXMessageDecoder.MessageListener() { public void onMessage(String message) { messages.add(message); diff --git a/quickfixj-core/src/test/java/quickfix/mina/message/ProtocolDecoderOutputForTest.java b/quickfixj-core/src/test/java/quickfix/mina/message/ProtocolDecoderOutputForTest.java index 0531f39de..9014682c6 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/message/ProtocolDecoderOutputForTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/message/ProtocolDecoderOutputForTest.java @@ -19,13 +19,13 @@ package quickfix.mina.message; +import org.apache.mina.filter.codec.ProtocolDecoderOutput; + import java.util.ArrayList; import java.util.List; -import org.apache.mina.filter.codec.ProtocolDecoderOutput; - public class ProtocolDecoderOutputForTest implements ProtocolDecoderOutput { - public final List messages = new ArrayList(); + public final List messages = new ArrayList<>(); public void write(Object message) { messages.add(message); diff --git a/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLAndNonSSLTest.java b/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLAndNonSSLTest.java index 3002c33fe..fdb9624a6 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLAndNonSSLTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLAndNonSSLTest.java @@ -19,18 +19,10 @@ package quickfix.mina.ssl; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.util.HashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.ApplicationAdapter; import quickfix.ConfigError; import quickfix.DefaultMessageFactory; @@ -49,6 +41,13 @@ import quickfix.mina.acceptor.AbstractSocketAcceptor; import quickfix.test.acceptance.ATApplication; +import java.util.HashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + public class SSLAndNonSSLTest { private final Logger log = LoggerFactory.getLogger(getClass()); @@ -98,7 +97,7 @@ private void doLogonTest(String clientCompId, String port, String useSSL) throws private SessionSettings getClientSessionSettings(SessionID clientSessionID, String socketConnectPort, String socketUseSSL) { SessionSettings settings = new SessionSettings(); - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "initiator"); defaults.put("SocketConnectProtocol", ProtocolFactory.getTypeString(ProtocolFactory.SOCKET)); defaults.put("SocketUseSSL", socketUseSSL); @@ -174,7 +173,7 @@ public ATServer() { public void run() { try { - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "acceptor"); defaults.put("SocketAcceptProtocol", ProtocolFactory.getTypeString(ProtocolFactory.SOCKET)); defaults.put("SocketTcpNoDelay", "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 c7921f3e7..40e3ddda2 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java @@ -19,16 +19,6 @@ package quickfix.mina.ssl; -import java.lang.reflect.Field; -import java.math.BigInteger; -import java.util.HashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.net.ssl.SSLPeerUnverifiedException; -import javax.net.ssl.SSLSession; -import javax.security.cert.X509Certificate; - import org.apache.mina.core.filterchain.IoFilterAdapter; import org.apache.mina.core.filterchain.IoFilterChain; import org.apache.mina.core.filterchain.IoFilterChainBuilder; @@ -36,7 +26,6 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.ApplicationAdapter; import quickfix.ConfigError; import quickfix.DefaultMessageFactory; @@ -54,6 +43,15 @@ import quickfix.mina.ProtocolFactory; import quickfix.mina.SessionConnector; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSession; +import javax.security.cert.X509Certificate; +import java.lang.reflect.Field; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + public class SSLCertificateTest { // Note: To diagnose cipher suite errors, run with -Djavax.net.debug=ssl:handshake @@ -697,7 +695,7 @@ public SessionConnector createConnector(SessionSettings sessionSettings) throws private SessionSettings createMultiSessionAcceptorSettings(String keyStoreName, boolean needClientAuth, String[] trustStoreNames, String cipherSuites, String protocols) { - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "acceptor"); defaults.put("SocketConnectProtocol", ProtocolFactory.getTypeString(ProtocolFactory.SOCKET)); defaults.put(SSLSupport.SETTING_USE_SSL, "Y"); @@ -738,7 +736,7 @@ private SessionSettings createMultiSessionAcceptorSettings(String keyStoreName, private SessionSettings createAcceptorSettings(String keyStoreName, boolean needClientAuth, String trustStoreName, String cipherSuites, String protocols, String keyStoreType, String trustStoreType) { - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "acceptor"); defaults.put("SocketConnectProtocol", ProtocolFactory.getTypeString(ProtocolFactory.SOCKET)); defaults.put(SSLSupport.SETTING_USE_SSL, "Y"); @@ -789,7 +787,7 @@ private SessionSettings createAcceptorSettings(String keyStoreName, boolean need private SessionSettings createInitiatorSettings(String keyStoreName, String trustStoreName, String cipherSuites, String protocols, String senderId, String targetId, String port, String keyStoreType, String trustStoreType) { - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "initiator"); defaults.put("SocketConnectProtocol", ProtocolFactory.getTypeString(ProtocolFactory.SOCKET)); defaults.put(SSLSupport.SETTING_USE_SSL, "Y"); diff --git a/quickfixj-core/src/test/java/quickfix/mina/ssl/SecureSocketTest.java b/quickfixj-core/src/test/java/quickfix/mina/ssl/SecureSocketTest.java index 56ff65a19..98152d11f 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/ssl/SecureSocketTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/ssl/SecureSocketTest.java @@ -19,19 +19,13 @@ package quickfix.mina.ssl; -import java.util.HashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - import junit.framework.TestCase; - import org.apache.mina.core.filterchain.IoFilterAdapter; import org.apache.mina.core.filterchain.IoFilterChain; import org.apache.mina.core.filterchain.IoFilterChainBuilder; import org.apache.mina.core.session.IoSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.ApplicationAdapter; import quickfix.ConfigError; import quickfix.DefaultMessageFactory; @@ -47,6 +41,10 @@ import quickfix.test.acceptance.ATServer; import quickfix.test.util.ExpectedTestFailure; +import java.util.HashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + public class SecureSocketTest extends TestCase { private final Logger log = LoggerFactory.getLogger(getClass()); private final int transportProtocol = ProtocolFactory.SOCKET; @@ -159,7 +157,7 @@ private void doLogonTest(String keyStoreName, String keyStorePassword) throws In private SessionSettings getClientSessionSettings(SessionID clientSessionID) { SessionSettings settings = new SessionSettings(); - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "initiator"); defaults.put("SocketConnectProtocol", ProtocolFactory.getTypeString(transportProtocol)); defaults.put("SocketUseSSL", "Y"); diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/ATMessageCracker.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/ATMessageCracker.java index e966197cb..9fd66e377 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/ATMessageCracker.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/ATMessageCracker.java @@ -19,13 +19,21 @@ package quickfix.test.acceptance; +import quickfix.FieldNotFound; +import quickfix.IncorrectTagValue; +import quickfix.Message; +import quickfix.Session; +import quickfix.SessionID; +import quickfix.SessionNotFound; +import quickfix.UnsupportedMessageType; +import quickfix.field.ClOrdID; +import quickfix.field.PossResend; + import java.util.HashSet; -import quickfix.*; -import quickfix.field.*; class ATMessageCracker extends quickfix.MessageCracker { - private HashSet orderIDs = new HashSet(); + private HashSet orderIDs = new HashSet<>(); public void reset() { orderIDs.clear(); diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java index 64f3d2c62..1f2c2d3d8 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java @@ -19,27 +19,11 @@ package quickfix.test.acceptance; -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadInfo; -import java.lang.management.ThreadMXBean; -import java.net.BindException; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - import junit.framework.TestSuite; - import org.apache.mina.core.filterchain.IoFilterChainBuilder; import org.junit.Assert; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.DefaultMessageFactory; import quickfix.FileStoreFactory; import quickfix.FixVersions; @@ -56,11 +40,25 @@ import quickfix.mina.ssl.SSLSupport; import quickfix.test.util.ReflectionUtil; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.net.BindException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + public class ATServer implements Runnable { private final Logger log = LoggerFactory.getLogger(ATServer.class); private final CountDownLatch initializationLatch = new CountDownLatch(1); private final CountDownLatch tearDownLatch = new CountDownLatch(1); - private final Set fixVersions = new HashSet(); + private final Set fixVersions = new HashSet<>(); private final SessionSettings settings = new SessionSettings(); private boolean resetOnDisconnect; private boolean usingMemoryStore; @@ -97,7 +95,7 @@ public ATServer(TestSuite suite, boolean threaded, int transportType, int port, public void run() { try { - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "acceptor"); defaults.put("SocketAcceptProtocol", ProtocolFactory.getTypeString(transportType)); defaults.put("SocketAcceptPort", Integer.toString(port)); @@ -196,7 +194,7 @@ public void run() { final ThreadMXBean bean = ManagementFactory.getThreadMXBean(); long[] threadIds = bean.findDeadlockedThreads(); - final List deadlockedThreads = new ArrayList(); + final List deadlockedThreads = new ArrayList<>(); if (threadIds != null) { for (long threadId : threadIds) { final ThreadInfo threadInfo = bean.getThreadInfo(threadId); diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/AcceptanceTestSuite.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/AcceptanceTestSuite.java index c018da624..c22d2aac7 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/AcceptanceTestSuite.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/AcceptanceTestSuite.java @@ -1,35 +1,33 @@ package quickfix.test.acceptance; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.InputStreamReader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - import junit.extensions.TestSetup; import junit.framework.AssertionFailedError; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestResult; import junit.framework.TestSuite; - import org.apache.mina.util.AvailablePortFinder; import org.logicalcobwebs.proxool.ProxoolException; import org.logicalcobwebs.proxool.ProxoolFacade; import org.logicalcobwebs.proxool.admin.SnapshotIF; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.Session; import quickfix.mina.ProtocolFactory; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + public class AcceptanceTestSuite extends TestSuite { private static final String ATEST_TIMEOUT_KEY = "atest.timeout"; private static final String ATEST_TRANSPORT_KEY = "atest.transport"; @@ -109,7 +107,7 @@ protected void printDatabasePoolingStatistics() { } private List load(String filename) throws IOException { - ArrayList steps = new ArrayList(); + ArrayList steps = new ArrayList<>(); log.info("load test: " + filename); BufferedReader in = null; try { @@ -252,17 +250,17 @@ public static Test suite() { acceptanceTests.addTest(new AcceptanceTestServerSetUp(new AcceptanceTestSuite("server", false))); acceptanceTests.addTest(new AcceptanceTestServerSetUp(new AcceptanceTestSuite("server", true))); - Map resendRequestChunkSizeProperties = new HashMap(); + Map resendRequestChunkSizeProperties = new HashMap<>(); resendRequestChunkSizeProperties.put(Session.SETTING_RESEND_REQUEST_CHUNK_SIZE, "5"); acceptanceTests.addTest(new AcceptanceTestServerSetUp(new AcceptanceTestSuite("resendRequestChunkSize", true, resendRequestChunkSizeProperties))); acceptanceTests.addTest(new AcceptanceTestServerSetUp(new AcceptanceTestSuite("resendRequestChunkSize", false, resendRequestChunkSizeProperties))); - Map lastMsgSeqNumProcessedProperties = new HashMap(); + Map lastMsgSeqNumProcessedProperties = new HashMap<>(); lastMsgSeqNumProcessedProperties.put(Session.SETTING_ENABLE_LAST_MSG_SEQ_NUM_PROCESSED, "Y"); acceptanceTests.addTest(new AcceptanceTestServerSetUp(new AcceptanceTestSuite("lastMsgSeqNumProcessed", true, lastMsgSeqNumProcessedProperties))); acceptanceTests.addTest(new AcceptanceTestServerSetUp(new AcceptanceTestSuite("lastMsgSeqNumProcessed", false, lastMsgSeqNumProcessedProperties))); - Map nextExpectedMsgSeqNumProperties = new HashMap(); + Map nextExpectedMsgSeqNumProperties = new HashMap<>(); nextExpectedMsgSeqNumProperties.put(Session.SETTING_ENABLE_NEXT_EXPECTED_MSG_SEQ_NUM, "Y"); acceptanceTests.addTest(new AcceptanceTestServerSetUp(new AcceptanceTestSuite("nextExpectedMsgSeqNum", true, nextExpectedMsgSeqNumProperties))); acceptanceTests.addTest(new AcceptanceTestServerSetUp(new AcceptanceTestSuite("nextExpectedMsgSeqNum", false, nextExpectedMsgSeqNumProperties))); diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/ExpectMessageStep.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/ExpectMessageStep.java index 9a92ee42d..cff2e0871 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/ExpectMessageStep.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/ExpectMessageStep.java @@ -19,6 +19,12 @@ package quickfix.test.acceptance; +import junit.framework.TestResult; +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import quickfix.test.util.ReflectionUtil; + import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; @@ -31,14 +37,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import junit.framework.TestResult; - -import org.junit.Assert; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import quickfix.test.util.ReflectionUtil; - public class ExpectMessageStep implements TestStep { public static long TIMEOUT_IN_MS = 10000; private final Logger log = LoggerFactory.getLogger(getClass()); @@ -66,7 +64,7 @@ public ExpectMessageStep(String data) { } private Map simpleParse(String data) { - HashMap fields = new HashMap(); + HashMap fields = new HashMap<>(); Matcher fieldMatcher = FIELD_PATTERN.matcher(data); while (fieldMatcher.find()) { fields.put(fieldMatcher.group(1), fieldMatcher.group(2)); @@ -83,7 +81,7 @@ public void run(TestResult result, final TestConnection connection) throws Inter final ThreadMXBean bean = ManagementFactory.getThreadMXBean(); long[] threadIds = bean.findDeadlockedThreads(); - final List deadlockedThreads = new ArrayList(); + final List deadlockedThreads = new ArrayList<>(); if (threadIds != null) { for (long threadId : threadIds) { final ThreadInfo threadInfo = bean.getThreadInfo(threadId); @@ -104,7 +102,7 @@ public void run(TestResult result, final TestConnection connection) throws Inter assertMessageEqual(actualFields); } - private static final HashSet timeFields = new HashSet(); + private static final HashSet timeFields = new HashSet<>(); static { timeFields.add("52"); diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/TestConnection.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/TestConnection.java index 82db6f665..de8303009 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/TestConnection.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/TestConnection.java @@ -19,20 +19,6 @@ package quickfix.test.acceptance; -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadInfo; -import java.lang.management.ThreadMXBean; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; - import org.apache.mina.core.future.CloseFuture; import org.apache.mina.core.future.ConnectFuture; import org.apache.mina.core.service.IoConnector; @@ -45,15 +31,28 @@ import org.junit.Assert; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.mina.ProtocolFactory; import quickfix.mina.message.FIXProtocolCodecFactory; import quickfix.test.util.ReflectionUtil; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + public class TestConnection { - private static final HashMap connectors = new HashMap(); + private static final HashMap connectors = new HashMap<>(); private final Logger log = LoggerFactory.getLogger(getClass()); - private final HashMap ioHandlers = new HashMap(); + private final HashMap ioHandlers = new HashMap<>(); public void sendMessage(int clientId, String message) throws IOException { TestIoHandler handler = getIoHandler(clientId); @@ -120,7 +119,7 @@ public void connect(int clientId, int transportType, int port) private class TestIoHandler extends IoHandlerAdapter { private IoSession session; - private final BlockingQueue messages = new LinkedBlockingQueue(); + private final BlockingQueue messages = new LinkedBlockingQueue<>(); private final CountDownLatch sessionCreatedLatch = new CountDownLatch(1); private final CountDownLatch disconnectLatch = new CountDownLatch(1); @@ -156,7 +155,7 @@ public IoSession getSession() { final ThreadMXBean bean = ManagementFactory.getThreadMXBean(); long[] threadIds = bean.findDeadlockedThreads(); - final List deadlockedThreads = new ArrayList(); + final List deadlockedThreads = new ArrayList<>(); if (threadIds != null) { for (long threadId : threadIds) { final ThreadInfo threadInfo = bean.getThreadInfo(threadId); diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/resynch/ResynchTestClient.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/resynch/ResynchTestClient.java index dadc3f674..e2cd3ad0c 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/resynch/ResynchTestClient.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/resynch/ResynchTestClient.java @@ -19,14 +19,8 @@ package quickfix.test.acceptance.resynch; -import java.util.HashMap; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.CountDownLatch; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.Application; import quickfix.ConfigError; import quickfix.DefaultMessageFactory; @@ -51,6 +45,11 @@ import quickfix.fix44.Heartbeat; import quickfix.fix44.Logon; +import java.util.HashMap; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.CountDownLatch; + public class ResynchTestClient extends MessageCracker implements Application { private final Logger log = LoggerFactory.getLogger(ResynchTestServer.class); private final SessionSettings settings = new SessionSettings(); @@ -99,7 +98,7 @@ private void stop(boolean failed) { } public void run() throws ConfigError, SessionNotFound, InterruptedException { - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "initiator"); defaults.put("HeartBtInt", "2"); defaults.put("SocketConnectHost", "localhost"); diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/resynch/ResynchTestServer.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/resynch/ResynchTestServer.java index d5feafae6..8f653a4db 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/resynch/ResynchTestServer.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/resynch/ResynchTestServer.java @@ -19,15 +19,8 @@ package quickfix.test.acceptance.resynch; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.IOException; -import java.util.HashMap; -import java.util.concurrent.CountDownLatch; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.Application; import quickfix.DefaultMessageFactory; import quickfix.DoNotSend; @@ -48,6 +41,12 @@ import quickfix.UnsupportedMessageType; import quickfix.mina.SessionConnector; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.util.HashMap; +import java.util.concurrent.CountDownLatch; + public class ResynchTestServer extends MessageCracker implements Application, Runnable, PropertyChangeListener { SocketAcceptor acceptor; @@ -105,7 +104,7 @@ public void stop() { @Override public void run() { try { - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "acceptor"); defaults.put("SocketAcceptPort", "19889"); defaults.put("StartTime", "00:00:00"); diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/timer/TimerTestClient.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/timer/TimerTestClient.java index 153460eeb..8426312f3 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/timer/TimerTestClient.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/timer/TimerTestClient.java @@ -19,14 +19,8 @@ package quickfix.test.acceptance.timer; -import java.util.HashMap; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.CountDownLatch; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.Application; import quickfix.ConfigError; import quickfix.DefaultMessageFactory; @@ -51,6 +45,11 @@ import quickfix.fix44.ListStatusRequest; import quickfix.fix44.TestRequest; +import java.util.HashMap; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.CountDownLatch; + /** * @author John Hensley */ @@ -88,7 +87,7 @@ private void stop(boolean failed) { } public void run() throws ConfigError, SessionNotFound, InterruptedException { - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "initiator"); defaults.put("HeartBtInt", "2"); defaults.put("SocketConnectHost", "localhost"); diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/timer/TimerTestServer.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/timer/TimerTestServer.java index 20b778673..7c7afb9a1 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/timer/TimerTestServer.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/timer/TimerTestServer.java @@ -19,15 +19,8 @@ package quickfix.test.acceptance.timer; -import java.util.HashMap; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.CountDownLatch; - -import org.apache.mina.util.AvailablePortFinder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.Application; import quickfix.DefaultMessageFactory; import quickfix.DoNotSend; @@ -51,6 +44,11 @@ import quickfix.fix44.ListStatusRequest; import quickfix.fix44.Logon; +import java.util.HashMap; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.CountDownLatch; + /** * @author John Hensley */ @@ -115,7 +113,7 @@ public void stop() { public void run() { try { - HashMap defaults = new HashMap(); + HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "acceptor"); defaults.put("SocketAcceptPort", "19888" ); defaults.put("StartTime", "00:00:00"); diff --git a/quickfixj-dictgenerator/pom.xml b/quickfixj-dictgenerator/pom.xml index a4ff92a36..5014a8984 100644 --- a/quickfixj-dictgenerator/pom.xml +++ b/quickfixj-dictgenerator/pom.xml @@ -24,23 +24,16 @@ - dom4j + org.dom4j dom4j - 1.6.1 + 2.0.0 true - - - - xml-apis - xml-apis - - jaxen jaxen - 1.1.4 + 1.1.6 runtime diff --git a/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Field.java b/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Field.java index e5a8e9d3c..f22dc17e6 100644 --- a/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Field.java +++ b/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Field.java @@ -25,7 +25,7 @@ public class Field { String tag = null, fieldName = null, type = null, desc = null, notReqXML = null; - final List enums = new ArrayList(); + final List enums = new ArrayList<>(); public Field(String tag, String fieldName, String type, String desc, String notReqXML) { this.tag = tag; diff --git a/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Generator.java b/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Generator.java index 2109823d9..2353fdf99 100644 --- a/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Generator.java +++ b/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Generator.java @@ -72,7 +72,7 @@ private void generateDictionary(String file, boolean admin, boolean merged) { builder.append("\n"); } - Map msgTypes = new LinkedHashMap(); + Map msgTypes = new LinkedHashMap<>(); if (!merged) { if (admin) { msgTypes.putAll(repository.getSessionMsgTypes()); @@ -181,7 +181,7 @@ private void generateDictionary(String file, boolean admin, boolean merged) { builder.append(" \n"); - Set enumDescCache = new HashSet(); + Set enumDescCache = new HashSet<>(); for (Enum theEnum : field.getEnums()) { String enumDesc = theEnum.getDesc().toUpperCase(); enumDesc = enumDesc.replaceAll("\\(.*\\)", ""); // remove stuff in parentheses @@ -241,7 +241,7 @@ private void addMsgContents(StringBuilder builder, List msgContents, Str } private Set getAllFieldsUsed(Map msgTypes) { - Set result = new TreeSet(); + Set result = new TreeSet<>(); for (MsgType msgType : msgTypes.values()) { result = addFields(result, msgType.getMsgContent()); } @@ -261,7 +261,7 @@ private Set addFields(Set result, List msgContents) { } private Set getAllComponentsUsed(Map msgTypes) { - Set result = new HashSet(); + Set result = new HashSet<>(); for (MsgType msgType : msgTypes.values()) { result = addComponents(result, msgType.getMsgContent()); } diff --git a/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Message.java b/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Message.java index 7c7bdd6b5..de1cd9bd5 100644 --- a/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Message.java +++ b/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Message.java @@ -26,7 +26,7 @@ public class Message { String msgID = null, name = null, type = null, category = null, notReqXML = null; - final List msgContents = new ArrayList(); + final List msgContents = new ArrayList<>(); public Message(String msgID, String name, String type, String category, String notReqXML) { this.msgID = msgID; diff --git a/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Repository.java b/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Repository.java index 00d3fb614..7589047c3 100644 --- a/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Repository.java +++ b/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Repository.java @@ -19,6 +19,10 @@ package org.quickfixj.dictgenerator; +import org.dom4j.Document; +import org.dom4j.Node; +import org.dom4j.io.SAXReader; + import java.io.File; import java.util.Collections; import java.util.Comparator; @@ -28,21 +32,17 @@ import java.util.Set; import java.util.TreeMap; -import org.dom4j.Document; -import org.dom4j.Node; -import org.dom4j.io.SAXReader; - public class Repository { private final File repository; private final Document components, enums, fields, msgContents, msgType; - private final Map sessionMsgTypes = new TreeMap(), applicationMsgTypes = new TreeMap(); - private final Map allFields = new TreeMap(); - private final Map allComponents = new TreeMap(); + private final Map sessionMsgTypes = new TreeMap<>(), applicationMsgTypes = new TreeMap<>(); + private final Map allFields = new TreeMap<>(); + private final Map allComponents = new TreeMap<>(); public Repository(File repositoryFile) throws Exception { this.repository = repositoryFile; - Set requiredFiles = new HashSet(); + Set requiredFiles = new HashSet<>(); requiredFiles.add("Components.xml"); requiredFiles.add("Enums.xml"); requiredFiles.add("Fields.xml"); diff --git a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/BanzaiApplication.java b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/BanzaiApplication.java index 79bde411c..3a76624be 100644 --- a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/BanzaiApplication.java +++ b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/BanzaiApplication.java @@ -19,14 +19,6 @@ package quickfix.examples.banzai; -import java.math.BigDecimal; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Observable; -import java.util.Observer; - -import javax.swing.SwingUtilities; - import quickfix.Application; import quickfix.DefaultMessageFactory; import quickfix.DoNotSend; @@ -72,6 +64,13 @@ import quickfix.field.TimeInForce; import quickfix.field.TransactTime; +import javax.swing.*; +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Observable; +import java.util.Observer; + public class BanzaiApplication implements Application { private final DefaultMessageFactory messageFactory = new DefaultMessageFactory(); private OrderTableModel orderTableModel = null; @@ -84,7 +83,7 @@ public class BanzaiApplication implements Application { static private final TwoWayMap sideMap = new TwoWayMap(); static private final TwoWayMap typeMap = new TwoWayMap(); static private final TwoWayMap tifMap = new TwoWayMap(); - static private final HashMap> execIDs = new HashMap>(); + static private final HashMap> execIDs = new HashMap<>(); public BanzaiApplication(OrderTableModel orderTableModel, ExecutionTableModel executionTableModel) { @@ -280,7 +279,7 @@ private void cancelReject(Message message, SessionID sessionID) throws FieldNotF private boolean alreadyProcessed(ExecID execID, SessionID sessionID) { HashSet set = execIDs.get(sessionID); if (set == null) { - set = new HashSet(); + set = new HashSet<>(); set.add(execID); execIDs.put(sessionID, set); return false; @@ -302,18 +301,26 @@ private void send(quickfix.Message message, SessionID sessionID) { public void send(Order order) { String beginString = order.getSessionID().getBeginString(); - if (beginString.equals(FixVersions.BEGINSTRING_FIX40)) - send40(order); - else if (beginString.equals(FixVersions.BEGINSTRING_FIX41)) - send41(order); - else if (beginString.equals(FixVersions.BEGINSTRING_FIX42)) - send42(order); - else if (beginString.equals(FixVersions.BEGINSTRING_FIX43)) - send43(order); - else if (beginString.equals(FixVersions.BEGINSTRING_FIX44)) - send44(order); - else if (beginString.equals(FixVersions.BEGINSTRING_FIXT11)) - send50(order); + switch (beginString) { + case FixVersions.BEGINSTRING_FIX40: + send40(order); + break; + case FixVersions.BEGINSTRING_FIX41: + send41(order); + break; + case FixVersions.BEGINSTRING_FIX42: + send42(order); + break; + case FixVersions.BEGINSTRING_FIX43: + send43(order); + break; + case FixVersions.BEGINSTRING_FIX44: + send44(order); + break; + case FixVersions.BEGINSTRING_FIXT11: + send50(order); + break; + } } public void send40(Order order) { @@ -396,12 +403,17 @@ else if (type == OrderType.STOP) { public void cancel(Order order) { String beginString = order.getSessionID().getBeginString(); - if (beginString.equals("FIX.4.0")) - cancel40(order); - else if (beginString.equals("FIX.4.1")) - cancel41(order); - else if (beginString.equals("FIX.4.2")) - cancel42(order); + switch (beginString) { + case "FIX.4.0": + cancel40(order); + break; + case "FIX.4.1": + cancel41(order); + break; + case "FIX.4.2": + cancel42(order); + break; + } } public void cancel40(Order order) { @@ -439,12 +451,17 @@ public void cancel42(Order order) { public void replace(Order order, Order newOrder) { String beginString = order.getSessionID().getBeginString(); - if (beginString.equals("FIX.4.0")) - replace40(order, newOrder); - else if (beginString.equals("FIX.4.1")) - replace41(order, newOrder); - else if (beginString.equals("FIX.4.2")) - replace42(order, newOrder); + switch (beginString) { + case "FIX.4.0": + replace40(order, newOrder); + break; + case "FIX.4.1": + replace41(order, newOrder); + break; + case "FIX.4.2": + replace42(order, newOrder); + break; + } } public void replace40(Order order, Order newOrder) { @@ -535,7 +552,7 @@ public void update(Order order) { } private static class ObservableLogon extends Observable { - private final HashSet set = new HashSet(); + private final HashSet set = new HashSet<>(); public void logon(SessionID sessionID) { set.add(sessionID); diff --git a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/ExecutionTableModel.java b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/ExecutionTableModel.java index b0867beef..095018de5 100644 --- a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/ExecutionTableModel.java +++ b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/ExecutionTableModel.java @@ -19,9 +19,8 @@ package quickfix.examples.banzai; -import java.util.HashMap; - import javax.swing.table.AbstractTableModel; +import java.util.HashMap; public class ExecutionTableModel extends AbstractTableModel { @@ -38,10 +37,10 @@ public class ExecutionTableModel extends AbstractTableModel { private final String[] headers; public ExecutionTableModel() { - rowToExecution = new HashMap(); - idToRow = new HashMap(); - idToExecution = new HashMap(); - exchangeIdToExecution = new HashMap(); + rowToExecution = new HashMap<>(); + idToRow = new HashMap<>(); + idToExecution = new HashMap<>(); + exchangeIdToExecution = new HashMap<>(); headers = new String[] {"Symbol", "Quantity", "Side", "Price"}; } diff --git a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/OrderSide.java b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/OrderSide.java index a9cbabb1c..b77d39a85 100644 --- a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/OrderSide.java +++ b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/OrderSide.java @@ -23,7 +23,7 @@ import java.util.Map; public class OrderSide { - static private final Map known = new HashMap(); + static private final Map known = new HashMap<>(); static public final OrderSide BUY = new OrderSide("Buy"); static public final OrderSide SELL = new OrderSide("Sell"); static public final OrderSide SHORT_SELL = new OrderSide("Short Sell"); diff --git a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/OrderTIF.java b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/OrderTIF.java index c15de36fc..34b93a902 100644 --- a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/OrderTIF.java +++ b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/OrderTIF.java @@ -23,7 +23,7 @@ import java.util.Map; public class OrderTIF { - static private final Map known = new HashMap(); + static private final Map known = new HashMap<>(); static public final OrderTIF DAY = new OrderTIF("Day"); static public final OrderTIF IOC = new OrderTIF("IOC"); static public final OrderTIF OPG = new OrderTIF("OPG"); diff --git a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/OrderTableModel.java b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/OrderTableModel.java index 44b5a291a..ae09c5e68 100644 --- a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/OrderTableModel.java +++ b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/OrderTableModel.java @@ -19,9 +19,8 @@ package quickfix.examples.banzai; -import java.util.HashMap; - import javax.swing.table.AbstractTableModel; +import java.util.HashMap; public class OrderTableModel extends AbstractTableModel { @@ -43,9 +42,9 @@ public class OrderTableModel extends AbstractTableModel { private final String[] headers; public OrderTableModel() { - rowToOrder = new HashMap(); - idToRow = new HashMap(); - idToOrder = new HashMap(); + rowToOrder = new HashMap<>(); + idToRow = new HashMap<>(); + idToOrder = new HashMap<>(); headers = new String[] {"Symbol", "Quantity", "Open", "Executed", diff --git a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/OrderType.java b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/OrderType.java index 223102974..b64ac9551 100644 --- a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/OrderType.java +++ b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/OrderType.java @@ -23,7 +23,7 @@ import java.util.Map; public class OrderType { - static private final Map known = new HashMap(); + static private final Map known = new HashMap<>(); static public final OrderType MARKET = new OrderType("Market"); static public final OrderType LIMIT = new OrderType("Limit"); static public final OrderType STOP = new OrderType("Stop"); diff --git a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/TwoWayMap.java b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/TwoWayMap.java index d901970ed..344372bf6 100644 --- a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/TwoWayMap.java +++ b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/TwoWayMap.java @@ -22,8 +22,8 @@ import java.util.HashMap; public class TwoWayMap { - private final HashMap firstToSecond = new HashMap(); - private final HashMap secondToFirst = new HashMap(); + private final HashMap firstToSecond = new HashMap<>(); + private final HashMap secondToFirst = new HashMap<>(); public void put(Object first, Object second) { firstToSecond.put(first, second); diff --git a/quickfixj-examples/executor/src/main/java/quickfix/examples/executor/Application.java b/quickfixj-examples/executor/src/main/java/quickfix/examples/executor/Application.java index dbcda3e90..f47375641 100644 --- a/quickfixj-examples/executor/src/main/java/quickfix/examples/executor/Application.java +++ b/quickfixj-examples/executor/src/main/java/quickfix/examples/executor/Application.java @@ -19,14 +19,8 @@ package quickfix.examples.executor; -import java.math.BigDecimal; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.ConfigError; import quickfix.DataDictionaryProvider; import quickfix.DoNotSend; @@ -62,6 +56,11 @@ import quickfix.field.Side; import quickfix.field.Symbol; +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + public class Application extends quickfix.MessageCracker implements quickfix.Application { private static final String DEFAULT_MARKET_PRICE_KEY = "DefaultMarketPrice"; private static final String ALWAYS_FILL_LIMIT_KEY = "AlwaysFillLimitOrders"; @@ -69,7 +68,7 @@ public class Application extends quickfix.MessageCracker implements quickfix.App private final Logger log = LoggerFactory.getLogger(getClass()); private final boolean alwaysFillLimitOrders; - private final HashSet validOrderTypes = new HashSet(); + private final HashSet validOrderTypes = new HashSet<>(); private MarketDataProvider marketDataProvider; public Application(SessionSettings settings) throws ConfigError, FieldConvertError { diff --git a/quickfixj-examples/executor/src/main/java/quickfix/examples/executor/Executor.java b/quickfixj-examples/executor/src/main/java/quickfix/examples/executor/Executor.java index e51b7ec9a..765a45562 100644 --- a/quickfixj-examples/executor/src/main/java/quickfix/examples/executor/Executor.java +++ b/quickfixj-examples/executor/src/main/java/quickfix/examples/executor/Executor.java @@ -19,27 +19,9 @@ package quickfix.examples.executor; -import static quickfix.Acceptor.SETTING_ACCEPTOR_TEMPLATE; -import static quickfix.Acceptor.SETTING_SOCKET_ACCEPT_ADDRESS; -import static quickfix.Acceptor.SETTING_SOCKET_ACCEPT_PORT; - -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import javax.management.JMException; -import javax.management.ObjectName; - import org.quickfixj.jmx.JmxExporter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import quickfix.ConfigError; import quickfix.DefaultMessageFactory; import quickfix.FieldConvertError; @@ -55,10 +37,26 @@ import quickfix.mina.acceptor.DynamicAcceptorSessionProvider; import quickfix.mina.acceptor.DynamicAcceptorSessionProvider.TemplateMapping; +import javax.management.JMException; +import javax.management.ObjectName; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import static quickfix.Acceptor.SETTING_ACCEPTOR_TEMPLATE; +import static quickfix.Acceptor.SETTING_SOCKET_ACCEPT_ADDRESS; +import static quickfix.Acceptor.SETTING_SOCKET_ACCEPT_PORT; + public class Executor { private final static Logger log = LoggerFactory.getLogger(Executor.class); private final SocketAcceptor acceptor; - private final Map> dynamicSessionMappings = new HashMap>(); + private final Map> dynamicSessionMappings = new HashMap<>(); private final JmxExporter jmxExporter; private final ObjectName connectorObjectName; @@ -108,7 +106,7 @@ private void configureDynamicSessions(SessionSettings settings, Application appl private List getMappings(InetSocketAddress address) { List mappings = dynamicSessionMappings.get(address); if (mappings == null) { - mappings = new ArrayList(); + mappings = new ArrayList<>(); dynamicSessionMappings.put(address, mappings); } return mappings; diff --git a/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/Application.java b/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/Application.java index 1f67754fa..b97f46d0a 100644 --- a/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/Application.java +++ b/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/Application.java @@ -19,8 +19,6 @@ package quickfix.examples.ordermatch; -import java.util.ArrayList; - import quickfix.DoNotSend; import quickfix.FieldNotFound; import quickfix.IncorrectDataFormat; @@ -60,6 +58,8 @@ import quickfix.fix42.NewOrderSingle; import quickfix.fix42.OrderCancelRequest; +import java.util.ArrayList; + public class Application extends MessageCracker implements quickfix.Application { private final OrderMatcher orderMatcher = new OrderMatcher(); private final IdGenerator generator = new IdGenerator(); @@ -129,7 +129,7 @@ private void processOrder(Order order) { if (orderMatcher.insert(order)) { acceptOrder(order); - ArrayList orders = new ArrayList(); + ArrayList orders = new ArrayList<>(); orderMatcher.match(order.getSymbol(), orders); while (orders.size() > 0) { diff --git a/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/Main.java b/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/Main.java index 5f2054f8f..a473fe1d5 100644 --- a/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/Main.java +++ b/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/Main.java @@ -19,11 +19,6 @@ package quickfix.examples.ordermatch; -import java.io.BufferedReader; -import java.io.FileInputStream; -import java.io.InputStream; -import java.io.InputStreamReader; - import quickfix.DefaultMessageFactory; import quickfix.FileStoreFactory; import quickfix.LogFactory; @@ -31,6 +26,11 @@ import quickfix.SessionSettings; import quickfix.SocketAcceptor; +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; + public class Main { public static void main(String[] args) { try { @@ -54,16 +54,20 @@ public static void main(String[] args) { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); acceptor.start(); + label: while (true) { System.out.println("type #quit to quit"); String value = in.readLine(); if (value != null) { - if (value.equals("#symbols")) { - application.orderMatcher().display(); - } else if (value.equals("#quit")) { - break; - } else { - application.orderMatcher().display(); + switch (value) { + case "#symbols": + application.orderMatcher().display(); + break; + case "#quit": + break label; + default: + application.orderMatcher().display(); + break; } } } diff --git a/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/Market.java b/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/Market.java index 613a22ec9..ebbea0bea 100644 --- a/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/Market.java +++ b/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/Market.java @@ -19,18 +19,18 @@ package quickfix.examples.ordermatch; +import quickfix.field.OrdType; +import quickfix.field.Side; + import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; -import quickfix.field.OrdType; -import quickfix.field.Side; - public class Market { - private final List bidOrders = new ArrayList(); - private final List askOrders = new ArrayList(); + private final List bidOrders = new ArrayList<>(); + private final List askOrders = new ArrayList<>(); public boolean match(String symbol, List orders) { while (true) { diff --git a/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/OrderMatcher.java b/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/OrderMatcher.java index 7e9645ce7..3fa123f19 100644 --- a/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/OrderMatcher.java +++ b/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/OrderMatcher.java @@ -23,7 +23,7 @@ import java.util.HashMap; public class OrderMatcher { - private final HashMap markets = new HashMap(); + private final HashMap markets = new HashMap<>(); private Market getMarket(String symbol) { Market m = markets.get(symbol); From e28e87d7529f19336bfac20147458d5f20a3c693 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Tue, 18 Oct 2016 10:38:04 +0200 Subject: [PATCH 007/165] QFJ-906: Compile QFJ 1.6.x against JDK7 and QFJ 1.7.x against JDK8 - set jdkLevel to 1.8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 39b8f1072..16d98d7c1 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,7 @@ UTF-8 UTF-8 - 1.7 + 1.8 1.7.21 4.12 From 655c12c6978b396b8bb305f2688745f3b6626783 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Wed, 2 Nov 2016 15:57:17 +0100 Subject: [PATCH 008/165] - updated to MINA 2.0.16 --- quickfixj-core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickfixj-core/pom.xml b/quickfixj-core/pom.xml index e835754fe..92c676d5b 100644 --- a/quickfixj-core/pom.xml +++ b/quickfixj-core/pom.xml @@ -59,7 +59,7 @@ org.apache.mina mina-core - 2.0.15 + 2.0.16 org.slf4j From 8e842e5b9605ee4c7006c8c6ab230f77a96d125d Mon Sep 17 00:00:00 2001 From: chrjohn Date: Thu, 3 Nov 2016 13:21:59 +0100 Subject: [PATCH 009/165] QFJ-876: Code Generator creates bad code for nested repeating groups - integrated patch submitted by Scott Harrington --- .../org/quickfixj/codegenerator/MessageSubclass.xsl | 5 ++++- .../src/main/resources/FIX50SP2.modified.xml | 4 ---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageSubclass.xsl b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageSubclass.xsl index 6eec7068d..56087ba66 100644 --- a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageSubclass.xsl +++ b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageSubclass.xsl @@ -191,7 +191,10 @@ import quickfix.Group; - + + + + diff --git a/quickfixj-messages/quickfixj-messages-fix50sp2/src/main/resources/FIX50SP2.modified.xml b/quickfixj-messages/quickfixj-messages-fix50sp2/src/main/resources/FIX50SP2.modified.xml index e54e8be4a..0c99390d2 100644 --- a/quickfixj-messages/quickfixj-messages-fix50sp2/src/main/resources/FIX50SP2.modified.xml +++ b/quickfixj-messages/quickfixj-messages-fix50sp2/src/main/resources/FIX50SP2.modified.xml @@ -3502,8 +3502,6 @@ - - @@ -3786,8 +3784,6 @@ - - From eabbedf71e45f6048ddc8fcb59637f238507f0b1 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Thu, 3 Nov 2016 15:05:12 +0100 Subject: [PATCH 010/165] - removed incorrect disconnect command from duplicate identity acceptance tests - the tests will disconnect anyway when there are no more commands in the file --- .../acceptance/definitions/server/fix40/1b_DuplicateIdentity.def | 1 - .../acceptance/definitions/server/fix41/1b_DuplicateIdentity.def | 1 - .../acceptance/definitions/server/fix42/1b_DuplicateIdentity.def | 1 - .../acceptance/definitions/server/fix43/1b_DuplicateIdentity.def | 1 - .../acceptance/definitions/server/fix44/1b_DuplicateIdentity.def | 1 - .../acceptance/definitions/server/fix50/1b_DuplicateIdentity.def | 1 - 6 files changed, 6 deletions(-) diff --git a/quickfixj-core/src/test/resources/quickfix/test/acceptance/definitions/server/fix40/1b_DuplicateIdentity.def b/quickfixj-core/src/test/resources/quickfix/test/acceptance/definitions/server/fix40/1b_DuplicateIdentity.def index 7fc0a804c..793a3364f 100644 --- a/quickfixj-core/src/test/resources/quickfix/test/acceptance/definitions/server/fix40/1b_DuplicateIdentity.def +++ b/quickfixj-core/src/test/resources/quickfix/test/acceptance/definitions/server/fix40/1b_DuplicateIdentity.def @@ -13,4 +13,3 @@ I2,8=FIX.4.035=A34=149=TW52= diff --git a/quickfixj-codegenerator/pom.xml b/quickfixj-codegenerator/pom.xml index d3941d30c..558b28eee 100644 --- a/quickfixj-codegenerator/pom.xml +++ b/quickfixj-codegenerator/pom.xml @@ -25,7 +25,7 @@ org.apache.maven maven-plugin-api - 3.3.9 + 3.5.0 org.apache.maven diff --git a/quickfixj-core/src/main/java/quickfix/DataDictionary.java b/quickfixj-core/src/main/java/quickfix/DataDictionary.java index 1b8b6344d..4f403c460 100644 --- a/quickfixj-core/src/main/java/quickfix/DataDictionary.java +++ b/quickfixj-core/src/main/java/quickfix/DataDictionary.java @@ -243,12 +243,7 @@ public boolean isAppMessage(String msgType) { } private void addMsgField(String msgType, int field) { - Set fields = messageFields.get(msgType); - if (fields == null) { - fields = new HashSet<>(); - messageFields.put(msgType, fields); - } - fields.add(field); + messageFields.computeIfAbsent(msgType, k -> new HashSet<>()).add(field); } /** @@ -299,12 +294,7 @@ public int getFieldTag(String name) { } private void addRequiredField(String msgType, int field) { - Set fields = requiredFields.get(msgType); - if (fields == null) { - fields = new HashSet<>(); - requiredFields.put(msgType, fields); - } - fields.add(field); + requiredFields.computeIfAbsent(msgType, k -> new HashSet<>()).add(field); } /** @@ -340,12 +330,7 @@ public boolean isRequiredTrailerField(int field) { } private void addFieldValue(int field, String value) { - Set values = fieldValues.get(field); - if (values == null) { - values = new HashSet<>(); - fieldValues.put(field, values); - } - values.add(value); + fieldValues.computeIfAbsent(field, k -> new HashSet<>()).add(value); } /** diff --git a/quickfixj-core/src/main/java/quickfix/FieldMap.java b/quickfixj-core/src/main/java/quickfix/FieldMap.java index ce147a0c9..24371a546 100644 --- a/quickfixj-core/src/main/java/quickfix/FieldMap.java +++ b/quickfixj-core/src/main/java/quickfix/FieldMap.java @@ -579,12 +579,7 @@ protected void setGroupCount(int countTag, int groupSize) { } public List getGroups(int field) { - List groupList = groups.get(field); - if (groupList == null) { - groupList = new ArrayList<>(); - groups.put(field, groupList); - } - return groupList; + return groups.computeIfAbsent(field, k -> new ArrayList<>()); } public Group getGroup(int num, Group group) throws FieldNotFound { diff --git a/quickfixj-core/src/main/java/quickfix/SessionSettings.java b/quickfixj-core/src/main/java/quickfix/SessionSettings.java index 68d86b6a3..6d9788e28 100644 --- a/quickfixj-core/src/main/java/quickfix/SessionSettings.java +++ b/quickfixj-core/src/main/java/quickfix/SessionSettings.java @@ -262,12 +262,7 @@ public int getInt(SessionID sessionID, String key) throws ConfigError, FieldConv } private Properties getOrCreateSessionProperties(SessionID sessionID) { - Properties p = sections.get(sessionID); - if (p == null) { - p = new Properties(sections.get(DEFAULT_SESSION_ID)); - sections.put(sessionID, p); - } - return p; + return sections.computeIfAbsent(sessionID, k -> new Properties(sections.get(DEFAULT_SESSION_ID))); } /** diff --git a/quickfixj-core/src/main/java/quickfix/mina/ThreadPerSessionEventHandlingStrategy.java b/quickfixj-core/src/main/java/quickfix/mina/ThreadPerSessionEventHandlingStrategy.java index e5ab4f1f6..209a78bc4 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/ThreadPerSessionEventHandlingStrategy.java +++ b/quickfixj-core/src/main/java/quickfix/mina/ThreadPerSessionEventHandlingStrategy.java @@ -27,7 +27,6 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.Iterator; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; @@ -100,13 +99,7 @@ public void stopDispatcherThreads() { Thread.currentThread().interrupt(); } - for (final Iterator iterator = dispatchersToShutdown - .iterator(); iterator.hasNext();) { - final MessageDispatchingThread messageDispatchingThread = iterator.next(); - if (messageDispatchingThread.isStopped()) { - iterator.remove(); - } - } + dispatchersToShutdown.removeIf(MessageDispatchingThread::isStopped); } } diff --git a/quickfixj-core/src/main/java/quickfix/mina/acceptor/AbstractSocketAcceptor.java b/quickfixj-core/src/main/java/quickfix/mina/acceptor/AbstractSocketAcceptor.java index 33ed3494b..ebb3d8e2a 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/acceptor/AbstractSocketAcceptor.java +++ b/quickfixj-core/src/main/java/quickfix/mina/acceptor/AbstractSocketAcceptor.java @@ -139,11 +139,9 @@ private void installSSL(AcceptorSocketDescriptor descriptor, private IoAcceptor getIoAcceptor(AcceptorSocketDescriptor socketDescriptor, boolean init) throws ConfigError { int transportType = ProtocolFactory.getAddressTransportType(socketDescriptor.getAddress()); - AcceptorSessionProvider sessionProvider = sessionProviders.get(socketDescriptor.getAddress()); - if (sessionProvider == null) { - sessionProvider = new DefaultAcceptorSessionProvider(socketDescriptor.getAcceptedSessions()); - sessionProviders.put(socketDescriptor.getAddress(), sessionProvider); - } + AcceptorSessionProvider sessionProvider = sessionProviders. + computeIfAbsent(socketDescriptor.getAddress(), + k -> new DefaultAcceptorSessionProvider(socketDescriptor.getAcceptedSessions())); IoAcceptor ioAcceptor = ioAcceptors.get(socketDescriptor); if (ioAcceptor == null && init) { diff --git a/quickfixj-examples/executor/src/main/java/quickfix/examples/executor/Executor.java b/quickfixj-examples/executor/src/main/java/quickfix/examples/executor/Executor.java index 765a45562..d773fb830 100644 --- a/quickfixj-examples/executor/src/main/java/quickfix/examples/executor/Executor.java +++ b/quickfixj-examples/executor/src/main/java/quickfix/examples/executor/Executor.java @@ -104,12 +104,7 @@ private void configureDynamicSessions(SessionSettings settings, Application appl } private List getMappings(InetSocketAddress address) { - List mappings = dynamicSessionMappings.get(address); - if (mappings == null) { - mappings = new ArrayList<>(); - dynamicSessionMappings.put(address, mappings); - } - return mappings; + return dynamicSessionMappings.computeIfAbsent(address, k -> new ArrayList<>()); } private InetSocketAddress getAcceptorSocketAddress(SessionSettings settings, SessionID sessionID) diff --git a/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/OrderMatcher.java b/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/OrderMatcher.java index 3fa123f19..79dac81d4 100644 --- a/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/OrderMatcher.java +++ b/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/OrderMatcher.java @@ -26,12 +26,7 @@ public class OrderMatcher { private final HashMap markets = new HashMap<>(); private Market getMarket(String symbol) { - Market m = markets.get(symbol); - if (m == null) { - m = new Market(); - markets.put(symbol, m); - } - return m; + return markets.computeIfAbsent(symbol, k -> new Market()); } public boolean insert(Order order) { From 95105e4933cc5cbe07b1869c059b55b6c056ecb1 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Fri, 28 Apr 2017 14:57:03 +0200 Subject: [PATCH 052/165] - cleanup resources in SessionDisconnectConcurrentlyTest --- .../test/java/quickfix/SessionDisconnectConcurrentlyTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java b/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java index bcc3c4bb6..f43f15c24 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java @@ -295,7 +295,7 @@ public void onLogout(SessionID sessionId) { ptpe.resume(); ptpe.awaitTermination(2, TimeUnit.SECONDS); - + ptpe.shutdownNow(); assertEquals(1, onLogoutCount.intValue()); } From 375c9d6206c34f162cf963176bd5b97cad697bae Mon Sep 17 00:00:00 2001 From: chrjohn Date: Fri, 5 May 2017 13:35:46 +0200 Subject: [PATCH 053/165] added some debug logging to diagnose problem occurring on build server --- quickfixj-core/src/test/java/quickfix/SessionTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/quickfixj-core/src/test/java/quickfix/SessionTest.java b/quickfixj-core/src/test/java/quickfix/SessionTest.java index 471270152..ea2902c17 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionTest.java @@ -520,6 +520,9 @@ public void testLogonIsFirstMessageOnAcceptor() throws Exception { // QFJ-773 @Test public void testLogonLogoutOnAcceptor() throws Exception { + + System.out.println("quickfix.SessionTest.testLogonLogoutOnAcceptor() XXXXXXXXXXXXXXX"); + final LocalDateTime now = LocalDateTime.ofInstant(Instant.ofEpochMilli(1348264800000L), ZoneOffset.of("+2")); final MockSystemTimeSource systemTimeSource = new MockSystemTimeSource( now.toInstant(ZoneOffset.of("+2")).toEpochMilli()); @@ -606,6 +609,8 @@ public void testLogonLogoutOnAcceptor() throws Exception { assertTrue("Session should be connected", session.isLoggedOn()); session.close(); + + System.out.println("quickfix.SessionTest.testLogonLogoutOnAcceptor() XXXXXXXXXXXXXXX"); } @Test From dd163a0f7d4e80286048b691337ba9743cbc85cf Mon Sep 17 00:00:00 2001 From: chrjohn Date: Tue, 23 May 2017 14:40:52 +0200 Subject: [PATCH 054/165] - corrected SessionTest.testLogonLogoutOnAcceptor() --- quickfixj-core/src/test/java/quickfix/SessionTest.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/quickfixj-core/src/test/java/quickfix/SessionTest.java b/quickfixj-core/src/test/java/quickfix/SessionTest.java index ea2902c17..1f5b252e5 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionTest.java @@ -521,11 +521,10 @@ public void testLogonIsFirstMessageOnAcceptor() throws Exception { @Test public void testLogonLogoutOnAcceptor() throws Exception { - System.out.println("quickfix.SessionTest.testLogonLogoutOnAcceptor() XXXXXXXXXXXXXXX"); - - final LocalDateTime now = LocalDateTime.ofInstant(Instant.ofEpochMilli(1348264800000L), ZoneOffset.of("+2")); + final LocalDateTime now = LocalDateTime.now(); + ZoneOffset offset = ZoneOffset.systemDefault().getRules().getOffset(now); final MockSystemTimeSource systemTimeSource = new MockSystemTimeSource( - now.toInstant(ZoneOffset.of("+2")).toEpochMilli()); + now.atOffset(offset).toInstant().toEpochMilli()); SystemTime.setTimeSource(systemTimeSource); // set up some basic stuff final SessionID sessionID = new SessionID( @@ -609,8 +608,6 @@ public void testLogonLogoutOnAcceptor() throws Exception { assertTrue("Session should be connected", session.isLoggedOn()); session.close(); - - System.out.println("quickfix.SessionTest.testLogonLogoutOnAcceptor() XXXXXXXXXXXXXXX"); } @Test From a3b0f4843463cdad32dc486ce67f0ebd21f9695e Mon Sep 17 00:00:00 2001 From: Kostya Date: Sat, 17 Jun 2017 16:06:06 +0200 Subject: [PATCH 055/165] Treating CumQty as a double value --- .../java/quickfix/examples/banzai/BanzaiApplication.java | 2 +- .../src/main/java/quickfix/examples/banzai/Order.java | 8 +++----- .../main/java/quickfix/examples/banzai/ui/OrderTable.java | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/BanzaiApplication.java b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/BanzaiApplication.java index 3a76624be..f2de35a6e 100644 --- a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/BanzaiApplication.java +++ b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/BanzaiApplication.java @@ -218,7 +218,7 @@ private void executionReport(Message message, SessionID sessionID) throws FieldN if (fillSize.compareTo(BigDecimal.ZERO) > 0) { order.setOpen(order.getOpen() - (int) Double.parseDouble(fillSize.toPlainString())); - order.setExecuted(Integer.parseInt(message.getString(CumQty.FIELD))); + order.setExecuted(Double.parseDouble(message.getString(CumQty.FIELD))); order.setAvgPx(Double.parseDouble(message.getString(AvgPx.FIELD))); } diff --git a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/Order.java b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/Order.java index 7292cfb9b..e666a6f38 100644 --- a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/Order.java +++ b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/Order.java @@ -26,7 +26,7 @@ public class Order implements Cloneable { private String symbol = null; private int quantity = 0; private int open = 0; - private int executed = 0; + private double executed = 0; private OrderSide side = OrderSide.BUY; private OrderType type = OrderType.MARKET; private OrderTIF tif = OrderTIF.DAY; @@ -95,13 +95,11 @@ public void setOpen(int open) { this.open = open; } - public int getExecuted() { + public double getExecuted() { return executed; } - public void setExecuted(int executed) { - this.executed = executed; - } + public void setExecuted(double executed) { this.executed = executed; } public OrderSide getSide() { return side; diff --git a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/ui/OrderTable.java b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/ui/OrderTable.java index c0d2724dd..5071b5990 100644 --- a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/ui/OrderTable.java +++ b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/ui/OrderTable.java @@ -41,7 +41,7 @@ public Component prepareRenderer(TableCellRenderer renderer, int row, int column Order order = ((OrderTableModel) dataModel).getOrder(row); int open = order.getOpen(); - int executed = order.getExecuted(); + double executed = order.getExecuted(); boolean rejected = order.getRejected(); boolean canceled = order.getCanceled(); @@ -52,7 +52,7 @@ public Component prepareRenderer(TableCellRenderer renderer, int row, int column r.setBackground(Color.red); else if (canceled) r.setBackground(Color.white); - else if (open == 0 && executed == 0) + else if (open == 0 && executed == 0.0) r.setBackground(Color.yellow); else if (open > 0) r.setBackground(Color.green); From f128378b119b79a010ee8132f584f9379f3393e9 Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Mon, 26 Jun 2017 14:44:00 +0100 Subject: [PATCH 056/165] first cut of failing test --- .../java/quickfix/SessionDisconnectTest.java | 212 ++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java diff --git a/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java b/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java new file mode 100644 index 000000000..5008e0583 --- /dev/null +++ b/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java @@ -0,0 +1,212 @@ +package quickfix; + +import org.junit.Test; +import quickfix.field.EncryptMethod; +import quickfix.field.HeartBtInt; +import quickfix.field.MsgSeqNum; +import quickfix.field.MsgType; +import quickfix.field.NextExpectedMsgSeqNum; +import quickfix.field.SenderCompID; +import quickfix.field.SendingTime; +import quickfix.field.TargetCompID; +import quickfix.fix44.Logon; + +import java.io.IOException; +import java.util.Collection; +import java.util.Date; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertEquals; + +/** + * @author Jon Freedman + */ +public class SessionDisconnectTest { + private final String EXTERNAL_COMP_ID = "THEM"; + private final String INTERNAL_COMP_ID = "US"; + + @Test + public void reconnectReceivingLogonResponseBeforeLogonRequestPersisted() throws Exception { + final UnitTestApplication application = new UnitTestApplication(); + final SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX44, INTERNAL_COMP_ID, EXTERNAL_COMP_ID); + final CountDownLatch notifyLatch = new CountDownLatch(1); + final CountDownLatch waitLatch = new CountDownLatch(1); + + final Session session = new Session(application, new BlockingStoreFactory(notifyLatch, waitLatch), sessionID, null, null, + new ScreenLogFactory(true, true, true), new ListeningMessageFactory(waitLatch), 60, false, 30, + UtcTimestampPrecision.MILLIS, false, false, false, false, false, + false, true, false, 1.5, null, + true, new int[]{5}, false, false, false, true, + false, true, false, null, true, + 0, true, false); + + final UnitTestResponder responder = new UnitTestResponder(); + session.setResponder(responder); + + final MessageStore messageStore = session.getStore(); + checkNextSeqNums(messageStore, 1, 1); + + session.logon(); + + final ExecutorService executor = Executors.newSingleThreadExecutor(); + try { + executor.execute(() -> { + try { + session.next(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } finally { + executor.shutdown(); + } + + notifyLatch.await(10, TimeUnit.SECONDS); + assertEquals(1, application.lastToAdminMessage().getHeader().getField(new MsgSeqNum()).getValue()); + checkNextSeqNums(messageStore, 1, 1); + + session.next(createLogonResponse()); + checkNextSeqNums(messageStore, 2, 2); + + waitLatch.countDown(); + + session.close(); + } + + private void checkNextSeqNums(final MessageStore messageStore, final int nextTarget, final int nextSender) throws IOException { + assertEquals("NextTargetMsgSeqNum", nextTarget, messageStore.getNextTargetMsgSeqNum()); + assertEquals("NextSenderMsgSeqNum", nextSender, messageStore.getNextSenderMsgSeqNum()); + } + + private Message createLogonResponse() throws FieldNotFound { + final Logon logonResponse = new Logon(new EncryptMethod(EncryptMethod.NONE_OTHER), new HeartBtInt(60)); + logonResponse.setField(new NextExpectedMsgSeqNum(2)); + final Message.Header header = logonResponse.getHeader(); + header.setField(new SenderCompID(EXTERNAL_COMP_ID)); + header.setField(new TargetCompID(INTERNAL_COMP_ID)); + header.setField(new MsgSeqNum(1)); + header.setField(new SendingTime(SystemTime.getLocalDateTime())); + return logonResponse; + } + + private class BlockingStoreFactory implements MessageStoreFactory { + private final MemoryStoreFactory factory = new MemoryStoreFactory(); + private final CountDownLatch notifyLatch; + private final CountDownLatch waitLatch; + + BlockingStoreFactory(final CountDownLatch notifyLatch, final CountDownLatch waitLatch) { + this.notifyLatch = notifyLatch; + this.waitLatch = waitLatch; + } + + @Override + public MessageStore create(final SessionID sessionID) { + return new MessageStore() { + private final MessageStore messageStore = factory.create(sessionID); + + @Override + public boolean set(final int sequence, final String message) throws IOException { + notifyLatch.countDown(); + try { + waitLatch.await(10, TimeUnit.SECONDS); + } catch (final InterruptedException e) { + throw new IOException(e); + } + return messageStore.set(sequence, message); + } + + @Override + public void get(final int startSequence, final int endSequence, final Collection messages) throws IOException { + messageStore.get(startSequence, endSequence, messages); + } + + @Override + public int getNextSenderMsgSeqNum() throws IOException { + return messageStore.getNextSenderMsgSeqNum(); + } + + @Override + public int getNextTargetMsgSeqNum() throws IOException { + return messageStore.getNextTargetMsgSeqNum(); + } + + @Override + public void setNextSenderMsgSeqNum(final int next) throws IOException { + messageStore.setNextSenderMsgSeqNum(next); + } + + @Override + public void setNextTargetMsgSeqNum(final int next) throws IOException { + messageStore.setNextTargetMsgSeqNum(next); + } + + @Override + public void incrNextSenderMsgSeqNum() throws IOException { + messageStore.incrNextSenderMsgSeqNum(); + } + + @Override + public void incrNextTargetMsgSeqNum() throws IOException { + messageStore.incrNextTargetMsgSeqNum(); + } + + @Override + public Date getCreationTime() throws IOException { + return messageStore.getCreationTime(); + } + + @Override + public void reset() throws IOException { + messageStore.reset(); + } + + @Override + public void refresh() throws IOException { + messageStore.refresh(); + } + }; + } + } + + private class ListeningMessageFactory implements MessageFactory { + private final MessageFactory factory = new DefaultMessageFactory(); + private final CountDownLatch waitLatch; + + public ListeningMessageFactory(final CountDownLatch waitLatch) { + this.waitLatch = waitLatch; + } + + @Override + public Message create(final String beginString, final String msgType) { + if (MsgType.LOGOUT.equals(msgType)) { + waitLatch.countDown(); + } + return factory.create(beginString, msgType); + } + + @Override + public Group create(final String beginString, final String msgType, final int correspondingFieldID) { + return factory.create(beginString, msgType, correspondingFieldID); + } + } + + private class UnitTestResponder implements Responder { + String sentMessageData; + + public boolean send(String data) { + sentMessageData = data; + return true; + } + + public String getRemoteAddress() { + return null; + } + + public void disconnect() { + } + } + +} From e87fee0e8f8c10fa0a90a7cac6b4732b72662503 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Mon, 3 Jul 2017 14:25:42 +0200 Subject: [PATCH 057/165] QFJ-926: Session reset happens after logon - make sure that it is checked if session needs to be reset before processing Logon --- .../src/main/java/quickfix/Session.java | 6 + .../src/test/java/quickfix/SessionTest.java | 140 +++++++++++++++++- 2 files changed, 144 insertions(+), 2 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index 16b7f67d3..66710f29f 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -1804,6 +1804,7 @@ public void next() throws IOException { } return; // since we are outside of session time window } else { + // reset when session becomes active resetIfSessionNotCurrent(sessionID, now); } } @@ -1823,6 +1824,8 @@ public void next() throws IOException { return; } } + // QFJ-926 - reset session before initiating Logon + resetIfSessionNotCurrent(sessionID, SystemTime.currentTimeMillis()); if (generateLogon()) { getLog().onEvent("Initiated logon request"); } else { @@ -2005,6 +2008,9 @@ private void nextLogon(Message logon) throws FieldNotFound, RejectLogon, Incorre throw new RejectLogon("Logon attempt not within session time"); } + // QFJ-926 - reset session before accepting Logon + resetIfSessionNotCurrent(sessionID, SystemTime.currentTimeMillis()); + if (isStateRefreshNeeded(MsgType.LOGON)) { getLog().onEvent("Refreshing message/state store at logon"); getStore().refresh(); diff --git a/quickfixj-core/src/test/java/quickfix/SessionTest.java b/quickfixj-core/src/test/java/quickfix/SessionTest.java index 1f5b252e5..0bd2bbd6b 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionTest.java @@ -730,6 +730,142 @@ public void testStartOfInitiatorInsideOfSessionTime() throws Exception { session.close(); } + @Test + // QFJ-926 + public void testSessionNotResetRightAfterLogonOnAcceptor() throws Exception { + // truncate to seconds, otherwise the session time check in Session.next() + // might already reset the session since the session schedule has only precision of seconds + final LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS); + ZoneOffset offset = ZoneOffset.systemDefault().getRules().getOffset(now); + final MockSystemTimeSource systemTimeSource = new MockSystemTimeSource( + now.toInstant(offset).toEpochMilli()); + SystemTime.setTimeSource(systemTimeSource); + // set up some basic stuff + final SessionID sessionID = new SessionID( + FixVersions.BEGINSTRING_FIX44, "SENDER", "TARGET"); + final SessionSettings settings = SessionSettingsTest.setUpSession(null); + // we want to start the session before the StartTime + settings.setString("StartTime", UtcTimeOnlyConverter.convert(now.toLocalTime().plus(4500L, ChronoUnit.MILLIS), UtcTimestampPrecision.SECONDS)); + settings.setString("EndTime", UtcTimeOnlyConverter.convert(now.toLocalTime().plus(3600000L, ChronoUnit.MILLIS), UtcTimestampPrecision.SECONDS)); + settings.setString("TimeZone", TimeZone.getDefault().getID()); + setupFileStoreForQFJ357(sessionID, settings); + + // Session gets constructed, triggering a reset + final UnitTestApplication application = new UnitTestApplication(); + final Session session = setUpFileStoreSession(application, false, + new UnitTestResponder(), settings, sessionID); + session.addStateListener(application); + final SessionState state = getSessionState(session); + + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + session.next(); + + // we should send no messages since we are outside of session time + assertEquals(0, application.toAdminMessages.size()); + // no reset should have been triggered by QF/J (since we were not logged on) + assertEquals(0, application.sessionResets); + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + // increase time to be within session time + systemTimeSource.increment(5000); + // there should be a Logon but no subsequent reset + logonTo(session, 1); + // call next() to provoke SessionTime check which should NOT reset seqnums now + session.next(); + assertEquals(1, application.toAdminMessages.size()); + assertEquals(2, state.getNextSenderMsgSeqNum()); + assertEquals(2, state.getNextTargetMsgSeqNum()); + assertTrue(session.isLoggedOn()); + assertEquals(1, application.sessionResets); + + systemTimeSource.increment(5000); + session.disconnect("test", false); + systemTimeSource.increment(5000); + session.next(); + session.setResponder(new UnitTestResponder()); + + logonTo(session, 2); + session.next(); + + // check that no reset is done on next Logon + assertEquals(1, application.sessionResets); + + session.close(); + } + + @Test + // QFJ-926 + public void testSessionNotResetRightAfterLogonOnInitiator() throws Exception { + // truncate to seconds, otherwise the session time check in Session.next() + // might already reset the session since the session schedule has only precision of seconds + final LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS); + ZoneOffset offset = ZoneOffset.systemDefault().getRules().getOffset(now); + final MockSystemTimeSource systemTimeSource = new MockSystemTimeSource( + now.toInstant(offset).toEpochMilli()); + SystemTime.setTimeSource(systemTimeSource); + // set up some basic stuff + final SessionID sessionID = new SessionID( + FixVersions.BEGINSTRING_FIX44, "SENDER", "TARGET"); + final SessionSettings settings = SessionSettingsTest.setUpSession(null); + // we want to start the session before the StartTime + settings.setString("StartTime", UtcTimeOnlyConverter.convert(now.toLocalTime().plus(5000L, ChronoUnit.MILLIS), UtcTimestampPrecision.SECONDS)); + settings.setString("EndTime", UtcTimeOnlyConverter.convert(now.toLocalTime().plus(3600000L, ChronoUnit.MILLIS), UtcTimestampPrecision.SECONDS)); + settings.setString("TimeZone", TimeZone.getDefault().getID()); + setupFileStoreForQFJ357(sessionID, settings); + + // Session gets constructed, triggering a reset + final UnitTestApplication application = new UnitTestApplication(); + UnitTestResponder responder = new UnitTestResponder(); + final Session session = setUpFileStoreSession(application, true, responder, settings, sessionID); + session.addStateListener(application); + final SessionState state = getSessionState(session); + + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + session.next(); + + // we should send no messages since we are outside of session time + assertEquals(0, application.toAdminMessages.size()); + // no reset should have been triggered by QF/J (since we were not logged on) + assertEquals(0, application.sessionResets); + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + // increase time to be almost within session time to check if session needs to be reset + // (will not reset since it is not yet within session time) + systemTimeSource.increment(4500); + session.next(); + // increase time further so that Logon is sent but reset is not done since last check + // of session time was done within one second + systemTimeSource.increment(600); + session.next(); + systemTimeSource.increment(1000); + session.next(createLogonResponse(new SessionID(FixVersions.BEGINSTRING_FIX44, "TARGET", "SENDER"), application.lastToAdminMessage(), 1)); + assertEquals(1, application.toAdminMessages.size()); + assertEquals(2, state.getNextSenderMsgSeqNum()); + assertEquals(2, state.getNextTargetMsgSeqNum()); + assertTrue(session.isLoggedOn()); + assertEquals(1, application.sessionResets); + + systemTimeSource.increment(5000); + session.disconnect("test", false); + systemTimeSource.increment(5000); + session.next(); + responder = new UnitTestResponder(); + session.setResponder(responder); + + session.next(); + session.next(createLogonResponse(new SessionID(FixVersions.BEGINSTRING_FIX44, "TARGET", "SENDER"), application.lastToAdminMessage(), 2)); + // check that no reset is done on next Logon + assertEquals(1, application.sessionResets); + + session.close(); + } + /** * QFJ-357 This test should make sure that outside the Session time _only_ a * Logout message is sent to the counterparty. Formerly it could be observed @@ -1698,9 +1834,9 @@ public void testGenerateRejectAndTargetSeqNum() throws Exception { session.setResponder(new UnitTestResponder()); + session.next(); session.setNextSenderMsgSeqNum(177); session.setNextTargetMsgSeqNum(223); - session.next(); String[] messages = { "8=FIX.4.2\0019=0081\00135=A\00149=THEM\00156=US\001369=177\00152=20100908-17:59:30.551\00134=227\00198=0\001108=30\00110=36\001", "8=FIX.4.2\0019=0107\00135=z\001115=THEM\00149=THEM\00156=US\001369=177\00152=20100908-17:59:30.551\00134=228\001336=1\001340=2\00176=US\001439=USS\00110=133\001", @@ -1760,7 +1896,7 @@ public void testLogonWithoutTargetCompID() throws Exception { session.close(); } - + // QFJ-751 @Test public void testSequenceResetGapFillWithZeroChunkSize() throws Exception { From de7ff03e949f3c87b7b2139e0e6c55796e5edcff Mon Sep 17 00:00:00 2001 From: chrjohn Date: Tue, 4 Jul 2017 09:14:24 +0200 Subject: [PATCH 058/165] - added some debug logging to diagnose problem only encountered on build server --- .../java/quickfix/SocketInitiatorTest.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java index 38d953c2a..5edbcc6aa 100644 --- a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java +++ b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java @@ -37,6 +37,8 @@ import java.lang.management.ThreadMXBean; import java.util.HashMap; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import org.junit.After; @@ -344,6 +346,24 @@ private SessionSettings getClientSessionSettings(SessionID clientSessionID) { private void assertLoggedOn(ClientApplication clientApplication, Session clientSession) throws InterruptedException { assertNotNull("no client session", clientSession); + + final ExecutorService executor = Executors.newSingleThreadExecutor(); + try { + executor.execute(() -> { + try { + Thread.sleep(5000); + } catch (InterruptedException ex) { + // ignore + } + if ( clientApplication.logonLatch.getCount() > 0 ) { + System.err.println("XXX Dumping threads since latch count is not zero..."); + ReflectionUtil.dumpStackTraces(); + } + }); + } finally { + executor.shutdown(); + } + final boolean await = clientApplication.logonLatch.await(20, TimeUnit.SECONDS); if (!await) { ReflectionUtil.dumpStackTraces(); @@ -376,10 +396,20 @@ public void stopAfterLogon(Initiator initiator) { } public void setUpLogonExpectation() { +// if (logonLatch!=null) { +// while (logonLatch.getCount()>1) { +// logonLatch.countDown(); +// } +// } logonLatch = new CountDownLatch(1); } public void setUpLogoutExpectation() { +// if (logoutLatch!=null) { +// while (logoutLatch.getCount()>1) { +// logoutLatch.countDown(); +// } +// } logoutLatch = new CountDownLatch(1); } From 5316fc969167324d718622e194168534fa7e327b Mon Sep 17 00:00:00 2001 From: chrjohn Date: Tue, 4 Jul 2017 14:22:02 +0200 Subject: [PATCH 059/165] QFJ-929: FieldException on Logon message is handled incorrectly - corrected behaviour and added unit test - minor refactoring: introduced method for logging "invalid message" and disconnecting --- .../src/main/java/quickfix/Session.java | 30 +++++++----- .../src/test/java/quickfix/SessionTest.java | 46 +++++++++++++++++++ 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index 66710f29f..5d7e7a940 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -1010,14 +1010,20 @@ private void next(Message message, boolean isProcessingQueuedMessages) throws Fi break; } } catch (final FieldException e) { - getLog().onErrorEvent("Rejecting invalid message: " + e + ": " + message); - if (resetOrDisconnectIfRequired(message)) { + if (logErrorAndDisconnectIfRequired(e, message)) { return; } - generateReject(message, e.getSessionRejectReason(), e.getField()); + if (msgType.equals(MsgType.LOGON)) { + final String reason = SessionRejectReasonText.getMessage(e.getSessionRejectReason()); + final String errorMessage = "Invalid Logon message: " + reason + " (field " + e.getField() + ")"; + generateLogout(errorMessage); + state.incrNextTargetMsgSeqNum(); + disconnect(errorMessage, true); + } else { + generateReject(message, e.getSessionRejectReason(), e.getField()); + } } catch (final FieldNotFound e) { - getLog().onErrorEvent("Rejecting invalid message: " + e + ": " + message); - if (resetOrDisconnectIfRequired(message)) { + if (logErrorAndDisconnectIfRequired(e, message)) { return; } if (sessionBeginString.compareTo(FixVersions.BEGINSTRING_FIX42) >= 0 @@ -1033,8 +1039,7 @@ private void next(Message message, boolean isProcessingQueuedMessages) throws Fi } } } catch (final IncorrectDataFormat e) { - getLog().onErrorEvent("Rejecting invalid message: " + e + ": " + message); - if (resetOrDisconnectIfRequired(message)) { + if (logErrorAndDisconnectIfRequired(e, message)) { return; } generateReject(message, SessionRejectReason.INCORRECT_DATA_FORMAT_FOR_VALUE, e.field); @@ -1059,8 +1064,7 @@ private void next(Message message, boolean isProcessingQueuedMessages) throws Fi state.incrNextTargetMsgSeqNum(); disconnect("Logon rejected: " + e, true); } catch (final UnsupportedMessageType e) { - getLog().onErrorEvent("Rejecting invalid message: " + e + ": " + message); - if (resetOrDisconnectIfRequired(message)) { + if (logErrorAndDisconnectIfRequired(e, message)) { return; } if (sessionBeginString.compareTo(FixVersions.BEGINSTRING_FIX42) >= 0) { @@ -1069,8 +1073,7 @@ private void next(Message message, boolean isProcessingQueuedMessages) throws Fi generateReject(message, "Unsupported message type"); } } catch (final UnsupportedVersion e) { - getLog().onErrorEvent("Rejecting invalid message: " + e + ": " + message); - if (resetOrDisconnectIfRequired(message)) { + if (logErrorAndDisconnectIfRequired(e, message)) { return; } if (msgType.equals(MsgType.LOGOUT)) { @@ -1125,6 +1128,11 @@ private void next(Message message, boolean isProcessingQueuedMessages) throws Fi } } + private boolean logErrorAndDisconnectIfRequired(final Exception e, Message message) { + getLog().onErrorEvent("Rejecting invalid message: " + e + ": " + message); + return resetOrDisconnectIfRequired(message); + } + /** * (Internal use only) */ diff --git a/quickfixj-core/src/test/java/quickfix/SessionTest.java b/quickfixj-core/src/test/java/quickfix/SessionTest.java index 0bd2bbd6b..57e7dd19d 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionTest.java @@ -866,6 +866,52 @@ public void testSessionNotResetRightAfterLogonOnInitiator() throws Exception { session.close(); } + @Test + // QFJ-929 + public void testLogonIsAnsweredWithLogoutOnFieldException() throws Exception { + + final SessionID sessionID = new SessionID( + FixVersions.BEGINSTRING_FIX44, "SENDER", "TARGET"); + UnitTestApplication application = new UnitTestApplication(); + Session session = SessionFactoryTestSupport.createSession(sessionID, application, + false, false, true, true, null); + UnitTestResponder responder = new UnitTestResponder(); + session.setResponder(responder); + session.logon(); + + session.next(); + Logon logonRequest = new Logon(); + setUpHeader(session.getSessionID(), logonRequest, true, 1); + logonRequest.setInt(HeartBtInt.FIELD, 30); + logonRequest.setString(EncryptMethod.FIELD, ""); + logonRequest.toString(); // calculate length and checksum + session.next(logonRequest); + // session should not be logged on due to empty EnryptMethod + assertFalse(session.isLoggedOn()); + + assertEquals(1, application.lastToAdminMessage().getHeader().getInt(MsgSeqNum.FIELD)); + assertEquals(5, application.lastToAdminMessage().getHeader().getInt(MsgType.FIELD)); + assertEquals(2, session.getStore().getNextTargetMsgSeqNum()); + assertEquals(2, session.getStore().getNextSenderMsgSeqNum()); + + session.setResponder(responder); + session.logon(); + session.next(); + setUpHeader(session.getSessionID(), logonRequest, true, 2); + logonRequest.removeField(EncryptMethod.FIELD); + logonRequest.toString(); // calculate length and checksum + session.next(logonRequest); + // session should not be logged on due to missing EnryptMethod + assertFalse(session.isLoggedOn()); + + assertEquals(2, application.lastToAdminMessage().getHeader().getInt(MsgSeqNum.FIELD)); + assertEquals(5, application.lastToAdminMessage().getHeader().getInt(MsgType.FIELD)); + assertEquals(3, session.getStore().getNextTargetMsgSeqNum()); + assertEquals(3, session.getStore().getNextSenderMsgSeqNum()); + + session.close(); + } + /** * QFJ-357 This test should make sure that outside the Session time _only_ a * Logout message is sent to the counterparty. Formerly it could be observed From f457fe17c690b43b12472898da33a6327255ec4f Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Tue, 4 Jul 2017 13:50:16 +0100 Subject: [PATCH 060/165] test now passes --- quickfixj-core/src/main/java/quickfix/Session.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index 16b7f67d3..fd51ce19c 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -2057,7 +2057,9 @@ private void nextLogon(Message logon) throws FieldNotFound, RejectLogon, Incorre if (logon.isSetField(NextExpectedMsgSeqNum.FIELD) && enableNextExpectedMsgSeqNum) { final int targetWantsNextSeqNumToBe = logon.getInt(NextExpectedMsgSeqNum.FIELD); + state.lockSenderMsgSeqNum(); final int actualNextNum = state.getMessageStore().getNextSenderMsgSeqNum(); + state.unlockSenderMsgSeqNum(); // Is the 789 we received too high ?? if (targetWantsNextSeqNumToBe > actualNextNum) { // barf! we can't resend what we never sent! something unrecoverable has happened. From cae848cd59fea9418b21322d2350de267fd32ab7 Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Tue, 4 Jul 2017 13:51:28 +0100 Subject: [PATCH 061/165] reduce coupling --- quickfixj-core/src/main/java/quickfix/Session.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index fd51ce19c..a715a1ddf 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -2058,7 +2058,7 @@ private void nextLogon(Message logon) throws FieldNotFound, RejectLogon, Incorre final int targetWantsNextSeqNumToBe = logon.getInt(NextExpectedMsgSeqNum.FIELD); state.lockSenderMsgSeqNum(); - final int actualNextNum = state.getMessageStore().getNextSenderMsgSeqNum(); + final int actualNextNum = state.getNextSenderMsgSeqNum(); state.unlockSenderMsgSeqNum(); // Is the 789 we received too high ?? if (targetWantsNextSeqNumToBe > actualNextNum) { From 15f8ee4fa7c6a0e05628deb1cd798cf2117cbf8d Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Tue, 4 Jul 2017 14:49:19 +0100 Subject: [PATCH 062/165] tidy up test --- .../java/quickfix/SessionDisconnectTest.java | 146 +++++++++++------- 1 file changed, 86 insertions(+), 60 deletions(-) diff --git a/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java b/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java index 5008e0583..fd8fc7554 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java @@ -20,59 +20,52 @@ import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** + * The purpose of this test is to simulate the situation where a logon response is received before a logon request can + * be successfully persisted to the MessageStore. + * * @author Jon Freedman */ public class SessionDisconnectTest { + private final int TIMEOUT_SECS = 1; private final String EXTERNAL_COMP_ID = "THEM"; private final String INTERNAL_COMP_ID = "US"; @Test public void reconnectReceivingLogonResponseBeforeLogonRequestPersisted() throws Exception { - final UnitTestApplication application = new UnitTestApplication(); - final SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX44, INTERNAL_COMP_ID, EXTERNAL_COMP_ID); - final CountDownLatch notifyLatch = new CountDownLatch(1); - final CountDownLatch waitLatch = new CountDownLatch(1); - - final Session session = new Session(application, new BlockingStoreFactory(notifyLatch, waitLatch), sessionID, null, null, - new ScreenLogFactory(true, true, true), new ListeningMessageFactory(waitLatch), 60, false, 30, - UtcTimestampPrecision.MILLIS, false, false, false, false, false, - false, true, false, 1.5, null, - true, new int[]{5}, false, false, false, true, - false, true, false, null, true, - 0, true, false); - - final UnitTestResponder responder = new UnitTestResponder(); - session.setResponder(responder); + final CountDownLatch storeMessageLatch = new CountDownLatch(1); + final CountDownLatch receiveLogonResponseLatch = new CountDownLatch(1); + final CountDownLatch sentLogoutLatch = new CountDownLatch(1); + + final UnitTestApplication application = new UnitTestApplication() { + @Override + public void fromAdmin(final Message message, final SessionID sessionId) throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, RejectLogon { + receiveLogonResponseLatch.countDown(); + super.fromAdmin(message, sessionId); + } + }; + final Session session = buildSession(application, storeMessageLatch, receiveLogonResponseLatch, sentLogoutLatch); final MessageStore messageStore = session.getStore(); checkNextSeqNums(messageStore, 1, 1); session.logon(); - final ExecutorService executor = Executors.newSingleThreadExecutor(); - try { - executor.execute(() -> { - try { - session.next(); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - } finally { - executor.shutdown(); - } - - notifyLatch.await(10, TimeUnit.SECONDS); + processOnSeparateThread(session::next); + assertTrue(String.format("Message not stored within %s secs", TIMEOUT_SECS), storeMessageLatch.await(TIMEOUT_SECS, TimeUnit.SECONDS)); assertEquals(1, application.lastToAdminMessage().getHeader().getField(new MsgSeqNum()).getValue()); checkNextSeqNums(messageStore, 1, 1); - session.next(createLogonResponse()); + processOnSeparateThread(() -> { + storeMessageLatch.await(TIMEOUT_SECS, TimeUnit.SECONDS); + session.next(createLogonResponse()); + }); + assertTrue(String.format("Logon response not received within %s secs", TIMEOUT_SECS), receiveLogonResponseLatch.await(TIMEOUT_SECS, TimeUnit.SECONDS)); + assertTrue(String.format("Logout/SequenceReset not sent %s secs", TIMEOUT_SECS * 2), sentLogoutLatch.await(TIMEOUT_SECS * 2, TimeUnit.SECONDS)); checkNextSeqNums(messageStore, 2, 2); - waitLatch.countDown(); - session.close(); } @@ -81,6 +74,34 @@ private void checkNextSeqNums(final MessageStore messageStore, final int nextTar assertEquals("NextSenderMsgSeqNum", nextSender, messageStore.getNextSenderMsgSeqNum()); } + private Session buildSession(final Application application, final CountDownLatch storeMessageLatch, final CountDownLatch receiveLogonResponseLatch, final CountDownLatch sentLogoutLatch) { + final SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX44, INTERNAL_COMP_ID, EXTERNAL_COMP_ID); + final Session session = new Session(application, new BlockingStoreFactory(storeMessageLatch, sentLogoutLatch), sessionID, null, null, + new ScreenLogFactory(true, true, true), new ListeningMessageFactory(sentLogoutLatch), 60, false, 30, + UtcTimestampPrecision.MILLIS, false, false, false, false, false, + false, true, false, 1.5, null, + true, new int[]{5}, false, false, false, true, + false, true, false, null, true, + 0, true, false); + session.setResponder(new Responder() { + @Override + public boolean send(final String data) { + return true; + } + + @Override + public void disconnect() { + } + + @Override + public String getRemoteAddress() { + return null; + } + }); + + return session; + } + private Message createLogonResponse() throws FieldNotFound { final Logon logonResponse = new Logon(new EncryptMethod(EncryptMethod.NONE_OTHER), new HeartBtInt(60)); logonResponse.setField(new NextExpectedMsgSeqNum(2)); @@ -92,14 +113,34 @@ private Message createLogonResponse() throws FieldNotFound { return logonResponse; } + private void processOnSeparateThread(final SessionAction action) { + final ExecutorService executor = Executors.newSingleThreadExecutor(); + try { + executor.execute(() -> { + try { + action.run(); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } finally { + executor.shutdown(); + } + } + + @FunctionalInterface + private interface SessionAction { + void run() throws Exception; + } + private class BlockingStoreFactory implements MessageStoreFactory { private final MemoryStoreFactory factory = new MemoryStoreFactory(); - private final CountDownLatch notifyLatch; - private final CountDownLatch waitLatch; + private final CountDownLatch storeMessageLatch; + private final CountDownLatch sentLogoutLatch; - BlockingStoreFactory(final CountDownLatch notifyLatch, final CountDownLatch waitLatch) { - this.notifyLatch = notifyLatch; - this.waitLatch = waitLatch; + BlockingStoreFactory(final CountDownLatch storeMessageLatch, final CountDownLatch sentLogoutLatch) { + this.storeMessageLatch = storeMessageLatch; + this.sentLogoutLatch = sentLogoutLatch; } @Override @@ -109,9 +150,10 @@ public MessageStore create(final SessionID sessionID) { @Override public boolean set(final int sequence, final String message) throws IOException { - notifyLatch.countDown(); + storeMessageLatch.countDown(); try { - waitLatch.await(10, TimeUnit.SECONDS); + // we are not verifying the return value of this call to #await as once the issue is fixed with locking this will return false + sentLogoutLatch.await(TIMEOUT_SECS, TimeUnit.SECONDS); } catch (final InterruptedException e) { throw new IOException(e); } @@ -173,16 +215,16 @@ public void refresh() throws IOException { private class ListeningMessageFactory implements MessageFactory { private final MessageFactory factory = new DefaultMessageFactory(); - private final CountDownLatch waitLatch; + private final CountDownLatch sentLogoutLatch; - public ListeningMessageFactory(final CountDownLatch waitLatch) { - this.waitLatch = waitLatch; + public ListeningMessageFactory(final CountDownLatch sentLogoutLatch) { + this.sentLogoutLatch = sentLogoutLatch; } @Override public Message create(final String beginString, final String msgType) { - if (MsgType.LOGOUT.equals(msgType)) { - waitLatch.countDown(); + if (MsgType.LOGOUT.equals(msgType) || MsgType.SEQUENCE_RESET.equals(msgType)) { + sentLogoutLatch.countDown(); } return factory.create(beginString, msgType); } @@ -193,20 +235,4 @@ public Group create(final String beginString, final String msgType, final int co } } - private class UnitTestResponder implements Responder { - String sentMessageData; - - public boolean send(String data) { - sentMessageData = data; - return true; - } - - public String getRemoteAddress() { - return null; - } - - public void disconnect() { - } - } - } From 9473d880a2966da73b3e74b118e78308b1df2650 Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Tue, 4 Jul 2017 16:07:13 +0100 Subject: [PATCH 063/165] add builder to SessionFactoryTestSupport --- .../java/quickfix/SessionDisconnectTest.java | 23 +- .../quickfix/SessionFactoryTestSupport.java | 210 ++++++++++++++---- 2 files changed, 184 insertions(+), 49 deletions(-) diff --git a/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java b/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java index fd8fc7554..84acd529c 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java @@ -46,7 +46,7 @@ public void fromAdmin(final Message message, final SessionID sessionId) throws F super.fromAdmin(message, sessionId); } }; - final Session session = buildSession(application, storeMessageLatch, receiveLogonResponseLatch, sentLogoutLatch); + final Session session = buildSession(application, storeMessageLatch, sentLogoutLatch); final MessageStore messageStore = session.getStore(); checkNextSeqNums(messageStore, 1, 1); @@ -74,15 +74,18 @@ private void checkNextSeqNums(final MessageStore messageStore, final int nextTar assertEquals("NextSenderMsgSeqNum", nextSender, messageStore.getNextSenderMsgSeqNum()); } - private Session buildSession(final Application application, final CountDownLatch storeMessageLatch, final CountDownLatch receiveLogonResponseLatch, final CountDownLatch sentLogoutLatch) { - final SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX44, INTERNAL_COMP_ID, EXTERNAL_COMP_ID); - final Session session = new Session(application, new BlockingStoreFactory(storeMessageLatch, sentLogoutLatch), sessionID, null, null, - new ScreenLogFactory(true, true, true), new ListeningMessageFactory(sentLogoutLatch), 60, false, 30, - UtcTimestampPrecision.MILLIS, false, false, false, false, false, - false, true, false, 1.5, null, - true, new int[]{5}, false, false, false, true, - false, true, false, null, true, - 0, true, false); + private Session buildSession(final Application application, final CountDownLatch storeMessageLatch, final CountDownLatch sentLogoutLatch) { + final Session session = new SessionFactoryTestSupport.Builder() + .setSessionId(new SessionID(FixVersions.BEGINSTRING_FIX44, INTERNAL_COMP_ID, EXTERNAL_COMP_ID)) + .setApplication(application) + .setMessageStoreFactory(new BlockingStoreFactory(storeMessageLatch, sentLogoutLatch)) + .setLogFactory(new ScreenLogFactory(true, true, true)) + .setMessageFactory(new ListeningMessageFactory(sentLogoutLatch)) + .setSessionHeartbeatInterval(60) + .setPersistMessages(true) + .setValidateSequenceNumbers(true) + .setEnableNextExpectedMsgSeqNum(true) + .build(); session.setResponder(new Responder() { @Override public boolean send(final String data) { diff --git a/quickfixj-core/src/test/java/quickfix/SessionFactoryTestSupport.java b/quickfixj-core/src/test/java/quickfix/SessionFactoryTestSupport.java index 0dc66753d..8f98a8039 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionFactoryTestSupport.java +++ b/quickfixj-core/src/test/java/quickfix/SessionFactoryTestSupport.java @@ -2,70 +2,202 @@ import quickfix.field.DefaultApplVerID; +import java.net.InetAddress; +import java.util.Set; +import java.util.function.Supplier; + public class SessionFactoryTestSupport implements SessionFactory { private static final SessionFactoryTestSupport instance = new SessionFactoryTestSupport(); + @Override public Session create(SessionID sessionID, SessionSettings settings) throws ConfigError { - if (sessionID == null) { - sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); - } - return createSession(sessionID, new UnitTestApplication(), false); + return new Builder().setSessionId(sessionID).build(); } public static Session createSession(SessionID sessionID, Application application, - boolean isInitiator) { - return new Session(application, new MemoryStoreFactory(), sessionID, null, null, - new ScreenLogFactory(true, true, true), new DefaultMessageFactory(), isInitiator - ? 30 - : 0); + boolean isInitiator) { + return new Builder().setSessionId(sessionID).setApplication(application).setIsInitiator(isInitiator).build(); } public static Session createFileStoreSession(SessionID sessionID, Application application, - boolean isInitiator, SessionSettings settings, SessionSchedule sessionSchedule) { - return new Session(application, new FileStoreFactory(settings), sessionID, null, - sessionSchedule, - new ScreenLogFactory(true, true, true), new DefaultMessageFactory(), isInitiator - ? 30 - : 0); + boolean isInitiator, SessionSettings settings, SessionSchedule sessionSchedule) { + return new Builder().setSessionId(sessionID).setApplication(application).setIsInitiator(isInitiator) + .setMessageStoreFactory(new FileStoreFactory(settings)).setSessionSchedule(sessionSchedule) + .build(); } public static Session createSession(SessionID sessionID, Application application, - boolean isInitiator, boolean resetOnLogon, boolean validateSequenceNumbers) { - return new Session(application, new MemoryStoreFactory(), sessionID, null, null, - new ScreenLogFactory(true, true, true), new DefaultMessageFactory(), isInitiator - ? 30 - : 0, false, 30, UtcTimestampPrecision.MILLIS, resetOnLogon, false, false, false, false, false, - true, false, 1.5, null, validateSequenceNumbers, new int[] { 5 }, false, false, false, true, - false, true, false, null, true, 0, false, false); + boolean isInitiator, boolean resetOnLogon, boolean validateSequenceNumbers) { + return new Builder().setSessionId(sessionID).setApplication(application).setIsInitiator(isInitiator) + .setResetOnLogon(resetOnLogon).setValidateSequenceNumbers(validateSequenceNumbers) + .setPersistMessages(true) + .build(); } public static Session createSession(SessionID sessionID, Application application, - boolean isInitiator, boolean resetOnLogon, boolean validateSequenceNumbers, - boolean useDataDictionary, DefaultApplVerID senderDefaultApplVerID) { - return new Session(application, new MemoryStoreFactory(), sessionID, - new DefaultDataDictionaryProvider(), null, new ScreenLogFactory(true, true, true), - new DefaultMessageFactory(), isInitiator ? 30 : 0, false, 30, UtcTimestampPrecision.MILLIS, resetOnLogon, - false, false, false, false, false, true, false, 1.5, senderDefaultApplVerID, - validateSequenceNumbers, new int[] { 5 }, false, false, false, true, false, true, - false, null, true, 0, false, false); + boolean isInitiator, boolean resetOnLogon, boolean validateSequenceNumbers, + boolean useDataDictionary, DefaultApplVerID senderDefaultApplVerID) { + return new Builder().setSessionId(sessionID).setApplication(application).setIsInitiator(isInitiator) + .setDataDictionaryProvider(new DefaultDataDictionaryProvider()) + .setResetOnLogon(resetOnLogon).setValidateSequenceNumbers(validateSequenceNumbers) + .setPersistMessages(true).setSenderDefaultApplVerID(senderDefaultApplVerID) + .build(); } public static Session createSession(SessionID sessionID, Application application, - boolean isInitiator, boolean resetOnLogon) { + boolean isInitiator, boolean resetOnLogon) { return createSession(sessionID, application, isInitiator, resetOnLogon, false); } - public static Session createNonpersistedSession(SessionID sessionID, Application application, - boolean isInitiator) { - return new Session(application, new MemoryStoreFactory(), sessionID, null, null, - new ScreenLogFactory(true, true, true), new DefaultMessageFactory(), isInitiator - ? 30 - : 0, false, 30, UtcTimestampPrecision.MILLIS, true, false, false, false, false, false, - false/*persistMessages*/, false, 1.5, null, true, new int[] { 5 }, false, false, - false, true, false, true, false, null, true, 0, false, false); + public static Session createNonpersistedSession(SessionID sessionID, Application application, boolean isInitiator) { + return new Builder().setSessionId(sessionID).setApplication(application).setIsInitiator(isInitiator) + .setResetOnLogon(true) + .build(); } public static Session createSession() throws ConfigError { return instance.create(null, null); } + + public static final class Builder { + private String beginString = "FIX.4.2"; + private String senderCompID = "SENDER"; + private String targetCompID = "TARGET"; + private boolean isInitiator = false; + private Supplier sessionIDSupplier = () -> new SessionID(beginString, senderCompID, targetCompID); + private Supplier applicationSupplier = UnitTestApplication::new; + private Supplier messageStoreFactorySupplier = MemoryStoreFactory::new; + private Supplier dataDictionaryProviderSupplier = () -> null; + private Supplier sessionScheduleSupplier = () -> null; + private Supplier logFactorySupplier = () -> new ScreenLogFactory(true, true, true); + private Supplier messageFactorySupplier = DefaultMessageFactory::new; + private Supplier sessionHeartbeatIntervalSupplier = () -> isInitiator ? 30 : 0; + private boolean checkLatency = false; + private int maxLatency = 30; + private UtcTimestampPrecision timestampPrecision = UtcTimestampPrecision.MILLIS; + private boolean resetOnLogon = false; + private boolean resetOnLogout = false; + private boolean resetOnDisconnect = false; + private boolean refreshMessageStoreAtLogon = false; + private boolean checkCompID = false; + private boolean redundantResentRequestsAllowed = false; + private boolean persistMessages = false; + private boolean useClosedRangeForResend = false; + private double testRequestDelayMultiplier = 1.5; + private DefaultApplVerID senderDefaultApplVerID = null; + private boolean validateSequenceNumbers = true; + private int[] logonIntervals = new int[]{5}; + private boolean resetOnError = false; + private boolean disconnectOnError = false; + private boolean disableHeartBeatCheck = false; + private boolean rejectInvalidMessage = true; + private boolean rejectMessageOnUnhandledException = false; + private boolean requiresOrigSendingTime = true; + private boolean forceResendWhenCorruptedStore = false; + private Set allowedRemoteAddresses = null; + private boolean validateIncomingMessage = true; + private int resendRequestChunkSize = 0; + private boolean enableNextExpectedMsgSeqNum = false; + private boolean enableLastMsgSeqNumProcessed = false; + + public Session build() { + return new Session(applicationSupplier.get(), messageStoreFactorySupplier.get(), sessionIDSupplier.get(), + dataDictionaryProviderSupplier.get(), sessionScheduleSupplier.get(), logFactorySupplier.get(), + messageFactorySupplier.get(), sessionHeartbeatIntervalSupplier.get(), checkLatency, maxLatency, + timestampPrecision, resetOnLogon, resetOnLogout, resetOnDisconnect, refreshMessageStoreAtLogon, + checkCompID, redundantResentRequestsAllowed, persistMessages, useClosedRangeForResend, + testRequestDelayMultiplier, senderDefaultApplVerID, validateSequenceNumbers, logonIntervals, + resetOnError, disconnectOnError, disableHeartBeatCheck, rejectInvalidMessage, + rejectMessageOnUnhandledException, requiresOrigSendingTime, forceResendWhenCorruptedStore, + allowedRemoteAddresses, validateIncomingMessage, resendRequestChunkSize, enableNextExpectedMsgSeqNum, + enableLastMsgSeqNumProcessed); + } + + public Builder setBeginString(final String beginString) { + this.beginString = beginString; + return this; + } + + public Builder setSenderCompID(final String senderCompID) { + this.senderCompID = senderCompID; + return this; + } + + public Builder setTargetCompID(final String targetCompID) { + this.targetCompID = targetCompID; + return this; + } + + public Builder setSessionId(final SessionID sessionId) { + if (sessionId != null) { + this.sessionIDSupplier = () -> sessionId; + } + return this; + } + + public Builder setApplication(final Application application) { + this.applicationSupplier = () -> application; + return this; + } + + public Builder setMessageStoreFactory(final MessageStoreFactory messageStoreFactory) { + this.messageStoreFactorySupplier = () -> messageStoreFactory; + return this; + } + + public Builder setDataDictionaryProvider(final DataDictionaryProvider dataDictionaryProvider) { + this.dataDictionaryProviderSupplier = () -> dataDictionaryProvider; + return this; + } + + public Builder setSessionSchedule(final SessionSchedule sessionSchedule) { + this.sessionScheduleSupplier = () -> sessionSchedule; + return this; + } + + public Builder setLogFactory(final LogFactory logFactory) { + this.logFactorySupplier = () -> logFactory; + return this; + } + + public Builder setMessageFactory(final MessageFactory messageFactory) { + this.messageFactorySupplier = () -> messageFactory; + return this; + } + + public Builder setIsInitiator(final boolean isInitiator) { + this.isInitiator = isInitiator; + return this; + } + + public Builder setSessionHeartbeatInterval(final int sessionHeartbeatInterval) { + this.sessionHeartbeatIntervalSupplier = () -> sessionHeartbeatInterval; + return this; + } + + public Builder setResetOnLogon(final boolean resetOnLogon) { + this.resetOnLogon = resetOnLogon; + return this; + } + + public Builder setValidateSequenceNumbers(final boolean validateSequenceNumbers) { + this.validateSequenceNumbers = validateSequenceNumbers; + return this; + } + + public Builder setPersistMessages(final boolean persistMessages) { + this.persistMessages = persistMessages; + return this; + } + + public Builder setSenderDefaultApplVerID(final DefaultApplVerID senderDefaultApplVerID) { + this.senderDefaultApplVerID = senderDefaultApplVerID; + return this; + } + + public Builder setEnableNextExpectedMsgSeqNum(final boolean enableNextExpectedMsgSeqNum) { + this.enableNextExpectedMsgSeqNum = enableNextExpectedMsgSeqNum; + return this; + } + } } From 66e9661b9c32c4d5a966e79c38ed492912203cff Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Tue, 4 Jul 2017 16:26:46 +0100 Subject: [PATCH 064/165] tweak builder settings --- .../quickfix/SessionFactoryTestSupport.java | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/quickfixj-core/src/test/java/quickfix/SessionFactoryTestSupport.java b/quickfixj-core/src/test/java/quickfix/SessionFactoryTestSupport.java index 8f98a8039..8d9ccd744 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionFactoryTestSupport.java +++ b/quickfixj-core/src/test/java/quickfix/SessionFactoryTestSupport.java @@ -11,18 +11,26 @@ public class SessionFactoryTestSupport implements SessionFactory { @Override public Session create(SessionID sessionID, SessionSettings settings) throws ConfigError { - return new Builder().setSessionId(sessionID).build(); + return new Builder().setSessionId(sessionID) + .setCheckLatency(true).setMaxLatency(Session.DEFAULT_MAX_LATENCY) + .setCheckCompID(true) + .build(); } public static Session createSession(SessionID sessionID, Application application, boolean isInitiator) { - return new Builder().setSessionId(sessionID).setApplication(application).setIsInitiator(isInitiator).build(); + return new Builder().setSessionId(sessionID).setApplication(application).setIsInitiator(isInitiator) + .setCheckLatency(true).setMaxLatency(Session.DEFAULT_MAX_LATENCY) + .setCheckCompID(true) + .build(); } public static Session createFileStoreSession(SessionID sessionID, Application application, boolean isInitiator, SessionSettings settings, SessionSchedule sessionSchedule) { return new Builder().setSessionId(sessionID).setApplication(application).setIsInitiator(isInitiator) .setMessageStoreFactory(new FileStoreFactory(settings)).setSessionSchedule(sessionSchedule) + .setCheckLatency(true).setMaxLatency(Session.DEFAULT_MAX_LATENCY) + .setCheckCompID(true) .build(); } @@ -175,11 +183,26 @@ public Builder setSessionHeartbeatInterval(final int sessionHeartbeatInterval) { return this; } + public Builder setCheckLatency(final boolean checkLatency) { + this.checkLatency = checkLatency; + return this; + } + + public Builder setMaxLatency(final int maxLatency) { + this.maxLatency = maxLatency; + return this; + } + public Builder setResetOnLogon(final boolean resetOnLogon) { this.resetOnLogon = resetOnLogon; return this; } + public Builder setCheckCompID(final boolean checkCompID) { + this.checkCompID = checkCompID; + return this; + } + public Builder setValidateSequenceNumbers(final boolean validateSequenceNumbers) { this.validateSequenceNumbers = validateSequenceNumbers; return this; From d9596b2968051546cc4f0cb80f4ddcd88f47c364 Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Wed, 5 Jul 2017 07:44:18 +0100 Subject: [PATCH 065/165] release lock in try/finally --- quickfixj-core/src/main/java/quickfix/Session.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index a715a1ddf..c5de20799 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -2058,8 +2058,12 @@ private void nextLogon(Message logon) throws FieldNotFound, RejectLogon, Incorre final int targetWantsNextSeqNumToBe = logon.getInt(NextExpectedMsgSeqNum.FIELD); state.lockSenderMsgSeqNum(); - final int actualNextNum = state.getNextSenderMsgSeqNum(); - state.unlockSenderMsgSeqNum(); + final int actualNextNum; + try { + actualNextNum = state.getNextSenderMsgSeqNum(); + } finally { + state.unlockSenderMsgSeqNum(); + } // Is the 789 we received too high ?? if (targetWantsNextSeqNumToBe > actualNextNum) { // barf! we can't resend what we never sent! something unrecoverable has happened. From 2cf399f6dba427b00c4750de6cc1d1f916bd2fb3 Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Thu, 6 Jul 2017 15:06:45 +0100 Subject: [PATCH 066/165] use Saxon instead of Xalan for XSLT update all .xsl files to XSLT 2.0 implement a sanitise description function which allows use of code generation with verbose data dictionaries --- quickfixj-codegenerator/pom.xml | 5 +++ .../codegenerator/MessageCodeGenerator.java | 2 +- .../org/quickfixj/codegenerator/Fields.xsl | 33 +++++++++++++------ .../org/quickfixj/codegenerator/Message.xsl | 2 +- .../codegenerator/MessageFactory.xsl | 2 +- .../codegenerator/MessageSubclass.xsl | 2 +- 6 files changed, 32 insertions(+), 14 deletions(-) diff --git a/quickfixj-codegenerator/pom.xml b/quickfixj-codegenerator/pom.xml index 558b28eee..eca44bf2f 100644 --- a/quickfixj-codegenerator/pom.xml +++ b/quickfixj-codegenerator/pom.xml @@ -32,6 +32,11 @@ maven-project 2.2.1 + + net.sf.saxon + Saxon-HE + 9.8.0-2 + diff --git a/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/MessageCodeGenerator.java b/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/MessageCodeGenerator.java index c75f93ad4..44d0b00cd 100644 --- a/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/MessageCodeGenerator.java +++ b/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/MessageCodeGenerator.java @@ -207,7 +207,7 @@ private Transformer createTransformer(Task task, String xsltFile) logInfo("Loading predefined xslt file:" + xsltFile); styleSource = new StreamSource(this.getClass().getResourceAsStream(xsltFile)); } - TransformerFactory transformerFactory = TransformerFactory.newInstance(); + TransformerFactory transformerFactory = new net.sf.saxon.TransformerFactoryImpl(); return transformerFactory.newTransformer(styleSource); } diff --git a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Fields.xsl b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Fields.xsl index 0826f023e..1f2228fb5 100644 --- a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Fields.xsl +++ b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Fields.xsl @@ -18,7 +18,7 @@ ***************************************************************************** --> - + @@ -151,26 +151,39 @@ public class extends + + + N_ + + .,+-=:()/&"'<> + + + + + + + - public static final String = ""; + public static final String = ""; - public static final String = ""; + public static final String = ""; - public static final String = ""; + public static final String = ""; - public static final boolean = ; + public static final boolean = ; - public static final int = ; + public static final int = ; - public static final int = ; + public static final int = ; - public static final String = ""; + public static final String = ""; - public static final String = ""; + public static final String = ""; - public static final char = ''; + public static final char = ''; diff --git a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Message.xsl b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Message.xsl index bd605b2fd..defc0a521 100644 --- a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Message.xsl +++ b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Message.xsl @@ -18,7 +18,7 @@ ***************************************************************************** --> - + diff --git a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl index ad15616e9..50a541e2d 100644 --- a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl +++ b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl @@ -18,7 +18,7 @@ ***************************************************************************** --> - + diff --git a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageSubclass.xsl b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageSubclass.xsl index 56087ba66..4333c3b62 100644 --- a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageSubclass.xsl +++ b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageSubclass.xsl @@ -18,7 +18,7 @@ ***************************************************************************** --> - + From ad0e1bc900e92ed5494a1911dfb1e7b69cbdc508 Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Thu, 6 Jul 2017 15:08:59 +0100 Subject: [PATCH 067/165] Revert "use Saxon instead of Xalan for XSLT" This reverts commit 2cf399f6dba427b00c4750de6cc1d1f916bd2fb3. --- quickfixj-codegenerator/pom.xml | 5 --- .../codegenerator/MessageCodeGenerator.java | 2 +- .../org/quickfixj/codegenerator/Fields.xsl | 33 ++++++------------- .../org/quickfixj/codegenerator/Message.xsl | 2 +- .../codegenerator/MessageFactory.xsl | 2 +- .../codegenerator/MessageSubclass.xsl | 2 +- 6 files changed, 14 insertions(+), 32 deletions(-) diff --git a/quickfixj-codegenerator/pom.xml b/quickfixj-codegenerator/pom.xml index eca44bf2f..558b28eee 100644 --- a/quickfixj-codegenerator/pom.xml +++ b/quickfixj-codegenerator/pom.xml @@ -32,11 +32,6 @@ maven-project 2.2.1 - - net.sf.saxon - Saxon-HE - 9.8.0-2 - diff --git a/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/MessageCodeGenerator.java b/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/MessageCodeGenerator.java index 44d0b00cd..c75f93ad4 100644 --- a/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/MessageCodeGenerator.java +++ b/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/MessageCodeGenerator.java @@ -207,7 +207,7 @@ private Transformer createTransformer(Task task, String xsltFile) logInfo("Loading predefined xslt file:" + xsltFile); styleSource = new StreamSource(this.getClass().getResourceAsStream(xsltFile)); } - TransformerFactory transformerFactory = new net.sf.saxon.TransformerFactoryImpl(); + TransformerFactory transformerFactory = TransformerFactory.newInstance(); return transformerFactory.newTransformer(styleSource); } diff --git a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Fields.xsl b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Fields.xsl index 1f2228fb5..0826f023e 100644 --- a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Fields.xsl +++ b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Fields.xsl @@ -18,7 +18,7 @@ ***************************************************************************** --> - + @@ -151,39 +151,26 @@ public class extends - - - N_ - - .,+-=:()/&"'<> - - - - - - - - public static final String = ""; + public static final String = ""; - public static final String = ""; + public static final String = ""; - public static final String = ""; + public static final String = ""; - public static final boolean = ; + public static final boolean = ; - public static final int = ; + public static final int = ; - public static final int = ; + public static final int = ; - public static final String = ""; + public static final String = ""; - public static final String = ""; + public static final String = ""; - public static final char = ''; + public static final char = ''; diff --git a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Message.xsl b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Message.xsl index defc0a521..bd605b2fd 100644 --- a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Message.xsl +++ b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Message.xsl @@ -18,7 +18,7 @@ ***************************************************************************** --> - + diff --git a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl index 50a541e2d..ad15616e9 100644 --- a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl +++ b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl @@ -18,7 +18,7 @@ ***************************************************************************** --> - + diff --git a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageSubclass.xsl b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageSubclass.xsl index 4333c3b62..56087ba66 100644 --- a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageSubclass.xsl +++ b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageSubclass.xsl @@ -18,7 +18,7 @@ ***************************************************************************** --> - + From 90c09356e938e069682bc78876e7ab49151d3718 Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Thu, 6 Jul 2017 15:06:45 +0100 Subject: [PATCH 068/165] use Saxon instead of Xalan for XSLT update all .xsl files to XSLT 2.0 implement a sanitise description function which allows use of code generation with verbose data dictionaries --- quickfixj-codegenerator/pom.xml | 5 +++ .../codegenerator/MessageCodeGenerator.java | 2 +- .../org/quickfixj/codegenerator/Fields.xsl | 33 +++++++++++++------ .../org/quickfixj/codegenerator/Message.xsl | 2 +- .../codegenerator/MessageFactory.xsl | 2 +- .../codegenerator/MessageSubclass.xsl | 2 +- 6 files changed, 32 insertions(+), 14 deletions(-) diff --git a/quickfixj-codegenerator/pom.xml b/quickfixj-codegenerator/pom.xml index 558b28eee..eca44bf2f 100644 --- a/quickfixj-codegenerator/pom.xml +++ b/quickfixj-codegenerator/pom.xml @@ -32,6 +32,11 @@ maven-project 2.2.1 + + net.sf.saxon + Saxon-HE + 9.8.0-2 + diff --git a/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/MessageCodeGenerator.java b/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/MessageCodeGenerator.java index c75f93ad4..44d0b00cd 100644 --- a/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/MessageCodeGenerator.java +++ b/quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/MessageCodeGenerator.java @@ -207,7 +207,7 @@ private Transformer createTransformer(Task task, String xsltFile) logInfo("Loading predefined xslt file:" + xsltFile); styleSource = new StreamSource(this.getClass().getResourceAsStream(xsltFile)); } - TransformerFactory transformerFactory = TransformerFactory.newInstance(); + TransformerFactory transformerFactory = new net.sf.saxon.TransformerFactoryImpl(); return transformerFactory.newTransformer(styleSource); } diff --git a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Fields.xsl b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Fields.xsl index 0826f023e..1f2228fb5 100644 --- a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Fields.xsl +++ b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Fields.xsl @@ -18,7 +18,7 @@ ***************************************************************************** --> - + @@ -151,26 +151,39 @@ public class extends + + + N_ + + .,+-=:()/&"'<> + + + + + + + - public static final String = ""; + public static final String = ""; - public static final String = ""; + public static final String = ""; - public static final String = ""; + public static final String = ""; - public static final boolean = ; + public static final boolean = ; - public static final int = ; + public static final int = ; - public static final int = ; + public static final int = ; - public static final String = ""; + public static final String = ""; - public static final String = ""; + public static final String = ""; - public static final char = ''; + public static final char = ''; diff --git a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Message.xsl b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Message.xsl index bd605b2fd..defc0a521 100644 --- a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Message.xsl +++ b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/Message.xsl @@ -18,7 +18,7 @@ ***************************************************************************** --> - + diff --git a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl index ad15616e9..50a541e2d 100644 --- a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl +++ b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageFactory.xsl @@ -18,7 +18,7 @@ ***************************************************************************** --> - + diff --git a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageSubclass.xsl b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageSubclass.xsl index 56087ba66..4333c3b62 100644 --- a/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageSubclass.xsl +++ b/quickfixj-codegenerator/src/main/resources/org/quickfixj/codegenerator/MessageSubclass.xsl @@ -18,7 +18,7 @@ ***************************************************************************** --> - + From 155d21d19fd268fdaa5437e8a574cf846f07a474 Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Thu, 6 Jul 2017 16:13:34 +0100 Subject: [PATCH 069/165] build on travis-ci --- .travis.yml | 5 +++++ README.md | 3 +++ 2 files changed, 8 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..91df27163 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +language: java +jdk: + - oraclejdk8 +after_success: + - mvn clean test \ No newline at end of file diff --git a/README.md b/README.md index 637b8861d..a82213811 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ QuickFIX/J ========== +[![Build Status](https://travis-ci.org/quickfix-j/quickfixj.svg?branch=master)](https://travis-ci.org/quickfix-j/quickfixj) +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.quickfixj/quickfixj-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.quickfixj/quickfixj-core) + This is the official QuickFIX/J project repository. The Financial Information eXchange (FIX) protocol is a messaging standard developed From 04fb3a85f445758ae1440334563736a5b026f9cc Mon Sep 17 00:00:00 2001 From: Jon Freedman Date: Thu, 6 Jul 2017 16:17:47 +0100 Subject: [PATCH 070/165] Update .travis.yml trigger build --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 91df27163..971324850 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,4 +2,4 @@ language: java jdk: - oraclejdk8 after_success: - - mvn clean test \ No newline at end of file + - mvn test From 5fdca013ad3a714ed0d7ddec16a3fb515b11f4a6 Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Thu, 6 Jul 2017 16:25:28 +0100 Subject: [PATCH 071/165] travis actually calls mvn test for us --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 91df27163..c4f11b7cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,3 @@ language: java jdk: - - oraclejdk8 -after_success: - - mvn clean test \ No newline at end of file + - oraclejdk8 \ No newline at end of file From bad17d08a2c112e4bd0a7418b2a2b2516268c80d Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Thu, 6 Jul 2017 16:30:49 +0100 Subject: [PATCH 072/165] give maven 2gb of heap --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c4f11b7cf..3bb545fb1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ language: java jdk: - - oraclejdk8 \ No newline at end of file + - oraclejdk8 +env: + - MAVEN_OPTS=-Xmx2048m \ No newline at end of file From ee652fca20aa50173f5b66a059fb3e39092ed13f Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Thu, 6 Jul 2017 16:44:11 +0100 Subject: [PATCH 073/165] set max heap in maven-compiler-plugin --- .travis.yml | 4 +--- pom.xml | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3bb545fb1..c4f11b7cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,3 @@ language: java jdk: - - oraclejdk8 -env: - - MAVEN_OPTS=-Xmx2048m \ No newline at end of file + - oraclejdk8 \ No newline at end of file diff --git a/pom.xml b/pom.xml index c11614d03..ff4bbfeaf 100644 --- a/pom.xml +++ b/pom.xml @@ -109,6 +109,7 @@ ${jdkLevel} ${jdkLevel} + 2g From 25221f4caecd15a0fc8b4d15352f752ad1d9e31d Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Thu, 6 Jul 2017 16:56:54 +0100 Subject: [PATCH 074/165] tweak compiler heap --- pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ff4bbfeaf..5aa413869 100644 --- a/pom.xml +++ b/pom.xml @@ -109,7 +109,8 @@ ${jdkLevel} ${jdkLevel} - 2g + 2g + 4g From 9878ab91009832d002b4fc4ec2952c2644bfa50c Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Thu, 6 Jul 2017 17:04:56 +0100 Subject: [PATCH 075/165] set MAVEN_OPTS --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c4f11b7cf..2438a481f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,3 @@ language: java -jdk: - - oraclejdk8 \ No newline at end of file +env: + - MAVEN_OPTS=-Xms2g -Xmx4g \ No newline at end of file From d1a50398b7c8547483299bf81b6da386285cbde4 Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Thu, 6 Jul 2017 17:08:29 +0100 Subject: [PATCH 076/165] set MAVEN_OPTS --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2438a481f..f4c35c714 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ language: java +jdk: + - oraclejdk8 env: - - MAVEN_OPTS=-Xms2g -Xmx4g \ No newline at end of file + - MAVEN_OPTS="-Xms2g -Xmx4g" \ No newline at end of file From c18792488f519c1ba2fa6f51781dc29c464344b7 Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Thu, 6 Jul 2017 17:20:44 +0100 Subject: [PATCH 077/165] tweak maven --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f4c35c714..36d720eb0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,4 +2,6 @@ language: java jdk: - oraclejdk8 env: - - MAVEN_OPTS="-Xms2g -Xmx4g" \ No newline at end of file + - MAVEN_OPTS="-Xms2g -Xmx4g" +script: + - mvn test -B -V -Xms2g -Xmx4g \ No newline at end of file From 8a51136f8fcc92a0f765944a02ad34bd940a3726 Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Thu, 6 Jul 2017 17:26:38 +0100 Subject: [PATCH 078/165] customise install step --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 36d720eb0..3fe19392e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,5 +3,7 @@ jdk: - oraclejdk8 env: - MAVEN_OPTS="-Xms2g -Xmx4g" +install: + - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V -Xms2g -Xmx4g script: - mvn test -B -V -Xms2g -Xmx4g \ No newline at end of file From 73f8eff3cf8474993ad8070856bab78f3d809fd2 Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Thu, 6 Jul 2017 17:31:40 +0100 Subject: [PATCH 079/165] make MAVEN_OPTS a global --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3fe19392e..d6896acde 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,9 @@ language: java jdk: - oraclejdk8 env: - - MAVEN_OPTS="-Xms2g -Xmx4g" + global: + - MAVEN_OPTS="-Xms2g -Xmx4g" install: - - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V -Xms2g -Xmx4g + - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V script: - - mvn test -B -V -Xms2g -Xmx4g \ No newline at end of file + - mvn test -B -V \ No newline at end of file From 798ec18f30ebd07c2279ab1b6dfc3ae5ae8e45fb Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Thu, 6 Jul 2017 17:40:45 +0100 Subject: [PATCH 080/165] set maven-compiler-plugin to inherited --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 5aa413869..32e925e90 100644 --- a/pom.xml +++ b/pom.xml @@ -106,6 +106,7 @@ org.apache.maven.plugins maven-compiler-plugin ${maven-compiler-plugin-version} + true ${jdkLevel} ${jdkLevel} From 6f23e7cacaa68c47c1d99b05bc5a45780c6789de Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Fri, 7 Jul 2017 08:02:23 +0100 Subject: [PATCH 081/165] put MAVEN_OPTS in ~/.mavenrc --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index d6896acde..378e8210a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,8 @@ language: java jdk: - oraclejdk8 -env: - global: - - MAVEN_OPTS="-Xms2g -Xmx4g" +before_install: + - echo "MAVEN_OPTS='-Xms2g -Xmx4g'" > ~/.mavenrc install: - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V script: From 552754ed3a953c75356a2b93f91ea510c6860cac Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Fri, 7 Jul 2017 08:11:31 +0100 Subject: [PATCH 082/165] remove build step customisation --- .travis.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 378e8210a..f86c1c5c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,4 @@ language: java jdk: - oraclejdk8 before_install: - - echo "MAVEN_OPTS='-Xms2g -Xmx4g'" > ~/.mavenrc -install: - - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V -script: - - mvn test -B -V \ No newline at end of file + - echo "MAVEN_OPTS='-Xms2g -Xmx3g'" > ~/.mavenrc \ No newline at end of file From 071e9ddbc381bddcbddf3a926465c38897ec918d Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Fri, 7 Jul 2017 09:43:35 +0100 Subject: [PATCH 083/165] make logging less verbose --- .travis.yml | 4 +- quickfixj-core/pom.xml | 823 +++++++++--------- .../quickfix/DefaultSessionFactoryTest.java | 11 +- .../test/java/quickfix/MultiAcceptorTest.java | 4 +- .../SessionDisconnectConcurrentlyTest.java | 4 +- .../quickfix/SessionFactoryTestSupport.java | 14 +- .../src/test/java/quickfix/SessionTest.java | 23 +- .../java/quickfix/SocketAcceptorTest.java | 14 +- .../java/quickfix/UnitTestApplication.java | 15 +- .../quickfix/mina/SessionConnectorTest.java | 8 +- ...ngleThreadedEventHandlingStrategyTest.java | 6 +- ...adPerSessionEventHandlingStrategyTest.java | 31 +- .../quickfix/mina/ssl/SSLAndNonSSLTest.java | 4 +- .../quickfix/test/acceptance/ATServer.java | 4 +- .../src/test/resources/logging.properties | 5 + 15 files changed, 481 insertions(+), 489 deletions(-) create mode 100644 quickfixj-core/src/test/resources/logging.properties diff --git a/.travis.yml b/.travis.yml index f86c1c5c5..8056778ab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,4 +2,6 @@ language: java jdk: - oraclejdk8 before_install: - - echo "MAVEN_OPTS='-Xms2g -Xmx3g'" > ~/.mavenrc \ No newline at end of file + - echo "MAVEN_OPTS='-Xms2g -Xmx3g'" > ~/.mavenrc +script: + - mvn test -B -V -Djava.util.logging.config.file=logging.properties \ No newline at end of file diff --git a/quickfixj-core/pom.xml b/quickfixj-core/pom.xml index 92c676d5b..49ce8b289 100644 --- a/quickfixj-core/pom.xml +++ b/quickfixj-core/pom.xml @@ -1,423 +1,424 @@ - - 4.0.0 - - org.quickfixj - quickfixj-parent - 1.7.0-SNAPSHOT - + + 4.0.0 + + org.quickfixj + quickfixj-parent + 1.7.0-SNAPSHOT + - quickfixj-core - bundle + quickfixj-core + bundle - QuickFIX/J Core engine - The core QuickFIX/J engine - http://www.quickfixj.org + QuickFIX/J Core engine + The core QuickFIX/J engine + http://www.quickfixj.org - - **/AcceptanceTestSuite.java - org.quickfixj.Version - + + **/AcceptanceTestSuite.java + org.quickfixj.Version + - - - junit - junit - ${junit.version} - test - - - org.mockito - mockito-all - 1.10.19 - test - - - org.hamcrest - hamcrest-all - 1.1 - test - - - hsqldb - hsqldb - 1.8.0.10 - test - - - tyrex - tyrex - 1.0.1 - test - - - org.slf4j - slf4j-jdk14 - ${slf4j.version} - test - + + + junit + junit + ${junit.version} + test + + + org.mockito + mockito-all + 1.10.19 + test + + + org.hamcrest + hamcrest-all + 1.1 + test + + + hsqldb + hsqldb + 1.8.0.10 + test + + + tyrex + tyrex + 1.0.1 + test + + + org.slf4j + slf4j-jdk14 + ${slf4j.version} + test + - - org.apache.mina - mina-core - 2.0.16 - - - org.slf4j - slf4j-api - ${slf4j.version} - + + org.apache.mina + mina-core + 2.0.16 + + + org.slf4j + slf4j-api + ${slf4j.version} + - - com.cloudhopper.proxool - proxool - 0.9.1 - true - - - - avalon-framework - avalon-framework-api - - - - commons-logging - commons-logging - - - - - com.cloudhopper.proxool - proxool-cglib - 0.9.1 - true - - - - avalon-framework - avalon-framework-api - - - - commons-logging - commons-logging - - - - - - org.slf4j - jcl-over-slf4j - ${slf4j.version} - runtime - true - - - berkeleydb - je - 2.1.30 - true - - + + com.cloudhopper.proxool + proxool + 0.9.1 + true + + + + avalon-framework + avalon-framework-api + + + + commons-logging + commons-logging + + + + + com.cloudhopper.proxool + proxool-cglib + 0.9.1 + true + + + + avalon-framework + avalon-framework-api + + + + commons-logging + commons-logging + + + + + + org.slf4j + jcl-over-slf4j + ${slf4j.version} + runtime + true + + + berkeleydb + je + 2.1.30 + true + + - - - - ../quickfixj-messages/quickfixj-messages-fixt11/src/main/resources - - - ../quickfixj-messages/quickfixj-messages-fix50/src/main/resources - - - ../quickfixj-messages/quickfixj-messages-fix44/src/main/resources - - - ../quickfixj-messages/quickfixj-messages-fix43/src/main/resources - - - ../quickfixj-messages/quickfixj-messages-fix42/src/main/resources - - - ../quickfixj-messages/quickfixj-messages-fix41/src/main/resources - - - ../quickfixj-messages/quickfixj-messages-fix40/src/main/resources - - - ../quickfixj-messages/quickfixj-messages-fix50sp1/src/main/resources - - - ../quickfixj-messages/quickfixj-messages-fix50sp2/src/main/resources - - + + + + ../quickfixj-messages/quickfixj-messages-fixt11/src/main/resources + + + ../quickfixj-messages/quickfixj-messages-fix50/src/main/resources + + + ../quickfixj-messages/quickfixj-messages-fix44/src/main/resources + + + ../quickfixj-messages/quickfixj-messages-fix43/src/main/resources + + + ../quickfixj-messages/quickfixj-messages-fix42/src/main/resources + + + ../quickfixj-messages/quickfixj-messages-fix41/src/main/resources + + + ../quickfixj-messages/quickfixj-messages-fix40/src/main/resources + + + ../quickfixj-messages/quickfixj-messages-fix50sp1/src/main/resources + + + ../quickfixj-messages/quickfixj-messages-fix50sp2/src/main/resources + + - - - src/test/resources - - - ../quickfixj-messages/quickfixj-messages-fixt11/src/main/resources - - - ../quickfixj-messages/quickfixj-messages-fix50sp2/src/main/resources - - - ../quickfixj-messages/quickfixj-messages-fix50sp1/src/main/resources - - - ../quickfixj-messages/quickfixj-messages-fix50/src/main/resources - - - ../quickfixj-messages/quickfixj-messages-fix44/src/main/resources - - - ../quickfixj-messages/quickfixj-messages-fix43/src/main/resources - - - ../quickfixj-messages/quickfixj-messages-fix42/src/main/resources - - - ../quickfixj-messages/quickfixj-messages-fix41/src/main/resources - - - ../quickfixj-messages/quickfixj-messages-fix40/src/main/resources - - - src/main/resources - - + + + src/test/resources + + + ../quickfixj-messages/quickfixj-messages-fixt11/src/main/resources + + + ../quickfixj-messages/quickfixj-messages-fix50sp2/src/main/resources + + + ../quickfixj-messages/quickfixj-messages-fix50sp1/src/main/resources + + + ../quickfixj-messages/quickfixj-messages-fix50/src/main/resources + + + ../quickfixj-messages/quickfixj-messages-fix44/src/main/resources + + + ../quickfixj-messages/quickfixj-messages-fix43/src/main/resources + + + ../quickfixj-messages/quickfixj-messages-fix42/src/main/resources + + + ../quickfixj-messages/quickfixj-messages-fix41/src/main/resources + + + ../quickfixj-messages/quickfixj-messages-fix40/src/main/resources + + + src/main/resources + + - - - org.quickfixj - quickfixj-codegenerator - ${project.version} - - - fixt11 - - generate - - - ../quickfixj-messages/quickfixj-messages-fixt11/src/main/resources/FIXT11.xml - quickfix.fixt11 - quickfix.field - ${generator.decimal} - - - - fix50 - - generate - - - ../quickfixj-messages/quickfixj-messages-fix50/src/main/resources/FIX50.xml - quickfix.fix50 - quickfix.field - ${generator.decimal} - - - - fix44 - - generate - - - ../quickfixj-messages/quickfixj-messages-fix44/src/main/resources/FIX44.modified.xml - quickfix.fix44 - quickfix.field - ${generator.decimal} - - - - fix43 - - generate - - - ../quickfixj-messages/quickfixj-messages-fix43/src/main/resources/FIX43.xml - quickfix.fix43 - quickfix.field - ${generator.decimal} - - - - fix42 - - generate - - - ../quickfixj-messages/quickfixj-messages-fix42/src/main/resources/FIX42.xml - quickfix.fix42 - quickfix.field - ${generator.decimal} - - - - fix41 - - generate - - - ../quickfixj-messages/quickfixj-messages-fix41/src/main/resources/FIX41.xml - quickfix.fix41 - quickfix.field - ${generator.decimal} - - - - fix40 - - generate - - - ../quickfixj-messages/quickfixj-messages-fix40/src/main/resources/FIX40.xml - quickfix.fix40 - quickfix.field - ${generator.decimal} - - - - fix50sp2 - - generate - - - ../quickfixj-messages/quickfixj-messages-fix50sp2/src/main/resources/FIX50SP2.modified.xml - quickfix.fix50sp2 - quickfix.field - ${generator.decimal} - - - - fix50sp1 - - generate - - - ../quickfixj-messages/quickfixj-messages-fix50sp1/src/main/resources/FIX50SP1.modified.xml - quickfix.fix50sp1 - quickfix.field - ${generator.decimal} - - - - - - org.apache.maven.plugins - maven-jar-plugin - ${maven-jar-plugin-version} - - - quickfix/** - org/** - quickfix/field/converter/* - FIX*.xml - - - quickfix/field/* - quickfix/fix*/** - - - - - org.apache.maven.plugins - maven-source-plugin - - - quickfix/** - org/** - quickfix/field/converter/* - FIX*.xml - - - quickfix/field/* - quickfix/fix*/** - - - - - org.apache.felix - maven-bundle-plugin - - - quickfix,quickfix.field.*,quickfix.mina.*,org.quickfixj.* - - - quickfix.fix40;resolution:=optional, - quickfix.fix41;resolution:=optional, - quickfix.fix42;resolution:=optional, - quickfix.fix43;resolution:=optional, - quickfix.fix44;resolution:=optional, - quickfix.fix50;resolution:=optional, - quickfix.fix50sp1;resolution:=optional, - quickfix.fix50sp2;resolution:=optional, - quickfix.fixt11;resolution:=optional, - - quickfix,quickfix.field,* - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - -Xmx512m -XX:MaxPermSize=256m - - **/*Test.java - ${acceptance.tests} - - - **/*ForTest.java - **/Abstract*Test.java - **/AcceptanceTestSuite$* - - - 5 - 60000 - 5 - false - - - - - + + + org.quickfixj + quickfixj-codegenerator + ${project.version} + + + fixt11 + + generate + + + ../quickfixj-messages/quickfixj-messages-fixt11/src/main/resources/FIXT11.xml + quickfix.fixt11 + quickfix.field + ${generator.decimal} + + + + fix50 + + generate + + + ../quickfixj-messages/quickfixj-messages-fix50/src/main/resources/FIX50.xml + quickfix.fix50 + quickfix.field + ${generator.decimal} + + + + fix44 + + generate + + + ../quickfixj-messages/quickfixj-messages-fix44/src/main/resources/FIX44.modified.xml + quickfix.fix44 + quickfix.field + ${generator.decimal} + + + + fix43 + + generate + + + ../quickfixj-messages/quickfixj-messages-fix43/src/main/resources/FIX43.xml + quickfix.fix43 + quickfix.field + ${generator.decimal} + + + + fix42 + + generate + + + ../quickfixj-messages/quickfixj-messages-fix42/src/main/resources/FIX42.xml + quickfix.fix42 + quickfix.field + ${generator.decimal} + + + + fix41 + + generate + + + ../quickfixj-messages/quickfixj-messages-fix41/src/main/resources/FIX41.xml + quickfix.fix41 + quickfix.field + ${generator.decimal} + + + + fix40 + + generate + + + ../quickfixj-messages/quickfixj-messages-fix40/src/main/resources/FIX40.xml + quickfix.fix40 + quickfix.field + ${generator.decimal} + + + + fix50sp2 + + generate + + + ../quickfixj-messages/quickfixj-messages-fix50sp2/src/main/resources/FIX50SP2.modified.xml + quickfix.fix50sp2 + quickfix.field + ${generator.decimal} + + + + fix50sp1 + + generate + + + ../quickfixj-messages/quickfixj-messages-fix50sp1/src/main/resources/FIX50SP1.modified.xml + quickfix.fix50sp1 + quickfix.field + ${generator.decimal} + + + + + + org.apache.maven.plugins + maven-jar-plugin + ${maven-jar-plugin-version} + + + quickfix/** + org/** + quickfix/field/converter/* + FIX*.xml + + + quickfix/field/* + quickfix/fix*/** + + + + + org.apache.maven.plugins + maven-source-plugin + + + quickfix/** + org/** + quickfix/field/converter/* + FIX*.xml + + + quickfix/field/* + quickfix/fix*/** + + + + + org.apache.felix + maven-bundle-plugin + + + quickfix,quickfix.field.*,quickfix.mina.*,org.quickfixj.* + + + quickfix.fix40;resolution:=optional, + quickfix.fix41;resolution:=optional, + quickfix.fix42;resolution:=optional, + quickfix.fix43;resolution:=optional, + quickfix.fix44;resolution:=optional, + quickfix.fix50;resolution:=optional, + quickfix.fix50sp1;resolution:=optional, + quickfix.fix50sp2;resolution:=optional, + quickfix.fixt11;resolution:=optional, + + quickfix,quickfix.field,* + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + -Xmx512m -XX:MaxPermSize=256m + + **/*Test.java + ${acceptance.tests} + + + **/*ForTest.java + **/Abstract*Test.java + **/AcceptanceTestSuite$* + + + 5 + 60000 + 5 + false + + + + + - - - - maven-surefire-report-plugin - ${maven-surefire-plugin-version} - - - true - - - - maven-javadoc-plugin - ${maven-javadoc-plugin-version} - - - maven-jxr-plugin - 2.5 - - - + + + + maven-surefire-report-plugin + ${maven-surefire-plugin-version} + + + true + + + + maven-javadoc-plugin + ${maven-javadoc-plugin-version} + + + maven-jxr-plugin + 2.5 + + + - - - - skipAT - - - skipAT - true - - - - - - - + + + + skipAT + + + skipAT + true + + + + + + + diff --git a/quickfixj-core/src/test/java/quickfix/DefaultSessionFactoryTest.java b/quickfixj-core/src/test/java/quickfix/DefaultSessionFactoryTest.java index 8ea871af9..0c305f303 100644 --- a/quickfixj-core/src/test/java/quickfix/DefaultSessionFactoryTest.java +++ b/quickfixj-core/src/test/java/quickfix/DefaultSessionFactoryTest.java @@ -29,12 +29,7 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; public class DefaultSessionFactoryTest { @@ -47,7 +42,7 @@ public void setUp() throws Exception { sessionID = new SessionID(FixVersions.BEGINSTRING_FIX42, "SENDER", "TARGET"); setUpDefaultSettings(sessionID); factory = new DefaultSessionFactory(new ATApplication(), new MemoryStoreFactory(), - new ScreenLogFactory(true, true, true)); + new SLF4JLogFactory(new SessionSettings())); } @Test @@ -60,7 +55,7 @@ public void testFixTMinimalSettings() throws Exception { sessionID = new SessionID(FixVersions.BEGINSTRING_FIXT11, "SENDER", "TARGET"); setUpDefaultSettings(sessionID); factory = new DefaultSessionFactory(new ATApplication(), new MemoryStoreFactory(), - new ScreenLogFactory(true, true, true)); + new SLF4JLogFactory(new SessionSettings())); Exception e = null; try { factory.create(sessionID, settings); diff --git a/quickfixj-core/src/test/java/quickfix/MultiAcceptorTest.java b/quickfixj-core/src/test/java/quickfix/MultiAcceptorTest.java index 0a9eef396..8b7edfd41 100644 --- a/quickfixj-core/src/test/java/quickfix/MultiAcceptorTest.java +++ b/quickfixj-core/src/test/java/quickfix/MultiAcceptorTest.java @@ -206,7 +206,7 @@ private Initiator createInitiator(boolean wrongPort) throws ConfigError { configureInitiatorForSession(settings, 3, wrongPort ? 1000 : 10003); MessageStoreFactory factory = new MemoryStoreFactory(); - quickfix.LogFactory logFactory = new ScreenLogFactory(true, true, true); + quickfix.LogFactory logFactory = new SLF4JLogFactory(new SessionSettings()); return new SocketInitiator(new ApplicationAdapter() { }, factory, settings, logFactory, new DefaultMessageFactory()); } @@ -235,7 +235,7 @@ private Acceptor createAcceptor() throws ConfigError { configureAcceptorForSession(settings, 3, 10003); MessageStoreFactory factory = new MemoryStoreFactory(); - quickfix.LogFactory logFactory = new ScreenLogFactory(true, true, true); + quickfix.LogFactory logFactory = new SLF4JLogFactory(new SessionSettings()); return new SocketAcceptor(testAcceptorApplication, factory, settings, logFactory, new DefaultMessageFactory()); } diff --git a/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java b/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java index f43f15c24..8f579c61f 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java @@ -168,7 +168,7 @@ private Initiator createInitiator() throws ConfigError { configureInitiatorForSession(settings, 1, 10001); MessageStoreFactory factory = new MemoryStoreFactory(); - quickfix.LogFactory logFactory = new ScreenLogFactory(true, true, true); + quickfix.LogFactory logFactory = new SLF4JLogFactory(new SessionSettings()); return new SocketInitiator(new ApplicationAdapter() { }, factory, settings, logFactory, new DefaultMessageFactory()); } @@ -197,7 +197,7 @@ private Acceptor createAcceptor() throws ConfigError { configureAcceptorForSession(settings, 1, 10001); MessageStoreFactory factory = new MemoryStoreFactory(); - quickfix.LogFactory logFactory = new ScreenLogFactory(true, true, true); + quickfix.LogFactory logFactory = new SLF4JLogFactory(new SessionSettings()); return new SocketAcceptor(testAcceptorApplication, factory, settings, logFactory, new DefaultMessageFactory()); } diff --git a/quickfixj-core/src/test/java/quickfix/SessionFactoryTestSupport.java b/quickfixj-core/src/test/java/quickfix/SessionFactoryTestSupport.java index 0dc66753d..c5c6d82a9 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionFactoryTestSupport.java +++ b/quickfixj-core/src/test/java/quickfix/SessionFactoryTestSupport.java @@ -15,7 +15,7 @@ public Session create(SessionID sessionID, SessionSettings settings) throws Conf public static Session createSession(SessionID sessionID, Application application, boolean isInitiator) { return new Session(application, new MemoryStoreFactory(), sessionID, null, null, - new ScreenLogFactory(true, true, true), new DefaultMessageFactory(), isInitiator + getLogFactory(), new DefaultMessageFactory(), isInitiator ? 30 : 0); } @@ -24,7 +24,7 @@ public static Session createFileStoreSession(SessionID sessionID, Application ap boolean isInitiator, SessionSettings settings, SessionSchedule sessionSchedule) { return new Session(application, new FileStoreFactory(settings), sessionID, null, sessionSchedule, - new ScreenLogFactory(true, true, true), new DefaultMessageFactory(), isInitiator + getLogFactory(), new DefaultMessageFactory(), isInitiator ? 30 : 0); } @@ -32,7 +32,7 @@ public static Session createFileStoreSession(SessionID sessionID, Application ap public static Session createSession(SessionID sessionID, Application application, boolean isInitiator, boolean resetOnLogon, boolean validateSequenceNumbers) { return new Session(application, new MemoryStoreFactory(), sessionID, null, null, - new ScreenLogFactory(true, true, true), new DefaultMessageFactory(), isInitiator + getLogFactory(), new DefaultMessageFactory(), isInitiator ? 30 : 0, false, 30, UtcTimestampPrecision.MILLIS, resetOnLogon, false, false, false, false, false, true, false, 1.5, null, validateSequenceNumbers, new int[] { 5 }, false, false, false, true, @@ -43,7 +43,7 @@ public static Session createSession(SessionID sessionID, Application application boolean isInitiator, boolean resetOnLogon, boolean validateSequenceNumbers, boolean useDataDictionary, DefaultApplVerID senderDefaultApplVerID) { return new Session(application, new MemoryStoreFactory(), sessionID, - new DefaultDataDictionaryProvider(), null, new ScreenLogFactory(true, true, true), + new DefaultDataDictionaryProvider(), null, getLogFactory(), new DefaultMessageFactory(), isInitiator ? 30 : 0, false, 30, UtcTimestampPrecision.MILLIS, resetOnLogon, false, false, false, false, false, true, false, 1.5, senderDefaultApplVerID, validateSequenceNumbers, new int[] { 5 }, false, false, false, true, false, true, @@ -58,7 +58,7 @@ public static Session createSession(SessionID sessionID, Application application public static Session createNonpersistedSession(SessionID sessionID, Application application, boolean isInitiator) { return new Session(application, new MemoryStoreFactory(), sessionID, null, null, - new ScreenLogFactory(true, true, true), new DefaultMessageFactory(), isInitiator + getLogFactory(), new DefaultMessageFactory(), isInitiator ? 30 : 0, false, 30, UtcTimestampPrecision.MILLIS, true, false, false, false, false, false, false/*persistMessages*/, false, 1.5, null, true, new int[] { 5 }, false, false, @@ -68,4 +68,8 @@ public static Session createNonpersistedSession(SessionID sessionID, Application public static Session createSession() throws ConfigError { return instance.create(null, null); } + + private static LogFactory getLogFactory() { + return new SLF4JLogFactory(new SessionSettings()); + } } diff --git a/quickfixj-core/src/test/java/quickfix/SessionTest.java b/quickfixj-core/src/test/java/quickfix/SessionTest.java index 1f5b252e5..5434a7c76 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionTest.java @@ -24,6 +24,7 @@ import quickfix.field.TargetCompID; import quickfix.field.TestReqID; import quickfix.field.Text; +import quickfix.field.converter.UtcTimeOnlyConverter; import quickfix.field.converter.UtcTimestampConverter; import quickfix.fix44.Heartbeat; import quickfix.fix44.Logon; @@ -49,22 +50,10 @@ import java.util.Date; import java.util.TimeZone; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.stub; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; import static quickfix.SessionFactoryTestSupport.createSession; -import quickfix.field.converter.UtcTimeOnlyConverter; /** * Note: most session tests are in the form of acceptance tests. @@ -1795,7 +1784,7 @@ private void testSequenceResetGapFillWithChunkSize(int chunkSize) Session session = new Session(new UnitTestApplication(), new MemoryStoreFactory(), sessionID, null, null, - new ScreenLogFactory(true, true, true), + new SLF4JLogFactory(new SessionSettings()), new DefaultMessageFactory(), isInitiator ? 30 : 0, false, 30, UtcTimestampPrecision.MILLIS, resetOnLogon, false, false, false, false, false, true, false, 1.5, null, validateSequenceNumbers, new int[] { 5 }, @@ -1955,7 +1944,7 @@ public void testMsgSeqNumTooHighWithDisconnectOnError() throws Exception { Session session = new Session(new UnitTestApplication(), new MemoryStoreFactory(), sessionID, null, null, - new ScreenLogFactory(true, true, true), + new SLF4JLogFactory(new SessionSettings()), new DefaultMessageFactory(), isInitiator ? 30 : 0, false, 30, UtcTimestampPrecision.MILLIS, resetOnLogon, false, false, false, false, false, true, false, 1.5, null, validateSequenceNumbers, new int[] { 5 }, @@ -1992,7 +1981,7 @@ public void testTimestampPrecision() throws Exception { Session session = new Session(unitTestApplication, new MemoryStoreFactory(), sessionID, null, null, - new ScreenLogFactory(true, true, true), + new SLF4JLogFactory(new SessionSettings()), new DefaultMessageFactory(), isInitiator ? 30 : 0, false, 30, UtcTimestampPrecision.NANOS, resetOnLogon, false, false, false, false, false, true, false, 1.5, null, validateSequenceNumbers, new int[] { 5 }, diff --git a/quickfixj-core/src/test/java/quickfix/SocketAcceptorTest.java b/quickfixj-core/src/test/java/quickfix/SocketAcceptorTest.java index 271423f81..6593d606a 100644 --- a/quickfixj-core/src/test/java/quickfix/SocketAcceptorTest.java +++ b/quickfixj-core/src/test/java/quickfix/SocketAcceptorTest.java @@ -19,9 +19,11 @@ package quickfix; +import org.junit.After; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import quickfix.field.MsgType; import quickfix.mina.ProtocolFactory; import quickfix.mina.SingleThreadedEventHandlingStrategy; @@ -32,14 +34,8 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.logging.Level; -import org.junit.After; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import quickfix.field.MsgType; +import static org.junit.Assert.*; /** * QFJ-643: Unable to restart a stopped acceptor (SocketAcceptor) @@ -214,7 +210,7 @@ private Acceptor createAcceptor(TestAcceptorApplication testAcceptorApplication) settings.set(defaults); MessageStoreFactory factory = new MemoryStoreFactory(); - quickfix.LogFactory logFactory = new ScreenLogFactory(true, true, true); + quickfix.LogFactory logFactory = new SLF4JLogFactory(new SessionSettings()); return new SocketAcceptor(testAcceptorApplication, factory, settings, logFactory, new DefaultMessageFactory()); } @@ -236,7 +232,7 @@ private Initiator createInitiator() throws ConfigError { settings.set(defaults); MessageStoreFactory factory = new MemoryStoreFactory(); - quickfix.LogFactory logFactory = new ScreenLogFactory(true, true, true); + quickfix.LogFactory logFactory = new SLF4JLogFactory(new SessionSettings()); return new SocketInitiator(new ApplicationAdapter() { }, factory, settings, logFactory, new DefaultMessageFactory()); } diff --git a/quickfixj-core/src/test/java/quickfix/UnitTestApplication.java b/quickfixj-core/src/test/java/quickfix/UnitTestApplication.java index 034aa9689..597d8ded6 100644 --- a/quickfixj-core/src/test/java/quickfix/UnitTestApplication.java +++ b/quickfixj-core/src/test/java/quickfix/UnitTestApplication.java @@ -19,10 +19,15 @@ package quickfix; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.ArrayList; import java.util.List; public class UnitTestApplication implements ApplicationExtended, SessionStateListener { + private final Logger log = LoggerFactory.getLogger(UnitTestApplication.class); + public final List fromAppMessages = new ArrayList<>(); public final List toAppMessages = new ArrayList<>(); public final List fromAdminMessages = new ArrayList<>(); @@ -38,28 +43,28 @@ public boolean canLogon(SessionID sessionID) { public void fromApp(Message message, SessionID sessionId) throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType { - System.out.println("from app [" + sessionId + "] " + message); + log.info("from app [" + sessionId + "] " + message); fromAppMessages.add(message); } public void toApp(Message message, SessionID sessionId) throws DoNotSend { - System.out.println("to app [" + sessionId + "] " + message); + log.info("to app [" + sessionId + "] " + message); toAppMessages.add(message); } public void fromAdmin(Message message, SessionID sessionId) throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, RejectLogon { - System.out.println("from admin [" + sessionId + "] "+message); + log.info("from admin [" + sessionId + "] "+message); fromAdminMessages.add(message); } public void toAdmin(Message message, SessionID sessionId) { - System.out.println("to admin [" + sessionId + "] " + message); + log.info("to admin [" + sessionId + "] " + message); toAdminMessages.add(message); } public void onBeforeSessionReset(SessionID sessionId) { - System.out.println("onBeforeSessionReset [" + sessionId + "]"); + log.info("onBeforeSessionReset [" + sessionId + "]"); } public void onLogout(SessionID sessionId) { diff --git a/quickfixj-core/src/test/java/quickfix/mina/SessionConnectorTest.java b/quickfixj-core/src/test/java/quickfix/mina/SessionConnectorTest.java index 97a9cfe11..1d86e6360 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/SessionConnectorTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/SessionConnectorTest.java @@ -26,7 +26,7 @@ import quickfix.FixVersions; import quickfix.MemoryStoreFactory; import quickfix.RuntimeError; -import quickfix.ScreenLogFactory; +import quickfix.SLF4JLogFactory; import quickfix.Session; import quickfix.SessionFactory; import quickfix.SessionID; @@ -50,7 +50,7 @@ public void testConnector() throws Exception { SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX40, "TW", "ISLD"); SessionSettings settings = setUpSessionSettings(sessionID); DefaultSessionFactory sessionFactory = new DefaultSessionFactory(new UnitTestApplication(), - new MemoryStoreFactory(), new ScreenLogFactory(true, true, true)); + new MemoryStoreFactory(), new SLF4JLogFactory(new SessionSettings())); SessionConnector connector = new SessionConnectorUnderTest(settings, sessionFactory); @@ -91,7 +91,7 @@ public void testOneSessionLoggedOnOneSessionNotLoggedOne() throws Exception { SessionID sessionID1 = new SessionID(FixVersions.BEGINSTRING_FIX40, "TW", "ISLD"); SessionSettings settings = setUpSessionSettings(sessionID1); DefaultSessionFactory sessionFactory = new DefaultSessionFactory(new UnitTestApplication(), - new MemoryStoreFactory(), new ScreenLogFactory(true, true, true)); + new MemoryStoreFactory(), new SLF4JLogFactory(new SessionSettings())); SessionConnector connector = new SessionConnectorUnderTest(settings, sessionFactory); @@ -139,7 +139,7 @@ public void testAddingRemovingDymaicSessions() throws Exception { SessionID sessionID2 = new SessionID(FixVersions.BEGINSTRING_FIX40, "me", "you"); SessionSettings settings = setUpSessionSettings(sessionID); DefaultSessionFactory sessionFactory = new DefaultSessionFactory(new UnitTestApplication(), - new MemoryStoreFactory(), new ScreenLogFactory(true, true, true)); + new MemoryStoreFactory(), new SLF4JLogFactory(new SessionSettings())); SessionConnector connector = new SessionConnectorUnderTest(settings, sessionFactory); connector.setSessions(new HashMap<>()); diff --git a/quickfixj-core/src/test/java/quickfix/mina/SingleThreadedEventHandlingStrategyTest.java b/quickfixj-core/src/test/java/quickfix/mina/SingleThreadedEventHandlingStrategyTest.java index 254cc021b..63c5e74ff 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/SingleThreadedEventHandlingStrategyTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/SingleThreadedEventHandlingStrategyTest.java @@ -19,6 +19,7 @@ */ package quickfix.mina; +import org.junit.After; import org.junit.Assert; import org.junit.Test; import org.mockito.Mockito; @@ -29,7 +30,7 @@ import quickfix.FixVersions; import quickfix.MemoryStoreFactory; import quickfix.RuntimeError; -import quickfix.ScreenLogFactory; +import quickfix.SLF4JLogFactory; import quickfix.SessionFactory; import quickfix.SessionID; import quickfix.SessionSettings; @@ -45,7 +46,6 @@ import java.util.concurrent.CountDownLatch; import java.util.logging.Level; import java.util.logging.Logger; -import org.junit.After; /** * @@ -54,7 +54,7 @@ public class SingleThreadedEventHandlingStrategyTest { DefaultSessionFactory sessionFactory = new DefaultSessionFactory(new UnitTestApplication(), - new MemoryStoreFactory(), new ScreenLogFactory(true, true, true)); + new MemoryStoreFactory(), new SLF4JLogFactory(new SessionSettings())); SingleThreadedEventHandlingStrategy ehs = null; @After diff --git a/quickfixj-core/src/test/java/quickfix/mina/ThreadPerSessionEventHandlingStrategyTest.java b/quickfixj-core/src/test/java/quickfix/mina/ThreadPerSessionEventHandlingStrategyTest.java index 3152c1903..06d005f17 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/ThreadPerSessionEventHandlingStrategyTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/ThreadPerSessionEventHandlingStrategyTest.java @@ -19,25 +19,9 @@ package quickfix.mina; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; - -import java.util.Date; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import static junit.framework.Assert.assertTrue; import org.junit.After; import org.junit.Before; - import org.junit.Test; - import quickfix.ConfigError; import quickfix.DefaultSessionFactory; import quickfix.FieldNotFound; @@ -48,7 +32,7 @@ import quickfix.Message; import quickfix.RejectLogon; import quickfix.Responder; -import quickfix.ScreenLogFactory; +import quickfix.SLF4JLogFactory; import quickfix.Session; import quickfix.SessionFactory; import quickfix.SessionID; @@ -62,6 +46,17 @@ import quickfix.field.converter.UtcTimestampConverter; import quickfix.fix40.Logon; +import java.util.Date; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static junit.framework.Assert.assertTrue; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; + public class ThreadPerSessionEventHandlingStrategyTest { private final static class ThreadPerSessionEventHandlingStrategyUnderTest extends ThreadPerSessionEventHandlingStrategy { @@ -301,7 +296,7 @@ private Session setUpSession(SessionID sessionID) throws ConfigError { private Session setUpSession(SessionID sessionID, UnitTestApplication application) throws ConfigError { final DefaultSessionFactory sessionFactory = new DefaultSessionFactory(application, - new MemoryStoreFactory(), new ScreenLogFactory(true, true, true)); + new MemoryStoreFactory(), new SLF4JLogFactory(new SessionSettings())); final SessionSettings settings = new SessionSettings(); settings.setString(SessionFactory.SETTING_CONNECTION_TYPE, SessionFactory.ACCEPTOR_CONNECTION_TYPE); diff --git a/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLAndNonSSLTest.java b/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLAndNonSSLTest.java index fdb9624a6..d000fd656 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLAndNonSSLTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLAndNonSSLTest.java @@ -30,7 +30,7 @@ import quickfix.Initiator; import quickfix.MemoryStoreFactory; import quickfix.MessageStoreFactory; -import quickfix.ScreenLogFactory; +import quickfix.SLF4JLogFactory; import quickfix.Session; import quickfix.SessionID; import quickfix.SessionSettings; @@ -202,7 +202,7 @@ public void run() { ATApplication application = new ATApplication(); MessageStoreFactory factory = new MemoryStoreFactory(); - quickfix.LogFactory logFactory = new ScreenLogFactory(true, true, true); + quickfix.LogFactory logFactory = new SLF4JLogFactory(new SessionSettings()); acceptor = new SocketAcceptor(application, factory, settings, logFactory, new DefaultMessageFactory()); diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java index 1f2c2d3d8..4f666f8aa 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java @@ -30,7 +30,7 @@ import quickfix.MemoryStoreFactory; import quickfix.MessageStoreFactory; import quickfix.RuntimeError; -import quickfix.ScreenLogFactory; +import quickfix.SLF4JLogFactory; import quickfix.SessionID; import quickfix.SessionSettings; import quickfix.SocketAcceptor; @@ -159,7 +159,7 @@ public void run() { : new FileStoreFactory(settings); //MessageStoreFactory factory = new JdbcStoreFactory(settings); //LogFactory logFactory = new CommonsLogFactory(settings); - quickfix.LogFactory logFactory = new ScreenLogFactory(true, true, true); + quickfix.LogFactory logFactory = new SLF4JLogFactory(new SessionSettings()); //quickfix.LogFactory logFactory = new JdbcLogFactory(settings); if (threaded) { acceptor = new ThreadedSocketAcceptor(application, factory, settings, logFactory, diff --git a/quickfixj-core/src/test/resources/logging.properties b/quickfixj-core/src/test/resources/logging.properties new file mode 100644 index 000000000..059a6959f --- /dev/null +++ b/quickfixj-core/src/test/resources/logging.properties @@ -0,0 +1,5 @@ +handlers=java.util.logging.ConsoleHandler +java.util.logging.ConsoleHandler.level=WARN +java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter + +.level=WARN \ No newline at end of file From 551274e03d9f289b4498bf7b9d4b9c38d29c8618 Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Fri, 7 Jul 2017 09:57:07 +0100 Subject: [PATCH 084/165] replace more instances of ScreenLogFactory with SLF4JLogFactory --- .../src/test/java/quickfix/LoginTestCase.java | 2 +- .../src/test/java/quickfix/ScreenLogTest.java | 9 ++++----- .../src/test/java/quickfix/SessionTest.java | 2 +- .../src/test/java/quickfix/mina/LostLogoutTest.java | 11 +++++------ .../java/quickfix/mina/LostLogoutThreadedTest.java | 11 +++++------ .../acceptor/DynamicAcceptorSessionProviderTest.java | 4 ++-- .../test/acceptance/resynch/ResynchTestClient.java | 4 ++-- .../test/acceptance/resynch/ResynchTestServer.java | 4 ++-- .../test/acceptance/timer/TimerTestClient.java | 4 ++-- .../test/acceptance/timer/TimerTestServer.java | 4 ++-- 10 files changed, 26 insertions(+), 29 deletions(-) diff --git a/quickfixj-core/src/test/java/quickfix/LoginTestCase.java b/quickfixj-core/src/test/java/quickfix/LoginTestCase.java index 84b708fab..03dad7926 100644 --- a/quickfixj-core/src/test/java/quickfix/LoginTestCase.java +++ b/quickfixj-core/src/test/java/quickfix/LoginTestCase.java @@ -41,7 +41,7 @@ private static void login(final String senderCompID) { SessionID sessionID = settings.sectionIterator().next(); SocketInitiator initiator = new SocketInitiator(new TestApplication(sessionID), new FileStoreFactory(settings), settings, - new ScreenLogFactory(settings), new DefaultMessageFactory()); + new SLF4JLogFactory(settings), new DefaultMessageFactory()); System.out.println(senderCompID + ": starting initiator"); initiator.start(); diff --git a/quickfixj-core/src/test/java/quickfix/ScreenLogTest.java b/quickfixj-core/src/test/java/quickfix/ScreenLogTest.java index 5025597bd..f64d094e9 100644 --- a/quickfixj-core/src/test/java/quickfix/ScreenLogTest.java +++ b/quickfixj-core/src/test/java/quickfix/ScreenLogTest.java @@ -19,14 +19,13 @@ package quickfix; +import junit.framework.TestCase; +import quickfix.field.converter.UtcTimestampConverter; + import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.Date; -import quickfix.field.converter.UtcTimestampConverter; - -import junit.framework.TestCase; - public class ScreenLogTest extends TestCase { private long systemTime; @@ -64,7 +63,7 @@ private void doScreenLogTest(boolean includeHeartBeats) { sessionSettings.setBool(sessionID, ScreenLogFactory.SETTING_LOG_HEARTBEATS, includeHeartBeats); - ScreenLogFactory factory = new ScreenLogFactory(sessionSettings); + LogFactory factory = new SLF4JLogFactory(sessionSettings); ScreenLog log = (ScreenLog) factory.create(sessionID); log.setOut(new PrintStream(data)); diff --git a/quickfixj-core/src/test/java/quickfix/SessionTest.java b/quickfixj-core/src/test/java/quickfix/SessionTest.java index 5434a7c76..1b6b9b16e 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionTest.java @@ -1682,7 +1682,7 @@ public void testGenerateRejectAndTargetSeqNum() throws Exception { settings.setBool(Session.SETTING_CHECK_LATENCY, false); Session session = new DefaultSessionFactory(new ApplicationAdapter(), - new MemoryStoreFactory(), new ScreenLogFactory(settings)) + new MemoryStoreFactory(), new SLF4JLogFactory(settings)) .create(sessionID, settings); session.setResponder(new UnitTestResponder()); diff --git a/quickfixj-core/src/test/java/quickfix/mina/LostLogoutTest.java b/quickfixj-core/src/test/java/quickfix/mina/LostLogoutTest.java index 21762f5cb..63215c198 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/LostLogoutTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/LostLogoutTest.java @@ -1,9 +1,6 @@ package quickfix.mina; -import static org.junit.Assert.assertNotNull; - import org.junit.Test; - import quickfix.Application; import quickfix.DefaultMessageFactory; import quickfix.DoNotSend; @@ -13,7 +10,7 @@ import quickfix.MemoryStoreFactory; import quickfix.Message; import quickfix.RejectLogon; -import quickfix.ScreenLogFactory; +import quickfix.SLF4JLogFactory; import quickfix.Session; import quickfix.SessionID; import quickfix.SessionSettings; @@ -24,6 +21,8 @@ import quickfix.field.MsgType; import quickfix.fix44.News; +import static org.junit.Assert.assertNotNull; + /** * QFJ-790 * @@ -103,7 +102,7 @@ public ServerApp() throws Exception { settings.setString(sid, "TargetCompID", sid.getTargetCompID()); acceptor = new SocketAcceptor(this, new MemoryStoreFactory(), settings, - new ScreenLogFactory(), new DefaultMessageFactory()); + new SLF4JLogFactory(new SessionSettings()), new DefaultMessageFactory()); acceptor.start(); Thread.sleep(1000); } @@ -180,7 +179,7 @@ public ClientApp() throws Exception { settings.setString(sid, "TargetCompID", sid.getTargetCompID()); initiator = new SocketInitiator(this, new MemoryStoreFactory(), settings, - new ScreenLogFactory(), new DefaultMessageFactory()); + new SLF4JLogFactory(new SessionSettings()), new DefaultMessageFactory()); initiator.start(); session = Session.lookupSession(sid); } diff --git a/quickfixj-core/src/test/java/quickfix/mina/LostLogoutThreadedTest.java b/quickfixj-core/src/test/java/quickfix/mina/LostLogoutThreadedTest.java index 74226baae..1f1324084 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/LostLogoutThreadedTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/LostLogoutThreadedTest.java @@ -1,9 +1,6 @@ package quickfix.mina; -import static org.junit.Assert.assertNotNull; - import org.junit.Test; - import quickfix.Application; import quickfix.DefaultMessageFactory; import quickfix.DoNotSend; @@ -13,7 +10,7 @@ import quickfix.MemoryStoreFactory; import quickfix.Message; import quickfix.RejectLogon; -import quickfix.ScreenLogFactory; +import quickfix.SLF4JLogFactory; import quickfix.Session; import quickfix.SessionID; import quickfix.SessionSettings; @@ -24,6 +21,8 @@ import quickfix.field.MsgType; import quickfix.fix44.News; +import static org.junit.Assert.assertNotNull; + /** * QFJ-790 * @@ -103,7 +102,7 @@ public ServerApp() throws Exception { settings.setString(sid, "TargetCompID", sid.getTargetCompID()); acceptor = new ThreadedSocketAcceptor(this, new MemoryStoreFactory(), settings, - new ScreenLogFactory(), new DefaultMessageFactory()); + new SLF4JLogFactory(new SessionSettings()), new DefaultMessageFactory()); acceptor.start(); Thread.sleep(1000); } @@ -180,7 +179,7 @@ public ClientApp() throws Exception { settings.setString(sid, "TargetCompID", sid.getTargetCompID()); initiator = new ThreadedSocketInitiator(this, new MemoryStoreFactory(), settings, - new ScreenLogFactory(), new DefaultMessageFactory()); + new SLF4JLogFactory(new SessionSettings()), new DefaultMessageFactory()); initiator.start(); session = Session.lookupSession(sid); } diff --git a/quickfixj-core/src/test/java/quickfix/mina/acceptor/DynamicAcceptorSessionProviderTest.java b/quickfixj-core/src/test/java/quickfix/mina/acceptor/DynamicAcceptorSessionProviderTest.java index 8bbc8e1a8..bde9c3a16 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/acceptor/DynamicAcceptorSessionProviderTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/acceptor/DynamicAcceptorSessionProviderTest.java @@ -29,7 +29,7 @@ import quickfix.MessageFactory; import quickfix.MessageStoreFactory; import quickfix.RuntimeError; -import quickfix.ScreenLogFactory; +import quickfix.SLF4JLogFactory; import quickfix.Session; import quickfix.SessionFactory; import quickfix.SessionID; @@ -59,7 +59,7 @@ protected void setUp() throws Exception { templateMappings = new ArrayList<>(); application = new UnitTestApplication(); messageStoreFactory = new MemoryStoreFactory(); - logFactory = new ScreenLogFactory(); + logFactory = new SLF4JLogFactory(new SessionSettings()); messageFactory = new DefaultMessageFactory(); SessionID templateId1 = new SessionID("FIX.4.2", "ANY", "ANY"); diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/resynch/ResynchTestClient.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/resynch/ResynchTestClient.java index e2cd3ad0c..fb2130d27 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/resynch/ResynchTestClient.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/resynch/ResynchTestClient.java @@ -36,7 +36,7 @@ import quickfix.MessageStoreFactory; import quickfix.RejectLogon; import quickfix.RuntimeError; -import quickfix.ScreenLogFactory; +import quickfix.SLF4JLogFactory; import quickfix.SessionID; import quickfix.SessionNotFound; import quickfix.SessionSettings; @@ -119,7 +119,7 @@ public void run() throws ConfigError, SessionNotFound, InterruptedException { MessageStoreFactory storeFactory = new MemoryStoreFactory(); Initiator initiator = new SocketInitiator(this, storeFactory, settings, - new ScreenLogFactory(settings), new DefaultMessageFactory()); + new SLF4JLogFactory(settings), new DefaultMessageFactory()); initiator.start(); try { diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/resynch/ResynchTestServer.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/resynch/ResynchTestServer.java index 8f653a4db..93db791dc 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/resynch/ResynchTestServer.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/resynch/ResynchTestServer.java @@ -33,7 +33,7 @@ import quickfix.MessageCracker; import quickfix.MessageStoreFactory; import quickfix.RejectLogon; -import quickfix.ScreenLogFactory; +import quickfix.SLF4JLogFactory; import quickfix.Session; import quickfix.SessionID; import quickfix.SessionSettings; @@ -123,7 +123,7 @@ public void run() { MessageStoreFactory factory = new MemoryStoreFactory(); - acceptor = new SocketAcceptor(this, factory, settings, new ScreenLogFactory(settings), + acceptor = new SocketAcceptor(this, factory, settings, new SLF4JLogFactory(settings), new DefaultMessageFactory()); acceptor.addPropertyChangeListener(this); acceptor.start(); diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/timer/TimerTestClient.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/timer/TimerTestClient.java index 8426312f3..55765bcd8 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/timer/TimerTestClient.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/timer/TimerTestClient.java @@ -36,7 +36,7 @@ import quickfix.MessageStoreFactory; import quickfix.RejectLogon; import quickfix.RuntimeError; -import quickfix.ScreenLogFactory; +import quickfix.SLF4JLogFactory; import quickfix.SessionID; import quickfix.SessionNotFound; import quickfix.SessionSettings; @@ -107,7 +107,7 @@ public void run() throws ConfigError, SessionNotFound, InterruptedException { MessageStoreFactory storeFactory = new MemoryStoreFactory(); Initiator initiator = new SocketInitiator(this, storeFactory, settings, - new ScreenLogFactory(settings), new DefaultMessageFactory()); + new SLF4JLogFactory(settings), new DefaultMessageFactory()); initiator.start(); try { diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/timer/TimerTestServer.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/timer/TimerTestServer.java index 7c7afb9a1..f6ca060b9 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/timer/TimerTestServer.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/timer/TimerTestServer.java @@ -33,7 +33,7 @@ import quickfix.MessageCracker; import quickfix.MessageStoreFactory; import quickfix.RejectLogon; -import quickfix.ScreenLogFactory; +import quickfix.SLF4JLogFactory; import quickfix.Session; import quickfix.SessionID; import quickfix.SessionNotFound; @@ -130,7 +130,7 @@ public void run() { settings.setString(sessionID, "DataDictionary", FixVersions.BEGINSTRING_FIX44.replaceAll("\\.", "") + ".xml"); MessageStoreFactory factory = new MemoryStoreFactory(); - acceptor = new SocketAcceptor(this, factory, settings, new ScreenLogFactory(settings), + acceptor = new SocketAcceptor(this, factory, settings, new SLF4JLogFactory(settings), new DefaultMessageFactory()); acceptor.start(); try { From 571d5b6722997fab7a2b26069783407e30508fda Mon Sep 17 00:00:00 2001 From: jonfreedman Date: Fri, 7 Jul 2017 10:22:50 +0100 Subject: [PATCH 085/165] don't replace this one... --- quickfixj-core/src/test/java/quickfix/ScreenLogTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickfixj-core/src/test/java/quickfix/ScreenLogTest.java b/quickfixj-core/src/test/java/quickfix/ScreenLogTest.java index f64d094e9..dd3cf5703 100644 --- a/quickfixj-core/src/test/java/quickfix/ScreenLogTest.java +++ b/quickfixj-core/src/test/java/quickfix/ScreenLogTest.java @@ -63,7 +63,7 @@ private void doScreenLogTest(boolean includeHeartBeats) { sessionSettings.setBool(sessionID, ScreenLogFactory.SETTING_LOG_HEARTBEATS, includeHeartBeats); - LogFactory factory = new SLF4JLogFactory(sessionSettings); + ScreenLogFactory factory = new ScreenLogFactory(sessionSettings); ScreenLog log = (ScreenLog) factory.create(sessionID); log.setOut(new PrintStream(data)); From 5b699419d478ec6f75309fa27520a1fe100a4efd Mon Sep 17 00:00:00 2001 From: Christoph John Date: Tue, 11 Jul 2017 22:55:07 +0200 Subject: [PATCH 086/165] Update .travis.yml Tried higher build timeout because of missing screen output. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8056778ab..8842cc818 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,4 +4,4 @@ jdk: before_install: - echo "MAVEN_OPTS='-Xms2g -Xmx3g'" > ~/.mavenrc script: - - mvn test -B -V -Djava.util.logging.config.file=logging.properties \ No newline at end of file + - travis_wait 30 mvn test -B -V -Djava.util.logging.config.file=logging.properties From 6845d7800f3da1909972f81d0323917660bff930 Mon Sep 17 00:00:00 2001 From: Christoph John Date: Wed, 12 Jul 2017 11:19:31 +0200 Subject: [PATCH 087/165] Merge pull request #92 from soliad/QFJ_1_6_x QFJ-285 Proxy support fixes --- .../src/main/java/quickfix/mina/ProtocolFactory.java | 3 +-- .../java/quickfix/mina/initiator/IoSessionInitiator.java | 7 +++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/mina/ProtocolFactory.java b/quickfixj-core/src/main/java/quickfix/mina/ProtocolFactory.java index 204631557..0e9bfaf6d 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/ProtocolFactory.java +++ b/quickfixj-core/src/main/java/quickfix/mina/ProtocolFactory.java @@ -160,7 +160,6 @@ private static ProxyRequest createHttpProxyRequest(InetSocketAddress address, String proxyPassword, String proxyDomain, String proxyWorkstation) { - String uri = "http://" + address.getAddress().getHostAddress() + ":" + address.getPort(); HashMap props = new HashMap<>(); props.put(HttpProxyConstants.USER_PROPERTY, proxyUser); props.put(HttpProxyConstants.PWD_PROPERTY, proxyPassword); @@ -169,7 +168,7 @@ private static ProxyRequest createHttpProxyRequest(InetSocketAddress address, props.put(HttpProxyConstants.WORKSTATION_PROPERTY, proxyWorkstation); } - HttpProxyRequest req = new HttpProxyRequest(uri); + HttpProxyRequest req = new HttpProxyRequest(address); req.setProperties(props); if (proxyVersion != null && proxyVersion.equalsIgnoreCase("1.1")) { req.setHttpVersion(HttpProxyConstants.HTTP_1_1); diff --git a/quickfixj-core/src/main/java/quickfix/mina/initiator/IoSessionInitiator.java b/quickfixj-core/src/main/java/quickfix/mina/initiator/IoSessionInitiator.java index 71f1a8bf0..b2ad31721 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/initiator/IoSessionInitiator.java +++ b/quickfixj-core/src/main/java/quickfix/mina/initiator/IoSessionInitiator.java @@ -24,7 +24,6 @@ import org.apache.mina.core.service.IoConnector; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecFilter; -import org.apache.mina.filter.logging.LoggingFilter; import org.apache.mina.proxy.ProxyConnector; import org.apache.mina.transport.socket.SocketConnector; import org.slf4j.Logger; @@ -145,7 +144,7 @@ public ConnectTask(boolean sslEnabled, SocketAddress[] socketAddresses, private void setupIoConnector() throws ConfigError, GeneralSecurityException { final CompositeIoFilterChainBuilder ioFilterChainBuilder = new CompositeIoFilterChainBuilder(userIoFilterChainBuilder); - boolean hasProxy = proxyType != null && proxyPort > 0 && socketAddresses[0] instanceof InetSocketAddress; + boolean hasProxy = proxyType != null && proxyPort > 0 && socketAddresses[nextSocketAddressIndex] instanceof InetSocketAddress; SSLFilter sslFilter = null; if (sslEnabled) { @@ -155,14 +154,14 @@ private void setupIoConnector() throws ConfigError, GeneralSecurityException { ioFilterChainBuilder.addLast(FIXProtocolCodecFactory.FILTER_NAME, new ProtocolCodecFilter(new FIXProtocolCodecFactory())); IoConnector newConnector; - newConnector = ProtocolFactory.createIoConnector(socketAddresses[0]); + newConnector = ProtocolFactory.createIoConnector(socketAddresses[nextSocketAddressIndex]); newConnector.setHandler(new InitiatorIoHandler(fixSession, networkingOptions, eventHandlingStrategy)); newConnector.setFilterChainBuilder(ioFilterChainBuilder); if (hasProxy) { ProxyConnector proxyConnector = ProtocolFactory.createIoProxyConnector( (SocketConnector) newConnector, - (InetSocketAddress) socketAddresses[0], + (InetSocketAddress) socketAddresses[nextSocketAddressIndex], new InetSocketAddress(proxyHost, proxyPort), proxyType, proxyVersion, proxyUser, proxyPassword, proxyDomain, proxyWorkstation ); From 317fc6e781497df3af9b10d6dc7e55e33763c5ae Mon Sep 17 00:00:00 2001 From: chrjohn Date: Thu, 13 Jul 2017 11:48:39 +0200 Subject: [PATCH 088/165] added some time to cleanup resources after each test in SSLCertificateTest --- .../java/quickfix/mina/ssl/SSLCertificateTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 b971803eb..7577697c0 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java @@ -50,6 +50,8 @@ import java.util.HashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import org.junit.After; public class SSLCertificateTest { @@ -57,6 +59,15 @@ public class SSLCertificateTest { private static final String CIPHER_SUITES_ANON = "TLS_DH_anon_WITH_AES_128_CBC_SHA"; private static final String CIPHER_SUITES_TLS = "TLS_RSA_WITH_AES_128_CBC_SHA"; + @After + public void cleanup() { + try { + Thread.sleep(500); + } catch (InterruptedException ex) { + java.util.logging.Logger.getLogger(SSLCertificateTest.class.getName()).log(Level.SEVERE, null, ex); + } + } + @Test public void shouldAuthenticateServerCertificate() throws Exception { TestAcceptor acceptor = new TestAcceptor(createAcceptorSettings("single-session/server.keystore", false, From 0b7932332c395539a13c9d0d2f88cb5a40035cc4 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Thu, 13 Jul 2017 16:29:40 +0200 Subject: [PATCH 089/165] - use distinct ports on test execution to prevent problems when quickly starting/stopping connectors for the same port --- .../java/quickfix/SocketInitiatorTest.java | 68 +++++++++---------- .../quickfix/mina/ssl/SSLCertificateTest.java | 60 +++++++++------- .../quickfix/test/acceptance/ATServer.java | 4 ++ .../test/acceptance/AcceptanceTestSuite.java | 1 - 4 files changed, 74 insertions(+), 59 deletions(-) diff --git a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java index 5edbcc6aa..a315b5bc5 100644 --- a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java +++ b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java @@ -41,6 +41,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.logging.Level; +import org.apache.mina.util.AvailablePortFinder; import org.junit.After; import static org.junit.Assert.assertEquals; @@ -70,7 +71,8 @@ public void cleanup() { @Test public void testLogonAfterServerDisconnect() throws Exception { final WriteCounter initiatorWriteCounter = new WriteCounter("initiator"); - ServerThread serverThread = new ServerThread(); + int freePort = AvailablePortFinder.getNextAvailable(); + ServerThread serverThread = new ServerThread(freePort); try { serverThread.setDaemon(true); serverThread.start(); @@ -79,7 +81,7 @@ public void testLogonAfterServerDisconnect() throws Exception { Session serverSession = Session.lookupSession(serverSessionID); SessionID clientSessionID = new SessionID(FixVersions.BEGINSTRING_FIX42, "TW", "ISLD"); - SessionSettings settings = getClientSessionSettings(clientSessionID); + SessionSettings settings = getClientSessionSettings(clientSessionID, freePort); ClientApplication clientApplication = new ClientApplication(); ThreadedSocketInitiator initiator = new ThreadedSocketInitiator(clientApplication, new MemoryStoreFactory(), settings, new DefaultMessageFactory()); @@ -120,14 +122,15 @@ public void testLogonAfterServerDisconnect() throws Exception { @Test public void testBlockLogoffAfterLogon() throws Exception { - ServerThread serverThread = new ServerThread(); + int freePort = AvailablePortFinder.getNextAvailable(); + ServerThread serverThread = new ServerThread(freePort); try { serverThread.setDaemon(true); serverThread.start(); serverThread.waitForInitialization(); SessionID clientSessionID = new SessionID(FixVersions.BEGINSTRING_FIX42, "TW", "ISLD"); - SessionSettings settings = getClientSessionSettings(clientSessionID); + SessionSettings settings = getClientSessionSettings(clientSessionID, freePort); ClientApplication clientApplication = new ClientApplication(); final SocketInitiator initiator = new SocketInitiator(clientApplication, new MemoryStoreFactory(), settings, new DefaultMessageFactory()); @@ -149,40 +152,43 @@ public void testBlockLogoffAfterLogon() throws Exception { @Test public void testInitiatorStop() throws Exception { + int freePort = AvailablePortFinder.getNextAvailable(); SessionID clientSessionID = new SessionID(FixVersions.BEGINSTRING_FIX42, "TW", "ISLD"); - SessionSettings settings = getClientSessionSettings(clientSessionID); + SessionSettings settings = getClientSessionSettings(clientSessionID, freePort); ClientApplication clientApplication = new ClientApplication(); Initiator initiator = new SocketInitiator(clientApplication, new MemoryStoreFactory(), settings, new DefaultMessageFactory()); - doTestOfStop(clientSessionID, clientApplication, initiator); + doTestOfStop(clientSessionID, clientApplication, initiator, freePort); } @Test public void testInitiatorStopStart() throws Exception { + int freePort = AvailablePortFinder.getNextAvailable(); SessionID clientSessionID = new SessionID(FixVersions.BEGINSTRING_FIX42, "TW", "ISLD"); - SessionSettings settings = getClientSessionSettings(clientSessionID); + SessionSettings settings = getClientSessionSettings(clientSessionID, freePort); ClientApplication clientApplication = new ClientApplication(); Initiator initiator = new SocketInitiator(clientApplication, new MemoryStoreFactory(), settings, new DefaultMessageFactory()); - doTestOfRestart(clientSessionID, clientApplication, initiator, null); + doTestOfRestart(clientSessionID, clientApplication, initiator, null, freePort); } @Test public void testInitiatorStopThreaded() throws Exception { + int freePort = AvailablePortFinder.getNextAvailable(); SessionID clientSessionID = new SessionID(FixVersions.BEGINSTRING_FIX42, "TW", "ISLD"); - SessionSettings settings = getClientSessionSettings(clientSessionID); + SessionSettings settings = getClientSessionSettings(clientSessionID, freePort); ClientApplication clientApplication = new ClientApplication(); Initiator initiator = new ThreadedSocketInitiator(clientApplication, new MemoryStoreFactory(), settings, new DefaultMessageFactory()); - doTestOfStop(clientSessionID, clientApplication, initiator); + doTestOfStop(clientSessionID, clientApplication, initiator, freePort); } @Test public void testInitiatorStopStartFileLog() throws Exception { - + int freePort = AvailablePortFinder.getNextAvailable(); File messageLog = new File(getTempDirectory() + File.separatorChar + "FIX.4.2-TW-ISLD.messages.log"); File eventLog = new File(getTempDirectory() + File.separatorChar @@ -191,14 +197,14 @@ public void testInitiatorStopStartFileLog() throws Exception { eventLog.delete(); SessionID clientSessionID = new SessionID(FixVersions.BEGINSTRING_FIX42, "TW", "ISLD"); - SessionSettings settings = getClientSessionSettings(clientSessionID); + SessionSettings settings = getClientSessionSettings(clientSessionID, freePort); ClientApplication clientApplication = new ClientApplication(); settings.setString("FileLogPath", getTempDirectory()); settings.setString("ResetOnLogon", "Y"); FileLogFactory logFactory = new FileLogFactory(settings); Initiator initiator = new SocketInitiator(clientApplication, new MemoryStoreFactory(), settings, logFactory, new DefaultMessageFactory()); - doTestOfRestart(clientSessionID, clientApplication, initiator, messageLog); + doTestOfRestart(clientSessionID, clientApplication, initiator, messageLog, freePort); messageLog.delete(); eventLog.delete(); @@ -206,23 +212,25 @@ public void testInitiatorStopStartFileLog() throws Exception { @Test public void testInitiatorStopStartThreaded() throws Exception { + int freePort = AvailablePortFinder.getNextAvailable(); SessionID clientSessionID = new SessionID(FixVersions.BEGINSTRING_FIX42, "TW", "ISLD"); - SessionSettings settings = getClientSessionSettings(clientSessionID); + SessionSettings settings = getClientSessionSettings(clientSessionID, freePort); ClientApplication clientApplication = new ClientApplication(); Initiator initiator = new ThreadedSocketInitiator(clientApplication, new MemoryStoreFactory(), settings, new DefaultMessageFactory()); - doTestOfRestart(clientSessionID, clientApplication, initiator, null); + doTestOfRestart(clientSessionID, clientApplication, initiator, null, freePort); } // QFJ-825 @Test public void testDoubleStartOfInitiator() throws Exception { + int freePort = AvailablePortFinder.getNextAvailable(); Initiator initiator = null; try { ThreadMXBean bean = ManagementFactory.getThreadMXBean(); SessionID clientSessionID = new SessionID(FixVersions.BEGINSTRING_FIX42, "TW", "ISLD"); - SessionSettings settings = getClientSessionSettings(clientSessionID); + SessionSettings settings = getClientSessionSettings(clientSessionID, freePort); ClientApplication clientApplication = new ClientApplication(); initiator = new SocketInitiator(clientApplication, new MemoryStoreFactory(), settings, new DefaultMessageFactory()); @@ -245,8 +253,8 @@ public void testDoubleStartOfInitiator() throws Exception { } private void doTestOfRestart(SessionID clientSessionID, ClientApplication clientApplication, - final Initiator initiator, File messageLog) throws InterruptedException, ConfigError { - ServerThread serverThread = new ServerThread(); + final Initiator initiator, File messageLog, int port) throws InterruptedException, ConfigError { + ServerThread serverThread = new ServerThread(port); try { serverThread.setDaemon(true); serverThread.start(); @@ -294,8 +302,8 @@ private void doTestOfRestart(SessionID clientSessionID, ClientApplication client } private void doTestOfStop(SessionID clientSessionID, ClientApplication clientApplication, - Initiator initiator) throws InterruptedException, ConfigError { - ServerThread serverThread = new ServerThread(); + Initiator initiator, int freePort) throws InterruptedException, ConfigError { + ServerThread serverThread = new ServerThread(freePort); try { serverThread.setDaemon(true); serverThread.start(); @@ -323,13 +331,13 @@ private void doTestOfStop(SessionID clientSessionID, ClientApplication clientApp } } - private SessionSettings getClientSessionSettings(SessionID clientSessionID) { + private SessionSettings getClientSessionSettings(SessionID clientSessionID, int port) { SessionSettings settings = new SessionSettings(); HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "initiator"); defaults.put("SocketConnectProtocol", ProtocolFactory.getTypeString(ProtocolFactory.SOCKET)); defaults.put("SocketConnectHost", "localhost"); - defaults.put("SocketConnectPort", "9877"); + defaults.put("SocketConnectPort", Integer.toString(port)); defaults.put("StartTime", "00:00:00"); defaults.put("EndTime", "00:00:00"); defaults.put("HeartBtInt", "30"); @@ -396,20 +404,10 @@ public void stopAfterLogon(Initiator initiator) { } public void setUpLogonExpectation() { -// if (logonLatch!=null) { -// while (logonLatch.getCount()>1) { -// logonLatch.countDown(); -// } -// } logonLatch = new CountDownLatch(1); } public void setUpLogoutExpectation() { -// if (logoutLatch!=null) { -// while (logoutLatch.getCount()>1) { -// logoutLatch.countDown(); -// } -// } logoutLatch = new CountDownLatch(1); } @@ -489,10 +487,12 @@ public String toString() { private class ServerThread extends Thread { private final ATServer server; private final WriteCounter writeCounter = new WriteCounter("acceptor"); + private final int port; - public ServerThread() { + public ServerThread(final int port) { super("test server"); - server = new ATServer(); + this.port = port; + server = new ATServer(port); server.setIoFilterChainBuilder(chain -> chain.addLast("TestFilter", writeCounter)); } 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 7577697c0..3154f27ce 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java @@ -51,6 +51,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.logging.Level; +import org.apache.mina.util.AvailablePortFinder; import org.junit.After; public class SSLCertificateTest { @@ -70,15 +71,16 @@ public void cleanup() { @Test public void shouldAuthenticateServerCertificate() throws Exception { + int freePort = AvailablePortFinder.getNextAvailable(); TestAcceptor acceptor = new TestAcceptor(createAcceptorSettings("single-session/server.keystore", false, - "single-session/empty.keystore", CIPHER_SUITES_TLS, "TLSv1.2", "JKS", "JKS")); + "single-session/empty.keystore", CIPHER_SUITES_TLS, "TLSv1.2", "JKS", "JKS", freePort)); try { acceptor.start(); TestInitiator initiator = new TestInitiator( createInitiatorSettings("single-session/empty.keystore", "single-session/client.truststore", - CIPHER_SUITES_TLS, "TLSv1.2", "ZULU", "ALFA", "12340", "JKS", "JKS")); + CIPHER_SUITES_TLS, "TLSv1.2", "ZULU", "ALFA", Integer.toString(freePort), "JKS", "JKS")); try { initiator.start(); @@ -101,15 +103,16 @@ public void shouldAuthenticateServerCertificate() throws Exception { @Test public void shouldAuthenticateServerAndClientCertificates() throws Exception { + int freePort = AvailablePortFinder.getNextAvailable(); TestAcceptor acceptor = new TestAcceptor(createAcceptorSettings("single-session/server.keystore", true, - "single-session/server.truststore", CIPHER_SUITES_TLS, "TLSv1.2", "JKS", "JKS")); + "single-session/server.truststore", CIPHER_SUITES_TLS, "TLSv1.2", "JKS", "JKS", freePort)); try { acceptor.start(); TestInitiator initiator = new TestInitiator( createInitiatorSettings("single-session/client.keystore", "single-session/client.truststore", - CIPHER_SUITES_TLS, "TLSv1.2", "ZULU", "ALFA", "12340", "JKS", "JKS")); + CIPHER_SUITES_TLS, "TLSv1.2", "ZULU", "ALFA", Integer.toString(freePort), "JKS", "JKS")); try { initiator.start(); @@ -133,16 +136,17 @@ public void shouldAuthenticateServerAndClientCertificates() throws Exception { @Test public void shouldAuthenticateServerAndClientCertificatesWhenUsingDifferentKeystoreFormats() throws Exception { + int freePort = AvailablePortFinder.getNextAvailable(); TestAcceptor acceptor = new TestAcceptor(createAcceptorSettings("single-session/server-pkcs12.keystore", true, "single-session/server-jceks.truststore", CIPHER_SUITES_TLS, "TLSv1.2", "PKCS12", - "JCEKS")); + "JCEKS", freePort)); try { acceptor.start(); TestInitiator initiator = new TestInitiator(createInitiatorSettings("single-session/client-jceks.keystore", "single-session/client-jceks.keystore", CIPHER_SUITES_TLS, "TLSv1.2", "ZULU", "ALFA", - "12340", "JCEKS", "JCEKS")); + Integer.toString(freePort), "JCEKS", "JCEKS")); try { initiator.start(); @@ -284,15 +288,16 @@ public void shouldFailIndividualSessionsWhenInvalidCertificatesUsed() throws Exc @Test public void shouldCreateFixSessionWithoutAuthenticationWhenUsingEmptyServerKeyStoreWithAnonymousCipher() throws Exception { + int freePort = AvailablePortFinder.getNextAvailable(); TestAcceptor acceptor = new TestAcceptor(createAcceptorSettings("single-session/empty.keystore", false, - "single-session/empty.keystore", CIPHER_SUITES_ANON, null, "JKS", "JKS")); + "single-session/empty.keystore", CIPHER_SUITES_ANON, null, "JKS", "JKS", freePort)); try { acceptor.start(); TestInitiator initiator = new TestInitiator( createInitiatorSettings("single-session/empty.keystore", "single-session/empty.keystore", - CIPHER_SUITES_ANON, null, "ZULU", "ALFA", "12340", "JKS", "JKS")); + CIPHER_SUITES_ANON, null, "ZULU", "ALFA", Integer.toString(freePort), "JKS", "JKS")); try { initiator.start(); @@ -314,14 +319,15 @@ public void shouldCreateFixSessionWithoutAuthenticationWhenUsingEmptyServerKeySt @Test public void shouldCreateFixSessionWithoutAuthenticationWhenTrustStoresAreMissing() throws Exception { + int freePort = AvailablePortFinder.getNextAvailable(); TestAcceptor acceptor = new TestAcceptor(createAcceptorSettings("single-session/server.keystore", false, - "missing", CIPHER_SUITES_ANON, null, "JKS", "JKS")); + "missing", CIPHER_SUITES_ANON, null, "JKS", "JKS", freePort)); try { acceptor.start(); TestInitiator initiator = new TestInitiator(createInitiatorSettings("single-session/client.keystore", - "missing", CIPHER_SUITES_ANON, null, "ZULU", "ALFA", "12340", "JKS", "JKS")); + "missing", CIPHER_SUITES_ANON, null, "ZULU", "ALFA", Integer.toString(freePort), "JKS", "JKS")); try { initiator.start(); @@ -343,14 +349,15 @@ public void shouldCreateFixSessionWithoutAuthenticationWhenTrustStoresAreMissing @Test public void shouldCreateFixSessionWithoutAuthenticationWhenUsingDefaultKeystores() throws Exception { + int freePort = AvailablePortFinder.getNextAvailable(); TestAcceptor acceptor = new TestAcceptor(createAcceptorSettings("missing", false, "missing", - CIPHER_SUITES_ANON, null, "JKS", "JKS")); + CIPHER_SUITES_ANON, null, "JKS", "JKS", freePort)); try { acceptor.start(); TestInitiator initiator = new TestInitiator(createInitiatorSettings("missing", "missing", - CIPHER_SUITES_ANON, null, "ZULU", "ALFA", "12340", "JKS", "JKS")); + CIPHER_SUITES_ANON, null, "ZULU", "ALFA", Integer.toString(freePort), "JKS", "JKS")); try { initiator.start(); @@ -372,14 +379,15 @@ public void shouldCreateFixSessionWithoutAuthenticationWhenUsingDefaultKeystores @Test public void shouldFailWhenUsingEmptyServerKeyStore() throws Exception { + int freePort = AvailablePortFinder.getNextAvailable(); TestAcceptor acceptor = new TestAcceptor(createAcceptorSettings("single-session/empty.keystore", false, - "single-session/empty.keystore", null, null, "JKS", "JKS")); + "single-session/empty.keystore", null, null, "JKS", "JKS", freePort)); try { acceptor.start(); TestInitiator initiator = new TestInitiator(createInitiatorSettings("single-session/empty.keystore", - "single-session/empty.keystore", null, null, "ZULU", "ALFA", "12340", "JKS", "JKS")); + "single-session/empty.keystore", null, null, "ZULU", "ALFA", Integer.toString(freePort), "JKS", "JKS")); try { initiator.start(); @@ -401,15 +409,16 @@ public void shouldFailWhenUsingEmptyServerKeyStore() throws Exception { @Test public void shouldFailWhenUsingEmptyClientTruststore() throws Exception { + int freePort = AvailablePortFinder.getNextAvailable(); TestAcceptor acceptor = new TestAcceptor(createAcceptorSettings("single-session/server.keystore", false, - "single-session/empty.keystore", CIPHER_SUITES_TLS, "TLSv1.2", "JKS", "JKS")); + "single-session/empty.keystore", CIPHER_SUITES_TLS, "TLSv1.2", "JKS", "JKS", freePort)); try { acceptor.start(); TestInitiator initiator = new TestInitiator( createInitiatorSettings("single-session/empty.keystore", "single-session/empty.keystore", - CIPHER_SUITES_TLS, "TLSv1.2", "ZULU", "ALFA", "12340", "JKS", "JKS")); + CIPHER_SUITES_TLS, "TLSv1.2", "ZULU", "ALFA", Integer.toString(freePort), "JKS", "JKS")); try { initiator.start(); @@ -431,15 +440,16 @@ public void shouldFailWhenUsingEmptyClientTruststore() throws Exception { @Test public void shouldFailWhenUsingEmptyServerTrustore() throws Exception { + int freePort = AvailablePortFinder.getNextAvailable(); TestAcceptor acceptor = new TestAcceptor(createAcceptorSettings("single-session/server.keystore", true, - "single-session/empty.keystore", CIPHER_SUITES_TLS, "TLSv1.2", "JKS", "JKS")); + "single-session/empty.keystore", CIPHER_SUITES_TLS, "TLSv1.2", "JKS", "JKS", freePort)); try { acceptor.start(); TestInitiator initiator = new TestInitiator( createInitiatorSettings("single-session/client.keystore", "single-session/client.truststore", - CIPHER_SUITES_TLS, "TLSv1.2", "ZULU", "ALFA", "12340", "JKS", "JKS")); + CIPHER_SUITES_TLS, "TLSv1.2", "ZULU", "ALFA", Integer.toString(freePort), "JKS", "JKS")); try { initiator.start(); @@ -461,15 +471,16 @@ public void shouldFailWhenUsingEmptyServerTrustore() throws Exception { @Test public void shouldFailWhenUsingBadClientCertificate() throws Exception { + int freePort = AvailablePortFinder.getNextAvailable(); TestAcceptor acceptor = new TestAcceptor(createAcceptorSettings("single-session/server.keystore", true, - "single-session/server.truststore", CIPHER_SUITES_TLS, "TLSv1.2", "JKS", "JKS")); + "single-session/server.truststore", CIPHER_SUITES_TLS, "TLSv1.2", "JKS", "JKS", freePort)); try { acceptor.start(); TestInitiator initiator = new TestInitiator( createInitiatorSettings("single-session/server.keystore", "single-session/client.truststore", - CIPHER_SUITES_TLS, "TLSv1.2", "ZULU", "ALFA", "12340", "JKS", "JKS")); + CIPHER_SUITES_TLS, "TLSv1.2", "ZULU", "ALFA", Integer.toString(freePort), "JKS", "JKS")); try { initiator.start(); @@ -491,15 +502,16 @@ public void shouldFailWhenUsingBadClientCertificate() throws Exception { @Test public void shouldFailWhenUsingBadServerCertificate() throws Exception { + int freePort = AvailablePortFinder.getNextAvailable(); TestAcceptor acceptor = new TestAcceptor(createAcceptorSettings("single-session/client.keystore", false, - "single-session/empty.keystore", CIPHER_SUITES_TLS, "TLSv1.2", "JKS", "JKS")); + "single-session/empty.keystore", CIPHER_SUITES_TLS, "TLSv1.2", "JKS", "JKS", freePort)); try { acceptor.start(); TestInitiator initiator = new TestInitiator( createInitiatorSettings("single-session/empty.keystore", "single-session/client.truststore", - CIPHER_SUITES_TLS, "TLSv1.2", "ZULU", "ALFA", "12340", "JKS", "JKS")); + CIPHER_SUITES_TLS, "TLSv1.2", "ZULU", "ALFA", Integer.toString(freePort), "JKS", "JKS")); try { initiator.start(); @@ -740,7 +752,7 @@ private SessionSettings createMultiSessionAcceptorSettings(String keyStoreName, } private SessionSettings createAcceptorSettings(String keyStoreName, boolean needClientAuth, String trustStoreName, - String cipherSuites, String protocols, String keyStoreType, String trustStoreType) { + 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)); @@ -763,7 +775,7 @@ private SessionSettings createAcceptorSettings(String keyStoreName, boolean need defaults.put(SSLSupport.SETTING_NEED_CLIENT_AUTH, needClientAuth ? "Y" : "N"); defaults.put("SocketAcceptHost", "localhost"); - defaults.put("SocketAcceptPort", "12340"); + defaults.put("SocketAcceptPort", Integer.toString(port)); defaults.put("StartTime", "00:00:00"); defaults.put("EndTime", "00:00:00"); defaults.put("HeartBtInt", "30"); diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java index 4f666f8aa..adae4fc78 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java @@ -76,6 +76,10 @@ public ATServer() { // defaults } + public ATServer(int port) { + this.port = port; + } + public ATServer(TestSuite suite, boolean threaded, int transportType, int port) { this(suite, threaded, transportType, port, null); } diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/AcceptanceTestSuite.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/AcceptanceTestSuite.java index 9c0c71a8a..6bcbd1e01 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/AcceptanceTestSuite.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/AcceptanceTestSuite.java @@ -27,7 +27,6 @@ import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import quickfix.UtcTimestampPrecision; public class AcceptanceTestSuite extends TestSuite { private static final String ATEST_TIMEOUT_KEY = "atest.timeout"; From af84f71d4108b40598d5ce4e6c6362d47c8e6ac7 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Fri, 14 Jul 2017 09:11:29 +0200 Subject: [PATCH 090/165] - SocketInitiatorTest: changed protocol to VM_PIPE to test if disposal of NioSocketConnector is working more reliably than using SOCKET --- .../src/test/java/quickfix/SocketInitiatorTest.java | 4 ++-- .../src/test/java/quickfix/test/acceptance/ATServer.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java index a315b5bc5..0224253df 100644 --- a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java +++ b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java @@ -335,7 +335,7 @@ private SessionSettings getClientSessionSettings(SessionID clientSessionID, int SessionSettings settings = new SessionSettings(); HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "initiator"); - defaults.put("SocketConnectProtocol", ProtocolFactory.getTypeString(ProtocolFactory.SOCKET)); + defaults.put("SocketConnectProtocol", ProtocolFactory.getTypeString(ProtocolFactory.VM_PIPE)); defaults.put("SocketConnectHost", "localhost"); defaults.put("SocketConnectPort", Integer.toString(port)); defaults.put("StartTime", "00:00:00"); @@ -492,7 +492,7 @@ private class ServerThread extends Thread { public ServerThread(final int port) { super("test server"); this.port = port; - server = new ATServer(port); + server = new ATServer(port, ProtocolFactory.VM_PIPE); server.setIoFilterChainBuilder(chain -> chain.addLast("TestFilter", writeCounter)); } diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java index adae4fc78..5e492472b 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/ATServer.java @@ -76,8 +76,9 @@ public ATServer() { // defaults } - public ATServer(int port) { + public ATServer(int port, int transportType) { this.port = port; + this.transportType = transportType; } public ATServer(TestSuite suite, boolean threaded, int transportType, int port) { From a11ed13f954ef0c669b257d5431276211ce3a2d7 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Fri, 14 Jul 2017 09:59:29 +0200 Subject: [PATCH 091/165] - temporarily disable SocketInitiatorTest.testBlockLogoffAfterLogon() --- quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java index 0224253df..01d05059f 100644 --- a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java +++ b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java @@ -48,6 +48,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import org.junit.Ignore; import quickfix.field.MsgType; import quickfix.test.util.ReflectionUtil; @@ -121,6 +122,7 @@ public void testLogonAfterServerDisconnect() throws Exception { } @Test + @Ignore public void testBlockLogoffAfterLogon() throws Exception { int freePort = AvailablePortFinder.getNextAvailable(); ServerThread serverThread = new ServerThread(freePort); From ea7003a2b388078d48252637997de81a3d60a8b0 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Fri, 14 Jul 2017 15:23:34 +0200 Subject: [PATCH 092/165] - resolved conflicts in SessionFactoryTestSupport --- .../src/main/java/quickfix/Session.java | 8 +- .../java/quickfix/SessionDisconnectTest.java | 241 ++++++++++++++++++ .../quickfix/SessionFactoryTestSupport.java | 233 ++++++++++++++--- 3 files changed, 440 insertions(+), 42 deletions(-) create mode 100644 quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index 5d7e7a940..d2ac80c1d 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -2071,7 +2071,13 @@ private void nextLogon(Message logon) throws FieldNotFound, RejectLogon, Incorre if (logon.isSetField(NextExpectedMsgSeqNum.FIELD) && enableNextExpectedMsgSeqNum) { final int targetWantsNextSeqNumToBe = logon.getInt(NextExpectedMsgSeqNum.FIELD); - final int actualNextNum = state.getMessageStore().getNextSenderMsgSeqNum(); + state.lockSenderMsgSeqNum(); + final int actualNextNum; + try { + actualNextNum = state.getNextSenderMsgSeqNum(); + } finally { + state.unlockSenderMsgSeqNum(); + } // Is the 789 we received too high ?? if (targetWantsNextSeqNumToBe > actualNextNum) { // barf! we can't resend what we never sent! something unrecoverable has happened. diff --git a/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java b/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java new file mode 100644 index 000000000..84acd529c --- /dev/null +++ b/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java @@ -0,0 +1,241 @@ +package quickfix; + +import org.junit.Test; +import quickfix.field.EncryptMethod; +import quickfix.field.HeartBtInt; +import quickfix.field.MsgSeqNum; +import quickfix.field.MsgType; +import quickfix.field.NextExpectedMsgSeqNum; +import quickfix.field.SenderCompID; +import quickfix.field.SendingTime; +import quickfix.field.TargetCompID; +import quickfix.fix44.Logon; + +import java.io.IOException; +import java.util.Collection; +import java.util.Date; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * The purpose of this test is to simulate the situation where a logon response is received before a logon request can + * be successfully persisted to the MessageStore. + * + * @author Jon Freedman + */ +public class SessionDisconnectTest { + private final int TIMEOUT_SECS = 1; + private final String EXTERNAL_COMP_ID = "THEM"; + private final String INTERNAL_COMP_ID = "US"; + + @Test + public void reconnectReceivingLogonResponseBeforeLogonRequestPersisted() throws Exception { + final CountDownLatch storeMessageLatch = new CountDownLatch(1); + final CountDownLatch receiveLogonResponseLatch = new CountDownLatch(1); + final CountDownLatch sentLogoutLatch = new CountDownLatch(1); + + final UnitTestApplication application = new UnitTestApplication() { + @Override + public void fromAdmin(final Message message, final SessionID sessionId) throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, RejectLogon { + receiveLogonResponseLatch.countDown(); + super.fromAdmin(message, sessionId); + } + }; + final Session session = buildSession(application, storeMessageLatch, sentLogoutLatch); + + final MessageStore messageStore = session.getStore(); + checkNextSeqNums(messageStore, 1, 1); + + session.logon(); + + processOnSeparateThread(session::next); + assertTrue(String.format("Message not stored within %s secs", TIMEOUT_SECS), storeMessageLatch.await(TIMEOUT_SECS, TimeUnit.SECONDS)); + assertEquals(1, application.lastToAdminMessage().getHeader().getField(new MsgSeqNum()).getValue()); + checkNextSeqNums(messageStore, 1, 1); + + processOnSeparateThread(() -> { + storeMessageLatch.await(TIMEOUT_SECS, TimeUnit.SECONDS); + session.next(createLogonResponse()); + }); + assertTrue(String.format("Logon response not received within %s secs", TIMEOUT_SECS), receiveLogonResponseLatch.await(TIMEOUT_SECS, TimeUnit.SECONDS)); + assertTrue(String.format("Logout/SequenceReset not sent %s secs", TIMEOUT_SECS * 2), sentLogoutLatch.await(TIMEOUT_SECS * 2, TimeUnit.SECONDS)); + checkNextSeqNums(messageStore, 2, 2); + + session.close(); + } + + private void checkNextSeqNums(final MessageStore messageStore, final int nextTarget, final int nextSender) throws IOException { + assertEquals("NextTargetMsgSeqNum", nextTarget, messageStore.getNextTargetMsgSeqNum()); + assertEquals("NextSenderMsgSeqNum", nextSender, messageStore.getNextSenderMsgSeqNum()); + } + + private Session buildSession(final Application application, final CountDownLatch storeMessageLatch, final CountDownLatch sentLogoutLatch) { + final Session session = new SessionFactoryTestSupport.Builder() + .setSessionId(new SessionID(FixVersions.BEGINSTRING_FIX44, INTERNAL_COMP_ID, EXTERNAL_COMP_ID)) + .setApplication(application) + .setMessageStoreFactory(new BlockingStoreFactory(storeMessageLatch, sentLogoutLatch)) + .setLogFactory(new ScreenLogFactory(true, true, true)) + .setMessageFactory(new ListeningMessageFactory(sentLogoutLatch)) + .setSessionHeartbeatInterval(60) + .setPersistMessages(true) + .setValidateSequenceNumbers(true) + .setEnableNextExpectedMsgSeqNum(true) + .build(); + session.setResponder(new Responder() { + @Override + public boolean send(final String data) { + return true; + } + + @Override + public void disconnect() { + } + + @Override + public String getRemoteAddress() { + return null; + } + }); + + return session; + } + + private Message createLogonResponse() throws FieldNotFound { + final Logon logonResponse = new Logon(new EncryptMethod(EncryptMethod.NONE_OTHER), new HeartBtInt(60)); + logonResponse.setField(new NextExpectedMsgSeqNum(2)); + final Message.Header header = logonResponse.getHeader(); + header.setField(new SenderCompID(EXTERNAL_COMP_ID)); + header.setField(new TargetCompID(INTERNAL_COMP_ID)); + header.setField(new MsgSeqNum(1)); + header.setField(new SendingTime(SystemTime.getLocalDateTime())); + return logonResponse; + } + + private void processOnSeparateThread(final SessionAction action) { + final ExecutorService executor = Executors.newSingleThreadExecutor(); + try { + executor.execute(() -> { + try { + action.run(); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } finally { + executor.shutdown(); + } + } + + @FunctionalInterface + private interface SessionAction { + void run() throws Exception; + } + + private class BlockingStoreFactory implements MessageStoreFactory { + private final MemoryStoreFactory factory = new MemoryStoreFactory(); + private final CountDownLatch storeMessageLatch; + private final CountDownLatch sentLogoutLatch; + + BlockingStoreFactory(final CountDownLatch storeMessageLatch, final CountDownLatch sentLogoutLatch) { + this.storeMessageLatch = storeMessageLatch; + this.sentLogoutLatch = sentLogoutLatch; + } + + @Override + public MessageStore create(final SessionID sessionID) { + return new MessageStore() { + private final MessageStore messageStore = factory.create(sessionID); + + @Override + public boolean set(final int sequence, final String message) throws IOException { + storeMessageLatch.countDown(); + try { + // we are not verifying the return value of this call to #await as once the issue is fixed with locking this will return false + sentLogoutLatch.await(TIMEOUT_SECS, TimeUnit.SECONDS); + } catch (final InterruptedException e) { + throw new IOException(e); + } + return messageStore.set(sequence, message); + } + + @Override + public void get(final int startSequence, final int endSequence, final Collection messages) throws IOException { + messageStore.get(startSequence, endSequence, messages); + } + + @Override + public int getNextSenderMsgSeqNum() throws IOException { + return messageStore.getNextSenderMsgSeqNum(); + } + + @Override + public int getNextTargetMsgSeqNum() throws IOException { + return messageStore.getNextTargetMsgSeqNum(); + } + + @Override + public void setNextSenderMsgSeqNum(final int next) throws IOException { + messageStore.setNextSenderMsgSeqNum(next); + } + + @Override + public void setNextTargetMsgSeqNum(final int next) throws IOException { + messageStore.setNextTargetMsgSeqNum(next); + } + + @Override + public void incrNextSenderMsgSeqNum() throws IOException { + messageStore.incrNextSenderMsgSeqNum(); + } + + @Override + public void incrNextTargetMsgSeqNum() throws IOException { + messageStore.incrNextTargetMsgSeqNum(); + } + + @Override + public Date getCreationTime() throws IOException { + return messageStore.getCreationTime(); + } + + @Override + public void reset() throws IOException { + messageStore.reset(); + } + + @Override + public void refresh() throws IOException { + messageStore.refresh(); + } + }; + } + } + + private class ListeningMessageFactory implements MessageFactory { + private final MessageFactory factory = new DefaultMessageFactory(); + private final CountDownLatch sentLogoutLatch; + + public ListeningMessageFactory(final CountDownLatch sentLogoutLatch) { + this.sentLogoutLatch = sentLogoutLatch; + } + + @Override + public Message create(final String beginString, final String msgType) { + if (MsgType.LOGOUT.equals(msgType) || MsgType.SEQUENCE_RESET.equals(msgType)) { + sentLogoutLatch.countDown(); + } + return factory.create(beginString, msgType); + } + + @Override + public Group create(final String beginString, final String msgType, final int correspondingFieldID) { + return factory.create(beginString, msgType, correspondingFieldID); + } + } + +} diff --git a/quickfixj-core/src/test/java/quickfix/SessionFactoryTestSupport.java b/quickfixj-core/src/test/java/quickfix/SessionFactoryTestSupport.java index c5c6d82a9..8d9ccd744 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionFactoryTestSupport.java +++ b/quickfixj-core/src/test/java/quickfix/SessionFactoryTestSupport.java @@ -2,74 +2,225 @@ import quickfix.field.DefaultApplVerID; +import java.net.InetAddress; +import java.util.Set; +import java.util.function.Supplier; + public class SessionFactoryTestSupport implements SessionFactory { private static final SessionFactoryTestSupport instance = new SessionFactoryTestSupport(); + @Override public Session create(SessionID sessionID, SessionSettings settings) throws ConfigError { - if (sessionID == null) { - sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); - } - return createSession(sessionID, new UnitTestApplication(), false); + return new Builder().setSessionId(sessionID) + .setCheckLatency(true).setMaxLatency(Session.DEFAULT_MAX_LATENCY) + .setCheckCompID(true) + .build(); } public static Session createSession(SessionID sessionID, Application application, - boolean isInitiator) { - return new Session(application, new MemoryStoreFactory(), sessionID, null, null, - getLogFactory(), new DefaultMessageFactory(), isInitiator - ? 30 - : 0); + boolean isInitiator) { + return new Builder().setSessionId(sessionID).setApplication(application).setIsInitiator(isInitiator) + .setCheckLatency(true).setMaxLatency(Session.DEFAULT_MAX_LATENCY) + .setCheckCompID(true) + .build(); } public static Session createFileStoreSession(SessionID sessionID, Application application, - boolean isInitiator, SessionSettings settings, SessionSchedule sessionSchedule) { - return new Session(application, new FileStoreFactory(settings), sessionID, null, - sessionSchedule, - getLogFactory(), new DefaultMessageFactory(), isInitiator - ? 30 - : 0); + boolean isInitiator, SessionSettings settings, SessionSchedule sessionSchedule) { + return new Builder().setSessionId(sessionID).setApplication(application).setIsInitiator(isInitiator) + .setMessageStoreFactory(new FileStoreFactory(settings)).setSessionSchedule(sessionSchedule) + .setCheckLatency(true).setMaxLatency(Session.DEFAULT_MAX_LATENCY) + .setCheckCompID(true) + .build(); } public static Session createSession(SessionID sessionID, Application application, - boolean isInitiator, boolean resetOnLogon, boolean validateSequenceNumbers) { - return new Session(application, new MemoryStoreFactory(), sessionID, null, null, - getLogFactory(), new DefaultMessageFactory(), isInitiator - ? 30 - : 0, false, 30, UtcTimestampPrecision.MILLIS, resetOnLogon, false, false, false, false, false, - true, false, 1.5, null, validateSequenceNumbers, new int[] { 5 }, false, false, false, true, - false, true, false, null, true, 0, false, false); + boolean isInitiator, boolean resetOnLogon, boolean validateSequenceNumbers) { + return new Builder().setSessionId(sessionID).setApplication(application).setIsInitiator(isInitiator) + .setResetOnLogon(resetOnLogon).setValidateSequenceNumbers(validateSequenceNumbers) + .setPersistMessages(true) + .build(); } public static Session createSession(SessionID sessionID, Application application, - boolean isInitiator, boolean resetOnLogon, boolean validateSequenceNumbers, - boolean useDataDictionary, DefaultApplVerID senderDefaultApplVerID) { - return new Session(application, new MemoryStoreFactory(), sessionID, - new DefaultDataDictionaryProvider(), null, getLogFactory(), - new DefaultMessageFactory(), isInitiator ? 30 : 0, false, 30, UtcTimestampPrecision.MILLIS, resetOnLogon, - false, false, false, false, false, true, false, 1.5, senderDefaultApplVerID, - validateSequenceNumbers, new int[] { 5 }, false, false, false, true, false, true, - false, null, true, 0, false, false); + boolean isInitiator, boolean resetOnLogon, boolean validateSequenceNumbers, + boolean useDataDictionary, DefaultApplVerID senderDefaultApplVerID) { + return new Builder().setSessionId(sessionID).setApplication(application).setIsInitiator(isInitiator) + .setDataDictionaryProvider(new DefaultDataDictionaryProvider()) + .setResetOnLogon(resetOnLogon).setValidateSequenceNumbers(validateSequenceNumbers) + .setPersistMessages(true).setSenderDefaultApplVerID(senderDefaultApplVerID) + .build(); } public static Session createSession(SessionID sessionID, Application application, - boolean isInitiator, boolean resetOnLogon) { + boolean isInitiator, boolean resetOnLogon) { return createSession(sessionID, application, isInitiator, resetOnLogon, false); } - public static Session createNonpersistedSession(SessionID sessionID, Application application, - boolean isInitiator) { - return new Session(application, new MemoryStoreFactory(), sessionID, null, null, - getLogFactory(), new DefaultMessageFactory(), isInitiator - ? 30 - : 0, false, 30, UtcTimestampPrecision.MILLIS, true, false, false, false, false, false, - false/*persistMessages*/, false, 1.5, null, true, new int[] { 5 }, false, false, - false, true, false, true, false, null, true, 0, false, false); + public static Session createNonpersistedSession(SessionID sessionID, Application application, boolean isInitiator) { + return new Builder().setSessionId(sessionID).setApplication(application).setIsInitiator(isInitiator) + .setResetOnLogon(true) + .build(); } public static Session createSession() throws ConfigError { return instance.create(null, null); } - private static LogFactory getLogFactory() { - return new SLF4JLogFactory(new SessionSettings()); + public static final class Builder { + private String beginString = "FIX.4.2"; + private String senderCompID = "SENDER"; + private String targetCompID = "TARGET"; + private boolean isInitiator = false; + private Supplier sessionIDSupplier = () -> new SessionID(beginString, senderCompID, targetCompID); + private Supplier applicationSupplier = UnitTestApplication::new; + private Supplier messageStoreFactorySupplier = MemoryStoreFactory::new; + private Supplier dataDictionaryProviderSupplier = () -> null; + private Supplier sessionScheduleSupplier = () -> null; + private Supplier logFactorySupplier = () -> new ScreenLogFactory(true, true, true); + private Supplier messageFactorySupplier = DefaultMessageFactory::new; + private Supplier sessionHeartbeatIntervalSupplier = () -> isInitiator ? 30 : 0; + private boolean checkLatency = false; + private int maxLatency = 30; + private UtcTimestampPrecision timestampPrecision = UtcTimestampPrecision.MILLIS; + private boolean resetOnLogon = false; + private boolean resetOnLogout = false; + private boolean resetOnDisconnect = false; + private boolean refreshMessageStoreAtLogon = false; + private boolean checkCompID = false; + private boolean redundantResentRequestsAllowed = false; + private boolean persistMessages = false; + private boolean useClosedRangeForResend = false; + private double testRequestDelayMultiplier = 1.5; + private DefaultApplVerID senderDefaultApplVerID = null; + private boolean validateSequenceNumbers = true; + private int[] logonIntervals = new int[]{5}; + private boolean resetOnError = false; + private boolean disconnectOnError = false; + private boolean disableHeartBeatCheck = false; + private boolean rejectInvalidMessage = true; + private boolean rejectMessageOnUnhandledException = false; + private boolean requiresOrigSendingTime = true; + private boolean forceResendWhenCorruptedStore = false; + private Set allowedRemoteAddresses = null; + private boolean validateIncomingMessage = true; + private int resendRequestChunkSize = 0; + private boolean enableNextExpectedMsgSeqNum = false; + private boolean enableLastMsgSeqNumProcessed = false; + + public Session build() { + return new Session(applicationSupplier.get(), messageStoreFactorySupplier.get(), sessionIDSupplier.get(), + dataDictionaryProviderSupplier.get(), sessionScheduleSupplier.get(), logFactorySupplier.get(), + messageFactorySupplier.get(), sessionHeartbeatIntervalSupplier.get(), checkLatency, maxLatency, + timestampPrecision, resetOnLogon, resetOnLogout, resetOnDisconnect, refreshMessageStoreAtLogon, + checkCompID, redundantResentRequestsAllowed, persistMessages, useClosedRangeForResend, + testRequestDelayMultiplier, senderDefaultApplVerID, validateSequenceNumbers, logonIntervals, + resetOnError, disconnectOnError, disableHeartBeatCheck, rejectInvalidMessage, + rejectMessageOnUnhandledException, requiresOrigSendingTime, forceResendWhenCorruptedStore, + allowedRemoteAddresses, validateIncomingMessage, resendRequestChunkSize, enableNextExpectedMsgSeqNum, + enableLastMsgSeqNumProcessed); + } + + public Builder setBeginString(final String beginString) { + this.beginString = beginString; + return this; + } + + public Builder setSenderCompID(final String senderCompID) { + this.senderCompID = senderCompID; + return this; + } + + public Builder setTargetCompID(final String targetCompID) { + this.targetCompID = targetCompID; + return this; + } + + public Builder setSessionId(final SessionID sessionId) { + if (sessionId != null) { + this.sessionIDSupplier = () -> sessionId; + } + return this; + } + + public Builder setApplication(final Application application) { + this.applicationSupplier = () -> application; + return this; + } + + public Builder setMessageStoreFactory(final MessageStoreFactory messageStoreFactory) { + this.messageStoreFactorySupplier = () -> messageStoreFactory; + return this; + } + + public Builder setDataDictionaryProvider(final DataDictionaryProvider dataDictionaryProvider) { + this.dataDictionaryProviderSupplier = () -> dataDictionaryProvider; + return this; + } + + public Builder setSessionSchedule(final SessionSchedule sessionSchedule) { + this.sessionScheduleSupplier = () -> sessionSchedule; + return this; + } + + public Builder setLogFactory(final LogFactory logFactory) { + this.logFactorySupplier = () -> logFactory; + return this; + } + + public Builder setMessageFactory(final MessageFactory messageFactory) { + this.messageFactorySupplier = () -> messageFactory; + return this; + } + + public Builder setIsInitiator(final boolean isInitiator) { + this.isInitiator = isInitiator; + return this; + } + + public Builder setSessionHeartbeatInterval(final int sessionHeartbeatInterval) { + this.sessionHeartbeatIntervalSupplier = () -> sessionHeartbeatInterval; + return this; + } + + public Builder setCheckLatency(final boolean checkLatency) { + this.checkLatency = checkLatency; + return this; + } + + public Builder setMaxLatency(final int maxLatency) { + this.maxLatency = maxLatency; + return this; + } + + public Builder setResetOnLogon(final boolean resetOnLogon) { + this.resetOnLogon = resetOnLogon; + return this; + } + + public Builder setCheckCompID(final boolean checkCompID) { + this.checkCompID = checkCompID; + return this; + } + + public Builder setValidateSequenceNumbers(final boolean validateSequenceNumbers) { + this.validateSequenceNumbers = validateSequenceNumbers; + return this; + } + + public Builder setPersistMessages(final boolean persistMessages) { + this.persistMessages = persistMessages; + return this; + } + + public Builder setSenderDefaultApplVerID(final DefaultApplVerID senderDefaultApplVerID) { + this.senderDefaultApplVerID = senderDefaultApplVerID; + return this; + } + + public Builder setEnableNextExpectedMsgSeqNum(final boolean enableNextExpectedMsgSeqNum) { + this.enableNextExpectedMsgSeqNum = enableNextExpectedMsgSeqNum; + return this; + } } } From 7ea2bb5a3f5b0e57535f993ab272b3e19b705a04 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Mon, 17 Jul 2017 15:34:27 +0200 Subject: [PATCH 093/165] - clean up resources after unit tests - shutdown executors, set threads to daemon, cancel futures... --- .../java/quickfix/mina/SessionConnector.java | 2 +- .../SessionDisconnectConcurrentlyTest.java | 18 ++++++++++++------ .../test/java/quickfix/SessionResetTest.java | 4 ++++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java b/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java index d34737951..e20034a67 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java +++ b/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java @@ -292,7 +292,7 @@ protected void startSessionTimer() { protected void stopSessionTimer() { if (sessionTimerFuture != null) { - if (sessionTimerFuture.cancel(false)) + if (sessionTimerFuture.cancel(true)) log.info("SessionTimer canceled"); } } diff --git a/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java b/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java index 8f579c61f..48cad91c5 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java @@ -258,9 +258,13 @@ public void onLogout(SessionID sessionId) { }; final SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX44, "SENDER", "TARGET"); - - final Session session = SessionFactoryTestSupport.createSession(sessionID, application, true, false); - + final Session session = new SessionFactoryTestSupport.Builder() + .setSessionId(sessionID) + .setApplication(application) + .setLogFactory(null) + .setResetOnLogon(false) + .setIsInitiator(true) + .build(); final UnitTestResponder responder = new UnitTestResponder(); session.setResponder(responder); session.addStateListener(responder); @@ -284,13 +288,15 @@ public void onLogout(SessionID sessionId) { ptpe.pause(); for (int j=0; j<1000; j++) { - ptpe.submit(new Thread(() -> { + final Thread thread = new Thread(() -> { try { session.disconnect("No reason", false); } catch (IOException e) { e.printStackTrace(); } - }, "disconnectThread"+j)); + }, "disconnectThread"+j); + thread.setDaemon(true); + ptpe.submit(thread); } ptpe.resume(); @@ -342,5 +348,5 @@ public void onMissedHeartBeat() { public void onHeartBeatTimeout() { } } - + } diff --git a/quickfixj-core/src/test/java/quickfix/SessionResetTest.java b/quickfixj-core/src/test/java/quickfix/SessionResetTest.java index c5703d14e..77c79b537 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionResetTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionResetTest.java @@ -62,12 +62,14 @@ public void testSessionResetDeadlock() throws Exception { e.printStackTrace(); } }, "SessionReset"); + resetThread.setDaemon(true); Thread messageSender = new Thread(() -> { for (int i = 2; i <= NUMBER_OF_ADMIN_MESSAGES; i++) { session.send(createAdminMessage(i)); } }, "SessionSend"); + messageSender.setDaemon(true); // submit threads to pausable executor and try to let them start at the same time PausableThreadPoolExecutor ptpe = new PausableThreadPoolExecutor(); @@ -81,6 +83,8 @@ public void testSessionResetDeadlock() throws Exception { long[] threadIds = bean.findDeadlockedThreads(); assertNull("no threads should be deadlocked", threadIds); assertTrue("session should have been reset", responder.onResetCalled); + + ptpe.shutdownNow(); } private Message createAdminMessage(int sequence) { From 8055b889e9b1d719db9b27df89b013734357ecf2 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Mon, 17 Jul 2017 16:48:56 +0200 Subject: [PATCH 094/165] - added test for QFJ-907 which has already been fixed by QFJ-849 --- .../java/quickfix/SocketInitiatorTest.java | 144 +++++++++++++++++- 1 file changed, 143 insertions(+), 1 deletion(-) diff --git a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java index 01d05059f..b3f39fe00 100644 --- a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java +++ b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java @@ -32,21 +32,26 @@ import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; +import java.net.ServerSocket; +import java.net.Socket; import java.util.HashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; +import static junit.framework.TestCase.assertNotNull; import org.apache.mina.util.AvailablePortFinder; import org.junit.After; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import org.junit.Ignore; import quickfix.field.MsgType; @@ -254,6 +259,143 @@ public void testDoubleStartOfInitiator() throws Exception { } } + private interface LogSessionStateListener extends Log, SessionStateListener {} + + // QFJ-907 + @Test + public void testConnectedSocketsAreClosedAfterInitiatorClosed() throws Exception { + final ServerSocket serverSocket = new ServerSocket(0); + final int port = serverSocket.getLocalPort(); + + final AtomicBoolean socketConnected = new AtomicBoolean(false); + Thread socketThread = new Thread() { + public void run() { + Socket socket = null; + try { + socket = serverSocket.accept(); + socketConnected.set(true); + final InputStream is = socket.getInputStream(); + while (is.read() != -1) { + } + } catch (Exception e) { + } finally { + try { + serverSocket.close(); + } catch (Exception e) { + } + try { + socket.close(); + } catch (Exception e) { + } + socketConnected.set(false); + } + } + }; + + socketThread.setDaemon(true); + socketThread.start(); + + final SessionSettings settings = new SessionSettings(); + settings.setString("StartTime", "00:00:00"); + settings.setString("EndTime", "00:00:00"); + settings.setString("ReconnectInterval", "30"); + settings.setString("HeartBtInt", "30"); + + final SessionID sessionId = new SessionID("FIX.4.4", "SENDER", "TARGET"); + settings.setString(sessionId, "BeginString", "FIX.4.4"); + + settings.setString("ConnectionType", "initiator"); + settings.setLong(sessionId, "SocketConnectPort", port); + settings.setString(sessionId, "SocketConnectHost", "localhost"); + + final AtomicInteger onConnectCallCount = new AtomicInteger(0); + final AtomicInteger onDisconnectCallCount = new AtomicInteger(0); + + LogSessionStateListener logSessionStateListener = new LogSessionStateListener() { + @Override + public void clear() { + } + + @Override + public void onIncoming(String message) { + } + + @Override + public void onOutgoing(String message) { + } + + @Override + public void onEvent(String text) { + } + + @Override + public void onErrorEvent(String text) { + } + + @Override + public void onConnect() { + onConnectCallCount.incrementAndGet(); + } + + @Override + public void onDisconnect() { + onDisconnectCallCount.incrementAndGet(); + } + + @Override + public void onLogon() { + } + + @Override + public void onLogout() { + } + + @Override + public void onReset() { + } + + @Override + public void onRefresh() { + } + + @Override + public void onMissedHeartBeat() { + } + + @Override + public void onHeartBeatTimeout() { + } + }; + + LogFactory logFactory = new LogFactory() { + @Override + public Log create() { + return logSessionStateListener; + } + + @Override + public Log create(SessionID sessionID) { + return logSessionStateListener; + } + }; + + final SocketInitiator initiator = new SocketInitiator(new ApplicationAdapter(), new MemoryStoreFactory(), settings, + logFactory, new DefaultMessageFactory()); + initiator.start(); + + Thread.sleep(5000L); + assertTrue(socketConnected.get()); // make sure socket is connected + assertEquals(1, onConnectCallCount.intValue()); + assertEquals(0, onDisconnectCallCount.intValue()); + + initiator.stop(); + + Thread.sleep(5000L); + assertFalse(socketConnected.get()); // make sure socket is NOT connected after initiator is stopped + assertEquals(1, onConnectCallCount.intValue()); + assertEquals(1, onDisconnectCallCount.intValue()); + } + private void doTestOfRestart(SessionID clientSessionID, ClientApplication clientApplication, final Initiator initiator, File messageLog, int port) throws InterruptedException, ConfigError { ServerThread serverThread = new ServerThread(port); From 07be36d75390fa6f7577e71fde1e6eb7ab9186d3 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Tue, 18 Jul 2017 10:41:54 +0200 Subject: [PATCH 095/165] - used distinct session log where possible - introduced constant for attribute QFJ_RESET_IO_CONNECTOR - generate FIX50SP2 fields as last step --- quickfixj-core/pom.xml | 12 ++++++------ .../java/quickfix/mina/AbstractIoHandler.java | 15 ++++++++++----- .../java/quickfix/mina/IoSessionResponder.java | 2 +- .../main/java/quickfix/mina/SessionConnector.java | 3 ++- .../quickfix/mina/acceptor/AcceptorIoHandler.java | 4 ++-- .../mina/initiator/InitiatorIoHandler.java | 4 ++-- .../mina/initiator/IoSessionInitiator.java | 11 ++++------- 7 files changed, 27 insertions(+), 24 deletions(-) diff --git a/quickfixj-core/pom.xml b/quickfixj-core/pom.xml index 49ce8b289..6b17d946d 100644 --- a/quickfixj-core/pom.xml +++ b/quickfixj-core/pom.xml @@ -278,25 +278,25 @@ - fix50sp2 + fix50sp1 generate - ../quickfixj-messages/quickfixj-messages-fix50sp2/src/main/resources/FIX50SP2.modified.xml - quickfix.fix50sp2 + ../quickfixj-messages/quickfixj-messages-fix50sp1/src/main/resources/FIX50SP1.modified.xml + quickfix.fix50sp1 quickfix.field ${generator.decimal} - fix50sp1 + fix50sp2 generate - ../quickfixj-messages/quickfixj-messages-fix50sp1/src/main/resources/FIX50SP1.modified.xml - quickfix.fix50sp1 + ../quickfixj-messages/quickfixj-messages-fix50sp2/src/main/resources/FIX50SP2.modified.xml + quickfix.fix50sp2 quickfix.field ${generator.decimal} diff --git a/quickfixj-core/src/main/java/quickfix/mina/AbstractIoHandler.java b/quickfixj-core/src/main/java/quickfix/mina/AbstractIoHandler.java index cf3a026a0..f33dd3ab4 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/AbstractIoHandler.java +++ b/quickfixj-core/src/main/java/quickfix/mina/AbstractIoHandler.java @@ -87,10 +87,14 @@ public void exceptionCaught(IoSession ioSession, Throwable cause) throws Excepti ioSession.closeNow(); } } finally { - ioSession.setAttribute("QFJ_RESET_IO_CONNECTOR", Boolean.TRUE); + ioSession.setAttribute(SessionConnector.QFJ_RESET_IO_CONNECTOR, Boolean.TRUE); } } else { - log.error(reason, cause); + if (quickFixSession != null) { + LogUtil.logThrowable(quickFixSession.getLog(), reason, cause); + } else { + log.error(reason, cause); + } } } @@ -121,16 +125,17 @@ public void messageReceived(IoSession ioSession, Object message) throws Exceptio SessionID remoteSessionID = MessageUtils.getReverseSessionID(messageString); Session quickFixSession = findQFSession(ioSession, remoteSessionID); if (quickFixSession != null) { - quickFixSession.getLog().onIncoming(messageString); + final Log sessionLog = quickFixSession.getLog(); + sessionLog.onIncoming(messageString); try { Message fixMessage = parse(quickFixSession, messageString); processMessage(ioSession, fixMessage); } catch (InvalidMessage e) { if (MsgType.LOGON.equals(MessageUtils.getMessageType(messageString))) { - log.error("Invalid LOGON message, disconnecting: " + e.getMessage()); + sessionLog.onErrorEvent("Invalid LOGON message, disconnecting: " + e.getMessage()); ioSession.closeNow(); } else { - log.error("Invalid message: " + e.getMessage()); + sessionLog.onErrorEvent("Invalid message: " + e.getMessage()); } } } else { diff --git a/quickfixj-core/src/main/java/quickfix/mina/IoSessionResponder.java b/quickfixj-core/src/main/java/quickfix/mina/IoSessionResponder.java index d7351d5a3..840fb838b 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/IoSessionResponder.java +++ b/quickfixj-core/src/main/java/quickfix/mina/IoSessionResponder.java @@ -83,7 +83,7 @@ public void disconnect() { // close event from being processed by this thread (if // this thread is the MINA IO processor thread. ioSession.closeOnFlush(); - ioSession.setAttribute("QFJ_RESET_IO_CONNECTOR", Boolean.TRUE); + ioSession.setAttribute(SessionConnector.QFJ_RESET_IO_CONNECTOR, Boolean.TRUE); } @Override diff --git a/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java b/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java index e20034a67..77da1aed9 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java +++ b/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java @@ -58,7 +58,8 @@ public abstract class SessionConnector implements Connector { protected static final int DEFAULT_QUEUE_CAPACITY = 10000; public static final String SESSIONS_PROPERTY = "sessions"; - public final static String QF_SESSION = "QF_SESSION"; + public static final String QF_SESSION = "QF_SESSION"; + public static final String QFJ_RESET_IO_CONNECTOR = "QFJ_RESET_IO_CONNECTOR"; protected final Logger log = LoggerFactory.getLogger(getClass()); diff --git a/quickfixj-core/src/main/java/quickfix/mina/acceptor/AcceptorIoHandler.java b/quickfixj-core/src/main/java/quickfix/mina/acceptor/AcceptorIoHandler.java index 37921aafe..75664eb27 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/acceptor/AcceptorIoHandler.java +++ b/quickfixj-core/src/main/java/quickfix/mina/acceptor/AcceptorIoHandler.java @@ -55,7 +55,7 @@ public AcceptorIoHandler(AcceptorSessionProvider sessionProvider, @Override public void sessionCreated(IoSession session) throws Exception { super.sessionCreated(session); - log.info("MINA session created: " + "local=" + session.getLocalAddress() + ", " + log.info("MINA session created: local=" + session.getLocalAddress() + ", " + session.getClass() + ", remote=" + session.getRemoteAddress()); } @@ -91,7 +91,7 @@ protected void processMessage(IoSession protocolSession, Message message) throws final ApplVerID applVerID = new ApplVerID( message.getString(DefaultApplVerID.FIELD)); qfSession.setTargetDefaultApplicationVersionID(applVerID); - log.info("Setting DefaultApplVerID (" + DefaultApplVerID.FIELD + "=" + sessionLog.onEvent("Setting DefaultApplVerID (" + DefaultApplVerID.FIELD + "=" + applVerID.getValue() + ") from Logon"); } } diff --git a/quickfixj-core/src/main/java/quickfix/mina/initiator/InitiatorIoHandler.java b/quickfixj-core/src/main/java/quickfix/mina/initiator/InitiatorIoHandler.java index 1b40c2d25..08a6d64e9 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/initiator/InitiatorIoHandler.java +++ b/quickfixj-core/src/main/java/quickfix/mina/initiator/InitiatorIoHandler.java @@ -54,7 +54,7 @@ public void sessionCreated(IoSession session) throws Exception { networkingOptions.getSynchronousWrites(), networkingOptions.getSynchronousWriteTimeout(), quickfixSession.getMaxScheduledWriteRequests())); - log.info("MINA session created for " + quickfixSession.getSessionID() + ": local=" + quickfixSession.getLog().onEvent("MINA session created: " + quickfixSession.getSessionID() + ": local=" + session.getLocalAddress() + ", " + session.getClass() + ", remote=" + session.getRemoteAddress()); } @@ -67,7 +67,7 @@ protected void processMessage(IoSession protocolSession, Message message) throws if (message.isSetField(DefaultApplVerID.FIELD)) { final ApplVerID applVerID = new ApplVerID(message.getString(DefaultApplVerID.FIELD)); quickfixSession.setTargetDefaultApplicationVersionID(applVerID); - log.info("Setting DefaultApplVerID (" + DefaultApplVerID.FIELD + "=" + quickfixSession.getLog().onEvent("Setting DefaultApplVerID (" + DefaultApplVerID.FIELD + "=" + applVerID.getValue() + ") from Logon"); } } diff --git a/quickfixj-core/src/main/java/quickfix/mina/initiator/IoSessionInitiator.java b/quickfixj-core/src/main/java/quickfix/mina/initiator/IoSessionInitiator.java index b2ad31721..0fa9b0fca 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/initiator/IoSessionInitiator.java +++ b/quickfixj-core/src/main/java/quickfix/mina/initiator/IoSessionInitiator.java @@ -26,8 +26,6 @@ import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.proxy.ProxyConnector; import org.apache.mina.transport.socket.SocketConnector; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import quickfix.ConfigError; import quickfix.LogUtil; import quickfix.Session; @@ -51,6 +49,7 @@ import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import quickfix.mina.SessionConnector; public class IoSessionInitiator { private final static long CONNECT_POLL_TIMEOUT = 2000L; @@ -58,7 +57,6 @@ public class IoSessionInitiator { private final ConnectTask reconnectTask; private Future reconnectFuture; - protected final static Logger log = LoggerFactory.getLogger("display." + IoSessionInitiator.class.getName()); public IoSessionInitiator(Session fixSession, SocketAddress[] socketAddresses, SocketAddress localAddress, int[] reconnectIntervalInSeconds, @@ -81,7 +79,7 @@ public IoSessionInitiator(Session fixSession, SocketAddress[] socketAddresses, throw new ConfigError(e); } - log.info("[" + fixSession.getSessionID() + "] " + Arrays.asList(socketAddresses)); + fixSession.getLog().onEvent("Configured socket addresses for session: " + Arrays.asList(socketAddresses)); } private static class ConnectTask implements Runnable { @@ -332,17 +330,16 @@ public Session getFixSession() { } private void resetIoConnector() { - if (ioSession != null && Boolean.TRUE.equals(ioSession.getAttribute("QFJ_RESET_IO_CONNECTOR"))) { + if (ioSession != null && Boolean.TRUE.equals(ioSession.getAttribute(SessionConnector.QFJ_RESET_IO_CONNECTOR))) { try { setupIoConnector(); - log.info("[" + fixSession.getSessionID() + "] - reset IoConnector"); if (connectFuture != null) { connectFuture.cancel(); } connectFuture = null; ioSession = null; } catch (Throwable e) { - log.error("[" + fixSession.getSessionID() + "] - Exception during resetIoConnector call", e); + LogUtil.logThrowable(fixSession.getLog(), "Exception during resetIoConnector call", e); } } } From b2bdce5da6fe87fc6b3d00aed663659e50427ae4 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Tue, 18 Jul 2017 10:49:11 +0200 Subject: [PATCH 096/165] - removed sessionID from log string since the distinct session log is used anyway --- .../main/java/quickfix/mina/initiator/InitiatorIoHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickfixj-core/src/main/java/quickfix/mina/initiator/InitiatorIoHandler.java b/quickfixj-core/src/main/java/quickfix/mina/initiator/InitiatorIoHandler.java index 08a6d64e9..dd1033b18 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/initiator/InitiatorIoHandler.java +++ b/quickfixj-core/src/main/java/quickfix/mina/initiator/InitiatorIoHandler.java @@ -54,7 +54,7 @@ public void sessionCreated(IoSession session) throws Exception { networkingOptions.getSynchronousWrites(), networkingOptions.getSynchronousWriteTimeout(), quickfixSession.getMaxScheduledWriteRequests())); - quickfixSession.getLog().onEvent("MINA session created: " + quickfixSession.getSessionID() + ": local=" + quickfixSession.getLog().onEvent("MINA session created: local=" + session.getLocalAddress() + ", " + session.getClass() + ", remote=" + session.getRemoteAddress()); } From 5328e4b8d209ef8fb7d911609ee75c8b9c25103e Mon Sep 17 00:00:00 2001 From: Christoph John Date: Wed, 19 Jul 2017 14:53:39 +0200 Subject: [PATCH 097/165] QFJ-923: FileStore is leaking file handles (#124) - prevent calling Session.resetState() concurrently --- quickfixj-core/src/main/java/quickfix/Session.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index d2ac80c1d..b8d71efb9 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -394,6 +394,7 @@ public class Session implements Closeable { private int maxScheduledWriteRequests = 0; private final AtomicBoolean isResetting = new AtomicBoolean(); + private final AtomicBoolean isResettingState = new AtomicBoolean(); private final ListenerSupport stateListeners = new ListenerSupport(SessionStateListener.class); private final SessionStateListener stateListener = (SessionStateListener) stateListeners @@ -2542,8 +2543,15 @@ private void enqueueMessage(final Message msg, final int msgSeqNum) { } private void resetState() { - state.reset(); - stateListener.onReset(); + if (!isResettingState.compareAndSet(false, true)) { + return; + } + try { + state.reset(); + stateListener.onReset(); + } finally { + isResettingState.set(false); + } } /** From fbddaf35d09afe269870e1a207a7239e2758704a Mon Sep 17 00:00:00 2001 From: Christoph John Date: Fri, 21 Jul 2017 10:28:26 +0200 Subject: [PATCH 098/165] - deprecated block() methods in SocketAcceptor and SocketInitiator since they are likely to cause deadlocks (#125) - the start() methods should be used instead --- quickfixj-core/src/main/java/quickfix/Connector.java | 3 ++- quickfixj-core/src/main/java/quickfix/SocketAcceptor.java | 4 ++++ quickfixj-core/src/main/java/quickfix/SocketInitiator.java | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/quickfixj-core/src/main/java/quickfix/Connector.java b/quickfixj-core/src/main/java/quickfix/Connector.java index a4d1633ae..d7c09c26c 100644 --- a/quickfixj-core/src/main/java/quickfix/Connector.java +++ b/quickfixj-core/src/main/java/quickfix/Connector.java @@ -55,10 +55,11 @@ public interface Connector { * Start accepting connections. This method blocks until stop is called from * another thread. * This method must not be called by several threads concurrently. - * + * @deprecated Use start() instead. * @throws ConfigError Problem with acceptor configuration. * @throws RuntimeError Other unspecified error */ + @Deprecated void block() throws ConfigError, RuntimeError; /** diff --git a/quickfixj-core/src/main/java/quickfix/SocketAcceptor.java b/quickfixj-core/src/main/java/quickfix/SocketAcceptor.java index 5f683e6e1..1b8eb6b82 100644 --- a/quickfixj-core/src/main/java/quickfix/SocketAcceptor.java +++ b/quickfixj-core/src/main/java/quickfix/SocketAcceptor.java @@ -70,6 +70,10 @@ public SocketAcceptor(SessionFactory sessionFactory, SessionSettings settings) t } @Override + @Deprecated + /** + * Use SocketAcceptor.start(). + */ public void block() throws ConfigError, RuntimeError { initialize(false); } diff --git a/quickfixj-core/src/main/java/quickfix/SocketInitiator.java b/quickfixj-core/src/main/java/quickfix/SocketInitiator.java index 18d12ff6b..d55ad8536 100644 --- a/quickfixj-core/src/main/java/quickfix/SocketInitiator.java +++ b/quickfixj-core/src/main/java/quickfix/SocketInitiator.java @@ -79,6 +79,10 @@ public SocketInitiator(SessionFactory sessionFactory, SessionSettings settings, } @Override + @Deprecated + /** + * Use SocketInitiator.start(). + */ public void block() throws ConfigError, RuntimeError { initialize(false); } From cf1b0b2bf918ddb2eb22f51b941e3427b9f774da Mon Sep 17 00:00:00 2001 From: Christoph John Date: Mon, 24 Jul 2017 15:31:22 +0200 Subject: [PATCH 099/165] QFJ-914: Generate and package javadoc for release build (#128) - re-enabled generation of javadoc for FIX field and message classes - if you do not want this, then -Dmaven.javadoc.skip=true is your friend :) --- pom.xml | 3 --- quickfixj-core/pom.xml | 4 ---- quickfixj-distribution/pom.xml | 2 +- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 32e925e90..00f4f3cb4 100644 --- a/pom.xml +++ b/pom.xml @@ -158,9 +158,6 @@ org.apache.maven.plugins maven-javadoc-plugin ${maven-javadoc-plugin-version} - - quickfix.fix* - attach-javadocs diff --git a/quickfixj-core/pom.xml b/quickfixj-core/pom.xml index 6b17d946d..d4e14a904 100644 --- a/quickfixj-core/pom.xml +++ b/quickfixj-core/pom.xml @@ -395,10 +395,6 @@ true - - maven-javadoc-plugin - ${maven-javadoc-plugin-version} - maven-jxr-plugin 2.5 diff --git a/quickfixj-distribution/pom.xml b/quickfixj-distribution/pom.xml index 1b842f1ab..3d0b28848 100644 --- a/quickfixj-distribution/pom.xml +++ b/quickfixj-distribution/pom.xml @@ -151,7 +151,7 @@ protected - 1536m + 2g true From bfe54697b7fc2caa82baa0a8de0fd9deadbba608 Mon Sep 17 00:00:00 2001 From: Guido Medina Date: Mon, 24 Jul 2017 11:39:35 +0100 Subject: [PATCH 100/165] IntelliJ inspections corrected and some dependencies updated. --- pom.xml | 4 +-- quickfixj-codegenerator/pom.xml | 2 +- .../src/main/java/quickfix/FieldMap.java | 4 +-- .../src/main/java/quickfix/JdbcUtil.java | 2 +- .../src/main/java/quickfix/Session.java | 6 ++-- .../main/java/quickfix/UtcTimeOnlyField.java | 4 +-- .../main/java/quickfix/UtcTimeStampField.java | 4 +-- .../field/converter/UtcDateOnlyConverter.java | 2 +- .../field/converter/UtcTimeOnlyConverter.java | 2 +- .../converter/UtcTimestampConverter.java | 2 +- .../mina/ssl/X509TrustManagerWrapper.java | 2 +- .../src/test/java/quickfix/SessionTest.java | 1 - .../java/quickfix/SocketInitiatorTest.java | 36 +++++++++---------- ...ngleThreadedEventHandlingStrategyTest.java | 4 +-- .../mina/message/FIXMessageDecoderTest.java | 5 +-- quickfixj-dictgenerator/pom.xml | 2 +- .../quickfixj/dictgenerator/Repository.java | 5 ++- .../examples/banzai/ui/OrderEntryPanel.java | 1 + 18 files changed, 43 insertions(+), 45 deletions(-) diff --git a/pom.xml b/pom.xml index 32e925e90..d2685f533 100644 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,7 @@ - 3.3.9 + 3.5.0 @@ -77,7 +77,7 @@ 3.6.1 3.0.2 2.20 - 3.7 + 3.8 3.0.1 2.10.4 3.0.0 diff --git a/quickfixj-codegenerator/pom.xml b/quickfixj-codegenerator/pom.xml index eca44bf2f..d3e18bf57 100644 --- a/quickfixj-codegenerator/pom.xml +++ b/quickfixj-codegenerator/pom.xml @@ -35,7 +35,7 @@ net.sf.saxon Saxon-HE - 9.8.0-2 + 9.8.0-3 diff --git a/quickfixj-core/src/main/java/quickfix/FieldMap.java b/quickfixj-core/src/main/java/quickfix/FieldMap.java index 24371a546..f7edfe408 100644 --- a/quickfixj-core/src/main/java/quickfix/FieldMap.java +++ b/quickfixj-core/src/main/java/quickfix/FieldMap.java @@ -189,7 +189,7 @@ public void setUtcTimeStamp(int field, LocalDateTime value) { } public void setUtcTimeStamp(int field, LocalDateTime value, boolean includeMilliseconds) { - setField(new StringField(field, UtcTimestampConverter.convert(value, (includeMilliseconds == true) ? UtcTimestampPrecision.MILLIS : UtcTimestampPrecision.SECONDS))); + setField(new StringField(field, UtcTimestampConverter.convert(value, includeMilliseconds ? UtcTimestampPrecision.MILLIS : UtcTimestampPrecision.SECONDS))); } public void setUtcTimeStamp(int field, LocalDateTime value, UtcTimestampPrecision precision) { @@ -201,7 +201,7 @@ public void setUtcTimeOnly(int field, LocalTime value) { } public void setUtcTimeOnly(int field, LocalTime value, boolean includeMilliseconds) { - setField(new StringField(field, UtcTimeOnlyConverter.convert(value, (includeMilliseconds == true) ? UtcTimestampPrecision.MILLIS : UtcTimestampPrecision.SECONDS))); + setField(new StringField(field, UtcTimeOnlyConverter.convert(value, includeMilliseconds ? UtcTimestampPrecision.MILLIS : UtcTimestampPrecision.SECONDS))); } public void setUtcTimeOnly(int field, LocalTime value, UtcTimestampPrecision precision) { diff --git a/quickfixj-core/src/main/java/quickfix/JdbcUtil.java b/quickfixj-core/src/main/java/quickfix/JdbcUtil.java index d97d524e0..14ffc259e 100644 --- a/quickfixj-core/src/main/java/quickfix/JdbcUtil.java +++ b/quickfixj-core/src/main/java/quickfix/JdbcUtil.java @@ -39,7 +39,7 @@ class JdbcUtil { static final String CONNECTION_POOL_ALIAS = "quickfixj"; private static final Map dataSources = new ConcurrentHashMap<>(); - private static AtomicInteger dataSourceCounter = new AtomicInteger(); + private static final AtomicInteger dataSourceCounter = new AtomicInteger(); static DataSource getDataSource(SessionSettings settings, SessionID sessionID) throws ConfigError, FieldConvertError { diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index b8d71efb9..21ebf2cd9 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -2801,18 +2801,18 @@ public void setTargetDefaultApplicationVersionID(ApplVerID applVerID) { } private static String extractNumber(String txt, int from) { - String ret = ""; + final StringBuilder ret = new StringBuilder(); for (int i = from; i != txt.length(); ++i) { final char c = txt.charAt(i); if (c >= '0' && c <= '9') { - ret += c; + ret.append(c); } else { if (ret.length() != 0) { break; } } } - return ret.trim(); + return ret.toString(); } protected static Integer extractExpectedSequenceNumber(String txt) { diff --git a/quickfixj-core/src/main/java/quickfix/UtcTimeOnlyField.java b/quickfixj-core/src/main/java/quickfix/UtcTimeOnlyField.java index be311a9d0..f7ea1d73c 100644 --- a/quickfixj-core/src/main/java/quickfix/UtcTimeOnlyField.java +++ b/quickfixj-core/src/main/java/quickfix/UtcTimeOnlyField.java @@ -43,12 +43,12 @@ protected UtcTimeOnlyField(int field, LocalTime data, UtcTimestampPrecision prec public UtcTimeOnlyField(int field, boolean includeMilliseconds) { super(field, LocalTime.now()); - this.precision = (includeMilliseconds == true) ? UtcTimestampPrecision.MILLIS : UtcTimestampPrecision.SECONDS; + this.precision = includeMilliseconds ? UtcTimestampPrecision.MILLIS : UtcTimestampPrecision.SECONDS; } protected UtcTimeOnlyField(int field, LocalTime data, boolean includeMilliseconds) { super(field, data); - this.precision = (includeMilliseconds == true) ? UtcTimestampPrecision.MILLIS : UtcTimestampPrecision.SECONDS; + this.precision = includeMilliseconds ? UtcTimestampPrecision.MILLIS : UtcTimestampPrecision.SECONDS; } public UtcTimestampPrecision getPrecision() { diff --git a/quickfixj-core/src/main/java/quickfix/UtcTimeStampField.java b/quickfixj-core/src/main/java/quickfix/UtcTimeStampField.java index 085dd6e63..92c391630 100644 --- a/quickfixj-core/src/main/java/quickfix/UtcTimeStampField.java +++ b/quickfixj-core/src/main/java/quickfix/UtcTimeStampField.java @@ -43,7 +43,7 @@ protected UtcTimeStampField(int field, LocalDateTime data, UtcTimestampPrecision public UtcTimeStampField(int field, boolean includeMilliseconds) { super(field, LocalDateTime.now()); - this.precision = (includeMilliseconds == true) ? UtcTimestampPrecision.MILLIS : UtcTimestampPrecision.SECONDS; + this.precision = includeMilliseconds ? UtcTimestampPrecision.MILLIS : UtcTimestampPrecision.SECONDS; } public UtcTimeStampField(int field, UtcTimestampPrecision precision) { @@ -53,7 +53,7 @@ public UtcTimeStampField(int field, UtcTimestampPrecision precision) { protected UtcTimeStampField(int field, LocalDateTime data, boolean includeMilliseconds) { super(field, data); - this.precision = (includeMilliseconds == true) ? UtcTimestampPrecision.MILLIS : UtcTimestampPrecision.SECONDS; + this.precision = includeMilliseconds ? UtcTimestampPrecision.MILLIS : UtcTimestampPrecision.SECONDS; } public UtcTimestampPrecision getPrecision() { diff --git a/quickfixj-core/src/main/java/quickfix/field/converter/UtcDateOnlyConverter.java b/quickfixj-core/src/main/java/quickfix/field/converter/UtcDateOnlyConverter.java index bf47b0335..cdaa67786 100644 --- a/quickfixj-core/src/main/java/quickfix/field/converter/UtcDateOnlyConverter.java +++ b/quickfixj-core/src/main/java/quickfix/field/converter/UtcDateOnlyConverter.java @@ -34,7 +34,7 @@ */ public class UtcDateOnlyConverter extends AbstractDateTimeConverter { - static String TYPE = "date"; + static final String TYPE = "date"; static final int DATE_LENGTH = 8; // SimpleDateFormats are not thread safe. A thread local is being // used to maintain high concurrency among multiple session threads diff --git a/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimeOnlyConverter.java b/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimeOnlyConverter.java index 97a03b942..fbc2d609f 100644 --- a/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimeOnlyConverter.java +++ b/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimeOnlyConverter.java @@ -36,7 +36,7 @@ */ public class UtcTimeOnlyConverter extends AbstractDateTimeConverter { - static String TYPE = "time"; + static final String TYPE = "time"; static final int LENGTH_INCL_SECONDS = 8; static final int LENGTH_INCL_MILLIS = 12; static final int LENGTH_INCL_MICROS = 15; diff --git a/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimestampConverter.java b/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimestampConverter.java index 17601fa6a..d792ad2e0 100644 --- a/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimestampConverter.java +++ b/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimestampConverter.java @@ -38,7 +38,7 @@ */ public class UtcTimestampConverter extends AbstractDateTimeConverter { - static String TYPE = "timestamp"; + static final String TYPE = "timestamp"; static final int LENGTH_INCL_SECONDS = 17; static final int LENGTH_INCL_MILLIS = 21; static final int LENGTH_INCL_MICROS = 24; diff --git a/quickfixj-core/src/main/java/quickfix/mina/ssl/X509TrustManagerWrapper.java b/quickfixj-core/src/main/java/quickfix/mina/ssl/X509TrustManagerWrapper.java index 8c273a2ab..6a52c914b 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/ssl/X509TrustManagerWrapper.java +++ b/quickfixj-core/src/main/java/quickfix/mina/ssl/X509TrustManagerWrapper.java @@ -48,7 +48,7 @@ public static TrustManager[] wrap(TrustManager[] trustManagers) { return wrappers; } - private X509TrustManager trustManager; + private final X509TrustManager trustManager; public X509TrustManagerWrapper(final X509TrustManager trustManager) { this.trustManager = trustManager; diff --git a/quickfixj-core/src/test/java/quickfix/SessionTest.java b/quickfixj-core/src/test/java/quickfix/SessionTest.java index 9e7947900..0e185d857 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionTest.java @@ -51,7 +51,6 @@ import java.util.TimeZone; import static org.junit.Assert.*; -import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.*; import static quickfix.SessionFactoryTestSupport.createSession; diff --git a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java index b3f39fe00..8590886be 100644 --- a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java +++ b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java @@ -268,29 +268,27 @@ public void testConnectedSocketsAreClosedAfterInitiatorClosed() throws Exception final int port = serverSocket.getLocalPort(); final AtomicBoolean socketConnected = new AtomicBoolean(false); - Thread socketThread = new Thread() { - public void run() { - Socket socket = null; + Thread socketThread = new Thread(() -> { + Socket socket = null; + try { + socket = serverSocket.accept(); + socketConnected.set(true); + final InputStream is = socket.getInputStream(); + while (is.read() != -1) { + } + } catch (Exception e) { + } finally { try { - socket = serverSocket.accept(); - socketConnected.set(true); - final InputStream is = socket.getInputStream(); - while (is.read() != -1) { - } + serverSocket.close(); } catch (Exception e) { - } finally { - try { - serverSocket.close(); - } catch (Exception e) { - } - try { - socket.close(); - } catch (Exception e) { - } - socketConnected.set(false); } + try { + socket.close(); + } catch (Exception e) { + } + socketConnected.set(false); } - }; + }); socketThread.setDaemon(true); socketThread.start(); diff --git a/quickfixj-core/src/test/java/quickfix/mina/SingleThreadedEventHandlingStrategyTest.java b/quickfixj-core/src/test/java/quickfix/mina/SingleThreadedEventHandlingStrategyTest.java index 63c5e74ff..0f351f4c0 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/SingleThreadedEventHandlingStrategyTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/SingleThreadedEventHandlingStrategyTest.java @@ -221,7 +221,7 @@ public void shouldCleanUpAcceptorQFJMessageProcessorThreadAfterStop() throws Exc @Override public void run() { try { - acceptor.block(); + acceptor.start(); } catch (Exception e) { e.printStackTrace(); } finally { @@ -251,7 +251,7 @@ public void shouldCleanUpInitiatorQFJMessageProcessorThreadAfterStop() throws Ex @Override public void run() { try { - initiator.block(); + initiator.start(); } catch (Exception e) { e.printStackTrace(); } finally { diff --git a/quickfixj-core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java b/quickfixj-core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java index 811e7fa5a..cd7ef7f11 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java @@ -369,10 +369,11 @@ private void doTestMinaDemux(String message) throws Exception { final IoSessionStub mockSession = new IoSessionStub(); int count = 5; - String data = ""; + final StringBuilder builder = new StringBuilder(message.length() * 5); for (int i = 0; i < count; i++) { - data += message; + builder.append(message); } + final String data = builder.toString(); for (int i = 1; i < data.length(); i++) { String chunk1 = data.substring(0, i); diff --git a/quickfixj-dictgenerator/pom.xml b/quickfixj-dictgenerator/pom.xml index 5014a8984..d8b1c52fb 100644 --- a/quickfixj-dictgenerator/pom.xml +++ b/quickfixj-dictgenerator/pom.xml @@ -26,7 +26,7 @@ org.dom4j dom4j - 2.0.0 + 2.0.1 true diff --git a/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Repository.java b/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Repository.java index 7589047c3..ff1cbb24c 100644 --- a/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Repository.java +++ b/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Repository.java @@ -24,7 +24,6 @@ import org.dom4j.io.SAXReader; import java.io.File; -import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; @@ -159,7 +158,7 @@ private void initFields() { allFields.put(field.getTag(), field); // Find enums List enumNodes = enums.selectNodes("//dataroot/Enums[Tag=" + tag + "]"); - Collections.sort(enumNodes, new EnumNodeComparator()); + enumNodes.sort(new EnumNodeComparator()); if (!enumNodes.isEmpty()) { for (Object enumO : enumNodes) { Node enumNode = (Node) enumO; @@ -223,7 +222,7 @@ private void addComponentMsgContent(Component component, String prefix) { private List getMsgContents(String msgID) { List nodes = msgContents.selectNodes("//dataroot/MsgContents[MsgID=" + msgID + "]"); - Collections.sort(nodes, new MsgContentNodeComparator()); + nodes.sort(new MsgContentNodeComparator()); return nodes; } diff --git a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/ui/OrderEntryPanel.java b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/ui/OrderEntryPanel.java index ecf1541e1..704c46f11 100644 --- a/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/ui/OrderEntryPanel.java +++ b/quickfixj-examples/banzai/src/main/java/quickfix/examples/banzai/ui/OrderEntryPanel.java @@ -52,6 +52,7 @@ import quickfix.examples.banzai.OrderTableModel; import quickfix.examples.banzai.OrderType; +@SuppressWarnings("unchecked") public class OrderEntryPanel extends JPanel implements Observer { private boolean symbolEntered = false; private boolean quantityEntered = false; From bb8b3132a06c4408f78a8968a095c382faa868c8 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Tue, 25 Jul 2017 14:03:50 +0200 Subject: [PATCH 101/165] - added some missing cases to Ordermatch application, prevent NPE --- .../examples/ordermatch/Application.java | 48 +++++++++++++++++-- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/Application.java b/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/Application.java index b97f46d0a..21e5f9c1f 100644 --- a/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/Application.java +++ b/quickfixj-examples/ordermatch/src/main/java/quickfix/examples/ordermatch/Application.java @@ -55,10 +55,17 @@ import quickfix.field.TimeInForce; import quickfix.fix42.ExecutionReport; import quickfix.fix42.MarketDataRequest; +import quickfix.fix42.MarketDataSnapshotFullRefresh; import quickfix.fix42.NewOrderSingle; import quickfix.fix42.OrderCancelRequest; import java.util.ArrayList; +import quickfix.field.CxlRejResponseTo; +import quickfix.field.MDEntryPx; +import quickfix.field.MDEntryType; +import quickfix.field.MDReqID; +import quickfix.field.OrdRejReason; +import quickfix.fix42.OrderCancelReject; public class Application extends MessageCracker implements quickfix.Application { private final OrderMatcher orderMatcher = new OrderMatcher(); @@ -103,7 +110,7 @@ public void onMessage(NewOrderSingle message, SessionID sessionID) throws FieldN processOrder(order); } catch (Exception e) { - rejectOrder(senderCompId, targetCompId, clOrdId, symbol, side, e.getMessage()); + rejectOrder(targetCompId, senderCompId, clOrdId, symbol, side, e.getMessage()); } } @@ -117,6 +124,7 @@ private void rejectOrder(String senderCompId, String targetCompId, String clOrdI fixOrder.setString(ClOrdID.FIELD, clOrdId); fixOrder.setString(Text.FIELD, message); + fixOrder.setInt(OrdRejReason.FIELD, OrdRejReason.BROKER_EXCHANGE_OPTION); try { Session.sendToTarget(fixOrder, senderCompId, targetCompId); @@ -187,9 +195,23 @@ public void onMessage(OrderCancelRequest message, SessionID sessionID) throws Fi char side = message.getChar(Side.FIELD); String id = message.getString(OrigClOrdID.FIELD); Order order = orderMatcher.find(symbol, side, id); - order.cancel(); - cancelOrder(order); - orderMatcher.erase(order); + if (order != null) { + order.cancel(); + cancelOrder(order); + orderMatcher.erase(order); + } else { + OrderCancelReject fixOrderReject = new OrderCancelReject(new OrderID("NONE"), new ClOrdID(message.getString(ClOrdID.FIELD)), + new OrigClOrdID(message.getString(OrigClOrdID.FIELD)), new OrdStatus(OrdStatus.REJECTED), new CxlRejResponseTo(CxlRejResponseTo.ORDER_CANCEL_REQUEST)); + + String senderCompId = message.getHeader().getString(SenderCompID.FIELD); + String targetCompId = message.getHeader().getString(TargetCompID.FIELD); + fixOrderReject.getHeader().setString(SenderCompID.FIELD, targetCompId); + fixOrderReject.getHeader().setString(TargetCompID.FIELD, senderCompId); + try { + Session.sendToTarget(fixOrderReject, targetCompId, senderCompId); + } catch (SessionNotFound e) { + } + } } public void onMessage(MarketDataRequest message, SessionID sessionID) throws FieldNotFound, @@ -204,10 +226,26 @@ public void onMessage(MarketDataRequest message, SessionID sessionID) throws Fie //int marketDepth = message.getInt(MarketDepth.FIELD); int relatedSymbolCount = message.getInt(NoRelatedSym.FIELD); + MarketDataSnapshotFullRefresh fixMD = new MarketDataSnapshotFullRefresh(); + fixMD.setString(MDReqID.FIELD, message.getString(MDReqID.FIELD)); + for (int i = 1; i <= relatedSymbolCount; ++i) { message.getGroup(i, noRelatedSyms); String symbol = noRelatedSyms.getString(Symbol.FIELD); - System.err.println("*** market data: " + symbol); + fixMD.setString(Symbol.FIELD, symbol); + } + + MarketDataSnapshotFullRefresh.NoMDEntries noMDEntries = new MarketDataSnapshotFullRefresh.NoMDEntries(); + noMDEntries.setChar(MDEntryType.FIELD, '0'); + noMDEntries.setDouble(MDEntryPx.FIELD, 123.45); + fixMD.addGroup(noMDEntries); + String senderCompId = message.getHeader().getString(SenderCompID.FIELD); + String targetCompId = message.getHeader().getString(TargetCompID.FIELD); + fixMD.getHeader().setString(SenderCompID.FIELD, targetCompId); + fixMD.getHeader().setString(TargetCompID.FIELD, senderCompId); + try { + Session.sendToTarget(fixMD, targetCompId, senderCompId); + } catch (SessionNotFound e) { } } From 7a0bd5b38fb04631ff2ced713fd22d025598d162 Mon Sep 17 00:00:00 2001 From: traggatt Date: Thu, 3 Aug 2017 16:49:38 +0100 Subject: [PATCH 102/165] Fix for dropped logout message issue --- .../java/quickfix/mina/SessionConnector.java | 21 ++++++++++++++++++- .../quickfix/mina/SessionConnectorTest.java | 1 + 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java b/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java index 77da1aed9..4757b9a12 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java +++ b/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java @@ -195,6 +195,25 @@ public boolean isLoggedOn() { return true; } + /** + * Check if we have at least one session and that at least one session is logged on. + * + * @return false if no sessions exist or all sessions are logged off, true otherwise + */ + //visible for testing only + boolean anyLoggedOn() { + // if no session, not logged on + if (sessions.isEmpty()) + return false; + for (Session session : sessions.values()) { + // at least one session logged on + if (session.isLoggedOn()) + return true; + } + // no sessions are logged on + return false; + } + private Set getLoggedOnSessions() { Set loggedOnSessions = new HashSet<>(sessions.size()); for (Session session : sessions.values()) { @@ -219,7 +238,7 @@ protected void logoutAllSessions(boolean forceDisconnect) { } } - if (isLoggedOn()) { + if (anyLoggedOn()) { if (forceDisconnect) { for (Session session : sessions.values()) { try { diff --git a/quickfixj-core/src/test/java/quickfix/mina/SessionConnectorTest.java b/quickfixj-core/src/test/java/quickfix/mina/SessionConnectorTest.java index 1d86e6360..bb5f11def 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/SessionConnectorTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/SessionConnectorTest.java @@ -129,6 +129,7 @@ public void testOneSessionLoggedOnOneSessionNotLoggedOne() throws Exception { assertNotNull(session2); sessions.put(session2.getSessionID(), session2); assertFalse(connector.isLoggedOn()); + assertTrue(connector.anyLoggedOn()); } /** From c9e3a59a10828ddd0827ab01acbdea5dc56167d1 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Tue, 15 Aug 2017 12:59:32 +0200 Subject: [PATCH 103/165] increased memory for javadoc generation --- pom.xml | 1 + quickfixj-distribution/pom.xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d9b3ec3ed..2203330ff 100644 --- a/pom.xml +++ b/pom.xml @@ -166,6 +166,7 @@ -Xdoclint:none + 3g diff --git a/quickfixj-distribution/pom.xml b/quickfixj-distribution/pom.xml index 3d0b28848..53ab2ed3b 100644 --- a/quickfixj-distribution/pom.xml +++ b/quickfixj-distribution/pom.xml @@ -151,7 +151,7 @@ protected - 2g + 3g true From a1e22117b3a6c67fc1d9a789ea64c383aa840ae6 Mon Sep 17 00:00:00 2001 From: Arthurm1 Date: Sun, 20 Aug 2017 21:00:02 +0100 Subject: [PATCH 104/165] Add Weekday Scheduler --- .../src/main/java/quickfix/Session.java | 5 + .../java/quickfix/WeekdaySessionSchedule.java | 339 ++++++++++ .../WeekdaySessionScheduleFactory.java | 35 + .../quickfix/WeekdaySessionScheduleTest.java | 602 ++++++++++++++++++ 4 files changed, 981 insertions(+) create mode 100644 quickfixj-core/src/main/java/quickfix/WeekdaySessionSchedule.java create mode 100644 quickfixj-core/src/main/java/quickfix/WeekdaySessionScheduleFactory.java create mode 100644 quickfixj-core/src/test/java/quickfix/WeekdaySessionScheduleTest.java diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index 43622135a..015267814 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -145,6 +145,11 @@ public class Session implements Closeable { */ public static final String SETTING_END_TIME = "EndTime"; + /** + * Session scheduling setting to specify active days of the week when using a WeekdaySessionSchedule. + */ + public static final String SETTING_WEEKDAYS = "Weekdays"; + /** * Session setting to indicate whether a data dictionary should be used. If * a data dictionary is not used then message validation is not possble. diff --git a/quickfixj-core/src/main/java/quickfix/WeekdaySessionSchedule.java b/quickfixj-core/src/main/java/quickfix/WeekdaySessionSchedule.java new file mode 100644 index 000000000..da0ffefa5 --- /dev/null +++ b/quickfixj-core/src/main/java/quickfix/WeekdaySessionSchedule.java @@ -0,0 +1,339 @@ +/******************************************************************************* + * Copyright (c) quickfixengine.org All rights reserved. + * + * This file is part of the QuickFIX FIX Engine + * + * This file may be distributed under the terms of the quickfixengine.org + * license as defined by quickfixengine.org and appearing in the file + * LICENSE included in the packaging of this file. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING + * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * See http://www.quickfixengine.org/LICENSE for licensing information. + * + * Contact ask@quickfixengine.org if any conditions of this licensing + * are not clear to you. + ******************************************************************************/ + +package quickfix; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.TimeZone; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Daily schedule that can be configured to only login on specific days e.g. Mon -> Fri + * The day specified corresponds to the day that the StartTime is valid, + * this is relevant when StartTime is after EndTime + */ +public class WeekdaySessionSchedule implements SessionSchedule { + private static final Pattern TIME_PATTERN = Pattern.compile("(\\d{2}):(\\d{2}):(\\d{2})(.*)"); + + private final int[] weekdayOffsets; + private final TimeEndPoint startTime; + private final TimeEndPoint endTime; + + protected final static Logger log = LoggerFactory.getLogger(WeekdaySessionSchedule.class); + + WeekdaySessionSchedule(SessionSettings settings, SessionID sessionID) throws ConfigError, + FieldConvertError { + + TimeZone defaultTimeZone = getDefaultTimeZone(settings, sessionID); + + if (!settings.isSetting(sessionID, Session.SETTING_WEEKDAYS)) + throw new ConfigError("Session " + sessionID + ": does not have " + Session.SETTING_WEEKDAYS + " specified"); + + String weekdayNames = settings.getString(sessionID, Session.SETTING_WEEKDAYS); + if (weekdayNames.isEmpty()) + throw new ConfigError("Session " + sessionID + ": " + Session.SETTING_WEEKDAYS + " is empty"); + + String[] weekdayNameArray = weekdayNames.split(","); + weekdayOffsets = new int[weekdayNameArray.length]; + for (int i = 0; i < weekdayNameArray.length; i++) { + if (weekdayNameArray[i].length() != 3) + throw new ConfigError("Session " + sessionID + ": " + Session.SETTING_WEEKDAYS + " has an illegal weekday: [" + weekdayNameArray[i] + "] in " + weekdayNames); + + weekdayOffsets[i] = DayConverter.toInteger(weekdayNameArray[i]); + } + + startTime = getTimeEndPoint(settings, sessionID, defaultTimeZone, Session.SETTING_START_TIME); + endTime = getTimeEndPoint(settings, sessionID, defaultTimeZone, Session.SETTING_END_TIME); + + log.info("{} using schedule: {}", sessionID, toString()); + } + + private TimeEndPoint getTimeEndPoint(SessionSettings settings, SessionID sessionID, + TimeZone defaultTimeZone, String timeSetting) throws ConfigError, + FieldConvertError { + + Matcher matcher = TIME_PATTERN.matcher(settings.getString(sessionID, timeSetting)); + if (!matcher.find()) { + throw new ConfigError("Session " + sessionID + ": could not parse time '" + + settings.getString(sessionID, timeSetting) + "'."); + } + + return new TimeEndPoint( + Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)), + Integer.parseInt(matcher.group(3)), getTimeZone(matcher.group(4), defaultTimeZone)); + } + + private TimeZone getDefaultTimeZone(SessionSettings settings, SessionID sessionID) + throws ConfigError, FieldConvertError { + TimeZone sessionTimeZone; + if (settings.isSetting(sessionID, Session.SETTING_TIMEZONE)) { + String sessionTimeZoneID = settings.getString(sessionID, Session.SETTING_TIMEZONE); + sessionTimeZone = TimeZone.getTimeZone(sessionTimeZoneID); + if ("GMT".equals(sessionTimeZone.getID()) && !"GMT".equals(sessionTimeZoneID)) { + throw new ConfigError("Unrecognized time zone '" + sessionTimeZoneID + + "' for session " + sessionID); + } + } else { + sessionTimeZone = TimeZone.getTimeZone("UTC"); + } + return sessionTimeZone; + } + + private TimeZone getTimeZone(String tz, TimeZone defaultZone) { + return "".equals(tz) ? defaultZone : TimeZone.getTimeZone(tz.trim()); + } + + private class TimeEndPoint { + private final int hour; + private final int minute; + private final int second; + private final int timeInSeconds; + private final TimeZone tz; + + TimeEndPoint(int hour, int minute, int second, TimeZone tz) { + this.hour = hour; + this.minute = minute; + this.second = second; + this.tz = tz; + timeInSeconds = timeInSeconds(hour, minute, second); + } + + int getHour() { + return hour; + } + + int getMinute() { + return minute; + } + + int getSecond() { + return second; + } + + public String toString() { + Calendar calendar = Calendar.getInstance(tz); + calendar.set(Calendar.HOUR_OF_DAY, hour); + calendar.set(Calendar.MINUTE, minute); + calendar.set(Calendar.SECOND, second); + final SimpleDateFormat utc = new SimpleDateFormat("HH:mm:ss"); + utc.setTimeZone(TimeZone.getTimeZone("UTC")); + return utc.format(calendar.getTime()) + "-" + utc.getTimeZone().getID(); + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o instanceof TimeEndPoint) { + TimeEndPoint otherTime = (TimeEndPoint) o; + return timeInSeconds == otherTime.timeInSeconds; + } + return false; + } + + public int hashCode() { + assert false : "hashCode not supported"; + return 0; + } + + TimeZone getTimeZone() { + return tz; + } + } + + /** + * find the most recent session date/time range on or before t + * if t is in a session then that session will be returned + * @param t specific date/time + * @return relevant session date/time range + */ + private TimeInterval theMostRecentIntervalBefore(Calendar t) { + TimeInterval timeInterval = new TimeInterval(); + Calendar intervalStart = timeInterval.getStart(); + intervalStart.setTimeZone(startTime.getTimeZone()); + intervalStart.setTimeInMillis(t.getTimeInMillis()); + intervalStart.set(Calendar.HOUR_OF_DAY, startTime.getHour()); + intervalStart.set(Calendar.MINUTE, startTime.getMinute()); + intervalStart.set(Calendar.SECOND, startTime.getSecond()); + intervalStart.set(Calendar.MILLISECOND, 0); + + Calendar intervalEnd = timeInterval.getEnd(); + intervalEnd.setTimeZone(endTime.getTimeZone()); + intervalEnd.setTimeInMillis(t.getTimeInMillis()); + intervalEnd.set(Calendar.HOUR_OF_DAY, endTime.getHour()); + intervalEnd.set(Calendar.MINUTE, endTime.getMinute()); + intervalEnd.set(Calendar.SECOND, endTime.getSecond()); + intervalEnd.set(Calendar.MILLISECOND, 0); + + while (intervalStart.getTimeInMillis() > t.getTimeInMillis() || + !validDayOfWeek(intervalStart)) { + intervalStart.add(Calendar.DAY_OF_WEEK, -1); + intervalEnd.add(Calendar.DAY_OF_WEEK, -1); + } + + if (intervalEnd.getTimeInMillis() <= intervalStart.getTimeInMillis()) { + intervalEnd.add(Calendar.DAY_OF_WEEK, 1); + } + + return timeInterval; + } + + /** + * is the startDateTime a valid day based on the permitted days of week + * @param startDateTime time to test + * @return flag indicating if valid + */ + private boolean validDayOfWeek(Calendar startDateTime) { + int dow = startDateTime.get(Calendar.DAY_OF_WEEK); + for (int i = 0; i < weekdayOffsets.length; i++) + if (weekdayOffsets[i] == dow) + return true; + return false; + } + + private static class TimeInterval { + private final Calendar start = SystemTime.getUtcCalendar(); + private final Calendar end = SystemTime.getUtcCalendar(); + + boolean isContainingTime(Calendar t) { + return t.compareTo(start) >= 0 && t.compareTo(end) <= 0; + } + + public String toString() { + return start.getTime() + " --> " + end.getTime(); + } + + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof TimeInterval)) { + return false; + } + TimeInterval otherInterval = (TimeInterval) other; + return start.equals(otherInterval.start) && end.equals(otherInterval.end); + } + + public int hashCode() { + assert false : "hashCode not supported"; + return 0; + } + + Calendar getStart() { + return start; + } + + Calendar getEnd() { + return end; + } + } + + /** + * Predicate for determining if the two times are in the same session + * @param time1 test time 1 + * @param time2 test time 2 + * @return return true if in the same session + */ + @Override + public boolean isSameSession(Calendar time1, Calendar time2) { + TimeInterval interval1 = theMostRecentIntervalBefore(time1); + if (!interval1.isContainingTime(time1)) { + return false; + } + TimeInterval interval2 = theMostRecentIntervalBefore(time2); + return interval2.isContainingTime(time2) && interval1.equals(interval2); + } + + @Override + public boolean isNonStopSession() { + return false; + } + + /** + * Predicate for determining if the session should be active at the current time. + * + * @return true if session should be active, false otherwise. + */ + @Override + public boolean isSessionTime() { + return isSessionTime(SystemTime.getUtcCalendar()); + } + + boolean isSessionTime(Calendar time) { + TimeInterval interval = theMostRecentIntervalBefore(time); + return interval.isContainingTime(time); + } + + public String toString() { + StringBuilder buf = new StringBuilder(); + + SimpleDateFormat dowFormat = new SimpleDateFormat("EEEE"); + dowFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + + SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss-z"); + timeFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + + TimeInterval ti = theMostRecentIntervalBefore(SystemTime.getUtcCalendar()); + + formatTimeInterval(buf, ti, timeFormat, false); + + // Now the localized equivalents, if necessary + if (!startTime.getTimeZone().equals(SystemTime.UTC_TIMEZONE) + || !endTime.getTimeZone().equals(SystemTime.UTC_TIMEZONE)) { + buf.append(" ("); + formatTimeInterval(buf, ti, timeFormat, true); + buf.append(")"); + } + + return buf.toString(); + } + + private void formatTimeInterval(StringBuilder buf, TimeInterval timeInterval, + SimpleDateFormat timeFormat, boolean local) { + try { + for (int i = 0; i < weekdayOffsets.length; i++) { + buf.append(DayConverter.toString(weekdayOffsets[i])); + buf.append(", "); + } + } catch (ConfigError ex) { + // this can't happen as these are created using DayConverter.toInteger + } + + if (local) { + timeFormat.setTimeZone(startTime.getTimeZone()); + } + buf.append(timeFormat.format(timeInterval.getStart().getTime())); + + buf.append(" - "); + + if (local) { + timeFormat.setTimeZone(endTime.getTimeZone()); + } + buf.append(timeFormat.format(timeInterval.getEnd().getTime())); + } + + private int timeInSeconds(int hour, int minute, int second) { + return (hour * 3600) + (minute * 60) + second; + } +} diff --git a/quickfixj-core/src/main/java/quickfix/WeekdaySessionScheduleFactory.java b/quickfixj-core/src/main/java/quickfix/WeekdaySessionScheduleFactory.java new file mode 100644 index 000000000..d81902dc9 --- /dev/null +++ b/quickfixj-core/src/main/java/quickfix/WeekdaySessionScheduleFactory.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) quickfixengine.org All rights reserved. + * + * This file is part of the QuickFIX FIX Engine + * + * This file may be distributed under the terms of the quickfixengine.org + * license as defined by quickfixengine.org and appearing in the file + * LICENSE included in the packaging of this file. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING + * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * See http://www.quickfixengine.org/LICENSE for licensing information. + * + * Contact ask@quickfixengine.org if any conditions of this licensing + * are not clear to you. + ******************************************************************************/ + +package quickfix; + +/** + * Factory for creating weekday session schedules. + */ +public class WeekdaySessionScheduleFactory implements SessionScheduleFactory { + + public SessionSchedule create(SessionID sessionID, SessionSettings settings) throws ConfigError + { + try { + return new WeekdaySessionSchedule(settings, sessionID); + } catch (final FieldConvertError e) { + throw new ConfigError(e.getMessage()); + } + } +} \ No newline at end of file diff --git a/quickfixj-core/src/test/java/quickfix/WeekdaySessionScheduleTest.java b/quickfixj-core/src/test/java/quickfix/WeekdaySessionScheduleTest.java new file mode 100644 index 000000000..d59220937 --- /dev/null +++ b/quickfixj-core/src/test/java/quickfix/WeekdaySessionScheduleTest.java @@ -0,0 +1,602 @@ +/******************************************************************************* + * Copyright (c) quickfixengine.org All rights reserved. + * + * This file is part of the QuickFIX FIX Engine + * + * This file may be distributed under the terms of the quickfixengine.org + * license as defined by quickfixengine.org and appearing in the file + * LICENSE included in the packaging of this file. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING + * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * See http://www.quickfixengine.org/LICENSE for licensing information. + * + * Contact ask@quickfixengine.org if any conditions of this licensing + * are not clear to you. + ******************************************************************************/ + +package quickfix; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.text.DateFormat; +import java.text.DateFormatSymbols; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Locale; +import java.util.TimeZone; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import quickfix.field.converter.UtcTimeOnlyConverter; + +public class WeekdaySessionScheduleTest { + private MockSystemTimeSource mockSystemTimeSource; + private Locale defaultLocale; + + @Before + public void setUp() throws Exception { + mockSystemTimeSource = new MockSystemTimeSource(); + SystemTime.setTimeSource(mockSystemTimeSource); + defaultLocale = Locale.getDefault(); + Locale.setDefault(Locale.GERMANY); + } + + @After + public void tearDown() throws Exception { + SystemTime.setTimeSource(null); + Locale.setDefault(defaultLocale); + } + + private SessionSchedule newSessionSchedule(Date startTime, Date endTime, String weekdays) throws Exception { + SessionSettings settings = new SessionSettings(); + if (weekdays != null && weekdays.length() > 0) { + settings.setString(Session.SETTING_WEEKDAYS, weekdays); + } + if (startTime != null) { + settings.setString(Session.SETTING_START_TIME, UtcTimeOnlyConverter.convert(startTime, false)); + } + if (endTime != null) { + settings.setString(Session.SETTING_END_TIME, UtcTimeOnlyConverter.convert(endTime, false)); + } + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + return new WeekdaySessionSchedule(settings, sessionID); + } + + private void doIsSessionTimeTest(SessionSchedule schedule, boolean expectedInSession, int year, + int month, int day, int hour, int minute, int second) { + doIsSessionTimeTest(schedule, expectedInSession, year, month, day, hour, minute, second, + TimeZone.getTimeZone("UTC")); + } + + private void doIsSessionTimeTest(SessionSchedule schedule, boolean expectedInSession, int year, + int month, int day, int hour, int minute, int second, TimeZone timeZone) { + mockSystemTimeSource + .setTime(getTimeStamp(year, month, day, hour, minute, second, timeZone)); + assertEquals("in session expectation incorrect", expectedInSession, schedule + .isSessionTime()); + } + + private void doIsSessionTimeTest(SessionSettings settings, SessionID sessionID, + boolean expectedInSession, int year, int month, int day, int hour, int minute, + int second, String timeZoneID) throws ConfigError, FieldConvertError { + mockSystemTimeSource.setTime(getTimeStamp(year, month, day, hour, minute, second, TimeZone + .getTimeZone(timeZoneID))); + SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); + assertEquals("schedule is wrong", expectedInSession, schedule.isSessionTime()); + } + + @Test + public void testMissingStartTime() throws Exception { + Calendar end = getUtcTime(18, 0, 0); + try { + newSessionSchedule(null, end.getTime(), "Mon"); + fail("no exception"); + } catch (ConfigError e) { + // do nothing + } + } + + @Test + public void testMissingEndTime() throws Exception { + Calendar start = getUtcTime(3, 0, 0); + try { + newSessionSchedule(start.getTime(), null, "Mon"); + fail("no exception"); + } catch (ConfigError e) { + // do nothing + } + } + + @Test + public void testMissingWeekdays() throws Exception { + Calendar start = getUtcTime(3, 0, 0); + Calendar end = getUtcTime(18, 0, 0); + try { + newSessionSchedule(start.getTime(), end.getTime(), null); + fail("no exception"); + } catch (ConfigError e) { + // do nothing + } + } + + @Test + public void testInvalidWeekdays1() throws Exception { + Calendar start = getUtcTime(3, 0, 0); + Calendar end = getUtcTime(18, 0, 0); + try { + newSessionSchedule(start.getTime(), end.getTime(), "AAA"); + fail("no exception"); + } catch (ConfigError e) { + // do nothing + } + } + + @Test + public void testInvalidWeekdays2() throws Exception { + Calendar start = getUtcTime(3, 0, 0); + Calendar end = getUtcTime(18, 0, 0); + try { + newSessionSchedule(start.getTime(), end.getTime(), ",Mon"); + fail("no exception"); + } catch (ConfigError e) { + // do nothing + } + } + + @Test + public void testInvalidWeekdays3() throws Exception { + Calendar start = getUtcTime(3, 0, 0); + Calendar end = getUtcTime(18, 0, 0); + try { + newSessionSchedule(start.getTime(), end.getTime(), "Mon,,Tue"); + fail("no exception"); + } catch (ConfigError e) { + // do nothing + } + } + + @Test + public void testSessionTimeStartBeforeEnd() throws Exception { + Calendar start = getUtcTime(3, 0, 0); + Calendar end = getUtcTime(18, 0, 0); + SessionSchedule schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); + // Sunday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 2, 59, 59); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 18, 0, 1); + // Monday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 2, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 2, 3, 0, 0); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 2, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 18, 0, 1); + // Tuesday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 3, 2, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 3, 3, 0, 0); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 3, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 3, 18, 0, 1); + // Wednesday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 4, 2, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 4, 3, 0, 0); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 4, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 4, 18, 0, 1); + // Thursday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 5, 2, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 5, 3, 0, 0); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 5, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 5, 18, 0, 1); + // Friday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 6, 2, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 6, 3, 0, 0); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 6, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 6, 18, 0, 1); + // Saturday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 2, 59, 59); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 18, 0, 1); + } + @Test + public void testSessionTimeEndBeforeStart() throws Exception { + Calendar start = getUtcTime(18, 0, 0); + Calendar end = getUtcTime(3, 0, 0); + SessionSchedule schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); + // Sunday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 17, 59, 59); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 18, 0, 0); + // Monday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 17, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 2, 18, 0, 0); + // Tuesday + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 3, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 3, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 3, 17, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 3, 18, 0, 0); + // Wednesday + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 4, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 4, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 4, 17, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 4, 18, 0, 0); + // Thursday + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 5, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 5, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 5, 17, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 5, 18, 0, 0); + // Friday + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 6, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 6, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 6, 17, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 6, 18, 0, 0); + // Saturday + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 7, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 17, 59, 59); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 18, 0, 0); + } + + @Test + public void testIsSameSession() throws Exception { + // ===================================================== + // start time is less than end time + Calendar start = getUtcTime(3, 0, 0); + Calendar end = getUtcTime(18, 0, 0); + SessionSchedule schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); + + // same time + Calendar t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + Calendar t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // time 2 in same session but greater + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // time 2 in same session but less + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // time 1 not in session + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 1); + doIsSameSessionTest(schedule, t1, t2, false); + + // time 2 not in session + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 1); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + doIsSameSessionTest(schedule, t1, t2, false); + + // same time (in session window) two different days + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 3, 0, 0); + doIsSameSessionTest(schedule, t1, t2, false); + + // ===================================================== + // start time is greater than end time + start = getUtcTime(18, 0, 0); + end = getUtcTime(13, 0, 0); + schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); + + // same session same day + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 19, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // same time (in session window) two different days + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 18, 0, 0); + doIsSameSessionTest(schedule, t1, t2, false); + + // same session time 2 is in next day + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 3, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // same session time 1 is in next day + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 3, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // time 1 is 25 hours greater than time 2 + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 19, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + doIsSameSessionTest(schedule, t1, t2, false); + + // ===================================================== + // start time is equal to end time + start = getUtcTime(6, 0, 0); + end = getUtcTime(6, 0, 0); + schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); + + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 18, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + doIsSameSessionTest(schedule, t1, t2, false); + } + + @Test + public void testSettingsWithoutStartEndDayWithTimeZone() throws Exception { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, " US/Eastern "); + settings.setString(Session.SETTING_START_TIME, "01:00:00"); + settings.setString(Session.SETTING_END_TIME, "15:00:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); + TimeZone tz = TimeZone.getTimeZone("US/Eastern"); + doIsSessionTimeTest(schedule, false, 2002, 5, 5, 0, 59, 0, tz); + doIsSessionTimeTest(schedule, true, 2002, 7, 5, 14, 30, 0, tz); + doIsSessionTimeTest(schedule, false, 2003, 5, 5, 16, 30, 0, tz); + } + + @Test + public void testSettingsWithTimeZoneInTime() throws Exception { + // This test is very susceptible to whether the system time starts + // in daylight time or not, so we just force it that way. Otherwise + // the first time the mock time source gets set to a time with daylight time + // then the schedule appears to change 1 hr. + TimeZone tz = TimeZone.getTimeZone("US/Eastern"); + mockSystemTimeSource.setTime(getTimeStamp(2002, 5, 5, 0, 0, 0, tz)); + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_START_TIME, "01:00:00 US/Eastern"); + settings.setString(Session.SETTING_END_TIME, "15:00:00 US/Central"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); + doIsSessionTimeTest(schedule, false, 2002, 5, 5, 0, 59, 0, tz); + doIsSessionTimeTest(schedule, true, 2002, 7, 5, 14, 30, 0, tz); + + // The end time is actually 16:00 Eastern time but specified as + // 15:00 Central time. + doIsSessionTimeTest(schedule, true, 2003, 5, 5, 15, 59, 0, tz); + doIsSessionTimeTest(schedule, true, 2003, 5, 5, 16, 0, 0, tz); + doIsSessionTimeTest(schedule, false, 2003, 5, 5, 16, 1, 0, tz); + } + + /** + * From 1968 to 1971, GMT was an hour ahead of UTC. If we perform all our calculations in 1970, + * someone in GMT (e.g. London) will see sessions ending an hour later than expected. This test + * demonstrates the 1970 behavior and verifies that calculations on current dates give the proper results. + * + *

+ * More details at: + *

+ * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4644278 + * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4832236 + */ + @Test + public void testThatUTCAndGMTAreTheSameNow() throws ConfigError, FieldConvertError, + ParseException { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_START_TIME, "00:01:00"); + settings.setString(Session.SETTING_END_TIME, "21:50:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri,Sat,Sun"); + + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + + // In 1970, a session configured to end at 21:50 UTC would end at + // 22:50 London time any time of year. + doIsSessionTimeTest(settings, sessionID, true, 1970, Calendar.JANUARY, 27, 22, 50, 0, + "Europe/London"); + doIsSessionTimeTest(settings, sessionID, false, 1970, Calendar.JANUARY, 27, 22, 50, 1, + "Europe/London"); + doIsSessionTimeTest(settings, sessionID, true, 1970, Calendar.JULY, 27, 22, 50, 0, + "Europe/London"); + doIsSessionTimeTest(settings, sessionID, false, 1970, Calendar.JULY, 27, 22, 50, 1, + "Europe/London"); + + // Now, at least in winter, it should end at 21:50 in both zones -- + // if the end time session setting is being parsed correctly. + doIsSessionTimeTest(settings, sessionID, true, 2006, Calendar.FEBRUARY, 27, 21, 50, 0, + "Europe/London"); + doIsSessionTimeTest(settings, sessionID, false, 2006, Calendar.FEBRUARY, 27, 21, 50, 1, + "Europe/London"); + + // When summer time (BST) is in effect, London time will be an hour + // ahead again, and the session will end at 22:50 there. + doIsSessionTimeTest(settings, sessionID, true, 2006, Calendar.JULY, 27, 22, 50, 0, + "Europe/London"); + doIsSessionTimeTest(settings, sessionID, false, 2006, Calendar.JULY, 27, 22, 50, 1, + "Europe/London"); + + settings.setString(Session.SETTING_TIMEZONE, "Europe/London"); + + // In 1970, a session configured to end at 21:50 GMT would end at + // 20:50 UTC any time of year. + doIsSessionTimeTest(settings, sessionID, true, 1970, Calendar.JANUARY, 27, 20, 50, 0, "UTC"); + doIsSessionTimeTest(settings, sessionID, false, 1970, Calendar.JANUARY, 27, 20, 50, 1, + "UTC"); + doIsSessionTimeTest(settings, sessionID, true, 1970, Calendar.JULY, 27, 20, 50, 0, "UTC"); + doIsSessionTimeTest(settings, sessionID, false, 1970, Calendar.JULY, 27, 20, 50, 1, "UTC"); + + // Now, at least in winter, it should end at 21:50 in both zones -- + // if the end time session setting is being parsed correctly. + doIsSessionTimeTest(settings, sessionID, true, 2006, Calendar.FEBRUARY, 27, 21, 50, 0, + "UTC"); + doIsSessionTimeTest(settings, sessionID, false, 2006, Calendar.FEBRUARY, 27, 21, 50, 1, + "UTC"); + + // When summer time (BST) is in effect, London time will be an hour + // ahead again, and the session will end at 20:50 UTC there. + doIsSessionTimeTest(settings, sessionID, true, 2006, Calendar.JULY, 27, 20, 50, 0, "UTC"); + doIsSessionTimeTest(settings, sessionID, false, 2006, Calendar.JULY, 27, 20, 50, 1, "UTC"); + } + + @Test + public void testBadTimeSpecification() throws Exception { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, "US/Eastern"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + + try { + settings.setString(Session.SETTING_START_TIME, "01:xx:00"); + settings.setString(Session.SETTING_END_TIME, "15:00:00"); + new WeekdaySessionSchedule(settings, sessionID); + fail("no exception"); + } catch (ConfigError e) { + assertTrue(e.getMessage().contains("could not parse")); + } + + try { + settings.setString(Session.SETTING_START_TIME, "01:00:00"); + settings.setString(Session.SETTING_END_TIME, "15:00:yy"); + new WeekdaySessionSchedule(settings, sessionID); + fail("no exception"); + } catch (ConfigError e) { + assertTrue(e.getMessage().contains("could not parse")); + } + } + + @Test + public void testBadTimeZone() throws Exception { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, "US/BOGUS"); + settings.setString(Session.SETTING_START_TIME, "01:00:00"); + settings.setString(Session.SETTING_END_TIME, "15:00:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + + try { + new WeekdaySessionSchedule(settings, sessionID); + fail("no exception"); + } catch (ConfigError e) { + assertTrue(e.getMessage().contains("Unrecognized time zone")); + } + } + + @Test + public void testWeekdayToString() throws ConfigError, FieldConvertError { + // Just be sure it doesn't throw exceptions + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, "US/Eastern"); + settings.setString(Session.SETTING_START_TIME, "01:00:00"); + settings.setString(Session.SETTING_END_TIME, "15:00:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); + assertNotNull(schedule.toString()); + } + + @Test + public void testSettingsWithDST() throws Exception { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, "Europe/Zurich"); + settings.setString(Session.SETTING_START_TIME, "01:30:00"); + settings.setString(Session.SETTING_END_TIME, "03:15:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri,Sat,Sun"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + // + SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 20, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 20, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 20, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 20, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 20, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + schedule = new WeekdaySessionSchedule(settings, sessionID); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 27, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 27, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 27, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 27, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 27, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 28, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 28, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 28, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 28, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 28, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 29, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 29, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 29, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 29, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 29, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + schedule = new WeekdaySessionSchedule(settings, sessionID); + doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 30, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 30, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 30, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 30, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 30, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 31, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 31, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 31, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); // -> this is 03:16 ! + doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 31, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 31, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + doIsSessionTimeTest(schedule, false, 2013, Calendar.APRIL, 1, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.APRIL, 1, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.APRIL, 1, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.APRIL, 1, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2013, Calendar.APRIL, 1, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + } + + @Test + public void testSettingsWithStartEndDayWithDSTMocked() throws Exception { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, "America/New_York"); + settings.setString(Session.SETTING_START_TIME, "20:00:00"); + settings.setString(Session.SETTING_END_TIME, "17:00:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri,Sat,Sun"); + + mockSystemTimeSource.setTime(getTimeStamp(2008, Calendar.NOVEMBER, 2, 18, 0, 0, TimeZone.getTimeZone("America/New_York"))); + + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); + + //System.out.println(schedule); + + // November,2 -> Sunday + doIsSessionTimeTest(schedule, true, 2008, Calendar.NOVEMBER, 2, 20, 0, 0, + TimeZone.getTimeZone("America/New_York")); + // November,7 -> Friday + doIsSessionTimeTest(schedule, true, 2008, Calendar.NOVEMBER, 7, 17, 0, 0, + TimeZone.getTimeZone("America/New_York")); + } + + private final SimpleDateFormat dateFormat = new SimpleDateFormat("E M/d HH:mm:ss"); + + { + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + } + + private void doIsSameSessionTest(SessionSchedule schedule, Calendar time1, Calendar time2, + boolean isSameSession) { + assertEquals("isSameSession is wrong", isSameSession, schedule.isSameSession(time1, time2)); + assertEquals("isSameSession is wrong", isSameSession, schedule.isSameSession(time2, time1)); + } + + private Calendar getTimeStamp(int year, int month, int day, int hour, int minute, int second, + TimeZone timeZone) { + Calendar c = new GregorianCalendar(year, month, day, hour, minute, second); + c.setTimeZone(timeZone); + return c; + } + + private Calendar getUtcTimeStamp(int year, int month, int day, int hour, int minute, int second) { + return getTimeStamp(year, month, day, hour, minute, second, TimeZone.getTimeZone("UTC")); + } + + private Calendar getUtcTime(int hour, int minute, int second) { + // Monday + return getUtcTimeStamp(2017, Calendar.JANUARY, 2, hour, minute, second); + } +} From a98b761b224a9c33f7acadb8e8ccb1a0d48e3cae Mon Sep 17 00:00:00 2001 From: Arthurm1 Date: Sun, 20 Aug 2017 21:00:02 +0100 Subject: [PATCH 105/165] Add Weekday Scheduler --- .../src/main/java/quickfix/Session.java | 5 + .../java/quickfix/WeekdaySessionSchedule.java | 339 ++++++++++ .../WeekdaySessionScheduleFactory.java | 35 + .../quickfix/WeekdaySessionScheduleTest.java | 602 ++++++++++++++++++ 4 files changed, 981 insertions(+) create mode 100644 quickfixj-core/src/main/java/quickfix/WeekdaySessionSchedule.java create mode 100644 quickfixj-core/src/main/java/quickfix/WeekdaySessionScheduleFactory.java create mode 100644 quickfixj-core/src/test/java/quickfix/WeekdaySessionScheduleTest.java diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index 21ebf2cd9..ec23718a7 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -147,6 +147,11 @@ public class Session implements Closeable { */ public static final String SETTING_END_TIME = "EndTime"; + /** + * Session scheduling setting to specify active days of the week when using a WeekdaySessionSchedule. + */ + public static final String SETTING_WEEKDAYS = "Weekdays"; + /** * Session setting to indicate whether a data dictionary should be used. If * a data dictionary is not used then message validation is not possble. diff --git a/quickfixj-core/src/main/java/quickfix/WeekdaySessionSchedule.java b/quickfixj-core/src/main/java/quickfix/WeekdaySessionSchedule.java new file mode 100644 index 000000000..da0ffefa5 --- /dev/null +++ b/quickfixj-core/src/main/java/quickfix/WeekdaySessionSchedule.java @@ -0,0 +1,339 @@ +/******************************************************************************* + * Copyright (c) quickfixengine.org All rights reserved. + * + * This file is part of the QuickFIX FIX Engine + * + * This file may be distributed under the terms of the quickfixengine.org + * license as defined by quickfixengine.org and appearing in the file + * LICENSE included in the packaging of this file. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING + * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * See http://www.quickfixengine.org/LICENSE for licensing information. + * + * Contact ask@quickfixengine.org if any conditions of this licensing + * are not clear to you. + ******************************************************************************/ + +package quickfix; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.TimeZone; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Daily schedule that can be configured to only login on specific days e.g. Mon -> Fri + * The day specified corresponds to the day that the StartTime is valid, + * this is relevant when StartTime is after EndTime + */ +public class WeekdaySessionSchedule implements SessionSchedule { + private static final Pattern TIME_PATTERN = Pattern.compile("(\\d{2}):(\\d{2}):(\\d{2})(.*)"); + + private final int[] weekdayOffsets; + private final TimeEndPoint startTime; + private final TimeEndPoint endTime; + + protected final static Logger log = LoggerFactory.getLogger(WeekdaySessionSchedule.class); + + WeekdaySessionSchedule(SessionSettings settings, SessionID sessionID) throws ConfigError, + FieldConvertError { + + TimeZone defaultTimeZone = getDefaultTimeZone(settings, sessionID); + + if (!settings.isSetting(sessionID, Session.SETTING_WEEKDAYS)) + throw new ConfigError("Session " + sessionID + ": does not have " + Session.SETTING_WEEKDAYS + " specified"); + + String weekdayNames = settings.getString(sessionID, Session.SETTING_WEEKDAYS); + if (weekdayNames.isEmpty()) + throw new ConfigError("Session " + sessionID + ": " + Session.SETTING_WEEKDAYS + " is empty"); + + String[] weekdayNameArray = weekdayNames.split(","); + weekdayOffsets = new int[weekdayNameArray.length]; + for (int i = 0; i < weekdayNameArray.length; i++) { + if (weekdayNameArray[i].length() != 3) + throw new ConfigError("Session " + sessionID + ": " + Session.SETTING_WEEKDAYS + " has an illegal weekday: [" + weekdayNameArray[i] + "] in " + weekdayNames); + + weekdayOffsets[i] = DayConverter.toInteger(weekdayNameArray[i]); + } + + startTime = getTimeEndPoint(settings, sessionID, defaultTimeZone, Session.SETTING_START_TIME); + endTime = getTimeEndPoint(settings, sessionID, defaultTimeZone, Session.SETTING_END_TIME); + + log.info("{} using schedule: {}", sessionID, toString()); + } + + private TimeEndPoint getTimeEndPoint(SessionSettings settings, SessionID sessionID, + TimeZone defaultTimeZone, String timeSetting) throws ConfigError, + FieldConvertError { + + Matcher matcher = TIME_PATTERN.matcher(settings.getString(sessionID, timeSetting)); + if (!matcher.find()) { + throw new ConfigError("Session " + sessionID + ": could not parse time '" + + settings.getString(sessionID, timeSetting) + "'."); + } + + return new TimeEndPoint( + Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)), + Integer.parseInt(matcher.group(3)), getTimeZone(matcher.group(4), defaultTimeZone)); + } + + private TimeZone getDefaultTimeZone(SessionSettings settings, SessionID sessionID) + throws ConfigError, FieldConvertError { + TimeZone sessionTimeZone; + if (settings.isSetting(sessionID, Session.SETTING_TIMEZONE)) { + String sessionTimeZoneID = settings.getString(sessionID, Session.SETTING_TIMEZONE); + sessionTimeZone = TimeZone.getTimeZone(sessionTimeZoneID); + if ("GMT".equals(sessionTimeZone.getID()) && !"GMT".equals(sessionTimeZoneID)) { + throw new ConfigError("Unrecognized time zone '" + sessionTimeZoneID + + "' for session " + sessionID); + } + } else { + sessionTimeZone = TimeZone.getTimeZone("UTC"); + } + return sessionTimeZone; + } + + private TimeZone getTimeZone(String tz, TimeZone defaultZone) { + return "".equals(tz) ? defaultZone : TimeZone.getTimeZone(tz.trim()); + } + + private class TimeEndPoint { + private final int hour; + private final int minute; + private final int second; + private final int timeInSeconds; + private final TimeZone tz; + + TimeEndPoint(int hour, int minute, int second, TimeZone tz) { + this.hour = hour; + this.minute = minute; + this.second = second; + this.tz = tz; + timeInSeconds = timeInSeconds(hour, minute, second); + } + + int getHour() { + return hour; + } + + int getMinute() { + return minute; + } + + int getSecond() { + return second; + } + + public String toString() { + Calendar calendar = Calendar.getInstance(tz); + calendar.set(Calendar.HOUR_OF_DAY, hour); + calendar.set(Calendar.MINUTE, minute); + calendar.set(Calendar.SECOND, second); + final SimpleDateFormat utc = new SimpleDateFormat("HH:mm:ss"); + utc.setTimeZone(TimeZone.getTimeZone("UTC")); + return utc.format(calendar.getTime()) + "-" + utc.getTimeZone().getID(); + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o instanceof TimeEndPoint) { + TimeEndPoint otherTime = (TimeEndPoint) o; + return timeInSeconds == otherTime.timeInSeconds; + } + return false; + } + + public int hashCode() { + assert false : "hashCode not supported"; + return 0; + } + + TimeZone getTimeZone() { + return tz; + } + } + + /** + * find the most recent session date/time range on or before t + * if t is in a session then that session will be returned + * @param t specific date/time + * @return relevant session date/time range + */ + private TimeInterval theMostRecentIntervalBefore(Calendar t) { + TimeInterval timeInterval = new TimeInterval(); + Calendar intervalStart = timeInterval.getStart(); + intervalStart.setTimeZone(startTime.getTimeZone()); + intervalStart.setTimeInMillis(t.getTimeInMillis()); + intervalStart.set(Calendar.HOUR_OF_DAY, startTime.getHour()); + intervalStart.set(Calendar.MINUTE, startTime.getMinute()); + intervalStart.set(Calendar.SECOND, startTime.getSecond()); + intervalStart.set(Calendar.MILLISECOND, 0); + + Calendar intervalEnd = timeInterval.getEnd(); + intervalEnd.setTimeZone(endTime.getTimeZone()); + intervalEnd.setTimeInMillis(t.getTimeInMillis()); + intervalEnd.set(Calendar.HOUR_OF_DAY, endTime.getHour()); + intervalEnd.set(Calendar.MINUTE, endTime.getMinute()); + intervalEnd.set(Calendar.SECOND, endTime.getSecond()); + intervalEnd.set(Calendar.MILLISECOND, 0); + + while (intervalStart.getTimeInMillis() > t.getTimeInMillis() || + !validDayOfWeek(intervalStart)) { + intervalStart.add(Calendar.DAY_OF_WEEK, -1); + intervalEnd.add(Calendar.DAY_OF_WEEK, -1); + } + + if (intervalEnd.getTimeInMillis() <= intervalStart.getTimeInMillis()) { + intervalEnd.add(Calendar.DAY_OF_WEEK, 1); + } + + return timeInterval; + } + + /** + * is the startDateTime a valid day based on the permitted days of week + * @param startDateTime time to test + * @return flag indicating if valid + */ + private boolean validDayOfWeek(Calendar startDateTime) { + int dow = startDateTime.get(Calendar.DAY_OF_WEEK); + for (int i = 0; i < weekdayOffsets.length; i++) + if (weekdayOffsets[i] == dow) + return true; + return false; + } + + private static class TimeInterval { + private final Calendar start = SystemTime.getUtcCalendar(); + private final Calendar end = SystemTime.getUtcCalendar(); + + boolean isContainingTime(Calendar t) { + return t.compareTo(start) >= 0 && t.compareTo(end) <= 0; + } + + public String toString() { + return start.getTime() + " --> " + end.getTime(); + } + + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof TimeInterval)) { + return false; + } + TimeInterval otherInterval = (TimeInterval) other; + return start.equals(otherInterval.start) && end.equals(otherInterval.end); + } + + public int hashCode() { + assert false : "hashCode not supported"; + return 0; + } + + Calendar getStart() { + return start; + } + + Calendar getEnd() { + return end; + } + } + + /** + * Predicate for determining if the two times are in the same session + * @param time1 test time 1 + * @param time2 test time 2 + * @return return true if in the same session + */ + @Override + public boolean isSameSession(Calendar time1, Calendar time2) { + TimeInterval interval1 = theMostRecentIntervalBefore(time1); + if (!interval1.isContainingTime(time1)) { + return false; + } + TimeInterval interval2 = theMostRecentIntervalBefore(time2); + return interval2.isContainingTime(time2) && interval1.equals(interval2); + } + + @Override + public boolean isNonStopSession() { + return false; + } + + /** + * Predicate for determining if the session should be active at the current time. + * + * @return true if session should be active, false otherwise. + */ + @Override + public boolean isSessionTime() { + return isSessionTime(SystemTime.getUtcCalendar()); + } + + boolean isSessionTime(Calendar time) { + TimeInterval interval = theMostRecentIntervalBefore(time); + return interval.isContainingTime(time); + } + + public String toString() { + StringBuilder buf = new StringBuilder(); + + SimpleDateFormat dowFormat = new SimpleDateFormat("EEEE"); + dowFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + + SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss-z"); + timeFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + + TimeInterval ti = theMostRecentIntervalBefore(SystemTime.getUtcCalendar()); + + formatTimeInterval(buf, ti, timeFormat, false); + + // Now the localized equivalents, if necessary + if (!startTime.getTimeZone().equals(SystemTime.UTC_TIMEZONE) + || !endTime.getTimeZone().equals(SystemTime.UTC_TIMEZONE)) { + buf.append(" ("); + formatTimeInterval(buf, ti, timeFormat, true); + buf.append(")"); + } + + return buf.toString(); + } + + private void formatTimeInterval(StringBuilder buf, TimeInterval timeInterval, + SimpleDateFormat timeFormat, boolean local) { + try { + for (int i = 0; i < weekdayOffsets.length; i++) { + buf.append(DayConverter.toString(weekdayOffsets[i])); + buf.append(", "); + } + } catch (ConfigError ex) { + // this can't happen as these are created using DayConverter.toInteger + } + + if (local) { + timeFormat.setTimeZone(startTime.getTimeZone()); + } + buf.append(timeFormat.format(timeInterval.getStart().getTime())); + + buf.append(" - "); + + if (local) { + timeFormat.setTimeZone(endTime.getTimeZone()); + } + buf.append(timeFormat.format(timeInterval.getEnd().getTime())); + } + + private int timeInSeconds(int hour, int minute, int second) { + return (hour * 3600) + (minute * 60) + second; + } +} diff --git a/quickfixj-core/src/main/java/quickfix/WeekdaySessionScheduleFactory.java b/quickfixj-core/src/main/java/quickfix/WeekdaySessionScheduleFactory.java new file mode 100644 index 000000000..d81902dc9 --- /dev/null +++ b/quickfixj-core/src/main/java/quickfix/WeekdaySessionScheduleFactory.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) quickfixengine.org All rights reserved. + * + * This file is part of the QuickFIX FIX Engine + * + * This file may be distributed under the terms of the quickfixengine.org + * license as defined by quickfixengine.org and appearing in the file + * LICENSE included in the packaging of this file. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING + * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * See http://www.quickfixengine.org/LICENSE for licensing information. + * + * Contact ask@quickfixengine.org if any conditions of this licensing + * are not clear to you. + ******************************************************************************/ + +package quickfix; + +/** + * Factory for creating weekday session schedules. + */ +public class WeekdaySessionScheduleFactory implements SessionScheduleFactory { + + public SessionSchedule create(SessionID sessionID, SessionSettings settings) throws ConfigError + { + try { + return new WeekdaySessionSchedule(settings, sessionID); + } catch (final FieldConvertError e) { + throw new ConfigError(e.getMessage()); + } + } +} \ No newline at end of file diff --git a/quickfixj-core/src/test/java/quickfix/WeekdaySessionScheduleTest.java b/quickfixj-core/src/test/java/quickfix/WeekdaySessionScheduleTest.java new file mode 100644 index 000000000..d59220937 --- /dev/null +++ b/quickfixj-core/src/test/java/quickfix/WeekdaySessionScheduleTest.java @@ -0,0 +1,602 @@ +/******************************************************************************* + * Copyright (c) quickfixengine.org All rights reserved. + * + * This file is part of the QuickFIX FIX Engine + * + * This file may be distributed under the terms of the quickfixengine.org + * license as defined by quickfixengine.org and appearing in the file + * LICENSE included in the packaging of this file. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING + * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * See http://www.quickfixengine.org/LICENSE for licensing information. + * + * Contact ask@quickfixengine.org if any conditions of this licensing + * are not clear to you. + ******************************************************************************/ + +package quickfix; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.text.DateFormat; +import java.text.DateFormatSymbols; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Locale; +import java.util.TimeZone; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import quickfix.field.converter.UtcTimeOnlyConverter; + +public class WeekdaySessionScheduleTest { + private MockSystemTimeSource mockSystemTimeSource; + private Locale defaultLocale; + + @Before + public void setUp() throws Exception { + mockSystemTimeSource = new MockSystemTimeSource(); + SystemTime.setTimeSource(mockSystemTimeSource); + defaultLocale = Locale.getDefault(); + Locale.setDefault(Locale.GERMANY); + } + + @After + public void tearDown() throws Exception { + SystemTime.setTimeSource(null); + Locale.setDefault(defaultLocale); + } + + private SessionSchedule newSessionSchedule(Date startTime, Date endTime, String weekdays) throws Exception { + SessionSettings settings = new SessionSettings(); + if (weekdays != null && weekdays.length() > 0) { + settings.setString(Session.SETTING_WEEKDAYS, weekdays); + } + if (startTime != null) { + settings.setString(Session.SETTING_START_TIME, UtcTimeOnlyConverter.convert(startTime, false)); + } + if (endTime != null) { + settings.setString(Session.SETTING_END_TIME, UtcTimeOnlyConverter.convert(endTime, false)); + } + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + return new WeekdaySessionSchedule(settings, sessionID); + } + + private void doIsSessionTimeTest(SessionSchedule schedule, boolean expectedInSession, int year, + int month, int day, int hour, int minute, int second) { + doIsSessionTimeTest(schedule, expectedInSession, year, month, day, hour, minute, second, + TimeZone.getTimeZone("UTC")); + } + + private void doIsSessionTimeTest(SessionSchedule schedule, boolean expectedInSession, int year, + int month, int day, int hour, int minute, int second, TimeZone timeZone) { + mockSystemTimeSource + .setTime(getTimeStamp(year, month, day, hour, minute, second, timeZone)); + assertEquals("in session expectation incorrect", expectedInSession, schedule + .isSessionTime()); + } + + private void doIsSessionTimeTest(SessionSettings settings, SessionID sessionID, + boolean expectedInSession, int year, int month, int day, int hour, int minute, + int second, String timeZoneID) throws ConfigError, FieldConvertError { + mockSystemTimeSource.setTime(getTimeStamp(year, month, day, hour, minute, second, TimeZone + .getTimeZone(timeZoneID))); + SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); + assertEquals("schedule is wrong", expectedInSession, schedule.isSessionTime()); + } + + @Test + public void testMissingStartTime() throws Exception { + Calendar end = getUtcTime(18, 0, 0); + try { + newSessionSchedule(null, end.getTime(), "Mon"); + fail("no exception"); + } catch (ConfigError e) { + // do nothing + } + } + + @Test + public void testMissingEndTime() throws Exception { + Calendar start = getUtcTime(3, 0, 0); + try { + newSessionSchedule(start.getTime(), null, "Mon"); + fail("no exception"); + } catch (ConfigError e) { + // do nothing + } + } + + @Test + public void testMissingWeekdays() throws Exception { + Calendar start = getUtcTime(3, 0, 0); + Calendar end = getUtcTime(18, 0, 0); + try { + newSessionSchedule(start.getTime(), end.getTime(), null); + fail("no exception"); + } catch (ConfigError e) { + // do nothing + } + } + + @Test + public void testInvalidWeekdays1() throws Exception { + Calendar start = getUtcTime(3, 0, 0); + Calendar end = getUtcTime(18, 0, 0); + try { + newSessionSchedule(start.getTime(), end.getTime(), "AAA"); + fail("no exception"); + } catch (ConfigError e) { + // do nothing + } + } + + @Test + public void testInvalidWeekdays2() throws Exception { + Calendar start = getUtcTime(3, 0, 0); + Calendar end = getUtcTime(18, 0, 0); + try { + newSessionSchedule(start.getTime(), end.getTime(), ",Mon"); + fail("no exception"); + } catch (ConfigError e) { + // do nothing + } + } + + @Test + public void testInvalidWeekdays3() throws Exception { + Calendar start = getUtcTime(3, 0, 0); + Calendar end = getUtcTime(18, 0, 0); + try { + newSessionSchedule(start.getTime(), end.getTime(), "Mon,,Tue"); + fail("no exception"); + } catch (ConfigError e) { + // do nothing + } + } + + @Test + public void testSessionTimeStartBeforeEnd() throws Exception { + Calendar start = getUtcTime(3, 0, 0); + Calendar end = getUtcTime(18, 0, 0); + SessionSchedule schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); + // Sunday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 2, 59, 59); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 18, 0, 1); + // Monday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 2, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 2, 3, 0, 0); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 2, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 18, 0, 1); + // Tuesday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 3, 2, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 3, 3, 0, 0); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 3, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 3, 18, 0, 1); + // Wednesday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 4, 2, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 4, 3, 0, 0); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 4, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 4, 18, 0, 1); + // Thursday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 5, 2, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 5, 3, 0, 0); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 5, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 5, 18, 0, 1); + // Friday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 6, 2, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 6, 3, 0, 0); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 6, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 6, 18, 0, 1); + // Saturday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 2, 59, 59); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 18, 0, 1); + } + @Test + public void testSessionTimeEndBeforeStart() throws Exception { + Calendar start = getUtcTime(18, 0, 0); + Calendar end = getUtcTime(3, 0, 0); + SessionSchedule schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); + // Sunday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 17, 59, 59); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 18, 0, 0); + // Monday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 17, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 2, 18, 0, 0); + // Tuesday + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 3, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 3, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 3, 17, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 3, 18, 0, 0); + // Wednesday + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 4, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 4, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 4, 17, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 4, 18, 0, 0); + // Thursday + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 5, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 5, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 5, 17, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 5, 18, 0, 0); + // Friday + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 6, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 6, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 6, 17, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 6, 18, 0, 0); + // Saturday + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 7, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 17, 59, 59); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 18, 0, 0); + } + + @Test + public void testIsSameSession() throws Exception { + // ===================================================== + // start time is less than end time + Calendar start = getUtcTime(3, 0, 0); + Calendar end = getUtcTime(18, 0, 0); + SessionSchedule schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); + + // same time + Calendar t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + Calendar t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // time 2 in same session but greater + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // time 2 in same session but less + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // time 1 not in session + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 1); + doIsSameSessionTest(schedule, t1, t2, false); + + // time 2 not in session + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 1); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + doIsSameSessionTest(schedule, t1, t2, false); + + // same time (in session window) two different days + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 3, 0, 0); + doIsSameSessionTest(schedule, t1, t2, false); + + // ===================================================== + // start time is greater than end time + start = getUtcTime(18, 0, 0); + end = getUtcTime(13, 0, 0); + schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); + + // same session same day + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 19, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // same time (in session window) two different days + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 18, 0, 0); + doIsSameSessionTest(schedule, t1, t2, false); + + // same session time 2 is in next day + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 3, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // same session time 1 is in next day + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 3, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // time 1 is 25 hours greater than time 2 + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 19, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + doIsSameSessionTest(schedule, t1, t2, false); + + // ===================================================== + // start time is equal to end time + start = getUtcTime(6, 0, 0); + end = getUtcTime(6, 0, 0); + schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); + + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 18, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + doIsSameSessionTest(schedule, t1, t2, false); + } + + @Test + public void testSettingsWithoutStartEndDayWithTimeZone() throws Exception { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, " US/Eastern "); + settings.setString(Session.SETTING_START_TIME, "01:00:00"); + settings.setString(Session.SETTING_END_TIME, "15:00:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); + TimeZone tz = TimeZone.getTimeZone("US/Eastern"); + doIsSessionTimeTest(schedule, false, 2002, 5, 5, 0, 59, 0, tz); + doIsSessionTimeTest(schedule, true, 2002, 7, 5, 14, 30, 0, tz); + doIsSessionTimeTest(schedule, false, 2003, 5, 5, 16, 30, 0, tz); + } + + @Test + public void testSettingsWithTimeZoneInTime() throws Exception { + // This test is very susceptible to whether the system time starts + // in daylight time or not, so we just force it that way. Otherwise + // the first time the mock time source gets set to a time with daylight time + // then the schedule appears to change 1 hr. + TimeZone tz = TimeZone.getTimeZone("US/Eastern"); + mockSystemTimeSource.setTime(getTimeStamp(2002, 5, 5, 0, 0, 0, tz)); + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_START_TIME, "01:00:00 US/Eastern"); + settings.setString(Session.SETTING_END_TIME, "15:00:00 US/Central"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); + doIsSessionTimeTest(schedule, false, 2002, 5, 5, 0, 59, 0, tz); + doIsSessionTimeTest(schedule, true, 2002, 7, 5, 14, 30, 0, tz); + + // The end time is actually 16:00 Eastern time but specified as + // 15:00 Central time. + doIsSessionTimeTest(schedule, true, 2003, 5, 5, 15, 59, 0, tz); + doIsSessionTimeTest(schedule, true, 2003, 5, 5, 16, 0, 0, tz); + doIsSessionTimeTest(schedule, false, 2003, 5, 5, 16, 1, 0, tz); + } + + /** + * From 1968 to 1971, GMT was an hour ahead of UTC. If we perform all our calculations in 1970, + * someone in GMT (e.g. London) will see sessions ending an hour later than expected. This test + * demonstrates the 1970 behavior and verifies that calculations on current dates give the proper results. + * + *

+ * More details at: + *

+ * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4644278 + * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4832236 + */ + @Test + public void testThatUTCAndGMTAreTheSameNow() throws ConfigError, FieldConvertError, + ParseException { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_START_TIME, "00:01:00"); + settings.setString(Session.SETTING_END_TIME, "21:50:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri,Sat,Sun"); + + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + + // In 1970, a session configured to end at 21:50 UTC would end at + // 22:50 London time any time of year. + doIsSessionTimeTest(settings, sessionID, true, 1970, Calendar.JANUARY, 27, 22, 50, 0, + "Europe/London"); + doIsSessionTimeTest(settings, sessionID, false, 1970, Calendar.JANUARY, 27, 22, 50, 1, + "Europe/London"); + doIsSessionTimeTest(settings, sessionID, true, 1970, Calendar.JULY, 27, 22, 50, 0, + "Europe/London"); + doIsSessionTimeTest(settings, sessionID, false, 1970, Calendar.JULY, 27, 22, 50, 1, + "Europe/London"); + + // Now, at least in winter, it should end at 21:50 in both zones -- + // if the end time session setting is being parsed correctly. + doIsSessionTimeTest(settings, sessionID, true, 2006, Calendar.FEBRUARY, 27, 21, 50, 0, + "Europe/London"); + doIsSessionTimeTest(settings, sessionID, false, 2006, Calendar.FEBRUARY, 27, 21, 50, 1, + "Europe/London"); + + // When summer time (BST) is in effect, London time will be an hour + // ahead again, and the session will end at 22:50 there. + doIsSessionTimeTest(settings, sessionID, true, 2006, Calendar.JULY, 27, 22, 50, 0, + "Europe/London"); + doIsSessionTimeTest(settings, sessionID, false, 2006, Calendar.JULY, 27, 22, 50, 1, + "Europe/London"); + + settings.setString(Session.SETTING_TIMEZONE, "Europe/London"); + + // In 1970, a session configured to end at 21:50 GMT would end at + // 20:50 UTC any time of year. + doIsSessionTimeTest(settings, sessionID, true, 1970, Calendar.JANUARY, 27, 20, 50, 0, "UTC"); + doIsSessionTimeTest(settings, sessionID, false, 1970, Calendar.JANUARY, 27, 20, 50, 1, + "UTC"); + doIsSessionTimeTest(settings, sessionID, true, 1970, Calendar.JULY, 27, 20, 50, 0, "UTC"); + doIsSessionTimeTest(settings, sessionID, false, 1970, Calendar.JULY, 27, 20, 50, 1, "UTC"); + + // Now, at least in winter, it should end at 21:50 in both zones -- + // if the end time session setting is being parsed correctly. + doIsSessionTimeTest(settings, sessionID, true, 2006, Calendar.FEBRUARY, 27, 21, 50, 0, + "UTC"); + doIsSessionTimeTest(settings, sessionID, false, 2006, Calendar.FEBRUARY, 27, 21, 50, 1, + "UTC"); + + // When summer time (BST) is in effect, London time will be an hour + // ahead again, and the session will end at 20:50 UTC there. + doIsSessionTimeTest(settings, sessionID, true, 2006, Calendar.JULY, 27, 20, 50, 0, "UTC"); + doIsSessionTimeTest(settings, sessionID, false, 2006, Calendar.JULY, 27, 20, 50, 1, "UTC"); + } + + @Test + public void testBadTimeSpecification() throws Exception { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, "US/Eastern"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + + try { + settings.setString(Session.SETTING_START_TIME, "01:xx:00"); + settings.setString(Session.SETTING_END_TIME, "15:00:00"); + new WeekdaySessionSchedule(settings, sessionID); + fail("no exception"); + } catch (ConfigError e) { + assertTrue(e.getMessage().contains("could not parse")); + } + + try { + settings.setString(Session.SETTING_START_TIME, "01:00:00"); + settings.setString(Session.SETTING_END_TIME, "15:00:yy"); + new WeekdaySessionSchedule(settings, sessionID); + fail("no exception"); + } catch (ConfigError e) { + assertTrue(e.getMessage().contains("could not parse")); + } + } + + @Test + public void testBadTimeZone() throws Exception { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, "US/BOGUS"); + settings.setString(Session.SETTING_START_TIME, "01:00:00"); + settings.setString(Session.SETTING_END_TIME, "15:00:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + + try { + new WeekdaySessionSchedule(settings, sessionID); + fail("no exception"); + } catch (ConfigError e) { + assertTrue(e.getMessage().contains("Unrecognized time zone")); + } + } + + @Test + public void testWeekdayToString() throws ConfigError, FieldConvertError { + // Just be sure it doesn't throw exceptions + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, "US/Eastern"); + settings.setString(Session.SETTING_START_TIME, "01:00:00"); + settings.setString(Session.SETTING_END_TIME, "15:00:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); + assertNotNull(schedule.toString()); + } + + @Test + public void testSettingsWithDST() throws Exception { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, "Europe/Zurich"); + settings.setString(Session.SETTING_START_TIME, "01:30:00"); + settings.setString(Session.SETTING_END_TIME, "03:15:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri,Sat,Sun"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + // + SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 20, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 20, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 20, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 20, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 20, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + schedule = new WeekdaySessionSchedule(settings, sessionID); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 27, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 27, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 27, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 27, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 27, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 28, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 28, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 28, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 28, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 28, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 29, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 29, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 29, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 29, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 29, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + schedule = new WeekdaySessionSchedule(settings, sessionID); + doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 30, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 30, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 30, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 30, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 30, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 31, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 31, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 31, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); // -> this is 03:16 ! + doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 31, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 31, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + doIsSessionTimeTest(schedule, false, 2013, Calendar.APRIL, 1, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.APRIL, 1, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.APRIL, 1, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.APRIL, 1, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2013, Calendar.APRIL, 1, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + } + + @Test + public void testSettingsWithStartEndDayWithDSTMocked() throws Exception { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, "America/New_York"); + settings.setString(Session.SETTING_START_TIME, "20:00:00"); + settings.setString(Session.SETTING_END_TIME, "17:00:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri,Sat,Sun"); + + mockSystemTimeSource.setTime(getTimeStamp(2008, Calendar.NOVEMBER, 2, 18, 0, 0, TimeZone.getTimeZone("America/New_York"))); + + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); + + //System.out.println(schedule); + + // November,2 -> Sunday + doIsSessionTimeTest(schedule, true, 2008, Calendar.NOVEMBER, 2, 20, 0, 0, + TimeZone.getTimeZone("America/New_York")); + // November,7 -> Friday + doIsSessionTimeTest(schedule, true, 2008, Calendar.NOVEMBER, 7, 17, 0, 0, + TimeZone.getTimeZone("America/New_York")); + } + + private final SimpleDateFormat dateFormat = new SimpleDateFormat("E M/d HH:mm:ss"); + + { + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + } + + private void doIsSameSessionTest(SessionSchedule schedule, Calendar time1, Calendar time2, + boolean isSameSession) { + assertEquals("isSameSession is wrong", isSameSession, schedule.isSameSession(time1, time2)); + assertEquals("isSameSession is wrong", isSameSession, schedule.isSameSession(time2, time1)); + } + + private Calendar getTimeStamp(int year, int month, int day, int hour, int minute, int second, + TimeZone timeZone) { + Calendar c = new GregorianCalendar(year, month, day, hour, minute, second); + c.setTimeZone(timeZone); + return c; + } + + private Calendar getUtcTimeStamp(int year, int month, int day, int hour, int minute, int second) { + return getTimeStamp(year, month, day, hour, minute, second, TimeZone.getTimeZone("UTC")); + } + + private Calendar getUtcTime(int hour, int minute, int second) { + // Monday + return getUtcTimeStamp(2017, Calendar.JANUARY, 2, hour, minute, second); + } +} From 9979ace33ebec0461e9e6fb21d917f5a5be1d8c9 Mon Sep 17 00:00:00 2001 From: Arthurm1 Date: Fri, 25 Aug 2017 11:20:16 +0100 Subject: [PATCH 106/165] Add Weekdays schedule documentation --- .../doc/usermanual/usage/configuration.html | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/quickfixj-core/src/main/doc/usermanual/usage/configuration.html b/quickfixj-core/src/main/doc/usermanual/usage/configuration.html index c048af0ce..c41a4b1eb 100644 --- a/quickfixj-core/src/main/doc/usermanual/usage/configuration.html +++ b/quickfixj-core/src/main/doc/usermanual/usage/configuration.html @@ -202,18 +202,32 @@

QuickFIX Settings

StartDay - For week long sessions, the starting day of week for the session. Use in combination with StartTime. + For week long sessions, the starting day of week for the session. +
Use in combination with StartTime. +
Incompatible with Weekdays Day of week in the default locale (e.g. Monday, mon, lundi, lun. etc.)   EndDay - For week long sessions, the ending day of week for the session. Use in combination with EndTime. + For week long sessions, the ending day of week for the session. +
Use in combination with EndTime. +
Incompatible with Weekdays Day of week in the default locale (e.g. Monday, mon, lundi, lun. etc.)   + + Weekdays + For daily sessions that are active on specific days of the week. +
Use in combination with StartTime and EndTime. +
Incompatible with StartDay and EndDay. +
If StartTime is before EndTime then the day corresponds to the StartTime. + Comma-delimited list of days of the week in the default locale (e.g. "Sun,Mon,Tue", "Dimanche,Lundi,Mardi" etc.) + +   + NonStopSession If set the session will never reset. This is effectively the same as setting 00:00:00 as StartTime and EndTime. From 37b97fb54ef61de7deac4b70f9dfcd2925a38d47 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Fri, 25 Aug 2017 16:10:23 +0200 Subject: [PATCH 107/165] Integrated changes done by Arthur McGibbon @Arthurm1 #133 into DefaultSessionSchedule --- .../java/quickfix/DefaultSessionSchedule.java | 166 +++-- .../src/main/java/quickfix/Session.java | 4 +- .../main/java/quickfix/SessionSchedule.java | 12 + .../java/quickfix/WeekdaySessionSchedule.java | 339 ---------- .../WeekdaySessionScheduleFactory.java | 35 - .../java/quickfix/SessionScheduleTest.java | 455 ++++++++++++- .../quickfix/WeekdaySessionScheduleTest.java | 602 ------------------ 7 files changed, 577 insertions(+), 1036 deletions(-) delete mode 100644 quickfixj-core/src/main/java/quickfix/WeekdaySessionSchedule.java delete mode 100644 quickfixj-core/src/main/java/quickfix/WeekdaySessionScheduleFactory.java delete mode 100644 quickfixj-core/src/test/java/quickfix/WeekdaySessionScheduleTest.java diff --git a/quickfixj-core/src/main/java/quickfix/DefaultSessionSchedule.java b/quickfixj-core/src/main/java/quickfix/DefaultSessionSchedule.java index c48886bb6..0f4524b3b 100644 --- a/quickfixj-core/src/main/java/quickfix/DefaultSessionSchedule.java +++ b/quickfixj-core/src/main/java/quickfix/DefaultSessionSchedule.java @@ -31,38 +31,60 @@ /** * Corresponds to SessionTime in C++ code */ -public class DefaultSessionSchedule implements SessionSchedule { +public class DefaultSessionSchedule implements SessionSchedule { private static final int NOT_SET = -1; private static final Pattern TIME_PATTERN = Pattern.compile("(\\d{2}):(\\d{2}):(\\d{2})(.*)"); private final TimeEndPoint startTime; private final TimeEndPoint endTime; - private final boolean nonStopSession; - protected final static Logger log = LoggerFactory.getLogger(DefaultSessionSchedule.class); + private final boolean isNonStopSession; + private final boolean isWeekdaySession; + private final int[] weekdayOffsets; + protected static final Logger LOG = LoggerFactory.getLogger(DefaultSessionSchedule.class); public DefaultSessionSchedule(SessionSettings settings, SessionID sessionID) throws ConfigError, FieldConvertError { - nonStopSession = settings.isSetting(sessionID, Session.SETTING_NON_STOP_SESSION) && settings.getBool(sessionID, Session.SETTING_NON_STOP_SESSION); + isNonStopSession = settings.isSetting(sessionID, Session.SETTING_NON_STOP_SESSION) && settings.getBool(sessionID, Session.SETTING_NON_STOP_SESSION); TimeZone defaultTimeZone = getDefaultTimeZone(settings, sessionID); - if (nonStopSession) { + if (isNonStopSession) { + isWeekdaySession = false; + weekdayOffsets = new int[0]; startTime = endTime = new TimeEndPoint(NOT_SET, 0, 0, 0, defaultTimeZone); return; + } else { + isWeekdaySession = settings.isSetting(sessionID, Session.SETTING_WEEKDAYS); } boolean startDayPresent = settings.isSetting(sessionID, Session.SETTING_START_DAY); boolean endDayPresent = settings.isSetting(sessionID, Session.SETTING_END_DAY); - if (startDayPresent && !endDayPresent) { - throw new ConfigError("Session " + sessionID + ": StartDay used without EndDay"); - } + if (isWeekdaySession) { + if (startDayPresent || endDayPresent ) + throw new ConfigError("Session " + sessionID + ": usage of StartDay or EndDay is not compatible with setting " + Session.SETTING_WEEKDAYS); - if (endDayPresent && !startDayPresent) { - throw new ConfigError("Session " + sessionID + ": EndDay used without StartDay"); - } + String weekdayNames = settings.getString(sessionID, Session.SETTING_WEEKDAYS); + if (weekdayNames.isEmpty()) + throw new ConfigError("Session " + sessionID + ": " + Session.SETTING_WEEKDAYS + " is empty"); + + String[] weekdayNameArray = weekdayNames.split(","); + weekdayOffsets = new int[weekdayNameArray.length]; + for (int i = 0; i < weekdayNameArray.length; i++) { + weekdayOffsets[i] = DayConverter.toInteger(weekdayNameArray[i]); + } + } else { + weekdayOffsets = new int[0]; + + if (startDayPresent && !endDayPresent) { + throw new ConfigError("Session " + sessionID + ": StartDay used without EndDay"); + } + if (endDayPresent && !startDayPresent) { + throw new ConfigError("Session " + sessionID + ": EndDay used without StartDay"); + } + } startTime = getTimeEndPoint(settings, sessionID, defaultTimeZone, Session.SETTING_START_TIME, Session.SETTING_START_DAY); endTime = getTimeEndPoint(settings, sessionID, defaultTimeZone, Session.SETTING_END_TIME, Session.SETTING_END_DAY); - log.info("[" + sessionID + "] " + toString()); + LOG.info("[" + sessionID + "] " + toString()); } private TimeEndPoint getTimeEndPoint(SessionSettings settings, SessionID sessionID, @@ -75,7 +97,8 @@ private TimeEndPoint getTimeEndPoint(SessionSettings settings, SessionID session + settings.getString(sessionID, timeSetting) + "'."); } - return new TimeEndPoint(getDay(settings, sessionID, daySetting, NOT_SET), + return new TimeEndPoint( + getDay(settings, sessionID, daySetting, NOT_SET), Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)), Integer.parseInt(matcher.group(3)), getTimeZone(matcher.group(4), defaultTimeZone)); } @@ -100,7 +123,7 @@ private TimeZone getTimeZone(String tz, TimeZone defaultZone) { return "".equals(tz) ? defaultZone : TimeZone.getTimeZone(tz.trim()); } - private class TimeEndPoint { + private static class TimeEndPoint { private final int weekDay; private final int hour; private final int minute; @@ -117,34 +140,19 @@ public TimeEndPoint(int day, int hour, int minute, int second, TimeZone tz) { timeInSeconds = timeInSeconds(hour, minute, second); } - public int getHour() { + int getHour() { return hour; } - public int getMinute() { + int getMinute() { return minute; } - public int getSecond() { + int getSecond() { return second; } - public String toString() { - try { - Calendar calendar = Calendar.getInstance(tz); - calendar.set(Calendar.HOUR_OF_DAY, hour); - calendar.set(Calendar.MINUTE, minute); - calendar.set(Calendar.SECOND, second); - final SimpleDateFormat utc = new SimpleDateFormat("HH:mm:ss"); - utc.setTimeZone(TimeZone.getTimeZone("UTC")); - return (isSet(weekDay) ? DayConverter.toString(weekDay) + "," : "") - + utc.format(calendar.getTime()) + "-" + utc.getTimeZone().getID(); - } catch (ConfigError e) { - return "ERROR: " + e; - } - } - - public int getDay() { + int getDay() { return weekDay; } @@ -164,11 +172,17 @@ public int hashCode() { return 0; } - public TimeZone getTimeZone() { + TimeZone getTimeZone() { return tz; } } + /** + * find the most recent session date/time range on or before t + * if t is in a session then that session will be returned + * @param t specific date/time + * @return relevant session date/time range + */ private TimeInterval theMostRecentIntervalBefore(Calendar t) { TimeInterval timeInterval = new TimeInterval(); Calendar intervalStart = timeInterval.getStart(); @@ -187,24 +201,37 @@ private TimeInterval theMostRecentIntervalBefore(Calendar t) { intervalEnd.set(Calendar.SECOND, endTime.getSecond()); intervalEnd.set(Calendar.MILLISECOND, 0); - if (isSet(startTime.getDay())) { - intervalStart.set(Calendar.DAY_OF_WEEK, startTime.getDay()); - if (intervalStart.getTimeInMillis() > t.getTimeInMillis()) { - intervalStart.add(Calendar.WEEK_OF_YEAR, -1); - intervalEnd.add(Calendar.WEEK_OF_YEAR, -1); + if (isWeekdaySession) { + while (intervalStart.getTimeInMillis() > t.getTimeInMillis() || + !validDayOfWeek(intervalStart)) { + intervalStart.add(Calendar.DAY_OF_WEEK, -1); + intervalEnd.add(Calendar.DAY_OF_WEEK, -1); } - } else if (intervalStart.getTimeInMillis() > t.getTimeInMillis()) { - intervalStart.add(Calendar.DAY_OF_YEAR, -1); - intervalEnd.add(Calendar.DAY_OF_YEAR, -1); - } - if (isSet(endTime.getDay())) { - intervalEnd.set(Calendar.DAY_OF_WEEK, endTime.getDay()); if (intervalEnd.getTimeInMillis() <= intervalStart.getTimeInMillis()) { - intervalEnd.add(Calendar.WEEK_OF_MONTH, 1); + intervalEnd.add(Calendar.DAY_OF_WEEK, 1); + } + + } else { + if (isSet(startTime.getDay())) { + intervalStart.set(Calendar.DAY_OF_WEEK, startTime.getDay()); + if (intervalStart.getTimeInMillis() > t.getTimeInMillis()) { + intervalStart.add(Calendar.WEEK_OF_YEAR, -1); + intervalEnd.add(Calendar.WEEK_OF_YEAR, -1); + } + } else if (intervalStart.getTimeInMillis() > t.getTimeInMillis()) { + intervalStart.add(Calendar.DAY_OF_YEAR, -1); + intervalEnd.add(Calendar.DAY_OF_YEAR, -1); + } + + if (isSet(endTime.getDay())) { + intervalEnd.set(Calendar.DAY_OF_WEEK, endTime.getDay()); + if (intervalEnd.getTimeInMillis() <= intervalStart.getTimeInMillis()) { + intervalEnd.add(Calendar.WEEK_OF_MONTH, 1); + } + } else if (intervalEnd.getTimeInMillis() <= intervalStart.getTimeInMillis()) { + intervalEnd.add(Calendar.DAY_OF_WEEK, 1); } - } else if (intervalEnd.getTimeInMillis() <= intervalStart.getTimeInMillis()) { - intervalEnd.add(Calendar.DAY_OF_WEEK, 1); } return timeInterval; @@ -214,7 +241,7 @@ private static class TimeInterval { private final Calendar start = SystemTime.getUtcCalendar(); private final Calendar end = SystemTime.getUtcCalendar(); - public boolean isContainingTime(Calendar t) { + boolean isContainingTime(Calendar t) { return t.compareTo(start) >= 0 && t.compareTo(end) <= 0; } @@ -238,17 +265,18 @@ public int hashCode() { return 0; } - public Calendar getStart() { + Calendar getStart() { return start; } - public Calendar getEnd() { + Calendar getEnd() { return end; } } + @Override public boolean isSameSession(Calendar time1, Calendar time2) { - if (nonStopSession) + if (isNonStopSession()) return true; TimeInterval interval1 = theMostRecentIntervalBefore(time1); if (!interval1.isContainingTime(time1)) { @@ -258,16 +286,18 @@ public boolean isSameSession(Calendar time1, Calendar time2) { return interval2.isContainingTime(time2) && interval1.equals(interval2); } + @Override public boolean isNonStopSession() { - return nonStopSession; + return isNonStopSession; } private boolean isDailySession() { return !isSet(startTime.getDay()) && !isSet(endTime.getDay()); } - + + @Override public boolean isSessionTime() { - if(nonStopSession) { + if(isNonStopSession()) { return true; } Calendar now = SystemTime.getUtcCalendar(); @@ -301,7 +331,16 @@ public String toString() { private void formatTimeInterval(StringBuilder buf, TimeInterval timeInterval, SimpleDateFormat timeFormat, boolean local) { - if (!isDailySession()) { + if (isWeekdaySession) { + try { + for (int i = 0; i < weekdayOffsets.length; i++) { + buf.append(DayConverter.toString(weekdayOffsets[i])); + buf.append(", "); + } + } catch (ConfigError ex) { + // this can't happen as these are created using DayConverter.toInteger + } + } else if (!isDailySession()) { buf.append("weekly, "); formatDayOfWeek(buf, startTime.getDay()); buf.append(" "); @@ -349,7 +388,20 @@ private boolean isSet(int value) { return value != NOT_SET; } - private int timeInSeconds(int hour, int minute, int second) { + private static int timeInSeconds(int hour, int minute, int second) { return (hour * 3600) + (minute * 60) + second; } + + /** + * is the startDateTime a valid day based on the permitted days of week + * @param startDateTime time to test + * @return flag indicating if valid + */ + private boolean validDayOfWeek(Calendar startDateTime) { + int dow = startDateTime.get(Calendar.DAY_OF_WEEK); + for (int i = 0; i < weekdayOffsets.length; i++) + if (weekdayOffsets[i] == dow) + return true; + return false; + } } diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index ec23718a7..4122653c7 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -148,13 +148,13 @@ public class Session implements Closeable { public static final String SETTING_END_TIME = "EndTime"; /** - * Session scheduling setting to specify active days of the week when using a WeekdaySessionSchedule. + * Session scheduling setting to specify active days of the week. */ public static final String SETTING_WEEKDAYS = "Weekdays"; /** * Session setting to indicate whether a data dictionary should be used. If - * a data dictionary is not used then message validation is not possble. + * a data dictionary is not used then message validation is not possible. */ public static final String SETTING_USE_DATA_DICTIONARY = "UseDataDictionary"; diff --git a/quickfixj-core/src/main/java/quickfix/SessionSchedule.java b/quickfixj-core/src/main/java/quickfix/SessionSchedule.java index 17529b7c8..a19d612da 100644 --- a/quickfixj-core/src/main/java/quickfix/SessionSchedule.java +++ b/quickfixj-core/src/main/java/quickfix/SessionSchedule.java @@ -26,9 +26,21 @@ */ public interface SessionSchedule { + /** + * Predicate for determining if the two times are in the same session + * @param time1 test time 1 + * @param time2 test time 2 + * @return return true if in the same session + */ boolean isSameSession(Calendar time1, Calendar time2); boolean isNonStopSession(); + /** + * Predicate for determining if the session should be active at the current time. + * + * @return true if session should be active, false otherwise. + */ boolean isSessionTime(); + } diff --git a/quickfixj-core/src/main/java/quickfix/WeekdaySessionSchedule.java b/quickfixj-core/src/main/java/quickfix/WeekdaySessionSchedule.java deleted file mode 100644 index da0ffefa5..000000000 --- a/quickfixj-core/src/main/java/quickfix/WeekdaySessionSchedule.java +++ /dev/null @@ -1,339 +0,0 @@ -/******************************************************************************* - * Copyright (c) quickfixengine.org All rights reserved. - * - * This file is part of the QuickFIX FIX Engine - * - * This file may be distributed under the terms of the quickfixengine.org - * license as defined by quickfixengine.org and appearing in the file - * LICENSE included in the packaging of this file. - * - * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING - * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE. - * - * See http://www.quickfixengine.org/LICENSE for licensing information. - * - * Contact ask@quickfixengine.org if any conditions of this licensing - * are not clear to you. - ******************************************************************************/ - -package quickfix; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Daily schedule that can be configured to only login on specific days e.g. Mon -> Fri - * The day specified corresponds to the day that the StartTime is valid, - * this is relevant when StartTime is after EndTime - */ -public class WeekdaySessionSchedule implements SessionSchedule { - private static final Pattern TIME_PATTERN = Pattern.compile("(\\d{2}):(\\d{2}):(\\d{2})(.*)"); - - private final int[] weekdayOffsets; - private final TimeEndPoint startTime; - private final TimeEndPoint endTime; - - protected final static Logger log = LoggerFactory.getLogger(WeekdaySessionSchedule.class); - - WeekdaySessionSchedule(SessionSettings settings, SessionID sessionID) throws ConfigError, - FieldConvertError { - - TimeZone defaultTimeZone = getDefaultTimeZone(settings, sessionID); - - if (!settings.isSetting(sessionID, Session.SETTING_WEEKDAYS)) - throw new ConfigError("Session " + sessionID + ": does not have " + Session.SETTING_WEEKDAYS + " specified"); - - String weekdayNames = settings.getString(sessionID, Session.SETTING_WEEKDAYS); - if (weekdayNames.isEmpty()) - throw new ConfigError("Session " + sessionID + ": " + Session.SETTING_WEEKDAYS + " is empty"); - - String[] weekdayNameArray = weekdayNames.split(","); - weekdayOffsets = new int[weekdayNameArray.length]; - for (int i = 0; i < weekdayNameArray.length; i++) { - if (weekdayNameArray[i].length() != 3) - throw new ConfigError("Session " + sessionID + ": " + Session.SETTING_WEEKDAYS + " has an illegal weekday: [" + weekdayNameArray[i] + "] in " + weekdayNames); - - weekdayOffsets[i] = DayConverter.toInteger(weekdayNameArray[i]); - } - - startTime = getTimeEndPoint(settings, sessionID, defaultTimeZone, Session.SETTING_START_TIME); - endTime = getTimeEndPoint(settings, sessionID, defaultTimeZone, Session.SETTING_END_TIME); - - log.info("{} using schedule: {}", sessionID, toString()); - } - - private TimeEndPoint getTimeEndPoint(SessionSettings settings, SessionID sessionID, - TimeZone defaultTimeZone, String timeSetting) throws ConfigError, - FieldConvertError { - - Matcher matcher = TIME_PATTERN.matcher(settings.getString(sessionID, timeSetting)); - if (!matcher.find()) { - throw new ConfigError("Session " + sessionID + ": could not parse time '" - + settings.getString(sessionID, timeSetting) + "'."); - } - - return new TimeEndPoint( - Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)), - Integer.parseInt(matcher.group(3)), getTimeZone(matcher.group(4), defaultTimeZone)); - } - - private TimeZone getDefaultTimeZone(SessionSettings settings, SessionID sessionID) - throws ConfigError, FieldConvertError { - TimeZone sessionTimeZone; - if (settings.isSetting(sessionID, Session.SETTING_TIMEZONE)) { - String sessionTimeZoneID = settings.getString(sessionID, Session.SETTING_TIMEZONE); - sessionTimeZone = TimeZone.getTimeZone(sessionTimeZoneID); - if ("GMT".equals(sessionTimeZone.getID()) && !"GMT".equals(sessionTimeZoneID)) { - throw new ConfigError("Unrecognized time zone '" + sessionTimeZoneID - + "' for session " + sessionID); - } - } else { - sessionTimeZone = TimeZone.getTimeZone("UTC"); - } - return sessionTimeZone; - } - - private TimeZone getTimeZone(String tz, TimeZone defaultZone) { - return "".equals(tz) ? defaultZone : TimeZone.getTimeZone(tz.trim()); - } - - private class TimeEndPoint { - private final int hour; - private final int minute; - private final int second; - private final int timeInSeconds; - private final TimeZone tz; - - TimeEndPoint(int hour, int minute, int second, TimeZone tz) { - this.hour = hour; - this.minute = minute; - this.second = second; - this.tz = tz; - timeInSeconds = timeInSeconds(hour, minute, second); - } - - int getHour() { - return hour; - } - - int getMinute() { - return minute; - } - - int getSecond() { - return second; - } - - public String toString() { - Calendar calendar = Calendar.getInstance(tz); - calendar.set(Calendar.HOUR_OF_DAY, hour); - calendar.set(Calendar.MINUTE, minute); - calendar.set(Calendar.SECOND, second); - final SimpleDateFormat utc = new SimpleDateFormat("HH:mm:ss"); - utc.setTimeZone(TimeZone.getTimeZone("UTC")); - return utc.format(calendar.getTime()) + "-" + utc.getTimeZone().getID(); - } - - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o instanceof TimeEndPoint) { - TimeEndPoint otherTime = (TimeEndPoint) o; - return timeInSeconds == otherTime.timeInSeconds; - } - return false; - } - - public int hashCode() { - assert false : "hashCode not supported"; - return 0; - } - - TimeZone getTimeZone() { - return tz; - } - } - - /** - * find the most recent session date/time range on or before t - * if t is in a session then that session will be returned - * @param t specific date/time - * @return relevant session date/time range - */ - private TimeInterval theMostRecentIntervalBefore(Calendar t) { - TimeInterval timeInterval = new TimeInterval(); - Calendar intervalStart = timeInterval.getStart(); - intervalStart.setTimeZone(startTime.getTimeZone()); - intervalStart.setTimeInMillis(t.getTimeInMillis()); - intervalStart.set(Calendar.HOUR_OF_DAY, startTime.getHour()); - intervalStart.set(Calendar.MINUTE, startTime.getMinute()); - intervalStart.set(Calendar.SECOND, startTime.getSecond()); - intervalStart.set(Calendar.MILLISECOND, 0); - - Calendar intervalEnd = timeInterval.getEnd(); - intervalEnd.setTimeZone(endTime.getTimeZone()); - intervalEnd.setTimeInMillis(t.getTimeInMillis()); - intervalEnd.set(Calendar.HOUR_OF_DAY, endTime.getHour()); - intervalEnd.set(Calendar.MINUTE, endTime.getMinute()); - intervalEnd.set(Calendar.SECOND, endTime.getSecond()); - intervalEnd.set(Calendar.MILLISECOND, 0); - - while (intervalStart.getTimeInMillis() > t.getTimeInMillis() || - !validDayOfWeek(intervalStart)) { - intervalStart.add(Calendar.DAY_OF_WEEK, -1); - intervalEnd.add(Calendar.DAY_OF_WEEK, -1); - } - - if (intervalEnd.getTimeInMillis() <= intervalStart.getTimeInMillis()) { - intervalEnd.add(Calendar.DAY_OF_WEEK, 1); - } - - return timeInterval; - } - - /** - * is the startDateTime a valid day based on the permitted days of week - * @param startDateTime time to test - * @return flag indicating if valid - */ - private boolean validDayOfWeek(Calendar startDateTime) { - int dow = startDateTime.get(Calendar.DAY_OF_WEEK); - for (int i = 0; i < weekdayOffsets.length; i++) - if (weekdayOffsets[i] == dow) - return true; - return false; - } - - private static class TimeInterval { - private final Calendar start = SystemTime.getUtcCalendar(); - private final Calendar end = SystemTime.getUtcCalendar(); - - boolean isContainingTime(Calendar t) { - return t.compareTo(start) >= 0 && t.compareTo(end) <= 0; - } - - public String toString() { - return start.getTime() + " --> " + end.getTime(); - } - - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (!(other instanceof TimeInterval)) { - return false; - } - TimeInterval otherInterval = (TimeInterval) other; - return start.equals(otherInterval.start) && end.equals(otherInterval.end); - } - - public int hashCode() { - assert false : "hashCode not supported"; - return 0; - } - - Calendar getStart() { - return start; - } - - Calendar getEnd() { - return end; - } - } - - /** - * Predicate for determining if the two times are in the same session - * @param time1 test time 1 - * @param time2 test time 2 - * @return return true if in the same session - */ - @Override - public boolean isSameSession(Calendar time1, Calendar time2) { - TimeInterval interval1 = theMostRecentIntervalBefore(time1); - if (!interval1.isContainingTime(time1)) { - return false; - } - TimeInterval interval2 = theMostRecentIntervalBefore(time2); - return interval2.isContainingTime(time2) && interval1.equals(interval2); - } - - @Override - public boolean isNonStopSession() { - return false; - } - - /** - * Predicate for determining if the session should be active at the current time. - * - * @return true if session should be active, false otherwise. - */ - @Override - public boolean isSessionTime() { - return isSessionTime(SystemTime.getUtcCalendar()); - } - - boolean isSessionTime(Calendar time) { - TimeInterval interval = theMostRecentIntervalBefore(time); - return interval.isContainingTime(time); - } - - public String toString() { - StringBuilder buf = new StringBuilder(); - - SimpleDateFormat dowFormat = new SimpleDateFormat("EEEE"); - dowFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - - SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss-z"); - timeFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - - TimeInterval ti = theMostRecentIntervalBefore(SystemTime.getUtcCalendar()); - - formatTimeInterval(buf, ti, timeFormat, false); - - // Now the localized equivalents, if necessary - if (!startTime.getTimeZone().equals(SystemTime.UTC_TIMEZONE) - || !endTime.getTimeZone().equals(SystemTime.UTC_TIMEZONE)) { - buf.append(" ("); - formatTimeInterval(buf, ti, timeFormat, true); - buf.append(")"); - } - - return buf.toString(); - } - - private void formatTimeInterval(StringBuilder buf, TimeInterval timeInterval, - SimpleDateFormat timeFormat, boolean local) { - try { - for (int i = 0; i < weekdayOffsets.length; i++) { - buf.append(DayConverter.toString(weekdayOffsets[i])); - buf.append(", "); - } - } catch (ConfigError ex) { - // this can't happen as these are created using DayConverter.toInteger - } - - if (local) { - timeFormat.setTimeZone(startTime.getTimeZone()); - } - buf.append(timeFormat.format(timeInterval.getStart().getTime())); - - buf.append(" - "); - - if (local) { - timeFormat.setTimeZone(endTime.getTimeZone()); - } - buf.append(timeFormat.format(timeInterval.getEnd().getTime())); - } - - private int timeInSeconds(int hour, int minute, int second) { - return (hour * 3600) + (minute * 60) + second; - } -} diff --git a/quickfixj-core/src/main/java/quickfix/WeekdaySessionScheduleFactory.java b/quickfixj-core/src/main/java/quickfix/WeekdaySessionScheduleFactory.java deleted file mode 100644 index d81902dc9..000000000 --- a/quickfixj-core/src/main/java/quickfix/WeekdaySessionScheduleFactory.java +++ /dev/null @@ -1,35 +0,0 @@ -/******************************************************************************* - * Copyright (c) quickfixengine.org All rights reserved. - * - * This file is part of the QuickFIX FIX Engine - * - * This file may be distributed under the terms of the quickfixengine.org - * license as defined by quickfixengine.org and appearing in the file - * LICENSE included in the packaging of this file. - * - * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING - * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE. - * - * See http://www.quickfixengine.org/LICENSE for licensing information. - * - * Contact ask@quickfixengine.org if any conditions of this licensing - * are not clear to you. - ******************************************************************************/ - -package quickfix; - -/** - * Factory for creating weekday session schedules. - */ -public class WeekdaySessionScheduleFactory implements SessionScheduleFactory { - - public SessionSchedule create(SessionID sessionID, SessionSettings settings) throws ConfigError - { - try { - return new WeekdaySessionSchedule(settings, sessionID); - } catch (final FieldConvertError e) { - throw new ConfigError(e.getMessage()); - } - } -} \ No newline at end of file diff --git a/quickfixj-core/src/test/java/quickfix/SessionScheduleTest.java b/quickfixj-core/src/test/java/quickfix/SessionScheduleTest.java index 42e497a50..a23816beb 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionScheduleTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionScheduleTest.java @@ -905,7 +905,7 @@ private void doWeeklyIsSameSessionTest(SessionSchedule schedule, Calendar sessio } private final SimpleDateFormat dateFormat = new SimpleDateFormat("E M/d HH:mm:ss"); - + { dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); } @@ -951,4 +951,457 @@ private Calendar getUtcTime(int hour, int minute, int second) { return c; } + private SessionSchedule newSessionSchedule(Date startTime, Date endTime, String weekdays) throws Exception { + SessionSettings settings = new SessionSettings(); + if (weekdays != null && weekdays.length() > 0) { + settings.setString(Session.SETTING_WEEKDAYS, weekdays); + } + if (startTime != null) { + settings.setString(Session.SETTING_START_TIME, UtcTimeOnlyConverter.convert(startTime, false)); + } + if (endTime != null) { + settings.setString(Session.SETTING_END_TIME, UtcTimeOnlyConverter.convert(endTime, false)); + } + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + return new DefaultSessionSchedule(settings, sessionID); + } + + @Test + public void testMissingStartTime() throws Exception { + Calendar end = getUtcTime(18, 0, 0); + try { + newSessionSchedule(null, end.getTime(), "Mon"); + fail("no exception"); + } catch (ConfigError e) { + // do nothing + } + } + + @Test + public void testMissingEndTime() throws Exception { + Calendar start = getUtcTime(3, 0, 0); + try { + newSessionSchedule(start.getTime(), null, "Mon"); + fail("no exception"); + } catch (ConfigError e) { + // do nothing + } + } + + @Test + public void testInvalidWeekdays1() throws Exception { + Calendar start = getUtcTime(3, 0, 0); + Calendar end = getUtcTime(18, 0, 0); + try { + newSessionSchedule(start.getTime(), end.getTime(), "AAA"); + fail("no exception"); + } catch (ConfigError e) { + // do nothing + } + } + + @Test + public void testSessionTimeStartBeforeEndUsingWeekdays() throws Exception { + Calendar start = getUtcTime(3, 0, 0); + Calendar end = getUtcTime(18, 0, 0); + SessionSchedule schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); + // Sunday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 2, 59, 59); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 18, 0, 1); + // Monday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 2, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 2, 3, 0, 0); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 2, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 18, 0, 1); + // Tuesday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 3, 2, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 3, 3, 0, 0); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 3, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 3, 18, 0, 1); + // Wednesday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 4, 2, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 4, 3, 0, 0); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 4, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 4, 18, 0, 1); + // Thursday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 5, 2, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 5, 3, 0, 0); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 5, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 5, 18, 0, 1); + // Friday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 6, 2, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 6, 3, 0, 0); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 6, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 6, 18, 0, 1); + // Saturday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 2, 59, 59); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 18, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 18, 0, 1); + } + + @Test + public void testSessionTimeEndBeforeStartUsingWeekdays() throws Exception { + Calendar start = getUtcTime(18, 0, 0); + Calendar end = getUtcTime(3, 0, 0); + SessionSchedule schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); + // Sunday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 17, 59, 59); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 18, 0, 0); + // Monday + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 17, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 2, 18, 0, 0); + // Tuesday + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 3, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 3, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 3, 17, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 3, 18, 0, 0); + // Wednesday + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 4, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 4, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 4, 17, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 4, 18, 0, 0); + // Thursday + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 5, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 5, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 5, 17, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 5, 18, 0, 0); + // Friday + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 6, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 6, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 6, 17, 59, 59); + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 6, 18, 0, 0); + // Saturday + doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 7, 3, 0, 0); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 3, 0, 1); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 17, 59, 59); + doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 18, 0, 0); + } + + @Test + public void testIsSameSessionUsingWeekdays() throws Exception { + // ===================================================== + // start time is less than end time + Calendar start = getUtcTime(3, 0, 0); + Calendar end = getUtcTime(18, 0, 0); + SessionSchedule schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); + + // same time + Calendar t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + Calendar t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // time 2 in same session but greater + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // time 2 in same session but less + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // time 1 not in session + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 1); + doIsSameSessionTest(schedule, t1, t2, false); + + // time 2 not in session + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 1); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + doIsSameSessionTest(schedule, t1, t2, false); + + // same time (in session window) two different days + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 3, 0, 0); + doIsSameSessionTest(schedule, t1, t2, false); + + // ===================================================== + // start time is greater than end time + start = getUtcTime(18, 0, 0); + end = getUtcTime(13, 0, 0); + schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); + + // same session same day + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 19, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // same time (in session window) two different days + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 18, 0, 0); + doIsSameSessionTest(schedule, t1, t2, false); + + // same session time 2 is in next day + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 3, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // same session time 1 is in next day + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 3, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + doIsSameSessionTest(schedule, t1, t2, true); + + // time 1 is 25 hours greater than time 2 + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 19, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + doIsSameSessionTest(schedule, t1, t2, false); + + // ===================================================== + // start time is equal to end time + start = getUtcTime(6, 0, 0); + end = getUtcTime(6, 0, 0); + schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); + + t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 18, 0, 0); + t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); + doIsSameSessionTest(schedule, t1, t2, false); + } + + @Test + public void testSettingsWithoutStartEndDayWithTimeZoneUsingWeekdays() throws Exception { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, " US/Eastern "); + settings.setString(Session.SETTING_START_TIME, "01:00:00"); + settings.setString(Session.SETTING_END_TIME, "15:00:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + SessionSchedule schedule = new DefaultSessionSchedule(settings, sessionID); + TimeZone tz = TimeZone.getTimeZone("US/Eastern"); + doIsSessionTimeTest(schedule, false, 2002, 5, 5, 0, 59, 0, tz); + doIsSessionTimeTest(schedule, true, 2002, 7, 5, 14, 30, 0, tz); + doIsSessionTimeTest(schedule, false, 2003, 5, 5, 16, 30, 0, tz); + } + + @Test + public void testSettingsWithTimeZoneInTimeUsingWeekdays() throws Exception { + // This test is very susceptible to whether the system time starts + // in daylight time or not, so we just force it that way. Otherwise + // the first time the mock time source gets set to a time with daylight time + // then the schedule appears to change 1 hr. + TimeZone tz = TimeZone.getTimeZone("US/Eastern"); + mockSystemTimeSource.setTime(getTimeStamp(2002, 5, 5, 0, 0, 0, tz)); + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_START_TIME, "01:00:00 US/Eastern"); + settings.setString(Session.SETTING_END_TIME, "15:00:00 US/Central"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + SessionSchedule schedule = new DefaultSessionSchedule(settings, sessionID); + doIsSessionTimeTest(schedule, false, 2002, 5, 5, 0, 59, 0, tz); + doIsSessionTimeTest(schedule, true, 2002, 7, 5, 14, 30, 0, tz); + + // The end time is actually 16:00 Eastern time but specified as + // 15:00 Central time. + doIsSessionTimeTest(schedule, true, 2003, 5, 5, 15, 59, 0, tz); + doIsSessionTimeTest(schedule, true, 2003, 5, 5, 16, 0, 0, tz); + doIsSessionTimeTest(schedule, false, 2003, 5, 5, 16, 1, 0, tz); + } + + /** + * From 1968 to 1971, GMT was an hour ahead of UTC. If we perform all our calculations in 1970, + * someone in GMT (e.g. London) will see sessions ending an hour later than expected. This test + * demonstrates the 1970 behavior and verifies that calculations on current dates give the proper results. + * + *

+ * More details at: + *

+ * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4644278 + * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4832236 + */ + @Test + public void testThatUTCAndGMTAreTheSameNowUsingWeekdays() throws ConfigError, FieldConvertError, + ParseException { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_START_TIME, "00:01:00"); + settings.setString(Session.SETTING_END_TIME, "21:50:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri,Sat,Sun"); + + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + + // In 1970, a session configured to end at 21:50 UTC would end at + // 22:50 London time any time of year. + doIsSessionTimeTest(settings, sessionID, true, 1970, Calendar.JANUARY, 27, 22, 50, 0, + "Europe/London"); + doIsSessionTimeTest(settings, sessionID, false, 1970, Calendar.JANUARY, 27, 22, 50, 1, + "Europe/London"); + doIsSessionTimeTest(settings, sessionID, true, 1970, Calendar.JULY, 27, 22, 50, 0, + "Europe/London"); + doIsSessionTimeTest(settings, sessionID, false, 1970, Calendar.JULY, 27, 22, 50, 1, + "Europe/London"); + + // Now, at least in winter, it should end at 21:50 in both zones -- + // if the end time session setting is being parsed correctly. + doIsSessionTimeTest(settings, sessionID, true, 2006, Calendar.FEBRUARY, 27, 21, 50, 0, + "Europe/London"); + doIsSessionTimeTest(settings, sessionID, false, 2006, Calendar.FEBRUARY, 27, 21, 50, 1, + "Europe/London"); + + // When summer time (BST) is in effect, London time will be an hour + // ahead again, and the session will end at 22:50 there. + doIsSessionTimeTest(settings, sessionID, true, 2006, Calendar.JULY, 27, 22, 50, 0, + "Europe/London"); + doIsSessionTimeTest(settings, sessionID, false, 2006, Calendar.JULY, 27, 22, 50, 1, + "Europe/London"); + + settings.setString(Session.SETTING_TIMEZONE, "Europe/London"); + + // In 1970, a session configured to end at 21:50 GMT would end at + // 20:50 UTC any time of year. + doIsSessionTimeTest(settings, sessionID, true, 1970, Calendar.JANUARY, 27, 20, 50, 0, "UTC"); + doIsSessionTimeTest(settings, sessionID, false, 1970, Calendar.JANUARY, 27, 20, 50, 1, + "UTC"); + doIsSessionTimeTest(settings, sessionID, true, 1970, Calendar.JULY, 27, 20, 50, 0, "UTC"); + doIsSessionTimeTest(settings, sessionID, false, 1970, Calendar.JULY, 27, 20, 50, 1, "UTC"); + + // Now, at least in winter, it should end at 21:50 in both zones -- + // if the end time session setting is being parsed correctly. + doIsSessionTimeTest(settings, sessionID, true, 2006, Calendar.FEBRUARY, 27, 21, 50, 0, + "UTC"); + doIsSessionTimeTest(settings, sessionID, false, 2006, Calendar.FEBRUARY, 27, 21, 50, 1, + "UTC"); + + // When summer time (BST) is in effect, London time will be an hour + // ahead again, and the session will end at 20:50 UTC there. + doIsSessionTimeTest(settings, sessionID, true, 2006, Calendar.JULY, 27, 20, 50, 0, "UTC"); + doIsSessionTimeTest(settings, sessionID, false, 2006, Calendar.JULY, 27, 20, 50, 1, "UTC"); + } + + @Test + public void testBadTimeSpecificationUsingWeekdays() throws Exception { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, "US/Eastern"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + + try { + settings.setString(Session.SETTING_START_TIME, "01:xx:00"); + settings.setString(Session.SETTING_END_TIME, "15:00:00"); + new DefaultSessionSchedule(settings, sessionID); + fail("no exception"); + } catch (ConfigError e) { + assertTrue(e.getMessage().contains("could not parse")); + } + + try { + settings.setString(Session.SETTING_START_TIME, "01:00:00"); + settings.setString(Session.SETTING_END_TIME, "15:00:yy"); + new DefaultSessionSchedule(settings, sessionID); + fail("no exception"); + } catch (ConfigError e) { + assertTrue(e.getMessage().contains("could not parse")); + } + } + + @Test + public void testBadTimeZoneUsingWeekdays() throws Exception { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, "US/BOGUS"); + settings.setString(Session.SETTING_START_TIME, "01:00:00"); + settings.setString(Session.SETTING_END_TIME, "15:00:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + + try { + new DefaultSessionSchedule(settings, sessionID); + fail("no exception"); + } catch (ConfigError e) { + assertTrue(e.getMessage().contains("Unrecognized time zone")); + } + } + + @Test + public void testWeekdayToString() throws ConfigError, FieldConvertError { + // Just be sure it doesn't throw exceptions + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, "US/Eastern"); + settings.setString(Session.SETTING_START_TIME, "01:00:00"); + settings.setString(Session.SETTING_END_TIME, "15:00:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + SessionSchedule schedule = new DefaultSessionSchedule(settings, sessionID); + assertNotNull(schedule.toString()); + } + + @Test + public void testSettingsWithDSTUsingWeekdays() throws Exception { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, "Europe/Zurich"); + settings.setString(Session.SETTING_START_TIME, "01:30:00"); + settings.setString(Session.SETTING_END_TIME, "03:15:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri,Sat,Sun"); + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + // + SessionSchedule schedule = new DefaultSessionSchedule(settings, sessionID); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 20, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 20, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 20, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 20, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 20, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + schedule = new DefaultSessionSchedule(settings, sessionID); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 27, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 27, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 27, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 27, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 27, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 28, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 28, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 28, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 28, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 28, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 29, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 29, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 29, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 29, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 29, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + schedule = new DefaultSessionSchedule(settings, sessionID); + doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 30, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 30, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 30, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 30, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 30, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 31, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 31, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 31, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); // -> this is 03:16 ! + doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 31, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 31, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + // + doIsSessionTimeTest(schedule, false, 2013, Calendar.APRIL, 1, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.APRIL, 1, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.APRIL, 1, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, true, 2013, Calendar.APRIL, 1, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); + doIsSessionTimeTest(schedule, false, 2013, Calendar.APRIL, 1, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); + } + + @Test + public void testSettingsWithStartEndDayWithDSTMockedUsingWeekdays() throws Exception { + SessionSettings settings = new SessionSettings(); + settings.setString(Session.SETTING_TIMEZONE, "America/New_York"); + settings.setString(Session.SETTING_START_TIME, "20:00:00"); + settings.setString(Session.SETTING_END_TIME, "17:00:00"); + settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri,Sat,Sun"); + + mockSystemTimeSource.setTime(getTimeStamp(2008, Calendar.NOVEMBER, 2, 18, 0, 0, TimeZone.getTimeZone("America/New_York"))); + + SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); + SessionSchedule schedule = new DefaultSessionSchedule(settings, sessionID); + + // November,2 -> Sunday + doIsSessionTimeTest(schedule, true, 2008, Calendar.NOVEMBER, 2, 20, 0, 0, + TimeZone.getTimeZone("America/New_York")); + // November,7 -> Friday + doIsSessionTimeTest(schedule, true, 2008, Calendar.NOVEMBER, 7, 17, 0, 0, + TimeZone.getTimeZone("America/New_York")); + } + } diff --git a/quickfixj-core/src/test/java/quickfix/WeekdaySessionScheduleTest.java b/quickfixj-core/src/test/java/quickfix/WeekdaySessionScheduleTest.java deleted file mode 100644 index d59220937..000000000 --- a/quickfixj-core/src/test/java/quickfix/WeekdaySessionScheduleTest.java +++ /dev/null @@ -1,602 +0,0 @@ -/******************************************************************************* - * Copyright (c) quickfixengine.org All rights reserved. - * - * This file is part of the QuickFIX FIX Engine - * - * This file may be distributed under the terms of the quickfixengine.org - * license as defined by quickfixengine.org and appearing in the file - * LICENSE included in the packaging of this file. - * - * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING - * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE. - * - * See http://www.quickfixengine.org/LICENSE for licensing information. - * - * Contact ask@quickfixengine.org if any conditions of this licensing - * are not clear to you. - ******************************************************************************/ - -package quickfix; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.text.DateFormat; -import java.text.DateFormatSymbols; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.Locale; -import java.util.TimeZone; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import quickfix.field.converter.UtcTimeOnlyConverter; - -public class WeekdaySessionScheduleTest { - private MockSystemTimeSource mockSystemTimeSource; - private Locale defaultLocale; - - @Before - public void setUp() throws Exception { - mockSystemTimeSource = new MockSystemTimeSource(); - SystemTime.setTimeSource(mockSystemTimeSource); - defaultLocale = Locale.getDefault(); - Locale.setDefault(Locale.GERMANY); - } - - @After - public void tearDown() throws Exception { - SystemTime.setTimeSource(null); - Locale.setDefault(defaultLocale); - } - - private SessionSchedule newSessionSchedule(Date startTime, Date endTime, String weekdays) throws Exception { - SessionSettings settings = new SessionSettings(); - if (weekdays != null && weekdays.length() > 0) { - settings.setString(Session.SETTING_WEEKDAYS, weekdays); - } - if (startTime != null) { - settings.setString(Session.SETTING_START_TIME, UtcTimeOnlyConverter.convert(startTime, false)); - } - if (endTime != null) { - settings.setString(Session.SETTING_END_TIME, UtcTimeOnlyConverter.convert(endTime, false)); - } - SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); - return new WeekdaySessionSchedule(settings, sessionID); - } - - private void doIsSessionTimeTest(SessionSchedule schedule, boolean expectedInSession, int year, - int month, int day, int hour, int minute, int second) { - doIsSessionTimeTest(schedule, expectedInSession, year, month, day, hour, minute, second, - TimeZone.getTimeZone("UTC")); - } - - private void doIsSessionTimeTest(SessionSchedule schedule, boolean expectedInSession, int year, - int month, int day, int hour, int minute, int second, TimeZone timeZone) { - mockSystemTimeSource - .setTime(getTimeStamp(year, month, day, hour, minute, second, timeZone)); - assertEquals("in session expectation incorrect", expectedInSession, schedule - .isSessionTime()); - } - - private void doIsSessionTimeTest(SessionSettings settings, SessionID sessionID, - boolean expectedInSession, int year, int month, int day, int hour, int minute, - int second, String timeZoneID) throws ConfigError, FieldConvertError { - mockSystemTimeSource.setTime(getTimeStamp(year, month, day, hour, minute, second, TimeZone - .getTimeZone(timeZoneID))); - SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); - assertEquals("schedule is wrong", expectedInSession, schedule.isSessionTime()); - } - - @Test - public void testMissingStartTime() throws Exception { - Calendar end = getUtcTime(18, 0, 0); - try { - newSessionSchedule(null, end.getTime(), "Mon"); - fail("no exception"); - } catch (ConfigError e) { - // do nothing - } - } - - @Test - public void testMissingEndTime() throws Exception { - Calendar start = getUtcTime(3, 0, 0); - try { - newSessionSchedule(start.getTime(), null, "Mon"); - fail("no exception"); - } catch (ConfigError e) { - // do nothing - } - } - - @Test - public void testMissingWeekdays() throws Exception { - Calendar start = getUtcTime(3, 0, 0); - Calendar end = getUtcTime(18, 0, 0); - try { - newSessionSchedule(start.getTime(), end.getTime(), null); - fail("no exception"); - } catch (ConfigError e) { - // do nothing - } - } - - @Test - public void testInvalidWeekdays1() throws Exception { - Calendar start = getUtcTime(3, 0, 0); - Calendar end = getUtcTime(18, 0, 0); - try { - newSessionSchedule(start.getTime(), end.getTime(), "AAA"); - fail("no exception"); - } catch (ConfigError e) { - // do nothing - } - } - - @Test - public void testInvalidWeekdays2() throws Exception { - Calendar start = getUtcTime(3, 0, 0); - Calendar end = getUtcTime(18, 0, 0); - try { - newSessionSchedule(start.getTime(), end.getTime(), ",Mon"); - fail("no exception"); - } catch (ConfigError e) { - // do nothing - } - } - - @Test - public void testInvalidWeekdays3() throws Exception { - Calendar start = getUtcTime(3, 0, 0); - Calendar end = getUtcTime(18, 0, 0); - try { - newSessionSchedule(start.getTime(), end.getTime(), "Mon,,Tue"); - fail("no exception"); - } catch (ConfigError e) { - // do nothing - } - } - - @Test - public void testSessionTimeStartBeforeEnd() throws Exception { - Calendar start = getUtcTime(3, 0, 0); - Calendar end = getUtcTime(18, 0, 0); - SessionSchedule schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); - // Sunday - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 2, 59, 59); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 3, 0, 0); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 18, 0, 0); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 18, 0, 1); - // Monday - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 2, 59, 59); - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 2, 3, 0, 0); - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 2, 18, 0, 0); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 18, 0, 1); - // Tuesday - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 3, 2, 59, 59); - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 3, 3, 0, 0); - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 3, 18, 0, 0); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 3, 18, 0, 1); - // Wednesday - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 4, 2, 59, 59); - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 4, 3, 0, 0); - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 4, 18, 0, 0); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 4, 18, 0, 1); - // Thursday - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 5, 2, 59, 59); - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 5, 3, 0, 0); - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 5, 18, 0, 0); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 5, 18, 0, 1); - // Friday - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 6, 2, 59, 59); - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 6, 3, 0, 0); - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 6, 18, 0, 0); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 6, 18, 0, 1); - // Saturday - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 2, 59, 59); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 3, 0, 0); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 18, 0, 0); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 18, 0, 1); - } - @Test - public void testSessionTimeEndBeforeStart() throws Exception { - Calendar start = getUtcTime(18, 0, 0); - Calendar end = getUtcTime(3, 0, 0); - SessionSchedule schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); - // Sunday - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 3, 0, 0); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 3, 0, 1); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 17, 59, 59); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 1, 18, 0, 0); - // Monday - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 3, 0, 0); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 3, 0, 1); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 2, 17, 59, 59); - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 2, 18, 0, 0); - // Tuesday - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 3, 3, 0, 0); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 3, 3, 0, 1); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 3, 17, 59, 59); - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 3, 18, 0, 0); - // Wednesday - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 4, 3, 0, 0); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 4, 3, 0, 1); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 4, 17, 59, 59); - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 4, 18, 0, 0); - // Thursday - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 5, 3, 0, 0); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 5, 3, 0, 1); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 5, 17, 59, 59); - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 5, 18, 0, 0); - // Friday - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 6, 3, 0, 0); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 6, 3, 0, 1); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 6, 17, 59, 59); - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 6, 18, 0, 0); - // Saturday - doIsSessionTimeTest(schedule, true, 2017, Calendar.JANUARY, 7, 3, 0, 0); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 3, 0, 1); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 17, 59, 59); - doIsSessionTimeTest(schedule, false, 2017, Calendar.JANUARY, 7, 18, 0, 0); - } - - @Test - public void testIsSameSession() throws Exception { - // ===================================================== - // start time is less than end time - Calendar start = getUtcTime(3, 0, 0); - Calendar end = getUtcTime(18, 0, 0); - SessionSchedule schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); - - // same time - Calendar t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); - Calendar t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); - doIsSameSessionTest(schedule, t1, t2, true); - - // time 2 in same session but greater - t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); - t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); - doIsSameSessionTest(schedule, t1, t2, true); - - // time 2 in same session but less - t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); - t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); - doIsSameSessionTest(schedule, t1, t2, true); - - // time 1 not in session - t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); - t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 1); - doIsSameSessionTest(schedule, t1, t2, false); - - // time 2 not in session - t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 1); - t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); - doIsSameSessionTest(schedule, t1, t2, false); - - // same time (in session window) two different days - t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 3, 0, 0); - t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 3, 0, 0); - doIsSameSessionTest(schedule, t1, t2, false); - - // ===================================================== - // start time is greater than end time - start = getUtcTime(18, 0, 0); - end = getUtcTime(13, 0, 0); - schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); - - // same session same day - t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); - t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 19, 0, 0); - doIsSameSessionTest(schedule, t1, t2, true); - - // same time (in session window) two different days - t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); - t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 18, 0, 0); - doIsSameSessionTest(schedule, t1, t2, false); - - // same session time 2 is in next day - t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); - t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 3, 0, 0); - doIsSameSessionTest(schedule, t1, t2, true); - - // same session time 1 is in next day - t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 3, 0, 0); - t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); - doIsSameSessionTest(schedule, t1, t2, true); - - // time 1 is 25 hours greater than time 2 - t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 19, 0, 0); - t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); - doIsSameSessionTest(schedule, t1, t2, false); - - // ===================================================== - // start time is equal to end time - start = getUtcTime(6, 0, 0); - end = getUtcTime(6, 0, 0); - schedule = newSessionSchedule(start.getTime(), end.getTime(), "Mon,Tue,Wed,Thu,Fri"); - - t1 = getUtcTimeStamp(2017, Calendar.JANUARY, 3, 18, 0, 0); - t2 = getUtcTimeStamp(2017, Calendar.JANUARY, 2, 18, 0, 0); - doIsSameSessionTest(schedule, t1, t2, false); - } - - @Test - public void testSettingsWithoutStartEndDayWithTimeZone() throws Exception { - SessionSettings settings = new SessionSettings(); - settings.setString(Session.SETTING_TIMEZONE, " US/Eastern "); - settings.setString(Session.SETTING_START_TIME, "01:00:00"); - settings.setString(Session.SETTING_END_TIME, "15:00:00"); - settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); - SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); - SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); - TimeZone tz = TimeZone.getTimeZone("US/Eastern"); - doIsSessionTimeTest(schedule, false, 2002, 5, 5, 0, 59, 0, tz); - doIsSessionTimeTest(schedule, true, 2002, 7, 5, 14, 30, 0, tz); - doIsSessionTimeTest(schedule, false, 2003, 5, 5, 16, 30, 0, tz); - } - - @Test - public void testSettingsWithTimeZoneInTime() throws Exception { - // This test is very susceptible to whether the system time starts - // in daylight time or not, so we just force it that way. Otherwise - // the first time the mock time source gets set to a time with daylight time - // then the schedule appears to change 1 hr. - TimeZone tz = TimeZone.getTimeZone("US/Eastern"); - mockSystemTimeSource.setTime(getTimeStamp(2002, 5, 5, 0, 0, 0, tz)); - SessionSettings settings = new SessionSettings(); - settings.setString(Session.SETTING_START_TIME, "01:00:00 US/Eastern"); - settings.setString(Session.SETTING_END_TIME, "15:00:00 US/Central"); - settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); - SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); - SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); - doIsSessionTimeTest(schedule, false, 2002, 5, 5, 0, 59, 0, tz); - doIsSessionTimeTest(schedule, true, 2002, 7, 5, 14, 30, 0, tz); - - // The end time is actually 16:00 Eastern time but specified as - // 15:00 Central time. - doIsSessionTimeTest(schedule, true, 2003, 5, 5, 15, 59, 0, tz); - doIsSessionTimeTest(schedule, true, 2003, 5, 5, 16, 0, 0, tz); - doIsSessionTimeTest(schedule, false, 2003, 5, 5, 16, 1, 0, tz); - } - - /** - * From 1968 to 1971, GMT was an hour ahead of UTC. If we perform all our calculations in 1970, - * someone in GMT (e.g. London) will see sessions ending an hour later than expected. This test - * demonstrates the 1970 behavior and verifies that calculations on current dates give the proper results. - * - *

- * More details at: - *

- * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4644278 - * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4832236 - */ - @Test - public void testThatUTCAndGMTAreTheSameNow() throws ConfigError, FieldConvertError, - ParseException { - SessionSettings settings = new SessionSettings(); - settings.setString(Session.SETTING_START_TIME, "00:01:00"); - settings.setString(Session.SETTING_END_TIME, "21:50:00"); - settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri,Sat,Sun"); - - SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); - - // In 1970, a session configured to end at 21:50 UTC would end at - // 22:50 London time any time of year. - doIsSessionTimeTest(settings, sessionID, true, 1970, Calendar.JANUARY, 27, 22, 50, 0, - "Europe/London"); - doIsSessionTimeTest(settings, sessionID, false, 1970, Calendar.JANUARY, 27, 22, 50, 1, - "Europe/London"); - doIsSessionTimeTest(settings, sessionID, true, 1970, Calendar.JULY, 27, 22, 50, 0, - "Europe/London"); - doIsSessionTimeTest(settings, sessionID, false, 1970, Calendar.JULY, 27, 22, 50, 1, - "Europe/London"); - - // Now, at least in winter, it should end at 21:50 in both zones -- - // if the end time session setting is being parsed correctly. - doIsSessionTimeTest(settings, sessionID, true, 2006, Calendar.FEBRUARY, 27, 21, 50, 0, - "Europe/London"); - doIsSessionTimeTest(settings, sessionID, false, 2006, Calendar.FEBRUARY, 27, 21, 50, 1, - "Europe/London"); - - // When summer time (BST) is in effect, London time will be an hour - // ahead again, and the session will end at 22:50 there. - doIsSessionTimeTest(settings, sessionID, true, 2006, Calendar.JULY, 27, 22, 50, 0, - "Europe/London"); - doIsSessionTimeTest(settings, sessionID, false, 2006, Calendar.JULY, 27, 22, 50, 1, - "Europe/London"); - - settings.setString(Session.SETTING_TIMEZONE, "Europe/London"); - - // In 1970, a session configured to end at 21:50 GMT would end at - // 20:50 UTC any time of year. - doIsSessionTimeTest(settings, sessionID, true, 1970, Calendar.JANUARY, 27, 20, 50, 0, "UTC"); - doIsSessionTimeTest(settings, sessionID, false, 1970, Calendar.JANUARY, 27, 20, 50, 1, - "UTC"); - doIsSessionTimeTest(settings, sessionID, true, 1970, Calendar.JULY, 27, 20, 50, 0, "UTC"); - doIsSessionTimeTest(settings, sessionID, false, 1970, Calendar.JULY, 27, 20, 50, 1, "UTC"); - - // Now, at least in winter, it should end at 21:50 in both zones -- - // if the end time session setting is being parsed correctly. - doIsSessionTimeTest(settings, sessionID, true, 2006, Calendar.FEBRUARY, 27, 21, 50, 0, - "UTC"); - doIsSessionTimeTest(settings, sessionID, false, 2006, Calendar.FEBRUARY, 27, 21, 50, 1, - "UTC"); - - // When summer time (BST) is in effect, London time will be an hour - // ahead again, and the session will end at 20:50 UTC there. - doIsSessionTimeTest(settings, sessionID, true, 2006, Calendar.JULY, 27, 20, 50, 0, "UTC"); - doIsSessionTimeTest(settings, sessionID, false, 2006, Calendar.JULY, 27, 20, 50, 1, "UTC"); - } - - @Test - public void testBadTimeSpecification() throws Exception { - SessionSettings settings = new SessionSettings(); - settings.setString(Session.SETTING_TIMEZONE, "US/Eastern"); - settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); - SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); - - try { - settings.setString(Session.SETTING_START_TIME, "01:xx:00"); - settings.setString(Session.SETTING_END_TIME, "15:00:00"); - new WeekdaySessionSchedule(settings, sessionID); - fail("no exception"); - } catch (ConfigError e) { - assertTrue(e.getMessage().contains("could not parse")); - } - - try { - settings.setString(Session.SETTING_START_TIME, "01:00:00"); - settings.setString(Session.SETTING_END_TIME, "15:00:yy"); - new WeekdaySessionSchedule(settings, sessionID); - fail("no exception"); - } catch (ConfigError e) { - assertTrue(e.getMessage().contains("could not parse")); - } - } - - @Test - public void testBadTimeZone() throws Exception { - SessionSettings settings = new SessionSettings(); - settings.setString(Session.SETTING_TIMEZONE, "US/BOGUS"); - settings.setString(Session.SETTING_START_TIME, "01:00:00"); - settings.setString(Session.SETTING_END_TIME, "15:00:00"); - settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); - SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); - - try { - new WeekdaySessionSchedule(settings, sessionID); - fail("no exception"); - } catch (ConfigError e) { - assertTrue(e.getMessage().contains("Unrecognized time zone")); - } - } - - @Test - public void testWeekdayToString() throws ConfigError, FieldConvertError { - // Just be sure it doesn't throw exceptions - SessionSettings settings = new SessionSettings(); - settings.setString(Session.SETTING_TIMEZONE, "US/Eastern"); - settings.setString(Session.SETTING_START_TIME, "01:00:00"); - settings.setString(Session.SETTING_END_TIME, "15:00:00"); - settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri"); - SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); - SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); - assertNotNull(schedule.toString()); - } - - @Test - public void testSettingsWithDST() throws Exception { - SessionSettings settings = new SessionSettings(); - settings.setString(Session.SETTING_TIMEZONE, "Europe/Zurich"); - settings.setString(Session.SETTING_START_TIME, "01:30:00"); - settings.setString(Session.SETTING_END_TIME, "03:15:00"); - settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri,Sat,Sun"); - SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); - // - SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); - doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 20, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 20, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 20, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 20, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 20, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); - // - schedule = new WeekdaySessionSchedule(settings, sessionID); - doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 27, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 27, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 27, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 27, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 27, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); - // - doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 28, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 28, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 28, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 28, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 28, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); - // - doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 29, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 29, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 29, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2012, Calendar.OCTOBER, 29, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, false, 2012, Calendar.OCTOBER, 29, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); - // - schedule = new WeekdaySessionSchedule(settings, sessionID); - doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 30, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 30, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 30, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 30, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 30, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); - // - doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 31, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 31, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 31, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); // -> this is 03:16 ! - doIsSessionTimeTest(schedule, true, 2013, Calendar.MARCH, 31, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, false, 2013, Calendar.MARCH, 31, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); - // - doIsSessionTimeTest(schedule, false, 2013, Calendar.APRIL, 1, 1, 29, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2013, Calendar.APRIL, 1, 1, 31, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2013, Calendar.APRIL, 1, 2, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, true, 2013, Calendar.APRIL, 1, 3, 14, 0, TimeZone.getTimeZone("Europe/Zurich")); - doIsSessionTimeTest(schedule, false, 2013, Calendar.APRIL, 1, 3, 16, 0, TimeZone.getTimeZone("Europe/Zurich")); - } - - @Test - public void testSettingsWithStartEndDayWithDSTMocked() throws Exception { - SessionSettings settings = new SessionSettings(); - settings.setString(Session.SETTING_TIMEZONE, "America/New_York"); - settings.setString(Session.SETTING_START_TIME, "20:00:00"); - settings.setString(Session.SETTING_END_TIME, "17:00:00"); - settings.setString(Session.SETTING_WEEKDAYS, "Mon,Tue,Wed,Thu,Fri,Sat,Sun"); - - mockSystemTimeSource.setTime(getTimeStamp(2008, Calendar.NOVEMBER, 2, 18, 0, 0, TimeZone.getTimeZone("America/New_York"))); - - SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); - SessionSchedule schedule = new WeekdaySessionSchedule(settings, sessionID); - - //System.out.println(schedule); - - // November,2 -> Sunday - doIsSessionTimeTest(schedule, true, 2008, Calendar.NOVEMBER, 2, 20, 0, 0, - TimeZone.getTimeZone("America/New_York")); - // November,7 -> Friday - doIsSessionTimeTest(schedule, true, 2008, Calendar.NOVEMBER, 7, 17, 0, 0, - TimeZone.getTimeZone("America/New_York")); - } - - private final SimpleDateFormat dateFormat = new SimpleDateFormat("E M/d HH:mm:ss"); - - { - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - } - - private void doIsSameSessionTest(SessionSchedule schedule, Calendar time1, Calendar time2, - boolean isSameSession) { - assertEquals("isSameSession is wrong", isSameSession, schedule.isSameSession(time1, time2)); - assertEquals("isSameSession is wrong", isSameSession, schedule.isSameSession(time2, time1)); - } - - private Calendar getTimeStamp(int year, int month, int day, int hour, int minute, int second, - TimeZone timeZone) { - Calendar c = new GregorianCalendar(year, month, day, hour, minute, second); - c.setTimeZone(timeZone); - return c; - } - - private Calendar getUtcTimeStamp(int year, int month, int day, int hour, int minute, int second) { - return getTimeStamp(year, month, day, hour, minute, second, TimeZone.getTimeZone("UTC")); - } - - private Calendar getUtcTime(int hour, int minute, int second) { - // Monday - return getUtcTimeStamp(2017, Calendar.JANUARY, 2, hour, minute, second); - } -} From 158050e34e2f2e201643e657f3fee6559287f90b Mon Sep 17 00:00:00 2001 From: Philip Date: Mon, 18 Sep 2017 18:31:28 +0100 Subject: [PATCH 108/165] Use helper function to extract epochMillis --- .../src/test/java/quickfix/FieldMapTest.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/quickfixj-core/src/test/java/quickfix/FieldMapTest.java b/quickfixj-core/src/test/java/quickfix/FieldMapTest.java index ad33cdcf1..8e40d5e49 100644 --- a/quickfixj-core/src/test/java/quickfix/FieldMapTest.java +++ b/quickfixj-core/src/test/java/quickfix/FieldMapTest.java @@ -32,13 +32,13 @@ public void testSetUtcTimeStampField() throws Exception { FieldMap map = new Message(); LocalDateTime aDate = LocalDateTime.now(); map.setField(new UtcTimeStampField(EffectiveTime.FIELD, aDate, false)); - assertEquals("milliseconds should not be preserved", aDate.toInstant(ZoneOffset.UTC).toEpochMilli() - (aDate.toInstant(ZoneOffset.UTC).toEpochMilli() % 1000), - map.getField(new EffectiveTime()).getValue().toInstant(ZoneOffset.UTC).toEpochMilli()); + assertEquals("milliseconds should not be preserved", epochMilliOfLocalDate(aDate) - (epochMilliOfLocalDate(aDate) % 1000), + epochMilliOfLocalDate(map.getField(new EffectiveTime()).getValue())); // now set it with preserving millis map.setField(new UtcTimeStampField(EffectiveTime.FIELD, aDate, true)); - assertEquals("milliseconds should be preserved", aDate.toInstant(ZoneOffset.UTC).toEpochMilli(), - map.getField(new EffectiveTime()).getValue().toInstant(ZoneOffset.UTC).toEpochMilli()); + assertEquals("milliseconds should be preserved", epochMilliOfLocalDate(aDate), + epochMilliOfLocalDate(map.getField(new EffectiveTime()).getValue())); } public void testSetUtcTimeOnlyField() throws Exception { @@ -46,12 +46,12 @@ public void testSetUtcTimeOnlyField() throws Exception { LocalTime aDate = LocalTime.now(); map.setField(new UtcTimeOnlyField(MDEntryTime.FIELD, aDate, false)); assertEquals("milliseconds should not be preserved", UtcTimeOnlyConverter.convert(aDate, UtcTimestampPrecision.SECONDS), - UtcTimeOnlyConverter.convert(map.getField(new MDEntryTime()).getValue(), UtcTimestampPrecision.SECONDS)); + UtcTimeOnlyConverter.convert(map.getField(new MDEntryTime()).getValue(), UtcTimestampPrecision.SECONDS)); // now set it with preserving millis map.setField(new UtcTimeOnlyField(MDEntryTime.FIELD, aDate, true)); assertEquals("milliseconds should be preserved", UtcTimeOnlyConverter.convert(aDate, UtcTimestampPrecision.MILLIS), - UtcTimeOnlyConverter.convert(map.getField(new MDEntryTime()).getValue(), UtcTimestampPrecision.MILLIS)); + UtcTimeOnlyConverter.convert(map.getField(new MDEntryTime()).getValue(), UtcTimestampPrecision.MILLIS)); } /** @@ -61,12 +61,12 @@ public void testSpecificFields() throws Exception { FieldMap map = new Message(); LocalDateTime aDate = LocalDateTime.now(); map.setField(new EffectiveTime(aDate)); - assertEquals("milliseconds should be preserved", aDate.toInstant(ZoneOffset.UTC).toEpochMilli(), - map.getField(new EffectiveTime()).getValue().toInstant(ZoneOffset.UTC).toEpochMilli()); + assertEquals("milliseconds should be preserved", epochMilliOfLocalDate(aDate), + epochMilliOfLocalDate(map.getField(new EffectiveTime()).getValue())); LocalTime aTime = LocalTime.now(); map.setField(new MDEntryTime(aTime)); assertEquals("milliseconds should be preserved", UtcTimeOnlyConverter.convert(aTime, UtcTimestampPrecision.MILLIS), - UtcTimeOnlyConverter.convert(map.getField(new MDEntryTime()).getValue(), UtcTimestampPrecision.MILLIS)); + UtcTimeOnlyConverter.convert(map.getField(new MDEntryTime()).getValue(), UtcTimestampPrecision.MILLIS)); } private void testOrdering(int[] vals, int[] order, int[] expected) { @@ -90,4 +90,8 @@ public void testOrdering() { testOrdering(new int[] { 1, 2, 3 }, new int[] { 3, 1 }, new int[] { 3, 1, 2 }); testOrdering(new int[] { 3, 2, 1 }, new int[] { 3, 1 }, new int[] { 3, 1, 2 }); } + + private long epochMilliOfLocalDate(LocalDateTime localDateTime) { + return localDateTime.toInstant(ZoneOffset.UTC).toEpochMilli(); + } } From 67c381b67f26c3818ee7bfbb3d1f0a451ddf963f Mon Sep 17 00:00:00 2001 From: chrjohn Date: Tue, 19 Sep 2017 13:33:01 +0200 Subject: [PATCH 109/165] - fix javadoc generation - only create and include javadoc for the specific FIX messages classes - formerly every message javadoc package had all the docs for all messages included - same for the core module javadoc package --- quickfixj-core/pom.xml | 20 ++++++++++++++++++ .../quickfixj-messages-fix40/pom.xml | 20 ++++++++++++++++++ .../quickfixj-messages-fix41/pom.xml | 21 ++++++++++++++++++- .../quickfixj-messages-fix42/pom.xml | 21 ++++++++++++++++++- .../quickfixj-messages-fix43/pom.xml | 21 ++++++++++++++++++- .../quickfixj-messages-fix44/pom.xml | 21 ++++++++++++++++++- .../quickfixj-messages-fix50/pom.xml | 21 ++++++++++++++++++- .../quickfixj-messages-fix50sp1/pom.xml | 21 ++++++++++++++++++- .../quickfixj-messages-fix50sp2/pom.xml | 21 ++++++++++++++++++- .../quickfixj-messages-fixt11/pom.xml | 21 ++++++++++++++++++- 10 files changed, 200 insertions(+), 8 deletions(-) diff --git a/quickfixj-core/pom.xml b/quickfixj-core/pom.xml index d4e14a904..9086b31a8 100644 --- a/quickfixj-core/pom.xml +++ b/quickfixj-core/pom.xml @@ -336,6 +336,26 @@ + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin-version} + + + attach-javadocs + + jar + + + -Xdoclint:none + 3g + false + + src/main/java + + + + org.apache.felix maven-bundle-plugin diff --git a/quickfixj-messages/quickfixj-messages-fix40/pom.xml b/quickfixj-messages/quickfixj-messages-fix40/pom.xml index 869ae3471..74db0babb 100644 --- a/quickfixj-messages/quickfixj-messages-fix40/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix40/pom.xml @@ -41,6 +41,26 @@ + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin-version} + + + attach-javadocs + + jar + + + -Xdoclint:none + 3g + false + false + ${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/fix40;${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/field + + + + org.apache.felix maven-bundle-plugin diff --git a/quickfixj-messages/quickfixj-messages-fix41/pom.xml b/quickfixj-messages/quickfixj-messages-fix41/pom.xml index c032a35d7..aab28dd68 100644 --- a/quickfixj-messages/quickfixj-messages-fix41/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix41/pom.xml @@ -40,7 +40,26 @@ - + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin-version} + + + attach-javadocs + + jar + + + -Xdoclint:none + 3g + false + false + ${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/fix41;${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/field + + + + org.apache.felix maven-bundle-plugin diff --git a/quickfixj-messages/quickfixj-messages-fix42/pom.xml b/quickfixj-messages/quickfixj-messages-fix42/pom.xml index 06d3f4663..4320d6ecf 100644 --- a/quickfixj-messages/quickfixj-messages-fix42/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix42/pom.xml @@ -40,7 +40,26 @@ - + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin-version} + + + attach-javadocs + + jar + + + -Xdoclint:none + 3g + false + false + ${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/fix42;${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/field + + + + org.apache.felix maven-bundle-plugin diff --git a/quickfixj-messages/quickfixj-messages-fix43/pom.xml b/quickfixj-messages/quickfixj-messages-fix43/pom.xml index 76f17aae0..68e7e261c 100644 --- a/quickfixj-messages/quickfixj-messages-fix43/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix43/pom.xml @@ -40,7 +40,26 @@ - + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin-version} + + + attach-javadocs + + jar + + + -Xdoclint:none + 3g + false + false + ${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/fix43;${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/field + + + + org.apache.felix maven-bundle-plugin diff --git a/quickfixj-messages/quickfixj-messages-fix44/pom.xml b/quickfixj-messages/quickfixj-messages-fix44/pom.xml index d87af6710..4fde90196 100644 --- a/quickfixj-messages/quickfixj-messages-fix44/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix44/pom.xml @@ -40,7 +40,26 @@ - + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin-version} + + + attach-javadocs + + jar + + + -Xdoclint:none + 3g + false + false + ${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/fix44;${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/field + + + + org.apache.felix maven-bundle-plugin diff --git a/quickfixj-messages/quickfixj-messages-fix50/pom.xml b/quickfixj-messages/quickfixj-messages-fix50/pom.xml index a3269b728..ab8626e30 100644 --- a/quickfixj-messages/quickfixj-messages-fix50/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix50/pom.xml @@ -40,7 +40,26 @@ - + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin-version} + + + attach-javadocs + + jar + + + -Xdoclint:none + 3g + false + false + ${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/fix50;${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/field + + + + org.apache.felix maven-bundle-plugin diff --git a/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml b/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml index 8b2fd577a..a32b0679d 100644 --- a/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml @@ -40,7 +40,26 @@ - + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin-version} + + + attach-javadocs + + jar + + + -Xdoclint:none + 3g + false + false + ${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/fix50sp1;${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/field + + + + org.apache.felix maven-bundle-plugin diff --git a/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml b/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml index b4d05d737..811bf1f16 100644 --- a/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml @@ -40,7 +40,26 @@ - + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin-version} + + + attach-javadocs + + jar + + + -Xdoclint:none + 3g + false + false + ${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/fix50sp2;${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/field + + + + org.apache.felix maven-bundle-plugin diff --git a/quickfixj-messages/quickfixj-messages-fixt11/pom.xml b/quickfixj-messages/quickfixj-messages-fixt11/pom.xml index b6d95b0d7..bdd078b9d 100644 --- a/quickfixj-messages/quickfixj-messages-fixt11/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fixt11/pom.xml @@ -40,7 +40,26 @@ - + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin-version} + + + attach-javadocs + + jar + + + -Xdoclint:none + 3g + false + false + ${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/fixt11;${project.basedir}/../../quickfixj-core/target/generated-sources/quickfix/field + + + + org.apache.felix maven-bundle-plugin From 37c285bb33bc092794576cea6968804fdf87066c Mon Sep 17 00:00:00 2001 From: chrjohn Date: Tue, 19 Sep 2017 14:01:21 +0200 Subject: [PATCH 110/165] - changed version to 2.0.0-SNAPSHOT due to breaking API change (usage of Java DateTime API, QFJ-873) --- pom.xml | 2 +- quickfixj-all/pom.xml | 2 +- quickfixj-codegenerator/pom.xml | 2 +- quickfixj-core/pom.xml | 2 +- quickfixj-dictgenerator/pom.xml | 2 +- quickfixj-distribution/pom.xml | 2 +- quickfixj-examples/banzai/pom.xml | 2 +- quickfixj-examples/executor/pom.xml | 2 +- quickfixj-examples/ordermatch/pom.xml | 2 +- quickfixj-examples/pom.xml | 2 +- quickfixj-messages/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-all/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix40/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix41/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix42/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix43/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix44/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix50/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fixt11/pom.xml | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pom.xml b/pom.xml index 2203330ff..fc302cf69 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.quickfixj quickfixj-parent - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT pom QuickFIX/J Parent diff --git a/quickfixj-all/pom.xml b/quickfixj-all/pom.xml index 28fb8e9c2..732b67bda 100644 --- a/quickfixj-all/pom.xml +++ b/quickfixj-all/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-all diff --git a/quickfixj-codegenerator/pom.xml b/quickfixj-codegenerator/pom.xml index d3e18bf57..41eadb935 100644 --- a/quickfixj-codegenerator/pom.xml +++ b/quickfixj-codegenerator/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-codegenerator diff --git a/quickfixj-core/pom.xml b/quickfixj-core/pom.xml index d4e14a904..6c91b8210 100644 --- a/quickfixj-core/pom.xml +++ b/quickfixj-core/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-core diff --git a/quickfixj-dictgenerator/pom.xml b/quickfixj-dictgenerator/pom.xml index d8b1c52fb..e13703399 100644 --- a/quickfixj-dictgenerator/pom.xml +++ b/quickfixj-dictgenerator/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-dictgenerator diff --git a/quickfixj-distribution/pom.xml b/quickfixj-distribution/pom.xml index 53ab2ed3b..69aa535ab 100644 --- a/quickfixj-distribution/pom.xml +++ b/quickfixj-distribution/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-distribution diff --git a/quickfixj-examples/banzai/pom.xml b/quickfixj-examples/banzai/pom.xml index ca121fbb8..4c29f1d25 100644 --- a/quickfixj-examples/banzai/pom.xml +++ b/quickfixj-examples/banzai/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-examples - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-examples-banzai diff --git a/quickfixj-examples/executor/pom.xml b/quickfixj-examples/executor/pom.xml index 16de12e97..3a072c08b 100644 --- a/quickfixj-examples/executor/pom.xml +++ b/quickfixj-examples/executor/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-examples - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-examples-executor diff --git a/quickfixj-examples/ordermatch/pom.xml b/quickfixj-examples/ordermatch/pom.xml index 83b3700d9..851747fa9 100644 --- a/quickfixj-examples/ordermatch/pom.xml +++ b/quickfixj-examples/ordermatch/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-examples - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-examples-ordermatch diff --git a/quickfixj-examples/pom.xml b/quickfixj-examples/pom.xml index 109e93955..4564fef25 100644 --- a/quickfixj-examples/pom.xml +++ b/quickfixj-examples/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-examples diff --git a/quickfixj-messages/pom.xml b/quickfixj-messages/pom.xml index e748e115f..9efc63092 100644 --- a/quickfixj-messages/pom.xml +++ b/quickfixj-messages/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-messages diff --git a/quickfixj-messages/quickfixj-messages-all/pom.xml b/quickfixj-messages/quickfixj-messages-all/pom.xml index fb9b3e9f7..258c85dc0 100644 --- a/quickfixj-messages/quickfixj-messages-all/pom.xml +++ b/quickfixj-messages/quickfixj-messages-all/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-messages-all diff --git a/quickfixj-messages/quickfixj-messages-fix40/pom.xml b/quickfixj-messages/quickfixj-messages-fix40/pom.xml index 869ae3471..abd652b92 100644 --- a/quickfixj-messages/quickfixj-messages-fix40/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix40/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-messages-fix40 diff --git a/quickfixj-messages/quickfixj-messages-fix41/pom.xml b/quickfixj-messages/quickfixj-messages-fix41/pom.xml index c032a35d7..911f30a00 100644 --- a/quickfixj-messages/quickfixj-messages-fix41/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix41/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-messages-fix41 diff --git a/quickfixj-messages/quickfixj-messages-fix42/pom.xml b/quickfixj-messages/quickfixj-messages-fix42/pom.xml index 06d3f4663..15b5b48c2 100644 --- a/quickfixj-messages/quickfixj-messages-fix42/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix42/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-messages-fix42 diff --git a/quickfixj-messages/quickfixj-messages-fix43/pom.xml b/quickfixj-messages/quickfixj-messages-fix43/pom.xml index 76f17aae0..518f404f1 100644 --- a/quickfixj-messages/quickfixj-messages-fix43/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix43/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-messages-fix43 diff --git a/quickfixj-messages/quickfixj-messages-fix44/pom.xml b/quickfixj-messages/quickfixj-messages-fix44/pom.xml index d87af6710..81574a170 100644 --- a/quickfixj-messages/quickfixj-messages-fix44/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix44/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-messages-fix44 diff --git a/quickfixj-messages/quickfixj-messages-fix50/pom.xml b/quickfixj-messages/quickfixj-messages-fix50/pom.xml index a3269b728..45f8a981d 100644 --- a/quickfixj-messages/quickfixj-messages-fix50/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix50/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-messages-fix50 diff --git a/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml b/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml index 8b2fd577a..a39542c99 100644 --- a/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-messages-fix50sp1 diff --git a/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml b/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml index b4d05d737..9e8da056b 100644 --- a/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-messages-fix50sp2 diff --git a/quickfixj-messages/quickfixj-messages-fixt11/pom.xml b/quickfixj-messages/quickfixj-messages-fixt11/pom.xml index b6d95b0d7..2027ebe20 100644 --- a/quickfixj-messages/quickfixj-messages-fixt11/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fixt11/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 1.7.0-SNAPSHOT + 2.0.0-SNAPSHOT quickfixj-messages-fixt11 From 8dcc0041c9e6e6e2e5735b3299fc4fe5ea50ac6f Mon Sep 17 00:00:00 2001 From: chrjohn Date: Thu, 21 Sep 2017 13:39:58 +0200 Subject: [PATCH 111/165] QFJ-933: FieldNotFound when Logon without HeartBtInt is received - message is ignored - check for presence of HeartBtInt in AcceptorIoHandler - if field is not present assume 0 and leave the rest to the validation of the Logon message --- .../mina/acceptor/AcceptorIoHandler.java | 3 +- .../mina/acceptor/AcceptorIoHandlerTest.java | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/mina/acceptor/AcceptorIoHandler.java b/quickfixj-core/src/main/java/quickfix/mina/acceptor/AcceptorIoHandler.java index 75664eb27..0e565869e 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/acceptor/AcceptorIoHandler.java +++ b/quickfixj-core/src/main/java/quickfix/mina/acceptor/AcceptorIoHandler.java @@ -42,7 +42,6 @@ class AcceptorIoHandler extends AbstractIoHandler { private final EventHandlingStrategy eventHandlingStrategy; - private final AcceptorSessionProvider sessionProvider; public AcceptorIoHandler(AcceptorSessionProvider sessionProvider, @@ -77,7 +76,7 @@ protected void processMessage(IoSession protocolSession, Message message) throws } sessionLog.onEvent("Accepting session " + qfSession.getSessionID() + " from " + protocolSession.getRemoteAddress()); - final int heartbeatInterval = message.getInt(HeartBtInt.FIELD); + final int heartbeatInterval = message.isSetField(HeartBtInt.FIELD) ? message.getInt(HeartBtInt.FIELD) : 0; qfSession.setHeartBeatInterval(heartbeatInterval); sessionLog.onEvent("Acceptor heartbeat set to " + heartbeatInterval + " seconds"); diff --git a/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java b/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java index 15b79bfb6..8d33736ae 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java @@ -43,6 +43,7 @@ import java.util.HashMap; import java.util.Properties; +import static junit.framework.TestCase.fail; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; @@ -165,4 +166,40 @@ public void testMessageBeforeLogonWithKnownButUnboundSession() throws Exception verify(mockIoSession).getAttribute("QF_SESSION"); verifyNoMoreInteractions(mockEventHandlingStrategy); } + + // QFJ-933 + @Test + public void testLogonWithoutHeartBtInt() throws Exception { + EventHandlingStrategy mockEventHandlingStrategy = mock(EventHandlingStrategy.class); + IoSession mockIoSession = mock(IoSession.class); + + final SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIXT11, "SENDER", + "TARGET"); + final Session session = SessionFactoryTestSupport.createSession(sessionID, + new UnitTestApplication(), false); + stub(mockIoSession.getAttribute("QF_SESSION")).toReturn(null); // to create a new Session + + final HashMap acceptorSessions = new HashMap<>(); + acceptorSessions.put(sessionID, session); + final StaticAcceptorSessionProvider sessionProvider = createSessionProvider(acceptorSessions); + + final AcceptorIoHandler handler = new AcceptorIoHandler(sessionProvider, + new NetworkingOptions(new Properties()), mockEventHandlingStrategy); + + final DefaultApplVerID defaultApplVerID = new DefaultApplVerID(ApplVerID.FIX50SP2); + final Logon message = new Logon(new EncryptMethod(EncryptMethod.NONE_OTHER), + new HeartBtInt(30), defaultApplVerID); + message.getHeader().setString(TargetCompID.FIELD, sessionID.getSenderCompID()); + message.getHeader().setString(SenderCompID.FIELD, sessionID.getTargetCompID()); + message.getHeader().setField(new SendingTime(LocalDateTime.now())); + message.getHeader().setInt(MsgSeqNum.FIELD, 1); + // remove HeartBtInt field and make sure there is no Exception + message.removeField(HeartBtInt.FIELD); + try { + handler.processMessage(mockIoSession, message); + } catch (Exception e) { + fail("No exception should be thrown!"); + } + } + } From 620741576ae14dad70205bbc65986d668d307f6b Mon Sep 17 00:00:00 2001 From: Guido Medina Date: Thu, 21 Sep 2017 22:45:27 +0100 Subject: [PATCH 112/165] Dependencies and plugins updated to latest and some IntelliJ inspections suggestions applied. --- pom.xml | 8 ++++---- quickfixj-codegenerator/pom.xml | 2 +- quickfixj-core/src/main/java/quickfix/JdbcStore.java | 10 +++++----- quickfixj-core/src/main/java/quickfix/Session.java | 2 +- .../mina/initiator/AbstractSocketInitiator.java | 2 +- quickfixj-dictgenerator/pom.xml | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index fc302cf69..76b753fbd 100644 --- a/pom.xml +++ b/pom.xml @@ -74,14 +74,14 @@ 3.0.2 - 3.6.1 + 3.7.0 3.0.2 - 2.20 + 2.20.1 3.8 3.0.1 2.10.4 - 3.0.0 - 3.0.0 + 3.1.0 + 3.1.0 3.3.0 1.6 2.8.2 diff --git a/quickfixj-codegenerator/pom.xml b/quickfixj-codegenerator/pom.xml index 41eadb935..7f50e59a9 100644 --- a/quickfixj-codegenerator/pom.xml +++ b/quickfixj-codegenerator/pom.xml @@ -35,7 +35,7 @@ net.sf.saxon Saxon-HE - 9.8.0-3 + 9.8.0-4 diff --git a/quickfixj-core/src/main/java/quickfix/JdbcStore.java b/quickfixj-core/src/main/java/quickfix/JdbcStore.java index 46571aec1..1874d0953 100644 --- a/quickfixj-core/src/main/java/quickfix/JdbcStore.java +++ b/quickfixj-core/src/main/java/quickfix/JdbcStore.java @@ -192,7 +192,7 @@ public void reset() throws IOException { setSessionIdParameters(updateTime, 4); updateTime.execute(); } catch (SQLException e) { - throw (IOException) new IOException(e.getMessage()).initCause(e); + throw new IOException(e.getMessage(), e); } finally { JdbcUtil.close(sessionID, deleteMessages); JdbcUtil.close(sessionID, updateTime); @@ -217,7 +217,7 @@ public void get(int startSequence, int endSequence, Collection messages) messages.add(message); } } catch (SQLException e) { - throw (IOException) new IOException(e.getMessage()).initCause(e); + throw new IOException(e.getMessage(), e); } finally { JdbcUtil.close(sessionID, rs); JdbcUtil.close(sessionID, query); @@ -247,7 +247,7 @@ public boolean set(int sequence, String message) throws IOException { boolean status = update.execute(); return !status && update.getUpdateCount() > 0; } catch (SQLException e) { - throw (IOException) new IOException(e.getMessage()).initCause(e); + throw new IOException(e.getMessage(), e); } finally { JdbcUtil.close(sessionID, update); } @@ -281,7 +281,7 @@ private void storeSequenceNumbers() throws IOException { setSessionIdParameters(update, 3); update.execute(); } catch (SQLException e) { - throw (IOException) new IOException(e.getMessage()).initCause(e); + throw new IOException(e.getMessage(), e); } finally { JdbcUtil.close(sessionID, update); JdbcUtil.close(sessionID, connection); @@ -292,7 +292,7 @@ public void refresh() throws IOException { try { loadCache(); } catch (SQLException e) { - throw (IOException) new IOException(e.getMessage()).initCause(e); + throw new IOException(e.getMessage(), e); } } diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index 4122653c7..21180b83a 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -2806,7 +2806,7 @@ public void setTargetDefaultApplicationVersionID(ApplVerID applVerID) { } private static String extractNumber(String txt, int from) { - final StringBuilder ret = new StringBuilder(); + final StringBuilder ret = new StringBuilder(txt.length() - from); for (int i = from; i != txt.length(); ++i) { final char c = txt.charAt(i); if (c >= '0' && c <= '9') { diff --git a/quickfixj-core/src/main/java/quickfix/mina/initiator/AbstractSocketInitiator.java b/quickfixj-core/src/main/java/quickfix/mina/initiator/AbstractSocketInitiator.java index deb49a88d..9db5ab481 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/initiator/AbstractSocketInitiator.java +++ b/quickfixj-core/src/main/java/quickfix/mina/initiator/AbstractSocketInitiator.java @@ -254,7 +254,7 @@ private SocketAddress[] getSocketAddresses(SessionID sessionID) throws ConfigErr break; } } catch (final FieldConvertError e) { - throw (ConfigError) new ConfigError(e.getMessage()).initCause(e); + throw new ConfigError(e.getMessage(), e); } } diff --git a/quickfixj-dictgenerator/pom.xml b/quickfixj-dictgenerator/pom.xml index e13703399..cb92d3d72 100644 --- a/quickfixj-dictgenerator/pom.xml +++ b/quickfixj-dictgenerator/pom.xml @@ -26,7 +26,7 @@ org.dom4j dom4j - 2.0.1 + 2.1.0 true From 4da4169dacd9feb628a15aa7b607d582f21fc8c8 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Tue, 26 Sep 2017 14:02:14 +0200 Subject: [PATCH 113/165] QFJ-934: Message with nested repeating group and missing delimiter tag is silently ignored - changed to throw FieldException instead of InvalidMessage - send Reject message with meaningful error message --- .../src/main/java/quickfix/Message.java | 20 ++++++----- .../src/main/java/quickfix/Session.java | 17 +++++++-- .../java/quickfix/RepeatingGroupTest.java | 36 +++++++++++++------ ...4_MissingDelimiterNestedRepeatingGroup.def | 24 +++++++++++++ 4 files changed, 75 insertions(+), 22 deletions(-) create mode 100644 quickfixj-core/src/test/resources/quickfix/test/acceptance/definitions/server/fix44/QFJ934_MissingDelimiterNestedRepeatingGroup.def diff --git a/quickfixj-core/src/main/java/quickfix/Message.java b/quickfixj-core/src/main/java/quickfix/Message.java index 0ab1b47fd..9fd0dbcd0 100644 --- a/quickfixj-core/src/main/java/quickfix/Message.java +++ b/quickfixj-core/src/main/java/quickfix/Message.java @@ -602,17 +602,11 @@ private void parseGroup(String msgType, StringField field, DataDictionary dd, Da parseGroup(msgType, field, groupDataDictionary, parentDD, group, doValidation); } } else if (groupDataDictionary.isGroup(msgType, tag)) { - if (!firstFieldFound) { - throw new InvalidMessage("The group " + groupCountTag - + " must set the delimiter field " + firstField + " in " + messageData); - } + // QFJ-934: message should be rejected and not ignored when first field not found + checkFirstFieldFound(firstFieldFound, groupCountTag, firstField, tag); parseGroup(msgType, field, groupDataDictionary, parentDD, group, doValidation); } else if (groupDataDictionary.isField(tag)) { - if (!firstFieldFound) { - throw new FieldException( - SessionRejectReason.REPEATING_GROUP_FIELDS_OUT_OF_ORDER, tag); - } - + checkFirstFieldFound(firstFieldFound, groupCountTag, firstField, tag); if (fieldOrder != null && dd.isCheckUnorderedGroupFields()) { final int offset = indexOf(tag, fieldOrder); if (offset > -1) { @@ -650,6 +644,14 @@ private void addGroupRefToParent(Group group, FieldMap parent) { } } + private void checkFirstFieldFound(boolean firstFieldFound, final int groupCountTag, final int firstField, int tag) throws FieldException { + if (!firstFieldFound) { + throw new FieldException( + SessionRejectReason.REPEATING_GROUP_FIELDS_OUT_OF_ORDER, "The group " + groupCountTag + + " must set the delimiter field " + firstField, tag); + } + } + private boolean checkFieldValidation(FieldMap parent, DataDictionary parentDD, StringField field, String msgType, boolean doValidation, Group group) throws FieldException { boolean isField = (parent instanceof Group) ? parentDD.isField(field.getTag()) : parentDD.isMsgField(msgType, field.getTag()); if (!isField) { diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index 4122653c7..8d2f28f8a 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -1021,12 +1021,13 @@ private void next(Message message, boolean isProcessingQueuedMessages) throws Fi } if (msgType.equals(MsgType.LOGON)) { final String reason = SessionRejectReasonText.getMessage(e.getSessionRejectReason()); - final String errorMessage = "Invalid Logon message: " + reason + " (field " + e.getField() + ")"; + final String errorMessage = "Invalid Logon message: " + (reason != null ? reason : "unspecific reason") + + " (field " + e.getField() + ")"; generateLogout(errorMessage); state.incrNextTargetMsgSeqNum(); disconnect(errorMessage, true); } else { - generateReject(message, e.getSessionRejectReason(), e.getField()); + generateReject(message, e.getMessage(), e.getSessionRejectReason(), e.getField()); } } catch (final FieldNotFound e) { if (logErrorAndDisconnectIfRequired(e, message)) { @@ -1490,7 +1491,17 @@ private boolean isPossibleDuplicate(Message message) throws FieldNotFound { private void generateReject(Message message, int err, int field) throws IOException, FieldNotFound { - final String reason = SessionRejectReasonText.getMessage(err); + generateReject(message, null, err, field); + } + + private void generateReject(Message message, String text, int err, int field) throws IOException, + FieldNotFound { + final String reason; + if (text != null) { + reason = text; + } else { + reason = SessionRejectReasonText.getMessage(err); + } if (!state.isLogonReceived()) { final String errorMessage = "Tried to send a reject while not logged on: " + reason + " (field " + field + ")"; diff --git a/quickfixj-core/src/test/java/quickfix/RepeatingGroupTest.java b/quickfixj-core/src/test/java/quickfix/RepeatingGroupTest.java index 8c9996349..e07031027 100644 --- a/quickfixj-core/src/test/java/quickfix/RepeatingGroupTest.java +++ b/quickfixj-core/src/test/java/quickfix/RepeatingGroupTest.java @@ -19,8 +19,10 @@ package quickfix; -import junit.framework.TestCase; import org.junit.Assert; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import org.junit.Test; import quickfix.field.BeginString; import quickfix.field.LegSymbol; import quickfix.field.OrderID; @@ -30,7 +32,7 @@ import quickfix.fix44.Quote; import quickfix.fix50sp2.QuoteRequest; -public class RepeatingGroupTest extends TestCase { +public class RepeatingGroupTest { // In this testcase we use only FIX4.4 message, but we could use the others // FIX version. Indeed the group @@ -43,6 +45,7 @@ private Quote.NoLegs buildGroupWithStandardFields(String settingValue) { return grp; } + @Test public void testSettingGettingGroupWithStandardFields() throws FieldNotFound { final String settingValue = "SETTING_VALUE"; @@ -63,6 +66,7 @@ private Quote.NoLegs buildGroupWithCustomFields(String settingValue) { return grp; } + @Test public void testSettingGettingGroupWithCustomFields() throws FieldNotFound { final String settingValue = "SETTING_VALUE"; @@ -85,6 +89,7 @@ private Quote.NoLegs buildGroupWithCustomAndStandardFields(String settingValue) return grp; } + @Test public void testSettingGettingGroupWithCustomAndStandardFields() throws FieldNotFound { final String settingValue = "SETTING_VALUE"; @@ -143,6 +148,7 @@ private quickfix.fix50sp2.QuoteRequest.NoRelatedSym buildNestedGroupWithStandard return gNoRelatedSym; } + @Test public void testSettingGettingNestedGroupWithStandardFields() throws FieldNotFound { final String settingValue = "SETTING_VALUE"; @@ -177,6 +183,7 @@ private quickfix.fix44.QuoteRequest.NoRelatedSym buildNestedGroupWithCustomField return gNoRelatedSym; } + @Test public void testSettingGettingNestedGroupWithCustomFields() throws FieldNotFound { final String settingValue = "SETTING_VALUE"; @@ -214,6 +221,7 @@ private quickfix.fix44.QuoteRequest.NoRelatedSym buildNestedGroupWithCustomAndSt return gNoRelatedSym; } + @Test public void testSettingGettingNestedGroupWithCustomAndStandardFields() throws FieldNotFound { final String settingValue = "SETTING_VALUE"; @@ -235,6 +243,7 @@ public void testSettingGettingNestedGroupWithCustomAndStandardFields() throws Fi .getValue()); } + @Test // Testing group re-usability when setting values public void testSettingGettingGroupByReusingGroup() throws FieldNotFound { // The root group @@ -295,6 +304,7 @@ private Message buildValidatedMessage(String sourceFIXString, DataDictionary dd) return message; } + @Test public void testValidationWithNestedGroupAndStandardFields() throws InvalidMessage { final quickfix.fix44.QuoteRequest quoteRequest = new quickfix.fix44.QuoteRequest(); @@ -320,6 +330,7 @@ public void testValidationWithNestedGroupAndStandardFields() throws InvalidMessa assertEquals("Message validation failed", sourceFIXString, validateFIXString); } + @Test public void testValidationWithNestedGroupAndStandardFieldsFIX50SP2() throws InvalidMessage, ConfigError { final quickfix.fix50sp2.QuoteRequest quoteRequest = new quickfix.fix50sp2.QuoteRequest(); @@ -345,7 +356,8 @@ public void testValidationWithNestedGroupAndStandardFieldsFIX50SP2() throws Inva assertEquals(2, validatedMessage.getGroupCount(gNoRelatedSym.getFieldTag())); } - public void testValidationWithNestedGroupAndStandardFieldsWithoutDelimiter() { + @Test + public void testValidationWithNestedGroupAndStandardFieldsWithoutDelimiter() throws InvalidMessage { final quickfix.fix44.QuoteRequest quoteRequest = new quickfix.fix44.QuoteRequest(); final quickfix.field.QuoteReqID gQuoteReqID = new quickfix.field.QuoteReqID(); @@ -355,19 +367,15 @@ public void testValidationWithNestedGroupAndStandardFieldsWithoutDelimiter() { final quickfix.fix44.QuoteRequest.NoRelatedSym gNoRelatedSym = buildNestedGroupWithStandardFields("DEFAULT_VALUE"); quoteRequest.addGroup(gNoRelatedSym); - quoteRequest.addGroup(gNoRelatedSym); final String sourceFIXString = quoteRequest.toString(); - try { - buildValidatedMessage(sourceFIXString, defaultDataDictionary); - fail("No Exception thrown"); - } catch (final InvalidMessage e) { - // We expect that Exception did happen, so we don't do anything. - } + Message buildValidatedMessage = buildValidatedMessage(sourceFIXString, defaultDataDictionary); + assertEquals("The group 146 must set the delimiter field 55", buildValidatedMessage.getException().getMessage()); } + @Test public void testGroupFieldsOrderWithCustomDataDictionary() throws InvalidMessage { final quickfix.fix44.QuoteRequest quoteRequest = new quickfix.fix44.QuoteRequest(); @@ -407,6 +415,7 @@ public void testGroupFieldsOrderWithCustomDataDictionary() throws InvalidMessage MessageUtils.checksum(sourceFIXString), MessageUtils.checksum(validatedFIXString)); } + @Test public void testOutOfOrderGroupMembersDelimiterField() throws Exception { final Message m = new Message( "8=FIX.4.4\0019=0\00135=D\00134=2\00149=TW\00152=

\n"); - Component standardHeader = repository.getStandardHeader(msgTypes.values().iterator().next()); + Component standardHeader = repository.getStandardHeader(getNextMsgType(msgTypes)); addMsgContents(builder, standardHeader.getMsgContent(), " "); builder.append("
\n"); builder.append(" \n"); - Component standardTrailer = repository.getStandardTrailer(msgTypes.values().iterator().next()); + Component standardTrailer = repository.getStandardTrailer(getNextMsgType(msgTypes)); addMsgContents(builder, standardTrailer.getMsgContent(), " "); builder.append(" \n"); } else { @@ -103,11 +98,11 @@ private void generateDictionary(String file, boolean admin, boolean merged) { } } else { builder.append("
\n"); - Component standardHeader = repository.getStandardHeader(msgTypes.values().iterator().next()); + Component standardHeader = repository.getStandardHeader(getNextMsgType(msgTypes)); addMsgContents(builder, standardHeader.getMsgContent(), " "); builder.append("
\n"); builder.append(" \n"); - Component standardTrailer = repository.getStandardTrailer(msgTypes.values().iterator().next()); + Component standardTrailer = repository.getStandardTrailer(getNextMsgType(msgTypes)); addMsgContents(builder, standardTrailer.getMsgContent(), " "); builder.append(" \n"); } @@ -222,6 +217,15 @@ private void generateDictionary(String file, boolean admin, boolean merged) { } } + private MsgType getNextMsgType(Map msgTypes) { + Iterator it = msgTypes.values().iterator(); + if(it.hasNext()) { + return it.next(); + } else { + throw new RuntimeException("Message type not found. Check the MsgType.xml file."); + } + } + private void addMsgContents(StringBuilder builder, List msgContents, String prefix) { for (Object o : msgContents) { if (o instanceof Field) { diff --git a/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Repository.java b/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Repository.java index ff1cbb24c..36fde2501 100644 --- a/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Repository.java +++ b/quickfixj-dictgenerator/src/main/java/org/quickfixj/dictgenerator/Repository.java @@ -108,11 +108,11 @@ private void initMsgTypes(Map msgTypeMap, String notReqXML) { List msgTypeNodes = msgType.selectNodes("//dataroot/MsgType[NotReqXML=" + notReqXML + "]"); for (Object o : msgTypeNodes) { Node node = (Node) o; - String msgID = node.selectSingleNode("MsgID").getText(); - String messageName = node.selectSingleNode("MessageName").getText(); - String componentType = node.selectSingleNode("ComponentType").getText(); - String category = node.selectSingleNode("Category").getText(); - String msgType = node.selectSingleNode("MsgType").getText(); + String msgID = getSingleNodeTextSafe(node, "MsgID"); + String messageName = getSingleNodeTextSafe(node, "MessageName"); + String componentType = getSingleNodeTextSafe(node, "ComponentType"); + String category = getSingleNodeTextSafe(node, "Category"); + String msgType = getSingleNodeTextSafe(node, "MsgType"); msgTypeMap.put(msgType, new MsgType(msgID, messageName, componentType, category, notReqXML, msgType)); } @@ -124,8 +124,8 @@ private void initMsgTypes(Map msgTypeMap, String notReqXML) { System.out.println("\t " + msgType.getName()); for (Object o : msgContentsNodes) { Node node = (Node) o; - String tagText = node.selectSingleNode("TagText").getText(); - String reqd = node.selectSingleNode("Reqd").getText(); + String tagText = getSingleNodeTextSafe(node, "TagText"); + String reqd = getSingleNodeTextSafe(node, "Reqd"); //if (allFields.containsKey(tagText) && notReqXML.equals(allFields.get(tagText).getNotReqXML())) { if (allFields.containsKey(tagText)) { MsgTypeField msgTypeField = new MsgTypeField(allFields.get(tagText), reqd); @@ -148,12 +148,12 @@ private void initFields() { List fieldNodes = fields.selectNodes("//dataroot/Fields"); for (Object o : fieldNodes) { Node node = (Node) o; - String tag = node.selectSingleNode("Tag").getText(); - String fieldName = node.selectSingleNode("FieldName").getText(); + String tag = getSingleNodeTextSafe(node, "Tag"); + String fieldName = getSingleNodeTextSafe(node, "FieldName"); System.out.println("\t " + fieldName + "(" + tag + ")"); - String type = node.selectSingleNode("Type").getText(); - String desc = node.selectSingleNode("Desc").getText(); - String notReqXML = node.selectSingleNode("NotReqXML").getText(); + String type = getSingleNodeTextSafe(node, "Type"); + String desc = getSingleNodeTextSafe(node, "Desc"); + String notReqXML = getSingleNodeTextSafe(node, "NotReqXML"); Field field = new Field(tag, fieldName, type, desc, notReqXML); allFields.put(field.getTag(), field); // Find enums @@ -162,9 +162,9 @@ private void initFields() { if (!enumNodes.isEmpty()) { for (Object enumO : enumNodes) { Node enumNode = (Node) enumO; - String enumName = enumNode.selectSingleNode("Enum").getText(); + String enumName = getSingleNodeTextSafe(enumNode, "Enum"); System.out.println("\t\t " + enumName); - String enumDesc = enumNode.selectSingleNode("Description").getText(); + String enumDesc = getSingleNodeTextSafe(enumNode, "Description"); field.addEnum(new Enum(enumName, enumDesc)); } } @@ -172,16 +172,24 @@ private void initFields() { System.out.println(getClass().getSimpleName() + ": " + allFields.size() + " Fields found"); } + private String getSingleNodeTextSafe(Node node, String tag) { + Node nodeWithTag = node.selectSingleNode(tag); + if(nodeWithTag != null) + return nodeWithTag.getText(); + else + throw new RuntimeException("Node with tag "+tag+" not found in "+node.getPath()); + } + private void initComponents() { System.out.println(getClass().getSimpleName() + ": Init Components..."); List componentNodes = components.selectNodes("//dataroot/Components"); for (Object o : componentNodes) { Node node = (Node) o; - String msgID = node.selectSingleNode("MsgID").getText(); - String componentName = node.selectSingleNode("ComponentName").getText(); - String componentType = node.selectSingleNode("ComponentType").getText(); - String category = node.selectSingleNode("Category").getText(); - String notReqXML = node.selectSingleNode("NotReqXML").getText(); + String msgID = getSingleNodeTextSafe(node, "MsgID"); + String componentName = getSingleNodeTextSafe(node, "ComponentName"); + String componentType = getSingleNodeTextSafe(node, "ComponentType"); + String category = getSingleNodeTextSafe(node, "Category"); + String notReqXML = getSingleNodeTextSafe(node, "NotReqXML"); allComponents.put(componentName, new Component(msgID, componentName, componentType, category, notReqXML)); } @@ -202,8 +210,8 @@ private void addComponentMsgContent(Component component, String prefix) { } for (Object o : msgContentsNodes) { Node node = (Node) o; - String tagText = node.selectSingleNode("TagText").getText(); - String reqd = node.selectSingleNode("Reqd").getText(); + String tagText = getSingleNodeTextSafe(node, "TagText"); + String reqd = getSingleNodeTextSafe(node, "Reqd"); if (allFields.containsKey(tagText)) { ComponentField componentField = new ComponentField(allFields.get(tagText), reqd); component.addMsgContent(componentField); @@ -229,8 +237,8 @@ private List getMsgContents(String msgID) { class MsgContentNodeComparator implements Comparator { public int compare(Object o1, Object o2) { try { - Double pos1 = Double.parseDouble(((Node) o1).selectSingleNode("Position").getText()); - Double pos2 = Double.parseDouble(((Node) o2).selectSingleNode("Position").getText()); + Double pos1 = Double.parseDouble(getSingleNodeTextSafe((Node) o1, "Position")); + Double pos2 = Double.parseDouble(getSingleNodeTextSafe((Node) o2, "Position")); return pos1.compareTo(pos2); } catch (Exception e) { return 0; @@ -241,8 +249,8 @@ public int compare(Object o1, Object o2) { class EnumNodeComparator implements Comparator { public int compare(Object o1, Object o2) { try { - Double pos1 = Double.parseDouble(((Node) o1).selectSingleNode("Sort").getText()); - Double pos2 = Double.parseDouble(((Node) o2).selectSingleNode("Sort").getText()); + Double pos1 = Double.parseDouble(getSingleNodeTextSafe((Node) o1, "Sort")); + Double pos2 = Double.parseDouble(getSingleNodeTextSafe((Node) o2, "Sort")); return pos1.compareTo(pos2); } catch (Exception e) { return 0; From 7b253d76d7677a6e73d17dfcc70d3c86f8d0f06a Mon Sep 17 00:00:00 2001 From: Christoph John Date: Fri, 27 Oct 2017 10:14:17 +0200 Subject: [PATCH 130/165] Playing with travis config --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 8842cc818..fdcef2648 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ language: java +sudo: required +dist: trusty jdk: - oraclejdk8 before_install: From acc0300ec009068231a7d42fed4037253b584ce7 Mon Sep 17 00:00:00 2001 From: Christoph John Date: Fri, 27 Oct 2017 11:00:50 +0200 Subject: [PATCH 131/165] Tested another Linux distribution --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fdcef2648..a7d5c0e00 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: java sudo: required -dist: trusty +dist: precise jdk: - oraclejdk8 before_install: From e220dd572896a87647776db9c16db4afc19278b1 Mon Sep 17 00:00:00 2001 From: Ruedi Steinmann Date: Fri, 17 Nov 2017 21:02:39 +0100 Subject: [PATCH 132/165] various fixes in install.html (#153) --- .../src/main/doc/usermanual/installation.html | 67 +++++++------------ 1 file changed, 24 insertions(+), 43 deletions(-) diff --git a/quickfixj-core/src/main/doc/usermanual/installation.html b/quickfixj-core/src/main/doc/usermanual/installation.html index 45d526638..500f09e8d 100644 --- a/quickfixj-core/src/main/doc/usermanual/installation.html +++ b/quickfixj-core/src/main/doc/usermanual/installation.html @@ -162,75 +162,56 @@

IDE support:

Maven Integration:

If you are using the Maven build system, you can reference - the pre-built QuickFIX/J libraries hosted at the Marketcetera + the pre-built QuickFIX/J libraries hosted at the Central Repository repository.

-
    -
  1. Add the following to your dependencies section, with appropriate modifications based on +

    Add the following to your dependencies section, with appropriate modifications based on the logging subsystem you choose:

     <!-- QuickFIX/J dependencies -->
     <dependency>
    -    <groupId>quickfixj</groupId>
    +    <groupId>org.quickfixj</groupId>
         <artifactId>quickfixj-core</artifactId>
    -    <version>1.6.0</version>
    -</dependency>
    -<dependency>
    -    <groupId>quickfixj</groupId>
    -    <artifactId>quickfixj-msg-fix40</artifactId>
    -    <version>1.6.0</version>
    +    <version>2.0.0</version>
     </dependency>
     <dependency>
    -    <groupId>quickfixj</groupId>
    -    <artifactId>quickfixj-msg-fix41</artifactId>
    -    <version>1.6.0</version>
    +    <groupId>org.quickfixj</groupId>
    +    <artifactId>quickfixj-messages-fix40</artifactId>
    +    <version>2.0.0</version>
     </dependency>
     <dependency>
    -    <groupId>quickfixj</groupId>
    -    <artifactId>quickfixj-msg-fix42</artifactId>
    -    <version>1.6.0</version>
    +    <groupId>org.quickfixj</groupId>
    +    <artifactId>quickfixj-messages-fix41</artifactId>
    +    <version>2.0.0</version>
     </dependency>
     <dependency>
    -    <groupId>quickfixj</groupId>
    -    <artifactId>quickfixj-msg-fix43</artifactId>
    -    <version>1.6.0</version>
    +    <groupId>org.quickfixj</groupId>
    +    <artifactId>quickfixj-messages-fix42</artifactId>
    +    <version>2.0.0</version>
     </dependency>
     <dependency>
    -    <groupId>quickfixj</groupId>
    -    <artifactId>quickfixj-msg-fix44</artifactId>
    -    <version>1.6.0</version>
    +    <groupId>org.quickfixj</groupId>
    +    <artifactId>quickfixj-messages-fix43</artifactId>
    +    <version>2.0.0</version>
     </dependency>
     <dependency>
    -    <groupId>org.apache.mina</groupId>
    -    <artifactId>mina-core</artifactId>
    -    <version>2.0.9</version>
    +    <groupId>org.quickfixj</groupId>
    +    <artifactId>quickfixj-messages-fix44</artifactId>
    +    <version>2.0.0</version>
     </dependency>
     <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-log4j12</artifactId>
    -    <version>1.7.12</version>
    +    <version>1.7.22</version>
     </dependency>
     <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
    -    <version>1.7.12</version>
    +    <version>1.7.22</version>
     </dependency>
    -
  2. -
  3. And add the Marketcetera Repository to your repository list:
    -
    -<repositories>
    -    <repository>
    -        <id>MarketceteraRepo</id>
    -        <url>http://repo.marketcetera.org/maven</url>
    -            <releases>
    -                <enabled>true</enabled>
    -            </releases>
    -    </repository>
    -</repositories>
    -
  4. -
-There's an example POM file if you need it. +

+

Generating the database for JDBC based store and log

-

Everything needed to generate your database is in the etc/sql subdirectories. +

Everything needed to generate your database is in the src/main/resources/config/sql subdirectories. For MySQL, there are the script and batch files create_mysql.sh and create_mysql.bat. These scripts will work on a newly installed mysql database with default permisions. The scripts will try to generate the database using the root MySQL account From 5c0625c6db961b4d895c833a28fc0d78b14b784c Mon Sep 17 00:00:00 2001 From: Christoph John Date: Fri, 17 Nov 2017 22:23:52 +0100 Subject: [PATCH 133/165] added -Djava.net.preferIPv4Stack=true to test config (#154) To hopefully prevent test failures on Windows --- quickfixj-core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickfixj-core/pom.xml b/quickfixj-core/pom.xml index 9ecd21344..0db104faf 100644 --- a/quickfixj-core/pom.xml +++ b/quickfixj-core/pom.xml @@ -384,7 +384,7 @@ org.apache.maven.plugins maven-surefire-plugin - -Xmx512m -XX:MaxPermSize=256m + -Xmx512m -XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true **/*Test.java ${acceptance.tests} From fab0ce8f8d0f4270e6b33cd10232f1f3fd6c2730 Mon Sep 17 00:00:00 2001 From: Christoph John Date: Sat, 18 Nov 2017 21:31:52 +0100 Subject: [PATCH 134/165] increased number of open files to see if this fixes hangs in SelectorImpl.select() --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index a7d5c0e00..11745ffdb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,8 @@ sudo: required dist: precise jdk: - oraclejdk8 +before_script: + - ulimit -n 4096 before_install: - echo "MAVEN_OPTS='-Xms2g -Xmx3g'" > ~/.mavenrc script: From a1bedae32786e92a6ed57246faf026275bea5243 Mon Sep 17 00:00:00 2001 From: Christoph John Date: Tue, 21 Nov 2017 14:20:23 +0100 Subject: [PATCH 135/165] Changed sudo and alternative distribution setting for Travis (#155) * Removed sudo and alternative distribution setting * use docker container on Travis --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 11745ffdb..030dd5522 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: java -sudo: required -dist: precise +sudo: false jdk: - oraclejdk8 before_script: From 01af2c36adb73127498f8f542530f4fe81f1052d Mon Sep 17 00:00:00 2001 From: Christoph John Date: Tue, 21 Nov 2017 14:54:44 +0100 Subject: [PATCH 136/165] forward caught exception to next filter (#156) minor cleanup --- .../src/test/java/quickfix/mina/ssl/SecureSocketTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/quickfixj-core/src/test/java/quickfix/mina/ssl/SecureSocketTest.java b/quickfixj-core/src/test/java/quickfix/mina/ssl/SecureSocketTest.java index 209a7cba6..f2012aea8 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/ssl/SecureSocketTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/ssl/SecureSocketTest.java @@ -68,6 +68,7 @@ public void testLogonWithBadCertificate() throws Exception { public void exceptionCaught(NextFilter nextFilter, IoSession session, Throwable cause) throws Exception { log.info("MINA exception: {}", cause.getMessage()); exceptionCaught.countDown(); + nextFilter.exceptionCaught(session, cause); } })); From cff2a5d6595cc3f36904d0bdf7370b7761b16d67 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Wed, 22 Nov 2017 10:48:56 +0100 Subject: [PATCH 137/165] changed version to 2.0.0 --- pom.xml | 4 ++-- quickfixj-all/pom.xml | 2 +- quickfixj-codegenerator/pom.xml | 2 +- quickfixj-core/pom.xml | 11 +++++------ quickfixj-dictgenerator/pom.xml | 2 +- quickfixj-distribution/pom.xml | 2 +- quickfixj-examples/banzai/pom.xml | 2 +- quickfixj-examples/executor/pom.xml | 2 +- quickfixj-examples/ordermatch/pom.xml | 2 +- quickfixj-examples/pom.xml | 2 +- quickfixj-messages/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-all/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix40/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix41/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix42/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix43/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix44/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix50/pom.xml | 2 +- .../quickfixj-messages-fix50sp1/pom.xml | 2 +- .../quickfixj-messages-fix50sp2/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fixt11/pom.xml | 2 +- 21 files changed, 26 insertions(+), 27 deletions(-) diff --git a/pom.xml b/pom.xml index 76b753fbd..60d4ea3df 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.quickfixj quickfixj-parent - 2.0.0-SNAPSHOT + 2.0.0 pom QuickFIX/J Parent @@ -71,7 +71,7 @@ 1.8 1.7.25 4.12 - + 3.0.2 3.7.0 diff --git a/quickfixj-all/pom.xml b/quickfixj-all/pom.xml index 732b67bda..a692ea954 100644 --- a/quickfixj-all/pom.xml +++ b/quickfixj-all/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-all diff --git a/quickfixj-codegenerator/pom.xml b/quickfixj-codegenerator/pom.xml index 7f50e59a9..307e53371 100644 --- a/quickfixj-codegenerator/pom.xml +++ b/quickfixj-codegenerator/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-codegenerator diff --git a/quickfixj-core/pom.xml b/quickfixj-core/pom.xml index 0db104faf..5a53de95e 100644 --- a/quickfixj-core/pom.xml +++ b/quickfixj-core/pom.xml @@ -1,10 +1,9 @@ - + 4.0.0 org.quickfixj quickfixj-parent - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-core @@ -376,7 +375,7 @@ quickfix,quickfix.field,* - + @@ -410,7 +409,7 @@ maven-surefire-report-plugin ${maven-surefire-plugin-version} - + true @@ -433,7 +432,7 @@ - + diff --git a/quickfixj-dictgenerator/pom.xml b/quickfixj-dictgenerator/pom.xml index cb92d3d72..ef3a7b923 100644 --- a/quickfixj-dictgenerator/pom.xml +++ b/quickfixj-dictgenerator/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-dictgenerator diff --git a/quickfixj-distribution/pom.xml b/quickfixj-distribution/pom.xml index 69aa535ab..9c6d75b3f 100644 --- a/quickfixj-distribution/pom.xml +++ b/quickfixj-distribution/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-distribution diff --git a/quickfixj-examples/banzai/pom.xml b/quickfixj-examples/banzai/pom.xml index 4c29f1d25..3ce785c89 100644 --- a/quickfixj-examples/banzai/pom.xml +++ b/quickfixj-examples/banzai/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-examples - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-examples-banzai diff --git a/quickfixj-examples/executor/pom.xml b/quickfixj-examples/executor/pom.xml index 3a072c08b..bc7d798e7 100644 --- a/quickfixj-examples/executor/pom.xml +++ b/quickfixj-examples/executor/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-examples - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-examples-executor diff --git a/quickfixj-examples/ordermatch/pom.xml b/quickfixj-examples/ordermatch/pom.xml index 851747fa9..49ec67b0e 100644 --- a/quickfixj-examples/ordermatch/pom.xml +++ b/quickfixj-examples/ordermatch/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-examples - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-examples-ordermatch diff --git a/quickfixj-examples/pom.xml b/quickfixj-examples/pom.xml index 4564fef25..2cdebcb76 100644 --- a/quickfixj-examples/pom.xml +++ b/quickfixj-examples/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-examples diff --git a/quickfixj-messages/pom.xml b/quickfixj-messages/pom.xml index 9efc63092..2175561b6 100644 --- a/quickfixj-messages/pom.xml +++ b/quickfixj-messages/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-messages diff --git a/quickfixj-messages/quickfixj-messages-all/pom.xml b/quickfixj-messages/quickfixj-messages-all/pom.xml index 258c85dc0..819eb4daf 100644 --- a/quickfixj-messages/quickfixj-messages-all/pom.xml +++ b/quickfixj-messages/quickfixj-messages-all/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-messages-all diff --git a/quickfixj-messages/quickfixj-messages-fix40/pom.xml b/quickfixj-messages/quickfixj-messages-fix40/pom.xml index 509df1cac..36f971d8c 100644 --- a/quickfixj-messages/quickfixj-messages-fix40/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix40/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-messages-fix40 diff --git a/quickfixj-messages/quickfixj-messages-fix41/pom.xml b/quickfixj-messages/quickfixj-messages-fix41/pom.xml index 78ae5fc15..5bb6f1011 100644 --- a/quickfixj-messages/quickfixj-messages-fix41/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix41/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-messages-fix41 diff --git a/quickfixj-messages/quickfixj-messages-fix42/pom.xml b/quickfixj-messages/quickfixj-messages-fix42/pom.xml index 8194c31df..300951296 100644 --- a/quickfixj-messages/quickfixj-messages-fix42/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix42/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-messages-fix42 diff --git a/quickfixj-messages/quickfixj-messages-fix43/pom.xml b/quickfixj-messages/quickfixj-messages-fix43/pom.xml index 762a6c823..f00b9e0ef 100644 --- a/quickfixj-messages/quickfixj-messages-fix43/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix43/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-messages-fix43 diff --git a/quickfixj-messages/quickfixj-messages-fix44/pom.xml b/quickfixj-messages/quickfixj-messages-fix44/pom.xml index f9e91abeb..b416f42f6 100644 --- a/quickfixj-messages/quickfixj-messages-fix44/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix44/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-messages-fix44 diff --git a/quickfixj-messages/quickfixj-messages-fix50/pom.xml b/quickfixj-messages/quickfixj-messages-fix50/pom.xml index 96ec4890b..1066b3538 100644 --- a/quickfixj-messages/quickfixj-messages-fix50/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix50/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-messages-fix50 diff --git a/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml b/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml index b16716c59..9bf2c4773 100644 --- a/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-messages-fix50sp1 diff --git a/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml b/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml index 08fe394fe..1c20b88c3 100644 --- a/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-messages-fix50sp2 diff --git a/quickfixj-messages/quickfixj-messages-fixt11/pom.xml b/quickfixj-messages/quickfixj-messages-fixt11/pom.xml index e2b36ab47..5eff238ee 100644 --- a/quickfixj-messages/quickfixj-messages-fixt11/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fixt11/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0-SNAPSHOT + 2.0.0 quickfixj-messages-fixt11 From 6ec3412de50f9f32c7f8a6ebb0c21438e1a98c33 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Wed, 22 Nov 2017 14:26:03 +0100 Subject: [PATCH 138/165] set version to 2.0.1-SNAPSHOT --- pom.xml | 2 +- quickfixj-all/pom.xml | 2 +- quickfixj-codegenerator/pom.xml | 2 +- quickfixj-core/pom.xml | 2 +- quickfixj-dictgenerator/pom.xml | 2 +- quickfixj-distribution/pom.xml | 2 +- quickfixj-examples/banzai/pom.xml | 2 +- quickfixj-examples/executor/pom.xml | 2 +- quickfixj-examples/ordermatch/pom.xml | 2 +- quickfixj-examples/pom.xml | 2 +- quickfixj-messages/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-all/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix40/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix41/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix42/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix43/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix44/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix50/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fixt11/pom.xml | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pom.xml b/pom.xml index 60d4ea3df..981f6b3ca 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.quickfixj quickfixj-parent - 2.0.0 + 2.0.1-SNAPSHOT pom QuickFIX/J Parent diff --git a/quickfixj-all/pom.xml b/quickfixj-all/pom.xml index a692ea954..6ac9115c1 100644 --- a/quickfixj-all/pom.xml +++ b/quickfixj-all/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-all diff --git a/quickfixj-codegenerator/pom.xml b/quickfixj-codegenerator/pom.xml index 307e53371..cec7dc978 100644 --- a/quickfixj-codegenerator/pom.xml +++ b/quickfixj-codegenerator/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-codegenerator diff --git a/quickfixj-core/pom.xml b/quickfixj-core/pom.xml index 5a53de95e..23dc556da 100644 --- a/quickfixj-core/pom.xml +++ b/quickfixj-core/pom.xml @@ -3,7 +3,7 @@ org.quickfixj quickfixj-parent - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-core diff --git a/quickfixj-dictgenerator/pom.xml b/quickfixj-dictgenerator/pom.xml index ef3a7b923..58a7fa22f 100644 --- a/quickfixj-dictgenerator/pom.xml +++ b/quickfixj-dictgenerator/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-dictgenerator diff --git a/quickfixj-distribution/pom.xml b/quickfixj-distribution/pom.xml index 9c6d75b3f..51aeca5f6 100644 --- a/quickfixj-distribution/pom.xml +++ b/quickfixj-distribution/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-distribution diff --git a/quickfixj-examples/banzai/pom.xml b/quickfixj-examples/banzai/pom.xml index 3ce785c89..3d92bf36b 100644 --- a/quickfixj-examples/banzai/pom.xml +++ b/quickfixj-examples/banzai/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-examples - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-examples-banzai diff --git a/quickfixj-examples/executor/pom.xml b/quickfixj-examples/executor/pom.xml index bc7d798e7..ef76ed39a 100644 --- a/quickfixj-examples/executor/pom.xml +++ b/quickfixj-examples/executor/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-examples - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-examples-executor diff --git a/quickfixj-examples/ordermatch/pom.xml b/quickfixj-examples/ordermatch/pom.xml index 49ec67b0e..c6dd458e6 100644 --- a/quickfixj-examples/ordermatch/pom.xml +++ b/quickfixj-examples/ordermatch/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-examples - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-examples-ordermatch diff --git a/quickfixj-examples/pom.xml b/quickfixj-examples/pom.xml index 2cdebcb76..6fd9c8099 100644 --- a/quickfixj-examples/pom.xml +++ b/quickfixj-examples/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-examples diff --git a/quickfixj-messages/pom.xml b/quickfixj-messages/pom.xml index 2175561b6..76b7b630f 100644 --- a/quickfixj-messages/pom.xml +++ b/quickfixj-messages/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-messages diff --git a/quickfixj-messages/quickfixj-messages-all/pom.xml b/quickfixj-messages/quickfixj-messages-all/pom.xml index 819eb4daf..7154da135 100644 --- a/quickfixj-messages/quickfixj-messages-all/pom.xml +++ b/quickfixj-messages/quickfixj-messages-all/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-messages-all diff --git a/quickfixj-messages/quickfixj-messages-fix40/pom.xml b/quickfixj-messages/quickfixj-messages-fix40/pom.xml index 36f971d8c..8a6bdd354 100644 --- a/quickfixj-messages/quickfixj-messages-fix40/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix40/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-messages-fix40 diff --git a/quickfixj-messages/quickfixj-messages-fix41/pom.xml b/quickfixj-messages/quickfixj-messages-fix41/pom.xml index 5bb6f1011..3ed73eeba 100644 --- a/quickfixj-messages/quickfixj-messages-fix41/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix41/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-messages-fix41 diff --git a/quickfixj-messages/quickfixj-messages-fix42/pom.xml b/quickfixj-messages/quickfixj-messages-fix42/pom.xml index 300951296..909da5fe7 100644 --- a/quickfixj-messages/quickfixj-messages-fix42/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix42/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-messages-fix42 diff --git a/quickfixj-messages/quickfixj-messages-fix43/pom.xml b/quickfixj-messages/quickfixj-messages-fix43/pom.xml index f00b9e0ef..a83d24a71 100644 --- a/quickfixj-messages/quickfixj-messages-fix43/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix43/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-messages-fix43 diff --git a/quickfixj-messages/quickfixj-messages-fix44/pom.xml b/quickfixj-messages/quickfixj-messages-fix44/pom.xml index b416f42f6..999cd62ea 100644 --- a/quickfixj-messages/quickfixj-messages-fix44/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix44/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-messages-fix44 diff --git a/quickfixj-messages/quickfixj-messages-fix50/pom.xml b/quickfixj-messages/quickfixj-messages-fix50/pom.xml index 1066b3538..711a007e2 100644 --- a/quickfixj-messages/quickfixj-messages-fix50/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix50/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-messages-fix50 diff --git a/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml b/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml index 9bf2c4773..ff24ab88d 100644 --- a/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-messages-fix50sp1 diff --git a/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml b/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml index 1c20b88c3..29c113eb5 100644 --- a/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-messages-fix50sp2 diff --git a/quickfixj-messages/quickfixj-messages-fixt11/pom.xml b/quickfixj-messages/quickfixj-messages-fixt11/pom.xml index 5eff238ee..51f46292a 100644 --- a/quickfixj-messages/quickfixj-messages-fixt11/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fixt11/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.0 + 2.0.1-SNAPSHOT quickfixj-messages-fixt11 From 7afb9f3a63644041f1329b38e46ecea48e3f2699 Mon Sep 17 00:00:00 2001 From: mmitya Date: Thu, 23 Nov 2017 08:49:45 +0000 Subject: [PATCH 139/165] Required component in group (#148) * Failing test case is added. * Test case is fixed. DataDictionary now makes a field req'd if 1. this field is req'd within a component 2. this component is req'd within a group --- .../main/java/quickfix/DataDictionary.java | 6 ++- .../java/quickfix/DataDictionaryTest.java | 52 ++++++++++++++----- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/DataDictionary.java b/quickfixj-core/src/main/java/quickfix/DataDictionary.java index fad3bdbe4..d41d9ffbf 100644 --- a/quickfixj-core/src/main/java/quickfix/DataDictionary.java +++ b/quickfixj-core/src/main/java/quickfix/DataDictionary.java @@ -1105,7 +1105,7 @@ private int addXMLComponentFields(Document document, Node node, String msgtype, final String required = getAttribute(componentFieldNode, "required"); if (required.equalsIgnoreCase("Y") && componentRequired) { - addRequiredField(msgtype, field); + dd.addRequiredField(msgtype, field); } dd.addField(field); @@ -1148,7 +1148,9 @@ private void addXMLGroup(Document document, Node node, String msgtype, DataDicti groupDD.addRequiredField(msgtype, field); } } else if (fieldNode.getNodeName().equals("component")) { - field = addXMLComponentFields(document, fieldNode, msgtype, groupDD, false); + final String required = getAttribute(fieldNode, "required"); + final boolean isRequired = required != null && required.equalsIgnoreCase("Y"); + field = addXMLComponentFields(document, fieldNode, msgtype, groupDD, isRequired); } else if (fieldNode.getNodeName().equals("group")) { field = lookupXMLFieldNumber(document, fieldNode); groupDD.addField(field); diff --git a/quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java b/quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java index 0a0610e4e..520361d94 100644 --- a/quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java +++ b/quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java @@ -19,20 +19,9 @@ package quickfix; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.io.ByteArrayInputStream; -import java.math.BigDecimal; -import java.net.URL; -import java.net.URLClassLoader; - import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; - import quickfix.field.Account; import quickfix.field.AvgPx; import quickfix.field.BodyLength; @@ -52,6 +41,7 @@ import quickfix.field.SenderCompID; import quickfix.field.SenderSubID; import quickfix.field.SendingTime; +import quickfix.field.SessionRejectReason; import quickfix.field.Side; import quickfix.field.Symbol; import quickfix.field.TargetCompID; @@ -60,6 +50,18 @@ import quickfix.fix44.NewOrderSingle; import quickfix.test.util.ExpectedTestFailure; +import java.io.ByteArrayInputStream; +import java.math.BigDecimal; +import java.net.URL; +import java.net.URLClassLoader; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.hasProperty; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + public class DataDictionaryTest { @Rule @@ -749,10 +751,36 @@ private Message createQuoteRequest() { Message quoteRequest = new Message(); quoteRequest.getHeader().setString(MsgType.FIELD, MsgType.QUOTE_REQUEST); quoteRequest.setString(QuoteReqID.FIELD, "QR-12345"); - quoteRequest.addGroup(new Group(NoRelatedSym.FIELD, Symbol.FIELD)); + final Group noRelatedSymGroup = new Group(NoRelatedSym.FIELD, Symbol.FIELD); + noRelatedSymGroup.setString(Symbol.FIELD, "AAPL"); + quoteRequest.addGroup(noRelatedSymGroup); return quoteRequest; } + /** + * Dictionary "FIX44.xml":
+ *

+     * message name=QuoteRequest msgtype=R msgcat=app
+     *   group name=NoRelatedSym required=Y
+     *     component name=Instrument required=Y
+     *       field name=Symbol required=Y
+     * 
+ * Field Symbol(55) is required, so validation must fail. + * @throws Exception + */ + @Test + public void testGroupWithReqdComponentWithReqdFieldValidation() throws Exception { + final Message quoteRequest = createQuoteRequest(); + quoteRequest.getGroup(1, NoRelatedSym.FIELD).removeField(Symbol.FIELD); + final DataDictionary dictionary = getDictionary(); + + expectedException.expect(FieldException.class); + expectedException.expect(hasProperty("sessionRejectReason", is(SessionRejectReason.REQUIRED_TAG_MISSING))); + expectedException.expect(hasProperty("field", is(Symbol.FIELD))); + + dictionary.validate(quoteRequest, true); + } + // // Group Validation Tests in RepeatingGroupTest // From 8a6f41705798176f54bb3b54f6d1385f68ed1718 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 23 Nov 2017 08:51:49 +0000 Subject: [PATCH 140/165] =?UTF-8?q?QFJ-533:=20Throw=20InvalidMessage=20whe?= =?UTF-8?q?n=20count=20field=20for=20repeating=20groups=20w=E2=80=A6=20(#1?= =?UTF-8?q?50)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * QFJ-533: Throw InvalidMessage when count field for repeating groups would throw a NumberFormatException * Change to include cause after feedback comment from @philipwhiuk PR #150 * Change to include cause after feedback comment from @philipwhiuk PR #150 --- .../src/main/java/quickfix/Message.java | 10 +++++++++- .../src/test/java/quickfix/MessageTest.java | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/quickfixj-core/src/main/java/quickfix/Message.java b/quickfixj-core/src/main/java/quickfix/Message.java index 9fd0dbcd0..d0419527b 100644 --- a/quickfixj-core/src/main/java/quickfix/Message.java +++ b/quickfixj-core/src/main/java/quickfix/Message.java @@ -578,7 +578,15 @@ private void parseGroup(String msgType, StringField field, DataDictionary dd, Da final int[] fieldOrder = groupDataDictionary.getOrderedFields(); int previousOffset = -1; final int groupCountTag = field.getField(); - final int declaredGroupCount = Integer.parseInt(field.getValue()); + // QFJ-533 + int declaredGroupCount = 0; + try { + declaredGroupCount = Integer.parseInt(field.getValue()); + } catch (final NumberFormatException e) { + InvalidMessage invalidMessage = new InvalidMessage("Repeating group count requires an Integer but found:" +field.getValue()); + invalidMessage.initCause(e); + throw invalidMessage; + } parent.setField(groupCountTag, field); final int firstField = rg.getDelimiterField(); boolean firstFieldFound = false; diff --git a/quickfixj-core/src/test/java/quickfix/MessageTest.java b/quickfixj-core/src/test/java/quickfix/MessageTest.java index 6cdbab56f..c8b22d45e 100644 --- a/quickfixj-core/src/test/java/quickfix/MessageTest.java +++ b/quickfixj-core/src/test/java/quickfix/MessageTest.java @@ -1713,6 +1713,24 @@ private void testRepeatingGroupCountForFieldOrder(int fieldOrder[]) throws Excep // but we still should have the repeating group set and not ignore it assertEquals(1, parsed.getGroupCount(555)); } + + // QFJ-533 + @Test + public void testRepeatingGroupCountWithNonIntegerValues() throws Exception { + DataDictionary dictionary = new DataDictionary(DataDictionaryTest.getDictionary()); + Message ioi = new quickfix.fix50.IOI(); + ioi.setString(quickfix.field.NoPartyIDs.FIELD, "abc"); + final String invalidCountMessage = ioi.toString(); + try { + Message message = new Message(invalidCountMessage, dictionary); + } catch (final InvalidMessage im) { + assertNotNull("InvalidMessage correctly thrown", im); + } catch (final Throwable e) { + e.printStackTrace(); + fail("InvalidMessage expected, got " + e.getClass().getName()); + } + } + // QFJ-770/QFJ-792 @Test From 622b858d4a6d972b0d2006b5029f2be354d1dcdc Mon Sep 17 00:00:00 2001 From: mmitya Date: Thu, 23 Nov 2017 08:54:39 +0000 Subject: [PATCH 141/165] After scheduled logout/disconnection FIX session starts connection attempts from the 1st host on the list (#152) * After scheduled logout/disconnection FIX session starts connection attempts from the 1st host on the list. * Documentation update. --- .../doc/usermanual/usage/configuration.html | 24 ++++++++++++++++--- .../mina/initiator/IoSessionInitiator.java | 3 ++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/quickfixj-core/src/main/doc/usermanual/usage/configuration.html b/quickfixj-core/src/main/doc/usermanual/usage/configuration.html index c41a4b1eb..9259dbf3c 100644 --- a/quickfixj-core/src/main/doc/usermanual/usage/configuration.html +++ b/quickfixj-core/src/main/doc/usermanual/usage/configuration.html @@ -497,12 +497,30 @@

QuickFIX Settings

"TCP" or "VM_PIPE". "TCP" + + SocketConnectPort<n> + Alternate socket port(s) for connecting to a session for failover or load balancing, + where n is a positive integer, i.e. SocketConnectPort1, SocketConnectPort2, etc. + Must be consecutive and have a matching SocketConnectHost<n> + + positive integer +   + SocketConnectHost<n> - Alternate socket hosts for connecting to a session for failover, where n is a - positive integer. (i.e.) SocketConnectHost1, SocketConnectHost2... must be consecutive - and have a matching SocketConnectPort[n] + Alternate socket host(s) for connecting to a session for failover or load balancing, + where n is a positive integer, i.e. SocketConnectHost1, SocketConnectHost2, etc. + Must be consecutive and have a matching SocketConnectPort<n> +

+ Connection list iteration rules: +

    +
  • Connections are tried one after another until one is successful: SocketConnectHost:SocketConnectPort, + SocketConnectHost1:SocketConnectPort1, etc.
  • +
  • Next connection attempt after a successful connection will start at first defined connection again: + SocketConnectHost:SocketConnectPort.
  • +
+ valid IP address in the format of x.x.x.x or a domain name   diff --git a/quickfixj-core/src/main/java/quickfix/mina/initiator/IoSessionInitiator.java b/quickfixj-core/src/main/java/quickfix/mina/initiator/IoSessionInitiator.java index 0fa9b0fca..c6d190ab1 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/initiator/IoSessionInitiator.java +++ b/quickfixj-core/src/main/java/quickfix/mina/initiator/IoSessionInitiator.java @@ -34,6 +34,7 @@ import quickfix.mina.EventHandlingStrategy; import quickfix.mina.NetworkingOptions; import quickfix.mina.ProtocolFactory; +import quickfix.mina.SessionConnector; import quickfix.mina.message.FIXProtocolCodecFactory; import quickfix.mina.ssl.SSLConfig; import quickfix.mina.ssl.SSLContextFactory; @@ -49,7 +50,6 @@ import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import quickfix.mina.SessionConnector; public class IoSessionInitiator { private final static long CONNECT_POLL_TIMEOUT = 2000L; @@ -228,6 +228,7 @@ private void pollConnectFuture() { if (connectFuture.getSession() != null) { ioSession = connectFuture.getSession(); connectionFailureCount = 0; + nextSocketAddressIndex = 0; lastConnectTime = System.currentTimeMillis(); connectFuture = null; } else { From f4f0a9f8b41e8bfddb4fdd2800c308788f444bbd Mon Sep 17 00:00:00 2001 From: Christoph John Date: Tue, 28 Nov 2017 07:53:22 +0100 Subject: [PATCH 142/165] Changes to stop() method of SocketAcceptor and SocketInitiator (#159) - try to stop processing messages before removing Sessions - this has now the same order as on the ThreadedSocketInitiator/Acceptor --- quickfixj-core/src/main/java/quickfix/SocketAcceptor.java | 2 +- quickfixj-core/src/main/java/quickfix/SocketInitiator.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/SocketAcceptor.java b/quickfixj-core/src/main/java/quickfix/SocketAcceptor.java index 30e329c81..c8dfc5edf 100644 --- a/quickfixj-core/src/main/java/quickfix/SocketAcceptor.java +++ b/quickfixj-core/src/main/java/quickfix/SocketAcceptor.java @@ -106,8 +106,8 @@ public void stop(boolean forceDisconnect) { } stopSessionTimer(); } finally { - Session.unregisterSessions(getSessions()); eventHandlingStrategy.stopHandlingMessages(); + Session.unregisterSessions(getSessions()); isStarted = Boolean.FALSE; } } diff --git a/quickfixj-core/src/main/java/quickfix/SocketInitiator.java b/quickfixj-core/src/main/java/quickfix/SocketInitiator.java index 5b5e46a31..71d5931ce 100644 --- a/quickfixj-core/src/main/java/quickfix/SocketInitiator.java +++ b/quickfixj-core/src/main/java/quickfix/SocketInitiator.java @@ -95,8 +95,8 @@ public void stop(boolean forceDisconnect) { logoutAllSessions(forceDisconnect); stopInitiators(); } finally { - Session.unregisterSessions(getSessions()); eventHandlingStrategy.stopHandlingMessages(); + Session.unregisterSessions(getSessions()); isStarted = Boolean.FALSE; } } From f8a5f08a6aafca35edcd3839eb938546c8a8d81d Mon Sep 17 00:00:00 2001 From: Christoph John Date: Tue, 28 Nov 2017 09:32:31 +0100 Subject: [PATCH 143/165] Minor changes to IncorrectTagValue and InvalidMessage (#158) - added constructor with cause for InvalidMessage - corrected usage of problematic value for IncorrectTagValue --- .../src/main/java/quickfix/IncorrectTagValue.java | 9 ++++++++- .../src/main/java/quickfix/InvalidMessage.java | 5 +++++ quickfixj-core/src/main/java/quickfix/Message.java | 4 +--- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/IncorrectTagValue.java b/quickfixj-core/src/main/java/quickfix/IncorrectTagValue.java index 1b1579e2a..9558a9fbf 100644 --- a/quickfixj-core/src/main/java/quickfix/IncorrectTagValue.java +++ b/quickfixj-core/src/main/java/quickfix/IncorrectTagValue.java @@ -37,7 +37,14 @@ public IncorrectTagValue(int field) { } public IncorrectTagValue(int field, String value) { - super(); + super(SessionRejectReasonText.getMessage(SessionRejectReason.VALUE_IS_INCORRECT) + ", field=" + field + (value != null ? ", value=" + value : "")); + this.field = field; + this.value = value; + this.sessionRejectReason = SessionRejectReason.VALUE_IS_INCORRECT; + } + + public IncorrectTagValue(int field, String value, String message) { + super(message); this.field = field; this.value = value; this.sessionRejectReason = SessionRejectReason.VALUE_IS_INCORRECT; diff --git a/quickfixj-core/src/main/java/quickfix/InvalidMessage.java b/quickfixj-core/src/main/java/quickfix/InvalidMessage.java index aa6a92090..4b2b4cc3b 100644 --- a/quickfixj-core/src/main/java/quickfix/InvalidMessage.java +++ b/quickfixj-core/src/main/java/quickfix/InvalidMessage.java @@ -32,4 +32,9 @@ public InvalidMessage() { public InvalidMessage(String message) { super(message); } + + public InvalidMessage(String message, Throwable cause) { + super(message, cause); + } + } diff --git a/quickfixj-core/src/main/java/quickfix/Message.java b/quickfixj-core/src/main/java/quickfix/Message.java index d0419527b..ae33a80de 100644 --- a/quickfixj-core/src/main/java/quickfix/Message.java +++ b/quickfixj-core/src/main/java/quickfix/Message.java @@ -583,9 +583,7 @@ private void parseGroup(String msgType, StringField field, DataDictionary dd, Da try { declaredGroupCount = Integer.parseInt(field.getValue()); } catch (final NumberFormatException e) { - InvalidMessage invalidMessage = new InvalidMessage("Repeating group count requires an Integer but found:" +field.getValue()); - invalidMessage.initCause(e); - throw invalidMessage; + throw new InvalidMessage("Repeating group count requires an Integer but found: " + field.getValue(), e); } parent.setField(groupCountTag, field); final int firstField = rg.getDelimiterField(); From 5a512d8a06b4e285a5557a05a807275bbad4b2a4 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Thu, 25 Jan 2018 08:43:45 +0100 Subject: [PATCH 144/165] set version to 2.1.0-SNAPSHOT --- pom.xml | 2 +- quickfixj-all/pom.xml | 2 +- quickfixj-codegenerator/pom.xml | 2 +- quickfixj-core/pom.xml | 2 +- quickfixj-dictgenerator/pom.xml | 2 +- quickfixj-distribution/pom.xml | 2 +- quickfixj-examples/banzai/pom.xml | 2 +- quickfixj-examples/executor/pom.xml | 2 +- quickfixj-examples/ordermatch/pom.xml | 2 +- quickfixj-examples/pom.xml | 2 +- quickfixj-messages/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-all/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix40/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix41/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix42/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix43/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix44/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix50/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml | 2 +- quickfixj-messages/quickfixj-messages-fixt11/pom.xml | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pom.xml b/pom.xml index 981f6b3ca..e5f578a5e 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.quickfixj quickfixj-parent - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT pom QuickFIX/J Parent diff --git a/quickfixj-all/pom.xml b/quickfixj-all/pom.xml index 6ac9115c1..2347ca65a 100644 --- a/quickfixj-all/pom.xml +++ b/quickfixj-all/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-all diff --git a/quickfixj-codegenerator/pom.xml b/quickfixj-codegenerator/pom.xml index cec7dc978..07938f278 100644 --- a/quickfixj-codegenerator/pom.xml +++ b/quickfixj-codegenerator/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-codegenerator diff --git a/quickfixj-core/pom.xml b/quickfixj-core/pom.xml index 23dc556da..65a58df01 100644 --- a/quickfixj-core/pom.xml +++ b/quickfixj-core/pom.xml @@ -3,7 +3,7 @@ org.quickfixj quickfixj-parent - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-core diff --git a/quickfixj-dictgenerator/pom.xml b/quickfixj-dictgenerator/pom.xml index 58a7fa22f..42c980f7b 100644 --- a/quickfixj-dictgenerator/pom.xml +++ b/quickfixj-dictgenerator/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-dictgenerator diff --git a/quickfixj-distribution/pom.xml b/quickfixj-distribution/pom.xml index 51aeca5f6..2e9d3b001 100644 --- a/quickfixj-distribution/pom.xml +++ b/quickfixj-distribution/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-distribution diff --git a/quickfixj-examples/banzai/pom.xml b/quickfixj-examples/banzai/pom.xml index 3d92bf36b..d435cb47f 100644 --- a/quickfixj-examples/banzai/pom.xml +++ b/quickfixj-examples/banzai/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-examples - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-examples-banzai diff --git a/quickfixj-examples/executor/pom.xml b/quickfixj-examples/executor/pom.xml index ef76ed39a..57f834a35 100644 --- a/quickfixj-examples/executor/pom.xml +++ b/quickfixj-examples/executor/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-examples - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-examples-executor diff --git a/quickfixj-examples/ordermatch/pom.xml b/quickfixj-examples/ordermatch/pom.xml index c6dd458e6..2397b3582 100644 --- a/quickfixj-examples/ordermatch/pom.xml +++ b/quickfixj-examples/ordermatch/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-examples - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-examples-ordermatch diff --git a/quickfixj-examples/pom.xml b/quickfixj-examples/pom.xml index 6fd9c8099..e0b4f843c 100644 --- a/quickfixj-examples/pom.xml +++ b/quickfixj-examples/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-examples diff --git a/quickfixj-messages/pom.xml b/quickfixj-messages/pom.xml index 76b7b630f..779579c90 100644 --- a/quickfixj-messages/pom.xml +++ b/quickfixj-messages/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-parent - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-messages diff --git a/quickfixj-messages/quickfixj-messages-all/pom.xml b/quickfixj-messages/quickfixj-messages-all/pom.xml index 7154da135..574a1b8c6 100644 --- a/quickfixj-messages/quickfixj-messages-all/pom.xml +++ b/quickfixj-messages/quickfixj-messages-all/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-messages-all diff --git a/quickfixj-messages/quickfixj-messages-fix40/pom.xml b/quickfixj-messages/quickfixj-messages-fix40/pom.xml index 8a6bdd354..757c28717 100644 --- a/quickfixj-messages/quickfixj-messages-fix40/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix40/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-messages-fix40 diff --git a/quickfixj-messages/quickfixj-messages-fix41/pom.xml b/quickfixj-messages/quickfixj-messages-fix41/pom.xml index 3ed73eeba..e4e729e22 100644 --- a/quickfixj-messages/quickfixj-messages-fix41/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix41/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-messages-fix41 diff --git a/quickfixj-messages/quickfixj-messages-fix42/pom.xml b/quickfixj-messages/quickfixj-messages-fix42/pom.xml index 909da5fe7..16ea74a56 100644 --- a/quickfixj-messages/quickfixj-messages-fix42/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix42/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-messages-fix42 diff --git a/quickfixj-messages/quickfixj-messages-fix43/pom.xml b/quickfixj-messages/quickfixj-messages-fix43/pom.xml index a83d24a71..342fd0f67 100644 --- a/quickfixj-messages/quickfixj-messages-fix43/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix43/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-messages-fix43 diff --git a/quickfixj-messages/quickfixj-messages-fix44/pom.xml b/quickfixj-messages/quickfixj-messages-fix44/pom.xml index 999cd62ea..4f3d740ed 100644 --- a/quickfixj-messages/quickfixj-messages-fix44/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix44/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-messages-fix44 diff --git a/quickfixj-messages/quickfixj-messages-fix50/pom.xml b/quickfixj-messages/quickfixj-messages-fix50/pom.xml index 711a007e2..80e006b57 100644 --- a/quickfixj-messages/quickfixj-messages-fix50/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix50/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-messages-fix50 diff --git a/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml b/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml index ff24ab88d..c94e97f79 100644 --- a/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix50sp1/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-messages-fix50sp1 diff --git a/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml b/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml index 29c113eb5..49bc2c947 100644 --- a/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fix50sp2/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-messages-fix50sp2 diff --git a/quickfixj-messages/quickfixj-messages-fixt11/pom.xml b/quickfixj-messages/quickfixj-messages-fixt11/pom.xml index 51f46292a..c959b475c 100644 --- a/quickfixj-messages/quickfixj-messages-fixt11/pom.xml +++ b/quickfixj-messages/quickfixj-messages-fixt11/pom.xml @@ -4,7 +4,7 @@ org.quickfixj quickfixj-messages - 2.0.1-SNAPSHOT + 2.1.0-SNAPSHOT quickfixj-messages-fixt11 From ea6a11d35602afccaffff2c6acd9e508d702a522 Mon Sep 17 00:00:00 2001 From: Eric Goebelbecker Date: Thu, 25 Jan 2018 05:28:34 -0500 Subject: [PATCH 145/165] Add getOptionalString + unit test to FieldMap (#162) --- .../src/main/java/quickfix/FieldMap.java | 16 ++++++++++------ .../src/test/java/quickfix/FieldMapTest.java | 11 +++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/FieldMap.java b/quickfixj-core/src/main/java/quickfix/FieldMap.java index f7edfe408..5a80be216 100644 --- a/quickfixj-core/src/main/java/quickfix/FieldMap.java +++ b/quickfixj-core/src/main/java/quickfix/FieldMap.java @@ -37,13 +37,8 @@ import java.time.LocalDate; import java.time.LocalTime; import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.TreeMap; /** * Field container used by messages, groups, and composites. @@ -232,6 +227,15 @@ public String getString(int field) throws FieldNotFound { return getField(field).getObject(); } + public Optional getOptionalString(int field) { + final StringField f = (StringField) fields.get(field); + if (f == null) { + return Optional.empty(); + } else { + return Optional.of(f.getValue()); + } + } + public boolean getBoolean(int field) throws FieldNotFound { try { return BooleanConverter.convert(getString(field)); diff --git a/quickfixj-core/src/test/java/quickfix/FieldMapTest.java b/quickfixj-core/src/test/java/quickfix/FieldMapTest.java index 8e40d5e49..c03f2cf7d 100644 --- a/quickfixj-core/src/test/java/quickfix/FieldMapTest.java +++ b/quickfixj-core/src/test/java/quickfix/FieldMapTest.java @@ -11,6 +11,7 @@ import quickfix.field.converter.UtcTimeOnlyConverter; import java.util.Iterator; +import java.util.Optional; /** * Tests the {@link FieldMap} class. @@ -91,6 +92,16 @@ public void testOrdering() { testOrdering(new int[] { 3, 2, 1 }, new int[] { 3, 1 }, new int[] { 3, 1, 2 }); } + public void testOptionalString() { + FieldMap map = new Message(); + map.setField(new StringField(128, "bigbank")); + Optional optValue = map.getOptionalString(128); + assertTrue(optValue.isPresent()); + assertEquals("bigbank", optValue.get()); + assertFalse(map.getOptionalString(129).isPresent()); + } + + private long epochMilliOfLocalDate(LocalDateTime localDateTime) { return localDateTime.toInstant(ZoneOffset.UTC).toEpochMilli(); } From d4b36c071829717e487af2546ebeb9166e5971b1 Mon Sep 17 00:00:00 2001 From: Philip Date: Thu, 25 Jan 2018 10:37:09 +0000 Subject: [PATCH 146/165] Add new header field to header list: ApplExtID (#165) --- quickfixj-core/src/main/java/quickfix/Message.java | 3 +++ quickfixj-core/src/test/java/quickfix/MessageTest.java | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/quickfixj-core/src/main/java/quickfix/Message.java b/quickfixj-core/src/main/java/quickfix/Message.java index ae33a80de..e3405f78b 100644 --- a/quickfixj-core/src/main/java/quickfix/Message.java +++ b/quickfixj-core/src/main/java/quickfix/Message.java @@ -33,6 +33,8 @@ import org.w3c.dom.CDATASection; import org.w3c.dom.Document; import org.w3c.dom.Element; + +import quickfix.field.ApplExtID; import quickfix.field.ApplVerID; import quickfix.field.BeginString; import quickfix.field.BodyLength; @@ -720,6 +722,7 @@ static boolean isHeaderField(int field) { case OnBehalfOfSendingTime.FIELD: case ApplVerID.FIELD: case CstmApplVerID.FIELD: + case ApplExtID.FIELD: case NoHops.FIELD: return true; default: diff --git a/quickfixj-core/src/test/java/quickfix/MessageTest.java b/quickfixj-core/src/test/java/quickfix/MessageTest.java index c8b22d45e..ecbbbc90b 100644 --- a/quickfixj-core/src/test/java/quickfix/MessageTest.java +++ b/quickfixj-core/src/test/java/quickfix/MessageTest.java @@ -24,6 +24,7 @@ import quickfix.field.Account; import quickfix.field.AllocAccount; import quickfix.field.AllocShares; +import quickfix.field.ApplExtID; import quickfix.field.ApplVerID; import quickfix.field.AvgPx; import quickfix.field.BeginString; @@ -588,6 +589,11 @@ public void testFix5HeaderFields() { assertTrue(Message.isHeaderField(CstmApplVerID.FIELD)); } + @Test + public void testApplExtIDIsHeaderField() { + assertTrue(Message.isHeaderField(ApplExtID.FIELD)); + } + @Test public void testCalculateStringWithNestedGroups() throws Exception { final NewOrderCross noc = new NewOrderCross(); From 3cf3964aef2057f94de1a5525c5b28a713522e91 Mon Sep 17 00:00:00 2001 From: Jon Freedman Date: Thu, 25 Jan 2018 12:23:46 +0000 Subject: [PATCH 147/165] Pass SessionID to MemoryStore constructor from MemoryStoreFactory (#161) * pass SessionID to MemoryStore on construction * Update MemoryStore.java * fix for NPE on session lookup which causes test failures --- quickfixj-core/src/main/java/quickfix/MemoryStore.java | 7 ++++--- .../src/main/java/quickfix/MemoryStoreFactory.java | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/MemoryStore.java b/quickfixj-core/src/main/java/quickfix/MemoryStore.java index fb3d1e49c..f10205651 100644 --- a/quickfixj-core/src/main/java/quickfix/MemoryStore.java +++ b/quickfixj-core/src/main/java/quickfix/MemoryStore.java @@ -43,8 +43,9 @@ public MemoryStore() throws IOException { reset(); } - public MemoryStore(SessionID sessionID) { + public MemoryStore(SessionID sessionID) throws IOException { this.sessionID = sessionID; + reset(); } public void get(int startSequence, int endSequence, Collection messages) throws IOException { @@ -111,8 +112,8 @@ public void setNextTargetMsgSeqNum(int next) throws IOException { public void refresh() throws IOException { // IOException is declared to maintain strict compatibility with QF JNI final String text = "memory store does not support refresh!"; - if (sessionID != null) { - Session session = Session.lookupSession(sessionID); + final Session session = sessionID != null ? Session.lookupSession(sessionID) : null; + if (session != null) { session.getLog().onErrorEvent("ERROR: " + text); } else { LoggerFactory.getLogger(MemoryStore.class).error(text); diff --git a/quickfixj-core/src/main/java/quickfix/MemoryStoreFactory.java b/quickfixj-core/src/main/java/quickfix/MemoryStoreFactory.java index 890365166..09b670b73 100644 --- a/quickfixj-core/src/main/java/quickfix/MemoryStoreFactory.java +++ b/quickfixj-core/src/main/java/quickfix/MemoryStoreFactory.java @@ -30,7 +30,7 @@ public class MemoryStoreFactory implements MessageStoreFactory { public MessageStore create(SessionID sessionID) { try { - return new MemoryStore(); + return new MemoryStore(sessionID); } catch (IOException e) { throw new RuntimeError(e); } From b77de84d68cd91e44552a4870eb72a111364b741 Mon Sep 17 00:00:00 2001 From: Philip Date: Fri, 26 Jan 2018 07:56:53 +0000 Subject: [PATCH 148/165] Don't increment sequence number on rejected logon (#164) * Don't increment sequence number on rejected logon * Changed to check expected seqnum on RejectLogon * Reverted unnecessary change in SessionTest --- .../src/main/java/quickfix/Session.java | 5 +- .../src/test/java/quickfix/SessionTest.java | 62 +++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index dbfd9235b..63392d6c4 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -1073,7 +1073,10 @@ ignore the message and let the problem correct itself (optimistic approach). generateLogout(e.getMessage()); } } - state.incrNextTargetMsgSeqNum(); + // Only increment seqnum if we are at the expected seqnum + if (getExpectedTargetNum() == header.getInt(MsgSeqNum.FIELD)) { + state.incrNextTargetMsgSeqNum(); + } disconnect("Logon rejected: " + e, true); } catch (final UnsupportedMessageType e) { if (logErrorAndDisconnectIfRequired(e, message)) { diff --git a/quickfixj-core/src/test/java/quickfix/SessionTest.java b/quickfixj-core/src/test/java/quickfix/SessionTest.java index 56e376343..a6e6fe5c6 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionTest.java @@ -2336,6 +2336,68 @@ private void testLargeQueue(int N) throws Exception { */ } + @Test + public void testResendSeqWithReject() throws Exception { + final SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX44, "SENDER", "TARGET"); + final boolean resetOnLogon = false; + final boolean validateSequenceNumbers = true; + boolean enableNextExpectedMsgSeqNum = false; + boolean isInitiator = false; + + UnitTestApplication app = new UnitTestApplication() { + private int logonCount = 0; + + @Override + public void fromAdmin(Message message, SessionID sessionId) throws FieldNotFound, + IncorrectDataFormat, IncorrectTagValue, RejectLogon { + super.fromAdmin(message, sessionId); + if (message.getHeader().getString(MsgType.FIELD).equals(Logon.MSGTYPE)) { + logonCount += 1; + } + if (logonCount == 2) { + throw new RejectLogon("RejectLogon"); + } + } + }; + + Session session = new Session(app, new MemoryStoreFactory(), + sessionID, null, null, null, + new DefaultMessageFactory(), isInitiator ? 30 : 0, false, 30, UtcTimestampPrecision.MILLIS, resetOnLogon, + false, false, false, false, false, true, false, 1.5, null, validateSequenceNumbers, + new int[]{5}, false, false, false, true, false, true, false, null, true, 0, + enableNextExpectedMsgSeqNum, false); + UnitTestResponder responder = new UnitTestResponder(); + session.setResponder(responder); + + logonTo(session, 1); + //Do Something + session.next(createAppMessage(2)); + session.next(createAppMessage(3)); + session.disconnect("Disconnecting", true); + session.next(); + session.logon(); + + //Logon + session.setResponder(responder); + logonTo(session, 105); + //Rejected + assertEquals(Logout.MSGTYPE, app.lastToAdminMessage().getHeader().getString(MsgType.FIELD)); + assertEquals("RejectLogon", app.lastToAdminMessage().getString(Text.FIELD)); + + //Logon + session.setResponder(responder); + logonTo(session, 106); + //Accepted + assertEquals(Logon.MSGTYPE, app.lastFromAdminMessage().getHeader().getString(MsgType.FIELD)); + + session.next(); + session.next(); + //ResendRequest + assertEquals(ResendRequest.MSGTYPE, app.lastToAdminMessage().getHeader().getString(MsgType.FIELD)); + assertEquals(4, app.lastToAdminMessage().getInt(BeginSeqNo.FIELD)); + assertEquals(0, app.lastToAdminMessage().getInt(EndSeqNo.FIELD)); + } + private News createPossDupAppMessage(int sequence) { // create a regular app message and and add the PossDup // and OrigSendingTime tags to it From 8d9b7ce126243acf5130c3ce89a94207993a92f0 Mon Sep 17 00:00:00 2001 From: Christoph John Date: Mon, 5 Feb 2018 14:50:41 +0100 Subject: [PATCH 149/165] QFJ-940 - Event log omits parts of received message in case of validation errors (#172) * QFJ-940: Event log omits parts of received message in case of validation errors - in case of errors: log raw message data instead of incompletely parsed message - added method Message.toRawString() which returns the message string as it was passed to the Message class - added unit test - improved some log messages in Session class --- .../src/main/java/quickfix/Message.java | 19 ++++++++ .../src/main/java/quickfix/Session.java | 45 ++++++++++--------- .../src/test/java/quickfix/MessageTest.java | 16 +++++++ 3 files changed, 59 insertions(+), 21 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/Message.java b/quickfixj-core/src/main/java/quickfix/Message.java index e3405f78b..da6d44074 100644 --- a/quickfixj-core/src/main/java/quickfix/Message.java +++ b/quickfixj-core/src/main/java/quickfix/Message.java @@ -129,6 +129,10 @@ private Object cloneTo(Message message) { * Do not call this method concurrently while modifying the contents of the message. * This is likely to produce unexpected results or will fail with a ConcurrentModificationException * since FieldMap.calculateString() is iterating over the TreeMap of fields. + * + * Use toRawString() to get the raw message data. + * + * @return Message as String with calculated body length and checksum. */ @Override public String toString() { @@ -144,6 +148,21 @@ public String toString() { return sb.toString(); } + /** + * Return the raw message data as it was passed to the Message class. + * + * This is only available after Message has been parsed via constructor or Message.fromString(). + * Otherwise this method will return NULL. + * + * This method neither does change fields nor calculate body length or checksum. + * Use toString() for that purpose. + * + * @return Message as String without recalculating body length and checksum. + */ + public String toRawString() { + return messageData; + } + public int bodyLength() { return header.calculateLength() + calculateLength() + trailer.calculateLength(); } diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index 63392d6c4..d4d099a19 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -929,7 +929,7 @@ private void next(Message message, boolean isProcessingQueuedMessages) throws Fi // QFJ-650 if (!header.isSetField(MsgSeqNum.FIELD)) { generateLogout("Received message without MsgSeqNum"); - disconnect("Received message without MsgSeqNum: " + message, true); + disconnect("Received message without MsgSeqNum: " + getMessageToLog(message), true); return; } @@ -975,7 +975,7 @@ private void next(Message message, boolean isProcessingQueuedMessages) throws Fi if (rejectInvalidMessage) { throw e; } else { - getLog().onErrorEvent("Warn: incoming message with " + e + ": " + message); + getLog().onErrorEvent("Warn: incoming message with " + e + ": " + getMessageToLog(message)); } } catch (final FieldException e) { if (message.isSetField(e.getField())) { @@ -984,7 +984,7 @@ private void next(Message message, boolean isProcessingQueuedMessages) throws Fi } else { getLog().onErrorEvent( "Warn: incoming message with incorrect field: " - + message.getField(e.getField()) + ": " + message); + + message.getField(e.getField()) + ": " + getMessageToLog(message)); } } else { if (rejectInvalidMessage) { @@ -992,14 +992,14 @@ private void next(Message message, boolean isProcessingQueuedMessages) throws Fi } else { getLog().onErrorEvent( "Warn: incoming message with missing field: " + e.getField() - + ": " + e.getMessage() + ": " + message); + + ": " + e.getMessage() + ": " + getMessageToLog(message)); } } } catch (final FieldNotFound e) { if (rejectInvalidMessage) { throw e; } else { - getLog().onErrorEvent("Warn: incoming " + e + ": " + message); + getLog().onErrorEvent("Warn: incoming " + e + ": " + getMessageToLog(message)); } } } @@ -1059,7 +1059,7 @@ private void next(Message message, boolean isProcessingQueuedMessages) throws Fi ignore the message and let the problem correct itself (optimistic approach). Target sequence number is not incremented, so it will trigger a ResendRequest on the next message that is received. */ - getLog().onErrorEvent("Skipping invalid message: " + e + ": " + message); + getLog().onErrorEvent("Skipping invalid message: " + e + ": " + getMessageToLog(message)); if (resetOrDisconnectIfRequired(message)) { return; } @@ -1102,7 +1102,7 @@ ignore the message and let the problem correct itself (optimistic approach). disconnect("Incorrect BeginString: " + e, true); } } catch (final IOException e) { - LogUtil.logThrowable(sessionID, "Error processing message: " + message, e); + LogUtil.logThrowable(sessionID, "Error processing message: " + getMessageToLog(message), e); if (resetOrDisconnectIfRequired(message)) { return; } @@ -1110,7 +1110,7 @@ ignore the message and let the problem correct itself (optimistic approach). // If there are any other Throwables we might catch them here if desired. // They were most probably thrown out of fromCallback(). if (rejectMessageOnUnhandledException) { - getLog().onErrorEvent("Rejecting message: " + t + ": " + message); + getLog().onErrorEvent("Rejecting message: " + t + ": " + getMessageToLog(message)); if (resetOrDisconnectIfRequired(message)) { return; } @@ -1147,7 +1147,7 @@ private void handleExceptionAndRejectMessage(final String msgType, final Message if (MsgType.LOGON.equals(msgType)) { logoutWithErrorMessage(e.getMessage()); } else { - getLog().onErrorEvent("Rejecting invalid message: " + e + ": " + message); + getLog().onErrorEvent("Rejecting invalid message: " + e + ": " + getMessageToLog(message)); generateReject(message, e.getMessage(), e.getSessionRejectReason(), e.getField()); } } @@ -1162,7 +1162,7 @@ private void logoutWithErrorMessage(final String reason) throws IOException { private boolean logErrorAndDisconnectIfRequired(final Exception e, Message message) { final boolean resetOrDisconnectIfRequired = resetOrDisconnectIfRequired(message); if (resetOrDisconnectIfRequired) { - getLog().onErrorEvent("Encountered invalid message: " + e + ": " + message); + getLog().onErrorEvent("Encountered invalid message: " + e + ": " + getMessageToLog(message)); } return resetOrDisconnectIfRequired; } @@ -1323,7 +1323,7 @@ private void generateSequenceReset(Message receivedMessage, int beginSeqNo, int receivedMessage.getHeader().getInt(MsgSeqNum.FIELD)); } catch (final FieldNotFound e) { // should not happen as MsgSeqNum must be present - getLog().onErrorEvent("Received message without MsgSeqNum " + receivedMessage); + getLog().onErrorEvent("Received message without MsgSeqNum " + getMessageToLog(receivedMessage)); } } sendRaw(sequenceReset, beginSeqNo); @@ -1508,7 +1508,7 @@ private void generateReject(Message message, String str) throws FieldNotFound, I reject.setString(Text.FIELD, str); sendRaw(reject, 0); - getLog().onErrorEvent("Reject sent for Message " + msgSeqNum + ": " + str); + getLog().onErrorEvent("Reject sent for message " + msgSeqNum + ": " + str); } private boolean isPossibleDuplicate(Message message) throws FieldNotFound { @@ -1531,7 +1531,7 @@ private void generateReject(Message message, String text, int err, int field) th } if (!state.isLogonReceived()) { final String errorMessage = "Tried to send a reject while not logged on: " + reason - + " (field " + field + ")"; + + (reason.endsWith("" + field) ? "" : " (field " + field + ")"); throw new SessionException(errorMessage); } @@ -1588,16 +1588,15 @@ private void generateReject(Message message, String text, int err, int field) th } finally { state.unlockTargetMsgSeqNum(); } - + final String logMessage = "Reject sent for message " + msgSeqNum; if (reason != null && (field > 0 || err == SessionRejectReason.INVALID_TAG_NUMBER)) { setRejectReason(reject, field, reason, true); - getLog().onErrorEvent( - "Reject sent for Message " + msgSeqNum + ": " + reason + ":" + field); + getLog().onErrorEvent(logMessage + ": " + reason + (reason.endsWith("" + field) ? "" : ":" + field)); } else if (reason != null) { setRejectReason(reject, reason); - getLog().onErrorEvent("Reject sent for Message " + msgSeqNum + ": " + reason); + getLog().onErrorEvent(logMessage + ": " + reason); } else { - getLog().onErrorEvent("Reject sent for Message " + msgSeqNum); + getLog().onErrorEvent(logMessage); } if (enableLastMsgSeqNumProcessed) { @@ -1651,7 +1650,7 @@ private void generateBusinessReject(Message message, int err, int field) throws final String reason = BusinessRejectReasonText.getMessage(err); setRejectReason(reject, field, reason, field != 0); getLog().onErrorEvent( - "Reject sent for Message " + msgSeqNum + (reason != null ? (": " + reason) : "") + "Reject sent for message " + msgSeqNum + (reason != null ? (": " + reason) : "") + (field != 0 ? (": tag=" + field) : "")); sendRaw(reject, 0); @@ -2283,7 +2282,7 @@ private void resendMessages(Message receivedMessage, int beginSeqNo, int endSeqN if (begin != 0) { generateSequenceReset(receivedMessage, begin, msgSeqNum); } - getLog().onEvent("Resending Message: " + msgSeqNum); + getLog().onEvent("Resending message: " + msgSeqNum); send(msg.toString()); begin = 0; appMessageJustSent = true; @@ -2577,7 +2576,7 @@ private boolean sendRaw(Message message, int num) { return result; } catch (final IOException e) { - logThrowable(getLog(), "Error Reading/Writing in MessageStore", e); + logThrowable(getLog(), "Error reading/writing in MessageStore", e); return false; } catch (final FieldNotFound e) { logThrowable(state.getLog(), "Error accessing message fields", e); @@ -2934,4 +2933,8 @@ private void resetIfSessionNotCurrent(SessionID sessionID, long time) throws IOE } } + private String getMessageToLog(final Message message) { + return (message.toRawString() != null ? message.toRawString() : message.toString()); + } + } diff --git a/quickfixj-core/src/test/java/quickfix/MessageTest.java b/quickfixj-core/src/test/java/quickfix/MessageTest.java index ecbbbc90b..9368604d2 100644 --- a/quickfixj-core/src/test/java/quickfix/MessageTest.java +++ b/quickfixj-core/src/test/java/quickfix/MessageTest.java @@ -1755,6 +1755,22 @@ public void testRepeatingGroupCountWithUnknownFields() throws Exception { assertEquals("780508", underlyingSymbol); } + @Test + // QFJ-940 + public void testRawString() throws Exception { + + String test = "8=FIX.4.4|9=431|35=d|49=1|34=2|52=20140117-18:20:26.629|56=3|57=21|322=388721|" + + "323=4|320=1|393=42|82=1|67=1|711=1|311=780508|309=text|305=8|463=FXXXXX|307=text|542=20140716|" + + "436=10.0|9013=1.0|9014=1.0|9017=10|9022=1|9024=1.0|9025=Y|916=20140701|917=20150731|9201=23974|" + + "9200=17|9202=text|9300=727|9301=text|9302=text|9303=text|998=text|9100=text|9101=text|9085=text|" + + "9083=0|9084=0|9061=579|9062=text|9063=text|9032=10.0|9002=F|9004=780415|9005=780503|10=223|"; + + DataDictionary dictionary = new DataDictionary(DataDictionaryTest.getDictionary()); + Message message = new Message(); + message.fromString(test.replaceAll("\\|", "\001"), dictionary, true); + assertEquals(test, message.toRawString().replaceAll("\001", "\\|")); + } + private void assertHeaderField(Message message, String expectedValue, int field) throws FieldNotFound { assertEquals(expectedValue, message.getHeader().getString(field)); From ecef090650f2f3cc8f5113a62800fbe6bb55165a Mon Sep 17 00:00:00 2001 From: Chris Kolek Date: Thu, 8 Feb 2018 09:22:18 -0500 Subject: [PATCH 150/165] QFJ-888: DefaultMessageFactory does not support FIX5.0 SP1/2 (#171) * Overload MessageFactory.create to accept ApplVerID for message creation. * Add DefaultMessageFactory constructor which accepts defaultApplVerID value. * Fix DefaultMessageFactory default constructor to pass ApplVerID value instead of BeginString value * Crack NOS for FIX50SPX in ATMessageCracker --- .../java/quickfix/DefaultMessageFactory.java | 50 +++++++++++------ .../main/java/quickfix/MessageFactory.java | 14 +++++ .../src/main/java/quickfix/MessageUtils.java | 2 +- .../quickfix/DefaultMessageFactoryTest.java | 53 ++++++++++++++++--- .../test/acceptance/ATMessageCracker.java | 10 ++++ 5 files changed, 105 insertions(+), 24 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/DefaultMessageFactory.java b/quickfixj-core/src/main/java/quickfix/DefaultMessageFactory.java index 60a3dfbf2..744249abe 100644 --- a/quickfixj-core/src/main/java/quickfix/DefaultMessageFactory.java +++ b/quickfixj-core/src/main/java/quickfix/DefaultMessageFactory.java @@ -19,9 +19,11 @@ package quickfix; +import quickfix.field.ApplVerID; import quickfix.field.MsgType; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import static quickfix.FixVersions.BEGINSTRING_FIX40; @@ -40,6 +42,8 @@ public class DefaultMessageFactory implements MessageFactory { private final Map messageFactories = new ConcurrentHashMap<>(); + private final ApplVerID defaultApplVerID; + /** * Constructs a DefaultMessageFactory, which dynamically loads and delegates to * the default version-specific message factories, if they are available at runtime. @@ -47,8 +51,28 @@ public class DefaultMessageFactory implements MessageFactory { * Callers can set the {@link Thread#setContextClassLoader context classloader}, * which will be used to load the classes if {@link Class#forName Class.forName} * fails to do so (e.g. in an OSGi environment). + *

+ * Equivalent to {@link #DefaultMessageFactory(String) DefaultMessageFactory}({@link ApplVerID#FIX50 ApplVerID.FIX50}). */ public DefaultMessageFactory() { + this(ApplVerID.FIX50); + } + + /** + * Constructs a DefaultMessageFactory, which dynamically loads and delegates to + * the default version-specific message factories, if they are available at runtime. + *

+ * Callers can set the {@link Thread#setContextClassLoader context classloader}, + * which will be used to load the classes if {@link Class#forName Class.forName} + * fails to do so (e.g. in an OSGi environment). + * + * @param defaultApplVerID ApplVerID value used by default for {@link #create(String, ApplVerID, String)} + */ + public DefaultMessageFactory(String defaultApplVerID) { + Objects.requireNonNull(defaultApplVerID, "defaultApplVerID"); + + this.defaultApplVerID = new ApplVerID(defaultApplVerID); + // To loosen the coupling between this factory and generated code, the // message factories are discovered at run time using reflection addFactory(BEGINSTRING_FIX40); @@ -118,27 +142,23 @@ public void addFactory(String beginString, Class facto } } + @Override public Message create(String beginString, String msgType) { + return create(beginString, defaultApplVerID, msgType); + } + + @Override + public Message create(String beginString, ApplVerID applVerID, String msgType) { MessageFactory messageFactory = messageFactories.get(beginString); - if (beginString.equals(BEGINSTRING_FIXT11)) { - // The default message factory assumes that only FIX 5.0 will be - // used with FIXT 1.1 sessions. A more flexible approach will require - // an extension to the QF JNI API. Until then, you will need a custom - // message factory if you want to use application messages prior to - // FIX 5.0 with a FIXT 1.1 session. - // - // TODO: how do we support 50/50SP1/50SP2 concurrently? - // - // If you need to determine admin message category based on a data - // dictionary, then use a custom message factory and don't use the - // static method used below. - if (!MessageUtils.isAdminMessage(msgType)) { - messageFactory = messageFactories.get(FIX50); + if (beginString.equals(BEGINSTRING_FIXT11) && !MessageUtils.isAdminMessage(msgType)) { + if (applVerID == null) { + applVerID = new ApplVerID(defaultApplVerID.getValue()); } + messageFactory = messageFactories.get(MessageUtils.toBeginString(applVerID)); } if (messageFactory != null) { - return messageFactory.create(beginString, msgType); + return messageFactory.create(beginString, applVerID, msgType); } Message message = new Message(); diff --git a/quickfixj-core/src/main/java/quickfix/MessageFactory.java b/quickfixj-core/src/main/java/quickfix/MessageFactory.java index 9cf30a1da..cf734f831 100644 --- a/quickfixj-core/src/main/java/quickfix/MessageFactory.java +++ b/quickfixj-core/src/main/java/quickfix/MessageFactory.java @@ -19,6 +19,8 @@ package quickfix; +import quickfix.field.ApplVerID; + /** * Used by a Session to create a Message. * @@ -35,6 +37,18 @@ public interface MessageFactory { */ Message create(String beginString, String msgType); + /** + * Creates a message for a specified type, FIX version, and ApplVerID. + * + * @param beginString the FIX version (for example, "FIX.4.2") + * @param applVerID the ApplVerID (for example "6" for FIX44) + * @param msgType the FIX message type (for example, "D" for an order) + * @return a message instance + */ + default Message create(String beginString, ApplVerID applVerID, String msgType) { + return create(beginString, msgType); + } + /** * Creates a group for the specified parent message type and * for the fields with the corresponding field ID diff --git a/quickfixj-core/src/main/java/quickfix/MessageUtils.java b/quickfixj-core/src/main/java/quickfix/MessageUtils.java index d22766945..01ade452a 100644 --- a/quickfixj-core/src/main/java/quickfix/MessageUtils.java +++ b/quickfixj-core/src/main/java/quickfix/MessageUtils.java @@ -142,7 +142,7 @@ public static Message parse(Session session, String messageString) throws Invali final DataDictionary applicationDataDictionary = ddProvider == null ? null : ddProvider .getApplicationDataDictionary(applVerID); - final quickfix.Message message = messageFactory.create(beginString, msgType); + final quickfix.Message message = messageFactory.create(beginString, applVerID, msgType); final DataDictionary payloadDictionary = MessageUtils.isAdminMessage(msgType) ? sessionDataDictionary : applicationDataDictionary; diff --git a/quickfixj-core/src/test/java/quickfix/DefaultMessageFactoryTest.java b/quickfixj-core/src/test/java/quickfix/DefaultMessageFactoryTest.java index 2af41cfe8..1fec31694 100644 --- a/quickfixj-core/src/test/java/quickfix/DefaultMessageFactoryTest.java +++ b/quickfixj-core/src/test/java/quickfix/DefaultMessageFactoryTest.java @@ -2,13 +2,13 @@ import static org.junit.Assert.*; import static quickfix.FixVersions.*; +import static quickfix.field.ApplVerID.*; import org.junit.Test; -import quickfix.field.LinesOfText; -import quickfix.field.MsgType; -import quickfix.field.NoLinesOfText; -import quickfix.field.NoMDEntries; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import quickfix.field.*; import quickfix.test.util.ExpectedTestFailure; /** @@ -17,8 +17,19 @@ * @author toli * @version $Id$ */ +@RunWith(Parameterized.class) public class DefaultMessageFactoryTest { - private final DefaultMessageFactory factory = new DefaultMessageFactory(); + private final DefaultMessageFactory factory; + private final Class fixtCreateExpectedClass; + + public DefaultMessageFactoryTest(String defaultApplVerID, Class fixtCreateExpectedClass) { + if (defaultApplVerID != null) { + this.factory = new DefaultMessageFactory(defaultApplVerID); + } else { + this.factory = new DefaultMessageFactory(); + } + this.fixtCreateExpectedClass = fixtCreateExpectedClass; + } @Test public void testMessageCreate() throws Exception { @@ -27,18 +38,28 @@ public void testMessageCreate() throws Exception { assertMessage(quickfix.fix42.Advertisement.class, MsgType.ADVERTISEMENT, factory.create(BEGINSTRING_FIX42, MsgType.ADVERTISEMENT)); assertMessage(quickfix.fix43.Advertisement.class, MsgType.ADVERTISEMENT, factory.create(BEGINSTRING_FIX43, MsgType.ADVERTISEMENT)); assertMessage(quickfix.fix44.Advertisement.class, MsgType.ADVERTISEMENT, factory.create(BEGINSTRING_FIX44, MsgType.ADVERTISEMENT)); - assertMessage(quickfix.fix50.Advertisement.class, MsgType.ADVERTISEMENT, factory.create(FIX50, MsgType.ADVERTISEMENT)); + assertMessage(quickfix.fix50.Advertisement.class, MsgType.ADVERTISEMENT, factory.create(FixVersions.FIX50, MsgType.ADVERTISEMENT)); + assertMessage(quickfix.fix50sp1.Advertisement.class, MsgType.ADVERTISEMENT, factory.create(FixVersions.FIX50SP1, MsgType.ADVERTISEMENT)); + assertMessage(quickfix.fix50sp2.Advertisement.class, MsgType.ADVERTISEMENT, factory.create(FixVersions.FIX50SP2, MsgType.ADVERTISEMENT)); assertMessage(quickfix.Message.class, MsgType.ADVERTISEMENT, factory.create("unknown", MsgType.ADVERTISEMENT)); } @Test public void testFixtCreate() throws Exception { assertMessage(quickfix.fixt11.Logon.class, MsgType.LOGON, factory.create(BEGINSTRING_FIXT11, MsgType.LOGON)); + assertMessage(fixtCreateExpectedClass, MsgType.EMAIL, factory.create(BEGINSTRING_FIXT11, MsgType.EMAIL)); + assertMessage(quickfix.fix40.Email.class, MsgType.EMAIL, factory.create(BEGINSTRING_FIXT11, new ApplVerID(FIX40), MsgType.EMAIL)); + assertMessage(quickfix.fix41.Email.class, MsgType.EMAIL, factory.create(BEGINSTRING_FIXT11, new ApplVerID(FIX41), MsgType.EMAIL)); + assertMessage(quickfix.fix42.Email.class, MsgType.EMAIL, factory.create(BEGINSTRING_FIXT11, new ApplVerID(FIX42), MsgType.EMAIL)); + assertMessage(quickfix.fix43.Email.class, MsgType.EMAIL, factory.create(BEGINSTRING_FIXT11, new ApplVerID(FIX43), MsgType.EMAIL)); + assertMessage(quickfix.fix44.Email.class, MsgType.EMAIL, factory.create(BEGINSTRING_FIXT11, new ApplVerID(FIX44), MsgType.EMAIL)); + assertMessage(quickfix.fix50.Email.class, MsgType.EMAIL, factory.create(BEGINSTRING_FIXT11, new ApplVerID(ApplVerID.FIX50), MsgType.EMAIL)); + assertMessage(quickfix.fix50sp1.Email.class, MsgType.EMAIL, factory.create(BEGINSTRING_FIXT11, new ApplVerID(ApplVerID.FIX50SP1), MsgType.EMAIL)); + assertMessage(quickfix.fix50sp2.Email.class, MsgType.EMAIL, factory.create(BEGINSTRING_FIXT11, new ApplVerID(ApplVerID.FIX50SP2), MsgType.EMAIL)); } @Test public void testGroupCreate() throws Exception { - new ExpectedTestFailure(IllegalArgumentException.class, "unknown") { protected void execute() throws Throwable { factory.create("unknown", MsgType.NEWS, LinesOfText.FIELD); @@ -50,7 +71,9 @@ protected void execute() throws Throwable { assertEquals(quickfix.fix42.News.LinesOfText.class, factory.create(BEGINSTRING_FIX42, MsgType.NEWS, LinesOfText.FIELD).getClass()); assertEquals(quickfix.fix43.News.LinesOfText.class, factory.create(BEGINSTRING_FIX43, MsgType.NEWS, LinesOfText.FIELD).getClass()); assertEquals(quickfix.fix44.News.LinesOfText.class, factory.create(BEGINSTRING_FIX44, MsgType.NEWS, LinesOfText.FIELD).getClass()); - assertEquals(quickfix.fix50.News.NoLinesOfText.class, factory.create(FIX50, MsgType.NEWS, NoLinesOfText.FIELD).getClass()); + assertEquals(quickfix.fix50.News.NoLinesOfText.class, factory.create(FixVersions.FIX50, MsgType.NEWS, NoLinesOfText.FIELD).getClass()); + assertEquals(quickfix.fix50sp1.News.NoLinesOfText.class, factory.create(FixVersions.FIX50SP1, MsgType.NEWS, NoLinesOfText.FIELD).getClass()); + assertEquals(quickfix.fix50sp2.News.NoLinesOfText.class, factory.create(FixVersions.FIX50SP2, MsgType.NEWS, NoLinesOfText.FIELD).getClass()); assertNull("if group can't be created return null", factory.create(BEGINSTRING_FIX40, MsgType.MARKET_DATA_SNAPSHOT_FULL_REFRESH, NoMDEntries.FIELD)); } @@ -59,4 +82,18 @@ private static void assertMessage(Class expectedMessageClass, String expected assertEquals(expectedMessageClass, message.getClass()); assertEquals(expectedMessageType, message.getHeader().getString(MsgType.FIELD)); } + + @Parameterized.Parameters(name = "defaultApplVerID = {0}") + public static Object[][] getParameters() { + return new Object[][] { + {ApplVerID.FIX40, quickfix.fix40.Email.class}, + {ApplVerID.FIX41, quickfix.fix41.Email.class}, + {ApplVerID.FIX42, quickfix.fix42.Email.class}, + {ApplVerID.FIX43, quickfix.fix43.Email.class}, + {ApplVerID.FIX44, quickfix.fix44.Email.class}, + {ApplVerID.FIX50, quickfix.fix50.Email.class}, + {ApplVerID.FIX50SP1, quickfix.fix50sp1.Email.class}, + {ApplVerID.FIX50SP2, quickfix.fix50sp2.Email.class} + }; + } } diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/ATMessageCracker.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/ATMessageCracker.java index 9fd66e377..42443528b 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/ATMessageCracker.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/ATMessageCracker.java @@ -65,6 +65,16 @@ public void onMessage(quickfix.fix50.NewOrderSingle message, SessionID sessionID process(message, sessionID); } + public void onMessage(quickfix.fix50sp1.NewOrderSingle message, SessionID sessionID) + throws FieldNotFound, UnsupportedMessageType, IncorrectTagValue { + process(message, sessionID); + } + + public void onMessage(quickfix.fix50sp2.NewOrderSingle message, SessionID sessionID) + throws FieldNotFound, UnsupportedMessageType, IncorrectTagValue { + process(message, sessionID); + } + public void onMessage(quickfix.fix50.SecurityDefinition message, SessionID sessionID) throws FieldNotFound, UnsupportedMessageType, IncorrectTagValue { try { From 2ec570ea50a79ec59985fc18b49eb0468fba5158 Mon Sep 17 00:00:00 2001 From: Christoph John Date: Fri, 9 Feb 2018 09:59:33 +0100 Subject: [PATCH 151/165] Minor logging change and correction of and-clause (#173) --- .../test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java | 2 +- .../src/test/java/quickfix/mina/ssl/SSLCertificateTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java b/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java index 8d33736ae..718b2882f 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java @@ -198,7 +198,7 @@ public void testLogonWithoutHeartBtInt() throws Exception { try { handler.processMessage(mockIoSession, message); } catch (Exception e) { - fail("No exception should be thrown!"); + fail("No exception should be thrown! " + e); } } 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 dd3206a4d..d2a06d544 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java @@ -621,7 +621,7 @@ public void assertNotAuthenticated(SessionID sessionID) throws Exception { try { X509Certificate[] peerCertificateChain = sslSession.getPeerCertificateChain(); - if (peerCertificateChain != null & peerCertificateChain.length > 0) { + if (peerCertificateChain != null && peerCertificateChain.length > 0) { throw new AssertionError("Certificate was authenticated"); } } catch (SSLPeerUnverifiedException e) { From be3b5db37ec74c36b92831ad199c4ad32ceaba97 Mon Sep 17 00:00:00 2001 From: jasonps01 Date: Mon, 19 Feb 2018 11:07:59 -0500 Subject: [PATCH 152/165] Fix a bug where some calls to isSetting() don't specify the session ID. (#174) Some calls to isSetting() don't specify the sessionID --- quickfixj-core/src/main/java/quickfix/JdbcLog.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/JdbcLog.java b/quickfixj-core/src/main/java/quickfix/JdbcLog.java index 8ccf5cdb0..308e37fad 100644 --- a/quickfixj-core/src/main/java/quickfix/JdbcLog.java +++ b/quickfixj-core/src/main/java/quickfix/JdbcLog.java @@ -61,22 +61,23 @@ public JdbcLog(SessionSettings settings, SessionID sessionID, DataSource ds) ? JdbcUtil.getDataSource(settings, sessionID) : ds; - logHeartbeats = !settings.isSetting(SETTING_JDBC_LOG_HEARTBEATS) || settings.getBool(SETTING_JDBC_LOG_HEARTBEATS); + logHeartbeats = !settings.isSetting(sessionID, SETTING_JDBC_LOG_HEARTBEATS) + || settings.getBool(sessionID, SETTING_JDBC_LOG_HEARTBEATS); setLogHeartbeats(logHeartbeats); - if (settings.isSetting(SETTING_LOG_OUTGOING_TABLE)) { + if (settings.isSetting(sessionID, SETTING_LOG_OUTGOING_TABLE)) { outgoingMessagesTableName = settings.getString(sessionID, SETTING_LOG_OUTGOING_TABLE); } else { outgoingMessagesTableName = DEFAULT_MESSAGES_LOG_TABLE; } - if (settings.isSetting(SETTING_LOG_INCOMING_TABLE)) { + if (settings.isSetting(sessionID, SETTING_LOG_INCOMING_TABLE)) { incomingMessagesTableName = settings.getString(sessionID, SETTING_LOG_INCOMING_TABLE); } else { incomingMessagesTableName = DEFAULT_MESSAGES_LOG_TABLE; } - if (settings.isSetting(SETTING_LOG_EVENT_TABLE)) { + if (settings.isSetting(sessionID, SETTING_LOG_EVENT_TABLE)) { eventTableName = settings.getString(sessionID, SETTING_LOG_EVENT_TABLE); } else { eventTableName = DEFAULT_EVENT_LOG_TABLE; From 746a35b0b79c654647c5264887eb878a1b1cff95 Mon Sep 17 00:00:00 2001 From: mrbald Date: Tue, 6 Mar 2018 21:16:43 +0100 Subject: [PATCH 153/165] =?UTF-8?q?QFJ-943:=20optional=20watermarks-based?= =?UTF-8?q?=20back=20pressure=20propagation=20from=20inbo=E2=80=A6=20(#168?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * QFJ-943: optional watermarks-based back pressure propagaion from inbound queue to the socket --- .../AbstractSessionConnectorBuilder.java | 74 ++++++++ .../main/java/quickfix/SocketAcceptor.java | 28 +++ .../main/java/quickfix/SocketInitiator.java | 28 +++ .../java/quickfix/ThreadedSocketAcceptor.java | 28 +++ .../quickfix/ThreadedSocketInitiator.java | 28 +++ .../quickfix/mina/EventHandlingStrategy.java | 1 - .../quickfix/mina/IoSessionResponder.java | 3 + .../main/java/quickfix/mina/QueueTracker.java | 11 ++ .../java/quickfix/mina/QueueTrackers.java | 89 +++++++++ .../SingleThreadedEventHandlingStrategy.java | 24 ++- ...ThreadPerSessionEventHandlingStrategy.java | 46 +++-- .../java/quickfix/mina/WatermarkTracker.java | 176 ++++++++++++++++++ ...adPerSessionEventHandlingStrategyTest.java | 5 +- .../quickfix/mina/WatermarkTrackerTest.java | 151 +++++++++++++++ 14 files changed, 666 insertions(+), 26 deletions(-) create mode 100644 quickfixj-core/src/main/java/quickfix/AbstractSessionConnectorBuilder.java create mode 100644 quickfixj-core/src/main/java/quickfix/mina/QueueTracker.java create mode 100644 quickfixj-core/src/main/java/quickfix/mina/QueueTrackers.java create mode 100644 quickfixj-core/src/main/java/quickfix/mina/WatermarkTracker.java create mode 100644 quickfixj-core/src/test/java/quickfix/mina/WatermarkTrackerTest.java diff --git a/quickfixj-core/src/main/java/quickfix/AbstractSessionConnectorBuilder.java b/quickfixj-core/src/main/java/quickfix/AbstractSessionConnectorBuilder.java new file mode 100644 index 000000000..7bddc45ea --- /dev/null +++ b/quickfixj-core/src/main/java/quickfix/AbstractSessionConnectorBuilder.java @@ -0,0 +1,74 @@ +package quickfix; + +public abstract class AbstractSessionConnectorBuilder { + private final Class derived; + Application application; + MessageStoreFactory messageStoreFactory; + SessionSettings settings; + LogFactory logFactory; + MessageFactory messageFactory; + + int queueCapacity = -1; + int queueLowerWatermark = -1; + int queueUpperWatermark = -1; + + AbstractSessionConnectorBuilder(Class derived) { + this.derived = derived; + } + + public Derived withApplication(Application val) throws ConfigError { + application = val; + return derived.cast(this); + } + + public Derived withMessageStoreFactory(MessageStoreFactory val) throws ConfigError { + messageStoreFactory = val; + return derived.cast(this); + } + + public Derived withSettings(SessionSettings val) { + settings = val; + return derived.cast(this); + } + + public Derived withLogFactory(LogFactory val) throws ConfigError { + logFactory = val; + return derived.cast(this); + } + + public Derived withMessageFactory(MessageFactory val) throws ConfigError { + messageFactory = val; + return derived.cast(this); + } + + public Derived withQueueCapacity(int val) throws ConfigError { + if (queueLowerWatermark >= 0) { + throw new ConfigError("queue capacity and watermarks may not be configured together"); + } else if (queueCapacity < 0) { + throw new ConfigError("negative queue capacity"); + } + queueCapacity = val; + return derived.cast(this); + } + + public Derived withQueueWatermarks(int lower, int upper) throws ConfigError { + if (queueCapacity >= 0) { + throw new ConfigError("queue capacity and watermarks may not be configured together"); + } else if (queueLowerWatermark < 0 || queueUpperWatermark <= queueLowerWatermark) { + throw new ConfigError("invalid queue watermarks, required: 0 <= lower watermark < upper watermark"); + } + queueLowerWatermark = lower; + queueUpperWatermark = upper; + return derived.cast(this); + } + + public final Product build() throws ConfigError { + if (logFactory == null) { + logFactory = new ScreenLogFactory(settings); + } + + return doBuild(); + } + + protected abstract Product doBuild() throws ConfigError; +} diff --git a/quickfixj-core/src/main/java/quickfix/SocketAcceptor.java b/quickfixj-core/src/main/java/quickfix/SocketAcceptor.java index c8dfc5edf..076bc3d76 100644 --- a/quickfixj-core/src/main/java/quickfix/SocketAcceptor.java +++ b/quickfixj-core/src/main/java/quickfix/SocketAcceptor.java @@ -31,6 +31,34 @@ public class SocketAcceptor extends AbstractSocketAcceptor { private volatile Boolean isStarted = Boolean.FALSE; private final SingleThreadedEventHandlingStrategy eventHandlingStrategy; + private SocketAcceptor(Builder builder) throws ConfigError { + super(builder.application, builder.messageStoreFactory, builder.settings, + builder.logFactory, builder.messageFactory); + + if (builder.queueCapacity >= 0) { + eventHandlingStrategy + = new SingleThreadedEventHandlingStrategy(this, builder.queueCapacity); + } else { + eventHandlingStrategy + = new SingleThreadedEventHandlingStrategy(this, builder.queueLowerWatermark, builder.queueUpperWatermark); + } + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static final class Builder extends AbstractSessionConnectorBuilder { + private Builder() { + super(Builder.class); + } + + @Override + protected SocketAcceptor doBuild() throws ConfigError { + return new SocketAcceptor(this); + } + } + public SocketAcceptor(Application application, MessageStoreFactory messageStoreFactory, SessionSettings settings, LogFactory logFactory, MessageFactory messageFactory, int queueCapacity) diff --git a/quickfixj-core/src/main/java/quickfix/SocketInitiator.java b/quickfixj-core/src/main/java/quickfix/SocketInitiator.java index 71d5931ce..184eeda15 100644 --- a/quickfixj-core/src/main/java/quickfix/SocketInitiator.java +++ b/quickfixj-core/src/main/java/quickfix/SocketInitiator.java @@ -31,6 +31,34 @@ public class SocketInitiator extends AbstractSocketInitiator { private volatile Boolean isStarted = Boolean.FALSE; private final SingleThreadedEventHandlingStrategy eventHandlingStrategy; + private SocketInitiator(Builder builder) throws ConfigError { + super(builder.application, builder.messageStoreFactory, builder.settings, + builder.logFactory, builder.messageFactory); + + if (builder.queueCapacity >= 0) { + eventHandlingStrategy + = new SingleThreadedEventHandlingStrategy(this, builder.queueCapacity); + } else { + eventHandlingStrategy + = new SingleThreadedEventHandlingStrategy(this, builder.queueLowerWatermark, builder.queueUpperWatermark); + } + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static final class Builder extends AbstractSessionConnectorBuilder { + private Builder() { + super(Builder.class); + } + + @Override + protected SocketInitiator doBuild() throws ConfigError { + return new SocketInitiator(this); + } + } + public SocketInitiator(Application application, MessageStoreFactory messageStoreFactory, SessionSettings settings, MessageFactory messageFactory, int queueCapacity) throws ConfigError { super(application, messageStoreFactory, settings, new ScreenLogFactory(settings), diff --git a/quickfixj-core/src/main/java/quickfix/ThreadedSocketAcceptor.java b/quickfixj-core/src/main/java/quickfix/ThreadedSocketAcceptor.java index adf3dbbb6..608f67711 100644 --- a/quickfixj-core/src/main/java/quickfix/ThreadedSocketAcceptor.java +++ b/quickfixj-core/src/main/java/quickfix/ThreadedSocketAcceptor.java @@ -29,6 +29,34 @@ public class ThreadedSocketAcceptor extends AbstractSocketAcceptor { private final ThreadPerSessionEventHandlingStrategy eventHandlingStrategy; + private ThreadedSocketAcceptor(Builder builder) throws ConfigError { + super(builder.application, builder.messageStoreFactory, builder.settings, + builder.logFactory, builder.messageFactory); + + if (builder.queueCapacity >= 0) { + eventHandlingStrategy + = new ThreadPerSessionEventHandlingStrategy(this, builder.queueCapacity); + } else { + eventHandlingStrategy + = new ThreadPerSessionEventHandlingStrategy(this, builder.queueLowerWatermark, builder.queueUpperWatermark); + } + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static final class Builder extends AbstractSessionConnectorBuilder { + private Builder() { + super(Builder.class); + } + + @Override + protected ThreadedSocketAcceptor doBuild() throws ConfigError { + return new ThreadedSocketAcceptor(this); + } + } + public ThreadedSocketAcceptor(Application application, MessageStoreFactory messageStoreFactory, SessionSettings settings, LogFactory logFactory, MessageFactory messageFactory, int queueCapacity ) diff --git a/quickfixj-core/src/main/java/quickfix/ThreadedSocketInitiator.java b/quickfixj-core/src/main/java/quickfix/ThreadedSocketInitiator.java index 29233c65a..a011c25ea 100644 --- a/quickfixj-core/src/main/java/quickfix/ThreadedSocketInitiator.java +++ b/quickfixj-core/src/main/java/quickfix/ThreadedSocketInitiator.java @@ -29,6 +29,34 @@ public class ThreadedSocketInitiator extends AbstractSocketInitiator { private final ThreadPerSessionEventHandlingStrategy eventHandlingStrategy; + private ThreadedSocketInitiator(Builder builder) throws ConfigError { + super(builder.application, builder.messageStoreFactory, builder.settings, + builder.logFactory, builder.messageFactory); + + if (builder.queueCapacity >= 0) { + eventHandlingStrategy + = new ThreadPerSessionEventHandlingStrategy(this, builder.queueCapacity); + } else { + eventHandlingStrategy + = new ThreadPerSessionEventHandlingStrategy(this, builder.queueLowerWatermark, builder.queueUpperWatermark); + } + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static final class Builder extends AbstractSessionConnectorBuilder { + private Builder() { + super(Builder.class); + } + + @Override + protected ThreadedSocketInitiator doBuild() throws ConfigError { + return new ThreadedSocketInitiator(this); + } + } + public ThreadedSocketInitiator(Application application, MessageStoreFactory messageStoreFactory, SessionSettings settings, LogFactory logFactory, MessageFactory messageFactory, int queueCapacity) throws ConfigError { diff --git a/quickfixj-core/src/main/java/quickfix/mina/EventHandlingStrategy.java b/quickfixj-core/src/main/java/quickfix/mina/EventHandlingStrategy.java index 1b2b50e81..573288f17 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/EventHandlingStrategy.java +++ b/quickfixj-core/src/main/java/quickfix/mina/EventHandlingStrategy.java @@ -28,7 +28,6 @@ * it only handles message reception events. */ public interface EventHandlingStrategy { - /** * Constant indicating how long we wait for an incoming message. After * thread has been asked to stop, it can take up to this long to terminate. diff --git a/quickfixj-core/src/main/java/quickfix/mina/IoSessionResponder.java b/quickfixj-core/src/main/java/quickfix/mina/IoSessionResponder.java index df3ba2660..1c32dcb36 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/IoSessionResponder.java +++ b/quickfixj-core/src/main/java/quickfix/mina/IoSessionResponder.java @@ -95,4 +95,7 @@ public String getRemoteAddress() { return null; } + IoSession getIoSession() { + return ioSession; + } } diff --git a/quickfixj-core/src/main/java/quickfix/mina/QueueTracker.java b/quickfixj-core/src/main/java/quickfix/mina/QueueTracker.java new file mode 100644 index 000000000..3f47341bf --- /dev/null +++ b/quickfixj-core/src/main/java/quickfix/mina/QueueTracker.java @@ -0,0 +1,11 @@ +package quickfix.mina; + +import java.util.Collection; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; + +interface QueueTracker { + void put(E e) throws InterruptedException; + E poll(long timeout, TimeUnit unit) throws InterruptedException; + int drainTo(Collection collection); +} diff --git a/quickfixj-core/src/main/java/quickfix/mina/QueueTrackers.java b/quickfixj-core/src/main/java/quickfix/mina/QueueTrackers.java new file mode 100644 index 000000000..00f1ecb3b --- /dev/null +++ b/quickfixj-core/src/main/java/quickfix/mina/QueueTrackers.java @@ -0,0 +1,89 @@ +package quickfix.mina; + +import org.apache.mina.core.session.IoSession; +import quickfix.Responder; +import quickfix.Session; + +import java.util.Collection; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +import static java.lang.String.format; + +/** + * Queue trackers factory methods + */ +final class QueueTrackers { + private static final String LOWER_WATERMARK_FMT = "inbound queue size < lower watermark (%d), socket reads resumed"; + private static final String UPPER_WATERMARK_FMT = "inbound queue size > upper watermark (%d), socket reads suspended"; + + /** + * Watermarks-based queue tracker + */ + static WatermarkTracker newMultiSessionWatermarkTracker( + BlockingQueue queue, + long lowerWatermark, long upperWatermark, + Function classifier) { + return WatermarkTracker.newMulti(queue, lowerWatermark, upperWatermark, classifier, + qfSession -> resumeReads(qfSession, (int)lowerWatermark), + qfSession -> suspendReads(qfSession, (int)upperWatermark)); + } + + /** + * Default no-op queue tracker + */ + static QueueTracker newDefaultQueueTracker(BlockingQueue queue) { + return new QueueTracker() { + @Override + public void put(E e) throws InterruptedException { + queue.put(e); + } + + @Override + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + return queue.poll(timeout, unit); + } + + @Override + public int drainTo(Collection collection) { + return queue.drainTo(collection); + } + }; + } + + private static IoSession lookupIoSession(Session qfSession) { + final Responder responder = qfSession.getResponder(); + + if (responder instanceof IoSessionResponder) { + return ((IoSessionResponder)responder).getIoSession(); + } else { + return null; + } + } + + private static void resumeReads(Session qfSession, int queueLowerWatermark) { + final IoSession ioSession = lookupIoSession(qfSession); + if (ioSession != null && ioSession.isReadSuspended()) { + ioSession.resumeRead(); + qfSession.getLog().onEvent(format(LOWER_WATERMARK_FMT, queueLowerWatermark)); + } + } + + private static void suspendReads(Session qfSession, int queueUpperWatermark) { + final IoSession ioSession = lookupIoSession(qfSession); + if (ioSession != null && !ioSession.isReadSuspended()) { + ioSession.suspendRead(); + qfSession.getLog().onEvent(format(UPPER_WATERMARK_FMT, queueUpperWatermark)); + } + } + + static WatermarkTracker newSingleSessionWatermarkTracker( + BlockingQueue queue, + long lowerWatermark, long upperWatermark, + Session qfSession) { + return WatermarkTracker.newMono(queue, lowerWatermark, upperWatermark, + () -> resumeReads(qfSession, (int)lowerWatermark), + () -> suspendReads(qfSession, (int)upperWatermark)); + } +} diff --git a/quickfixj-core/src/main/java/quickfix/mina/SingleThreadedEventHandlingStrategy.java b/quickfixj-core/src/main/java/quickfix/mina/SingleThreadedEventHandlingStrategy.java index e73056570..b14f4c653 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/SingleThreadedEventHandlingStrategy.java +++ b/quickfixj-core/src/main/java/quickfix/mina/SingleThreadedEventHandlingStrategy.java @@ -20,11 +20,7 @@ package quickfix.mina; -import quickfix.LogUtil; -import quickfix.Message; -import quickfix.Session; -import quickfix.SessionID; -import quickfix.SystemTime; +import quickfix.*; import java.util.ArrayList; import java.util.List; @@ -34,12 +30,16 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; +import static quickfix.mina.QueueTrackers.newDefaultQueueTracker; +import static quickfix.mina.QueueTrackers.newMultiSessionWatermarkTracker; + /** * Processes messages for all sessions in a single thread. */ public class SingleThreadedEventHandlingStrategy implements EventHandlingStrategy { public static final String MESSAGE_PROCESSOR_THREAD_NAME = "QFJ Message Processor"; private final BlockingQueue eventQueue; + private final QueueTracker queueTracker; private final SessionConnector sessionConnector; private volatile ThreadAdapter messageProcessingThread; private volatile boolean isStopped; @@ -49,6 +49,14 @@ public class SingleThreadedEventHandlingStrategy implements EventHandlingStrateg public SingleThreadedEventHandlingStrategy(SessionConnector connector, int queueCapacity) { sessionConnector = connector; eventQueue = new LinkedBlockingQueue<>(queueCapacity); + queueTracker = newDefaultQueueTracker(eventQueue); + } + + public SingleThreadedEventHandlingStrategy(SessionConnector connector, int queueLowerWatermark, int queueUpperWatermark) { + sessionConnector = connector; + eventQueue = new LinkedBlockingQueue<>(); + queueTracker = newMultiSessionWatermarkTracker(eventQueue, queueLowerWatermark, queueUpperWatermark, + evt -> evt.quickfixSession); } public void setExecutor(Executor executor) { @@ -61,7 +69,7 @@ public void onMessage(Session quickfixSession, Message message) { return; } try { - eventQueue.put(new SessionMessageEvent(quickfixSession, message)); + queueTracker.put(new SessionMessageEvent(quickfixSession, message)); } catch (InterruptedException e) { isStopped = true; throw new RuntimeException(e); @@ -79,7 +87,7 @@ public void block() { if (isStopped) { if (!eventQueue.isEmpty()) { final List tempList = new ArrayList<>(); - eventQueue.drainTo(tempList); + queueTracker.drainTo(tempList); for (SessionMessageEvent event : tempList) { event.processMessage(); } @@ -107,7 +115,7 @@ public void block() { } private SessionMessageEvent getMessage() throws InterruptedException { - return eventQueue.poll(THREAD_WAIT_FOR_MESSAGE_MS, TimeUnit.MILLISECONDS); + return queueTracker.poll(THREAD_WAIT_FOR_MESSAGE_MS, TimeUnit.MILLISECONDS); } /** diff --git a/quickfixj-core/src/main/java/quickfix/mina/ThreadPerSessionEventHandlingStrategy.java b/quickfixj-core/src/main/java/quickfix/mina/ThreadPerSessionEventHandlingStrategy.java index 209a78bc4..5cdd3bbe0 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/ThreadPerSessionEventHandlingStrategy.java +++ b/quickfixj-core/src/main/java/quickfix/mina/ThreadPerSessionEventHandlingStrategy.java @@ -20,10 +20,7 @@ package quickfix.mina; -import quickfix.LogUtil; -import quickfix.Message; -import quickfix.Session; -import quickfix.SessionID; +import quickfix.*; import java.util.ArrayList; import java.util.Collection; @@ -35,19 +32,32 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; +import static quickfix.mina.QueueTrackers.newDefaultQueueTracker; +import static quickfix.mina.QueueTrackers.newSingleSessionWatermarkTracker; + /** * Processes messages in a session-specific thread. */ public class ThreadPerSessionEventHandlingStrategy implements EventHandlingStrategy { - private final ConcurrentMap dispatchers = new ConcurrentHashMap<>(); private final SessionConnector sessionConnector; private final int queueCapacity; + private final int queueLowerWatermark; + private final int queueUpperWatermark; private volatile Executor executor; public ThreadPerSessionEventHandlingStrategy(SessionConnector connector, int queueCapacity) { sessionConnector = connector; this.queueCapacity = queueCapacity; + this.queueLowerWatermark = -1; + this.queueUpperWatermark = -1; + } + + public ThreadPerSessionEventHandlingStrategy(SessionConnector connector, int queueLowerWatermark, int queueUpperWatermark) { + sessionConnector = connector; + this.queueCapacity = -1; + this.queueLowerWatermark = queueLowerWatermark; + this.queueUpperWatermark = queueUpperWatermark; } public void setExecutor(Executor executor) { @@ -59,7 +69,7 @@ public void onMessage(Session quickfixSession, Message message) { MessageDispatchingThread dispatcher = dispatchers.get(quickfixSession.getSessionID()); if (dispatcher == null) { dispatcher = dispatchers.computeIfAbsent(quickfixSession.getSessionID(), sessionID -> { - final MessageDispatchingThread newDispatcher = new MessageDispatchingThread(quickfixSession, queueCapacity, executor); + final MessageDispatchingThread newDispatcher = new MessageDispatchingThread(quickfixSession, executor); startDispatcherThread(newDispatcher); return newDispatcher; }); @@ -161,13 +171,21 @@ public void execute(Runnable command) { protected class MessageDispatchingThread extends ThreadAdapter { private final Session quickfixSession; private final BlockingQueue messages; + private final QueueTracker queueTracker; private volatile boolean stopped; private volatile boolean stopping; - private MessageDispatchingThread(Session session, int queueCapacity, Executor executor) { + private MessageDispatchingThread(Session session, Executor executor) { super("QF/J Session dispatcher: " + session.getSessionID(), executor); quickfixSession = session; - messages = new LinkedBlockingQueue<>(queueCapacity); + if (queueCapacity >= 0) { + messages = new LinkedBlockingQueue<>(queueCapacity); + queueTracker = newDefaultQueueTracker(messages); + } else { + messages = new LinkedBlockingQueue<>(); + queueTracker = newSingleSessionWatermarkTracker(messages, queueLowerWatermark, queueUpperWatermark, + quickfixSession); + } } public void enqueue(Message message) { @@ -175,7 +193,7 @@ public void enqueue(Message message) { return; } try { - messages.put(message); + queueTracker.put(message); } catch (final InterruptedException e) { quickfixSession.getLog().onErrorEvent(e.toString()); } @@ -189,7 +207,7 @@ public int getQueueSize() { void doRun() { while (!stopping) { try { - final Message message = getNextMessage(messages); + final Message message = getNextMessage(queueTracker); if (message == null) { // no message available in polling interval continue; @@ -209,7 +227,7 @@ void doRun() { } if (!messages.isEmpty()) { final List tempList = new ArrayList<>(); - messages.drainTo(tempList); + queueTracker.drainTo(tempList); for (Message message : tempList) { try { quickfixSession.next(message); @@ -245,12 +263,12 @@ protected MessageDispatchingThread getDispatcher(SessionID sessionID) { * We do not block indefinitely as that would prevent this thread from ever stopping * * @see #THREAD_WAIT_FOR_MESSAGE_MS - * @param messages + * @param queueTracker * @return next message or null if nothing arrived within the timeout period * @throws InterruptedException */ - protected Message getNextMessage(BlockingQueue messages) throws InterruptedException { - return messages.poll(THREAD_WAIT_FOR_MESSAGE_MS, TimeUnit.MILLISECONDS); + protected Message getNextMessage(QueueTracker queueTracker) throws InterruptedException { + return queueTracker.poll(THREAD_WAIT_FOR_MESSAGE_MS, TimeUnit.MILLISECONDS); } @Override diff --git a/quickfixj-core/src/main/java/quickfix/mina/WatermarkTracker.java b/quickfixj-core/src/main/java/quickfix/mina/WatermarkTracker.java new file mode 100644 index 000000000..25e910e7b --- /dev/null +++ b/quickfixj-core/src/main/java/quickfix/mina/WatermarkTracker.java @@ -0,0 +1,176 @@ +/******************************************************************************* + * Copyright (c) quickfixengine.org All rights reserved. + * + * This file is part of the QuickFIX FIX Engine + * + * This file may be distributed under the terms of the quickfixengine.org + * license as defined by quickfixengine.org and appearing in the file + * LICENSE included in the packaging of this file. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING + * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * See http://www.quickfixengine.org/LICENSE for licensing information. + * + * Contact ask@quickfixengine.org if any conditions of this licensing + * are not clear to you. + ******************************************************************************/ + +package quickfix.mina; + +import java.util.AbstractCollection; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * A blocking queue wrapper implementing watermarks-based back pressure propagation + * from the queue sink to one or more logical sources. + * + * @param payload type + * @param logical source key type + * + * @author Vladimir Lysyy (mrbald@github) + */ +public class WatermarkTracker implements QueueTracker { + private final BlockingQueue queue; + private final long lowerWatermark; + private final long upperWatermark; + private final Consumer onLowerWatermarkCrossed; + private final Consumer onUpperWatermarkCrossed; + private final Function classifier; + private final Function trackerSupplier; + + class StreamTracker { + private final S key; + long counter = 0; + private boolean suspended = false; + + StreamTracker(S key) { + this.key = key; + } + + synchronized void incoming(int n) { + if ((counter += n) >= upperWatermark && !suspended) { + suspended = true; + onUpperWatermarkCrossed.accept(key); + } + } + + synchronized void outgoing(int n) { + if ((counter -= n) == lowerWatermark && suspended) { + suspended = false; + onLowerWatermarkCrossed.accept(key); + } + } + + synchronized boolean isSuspended() { + return suspended; + } + } + + static WatermarkTracker newMono( + BlockingQueue queue, + long lowerWatermark, long upperWatermark, + Runnable onLowerWatermarkCrossed, Runnable onUpperWatermarkCrossed) { + return new WatermarkTracker<>(queue, lowerWatermark, upperWatermark, onLowerWatermarkCrossed, onUpperWatermarkCrossed); + } + + static WatermarkTracker newMulti( + BlockingQueue queue, + long lowerWatermark, long upperWatermark, + Function classifier, + Consumer onLowerWatermarkCrossed, Consumer onUpperWatermarkCrossed) { + return new WatermarkTracker<>(queue, lowerWatermark, upperWatermark, classifier, onLowerWatermarkCrossed, onUpperWatermarkCrossed); + } + + private WatermarkTracker( + BlockingQueue queue, + long lowerWatermark, long upperWatermark, + Function classifier, + Consumer onLowerWatermarkCrossed, Consumer onUpperWatermarkCrossed) { + this.queue = queue; + this.lowerWatermark = lowerWatermark; + this.upperWatermark = upperWatermark; + this.classifier = classifier; + this.onLowerWatermarkCrossed = onLowerWatermarkCrossed; + this.onUpperWatermarkCrossed = onUpperWatermarkCrossed; + + final Map trackerMap = new ConcurrentHashMap<>(); + + this.trackerSupplier = key -> trackerMap.computeIfAbsent(key, StreamTracker::new); + } + + private WatermarkTracker( + BlockingQueue queue, + long lowerWatermark, long upperWatermark, + Runnable onLowerWatermarkCrossed, Runnable onUpperWatermarkCrossed) { + this.queue = queue; + this.lowerWatermark = lowerWatermark; + this.upperWatermark = upperWatermark; + this.classifier = x -> null; + this.onLowerWatermarkCrossed = x -> onLowerWatermarkCrossed.run(); + this.onUpperWatermarkCrossed = x -> onUpperWatermarkCrossed.run(); + + final StreamTracker streamTracker = new StreamTracker(null); + + this.trackerSupplier = key -> streamTracker; + } + + @Override + public void put(E e) throws InterruptedException { + queue.put(e); + trackerForPayload(e).incoming(1); + } + + @Override + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + final E e = queue.poll(timeout, unit); + + if (e != null) { + trackerForPayload(e).outgoing(1); + } + + return e; + } + + @Override + public int drainTo(Collection collection) { + return queue.drainTo(new AbstractCollection() { + @Override public Iterator iterator() { throw new UnsupportedOperationException(); } + @Override public int size() { throw new UnsupportedOperationException(); } + + public boolean add(E e) { + final boolean added = collection.add(e); + if (added) { + trackerForPayload(e).outgoing(1); + } + return added; + } + + }); + } + + public boolean isSuspended(S key) { + return trackerForStream(key).isSuspended(); + } + + public boolean isSuspended() { + return isSuspended(null); + } + + StreamTracker trackerForPayload(E e) { + return trackerForStream(classifier.apply(e)); + } + + StreamTracker trackerForStream(S s) { + return trackerSupplier.apply(s); + } + +} diff --git a/quickfixj-core/src/test/java/quickfix/mina/ThreadPerSessionEventHandlingStrategyTest.java b/quickfixj-core/src/test/java/quickfix/mina/ThreadPerSessionEventHandlingStrategyTest.java index 06d005f17..e1a286f1f 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/ThreadPerSessionEventHandlingStrategyTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/ThreadPerSessionEventHandlingStrategyTest.java @@ -47,7 +47,6 @@ import quickfix.fix40.Logon; import java.util.Date; -import java.util.concurrent.BlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -74,7 +73,7 @@ protected void startDispatcherThread( } @Override - protected Message getNextMessage(BlockingQueue messages) throws InterruptedException { + protected Message getNextMessage(QueueTracker queueTracker) throws InterruptedException { if (getMessageCount-- == 0) { throw new InterruptedException("END COUNT"); } @@ -84,7 +83,7 @@ protected Message getNextMessage(BlockingQueue messages) throws Interru } throw (RuntimeException) getNextMessageException; } - return super.getNextMessage(messages); + return super.getNextMessage(queueTracker); } } diff --git a/quickfixj-core/src/test/java/quickfix/mina/WatermarkTrackerTest.java b/quickfixj-core/src/test/java/quickfix/mina/WatermarkTrackerTest.java new file mode 100644 index 000000000..fbb6d9ccf --- /dev/null +++ b/quickfixj-core/src/test/java/quickfix/mina/WatermarkTrackerTest.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * Copyright (c) quickfixengine.org All rights reserved. + * + * This file is part of the QuickFIX FIX Engine + * + * This file may be distributed under the terms of the quickfixengine.org + * license as defined by quickfixengine.org and appearing in the file + * LICENSE included in the packaging of this file. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING + * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * See http://www.quickfixengine.org/LICENSE for licensing information. + * + * Contact ask@quickfixengine.org if any conditions of this licensing + * are not clear to you. + ******************************************************************************/ + +package quickfix.mina; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.function.Function; + +import static quickfix.mina.WatermarkTracker.newMono; +import static quickfix.mina.WatermarkTracker.newMulti; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class WatermarkTrackerTest { + @Mock + private Runnable onLowerMono; + + @Mock + private Runnable onUpperMono; + + @Mock + private Consumer onLowerMulti; + + @Mock + private Consumer onUpperMulti; + + private BlockingQueue queue; + + private WatermarkTracker mono; + + @Before + public void setUp() { + queue = new ArrayBlockingQueue<>(4); + mono = newMono(queue, 1, 3, onLowerMono, onUpperMono); + } + + @Test + public void basics() throws InterruptedException { + mono.put(1); + assertEquals(1, queue.size()); + + final Integer x = mono.poll(1, TimeUnit.DAYS); + assertEquals(0, queue.size()); + assertEquals(1, x.intValue()); + } + + /* + * Queue size over time in the below test, covers all scenarios + * + * (queue size) + * 3 * * + * 2 * * * + * 1 * * * + * 0 * * * + * 1 2 3 4 5 6 7 8 9 0 1 (steps) + */ + @Test + public void watermarks() throws InterruptedException { + // cross lower watermark up + mono.put(1); + verifyState(false, false, false); + + // cross lower watermark down while not suspended + mono.poll(1, TimeUnit.DAYS); + verifyState(false, false, false); + + // cross lower then upper watermarks up + mono.put(1); + verifyState(false, false, false); + + mono.put(2); + verifyState(false, false, false); + + mono.put(3); + verifyState(true, false, true); + + // cross upper watermark down + mono.poll(1, TimeUnit.DAYS); // 3 + verifyState(true, false, false); + + // cross upper watermark back up (without reaching the lower) + mono.put(3); + verifyState(true, false, false); + + // cross upper then lower watermarks down + mono.poll(1, TimeUnit.DAYS); // 2 + verifyState(true, false, false); + + mono.poll(1, TimeUnit.DAYS); // 2 + verifyState(false, true, false); + + mono.poll(1, TimeUnit.DAYS); // 1 + verifyState(false, false, false); + } + + @Test + public void multiShouldWork() throws InterruptedException { + final Function classifier = x -> x % 2; + final WatermarkTracker multi + = newMulti(queue, 1, 3, classifier, onLowerMulti, onUpperMulti); + + assertEquals(multi.trackerForStream(0), multi.trackerForStream(0)); + assertEquals(multi.trackerForStream(1), multi.trackerForStream(1)); + assertNotEquals(multi.trackerForStream(0), multi.trackerForStream(1)); + + assertEquals(multi.trackerForPayload(0), multi.trackerForPayload(2)); + assertEquals(multi.trackerForPayload(1), multi.trackerForPayload(3)); + assertNotEquals(multi.trackerForPayload(0), multi.trackerForPayload(1)); + + multi.put(1); + assertEquals(1, multi.trackerForPayload(1).counter); + multi.put(3); + assertEquals(2, multi.trackerForPayload(3).counter); + } + + // === helpers === + + private void verifyState(boolean suspended, boolean onLower, boolean onUpper) { + assertEquals(suspended, mono.isSuspended()); + verify(onLowerMono, times(onLower ? 1 : 0)).run(); + verify(onUpperMono, times(onUpper ? 1 : 0)).run(); + reset(onLowerMono, onUpperMono); + } +} \ No newline at end of file From 6b377f7f34188fc800854511f33543cc062f286b Mon Sep 17 00:00:00 2001 From: Christoph John Date: Tue, 6 Mar 2018 21:19:16 +0100 Subject: [PATCH 154/165] Cleanup Sessions on stop (#175) - added logic to unregister Session to Session.close() method - changed some tests to use try-with-resources on Session - changed Connector implementations to clean up used Sessions on stop - changed AbstractSocketInitiator to clean up internal map of initiators on stop --- .../src/main/java/quickfix/Session.java | 26 +- .../main/java/quickfix/SocketAcceptor.java | 3 +- .../main/java/quickfix/SocketInitiator.java | 3 +- .../java/quickfix/ThreadedSocketAcceptor.java | 3 +- .../quickfix/ThreadedSocketInitiator.java | 3 +- .../java/quickfix/mina/SessionConnector.java | 9 + .../initiator/AbstractSocketInitiator.java | 8 +- .../jmx/mbean/session/SessionAdminTest.java | 11 +- .../quickfix/DefaultSessionFactoryTest.java | 58 +- .../src/test/java/quickfix/FileLogTest.java | 17 +- .../src/test/java/quickfix/JdbcLogTest.java | 19 +- .../SessionDisconnectConcurrentlyTest.java | 79 +- .../java/quickfix/SessionDisconnectTest.java | 41 +- .../test/java/quickfix/SessionResetTest.java | 107 +- .../src/test/java/quickfix/SessionTest.java | 2207 ++++++++--------- .../java/quickfix/SocketAcceptorTest.java | 115 +- .../java/quickfix/SocketInitiatorTest.java | 8 +- .../quickfix/mina/SessionConnectorTest.java | 72 +- ...adPerSessionEventHandlingStrategyTest.java | 242 +- .../mina/acceptor/AcceptorIoHandlerTest.java | 172 +- .../DynamicAcceptorSessionProviderTest.java | 78 +- 21 files changed, 1712 insertions(+), 1569 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index d4d099a19..23f7665ca 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -676,15 +676,23 @@ static void registerSession(Session session) { sessions.put(session.getSessionID(), session); } - static void unregisterSessions(List sessionIds) { + static void unregisterSessions(List sessionIds, boolean doClose) { for (final SessionID sessionId : sessionIds) { - final Session session = sessions.remove(sessionId); - if (session != null) { - try { + unregisterSession(sessionId, doClose); + } + } + + static void unregisterSession(SessionID sessionId, boolean doClose) { + final Session session = sessions.get(sessionId); + if (session != null) { + try { + if (doClose) { session.close(); - } catch (final IOException e) { - LOG.error("Failed to close session resources", e); } + } catch (final IOException e) { + LOG.error("Failed to close session resources", e); + } finally { + sessions.remove(sessionId); } } } @@ -2911,13 +2919,15 @@ public boolean isAllowedForSession(InetAddress remoteInetAddress) { } /** - * Closes session resources. This is for internal use and should typically - * not be called by an user application. + * Closes session resources and unregisters session. This is for internal + * use and should typically not be called by an user application. */ @Override public void close() throws IOException { closeIfCloseable(getLog()); closeIfCloseable(getStore()); + // clean up session just in case close() was not called from Session.unregisterSession() + unregisterSession(this.sessionID, false); } private void closeIfCloseable(Object resource) throws IOException { diff --git a/quickfixj-core/src/main/java/quickfix/SocketAcceptor.java b/quickfixj-core/src/main/java/quickfix/SocketAcceptor.java index 076bc3d76..b64f807d5 100644 --- a/quickfixj-core/src/main/java/quickfix/SocketAcceptor.java +++ b/quickfixj-core/src/main/java/quickfix/SocketAcceptor.java @@ -135,7 +135,8 @@ public void stop(boolean forceDisconnect) { stopSessionTimer(); } finally { eventHandlingStrategy.stopHandlingMessages(); - Session.unregisterSessions(getSessions()); + Session.unregisterSessions(getSessions(), true); + clearConnectorSessions(); isStarted = Boolean.FALSE; } } diff --git a/quickfixj-core/src/main/java/quickfix/SocketInitiator.java b/quickfixj-core/src/main/java/quickfix/SocketInitiator.java index 184eeda15..efad4f404 100644 --- a/quickfixj-core/src/main/java/quickfix/SocketInitiator.java +++ b/quickfixj-core/src/main/java/quickfix/SocketInitiator.java @@ -124,7 +124,8 @@ public void stop(boolean forceDisconnect) { stopInitiators(); } finally { eventHandlingStrategy.stopHandlingMessages(); - Session.unregisterSessions(getSessions()); + Session.unregisterSessions(getSessions(), true); + clearConnectorSessions(); isStarted = Boolean.FALSE; } } diff --git a/quickfixj-core/src/main/java/quickfix/ThreadedSocketAcceptor.java b/quickfixj-core/src/main/java/quickfix/ThreadedSocketAcceptor.java index 608f67711..8f35bb801 100644 --- a/quickfixj-core/src/main/java/quickfix/ThreadedSocketAcceptor.java +++ b/quickfixj-core/src/main/java/quickfix/ThreadedSocketAcceptor.java @@ -115,7 +115,8 @@ public void stop(boolean forceDisconnect) { } stopSessionTimer(); eventHandlingStrategy.stopDispatcherThreads(); - Session.unregisterSessions(getSessions()); + Session.unregisterSessions(getSessions(), true); + clearConnectorSessions(); } public void block() throws ConfigError, RuntimeError { diff --git a/quickfixj-core/src/main/java/quickfix/ThreadedSocketInitiator.java b/quickfixj-core/src/main/java/quickfix/ThreadedSocketInitiator.java index a011c25ea..bf42ce20a 100644 --- a/quickfixj-core/src/main/java/quickfix/ThreadedSocketInitiator.java +++ b/quickfixj-core/src/main/java/quickfix/ThreadedSocketInitiator.java @@ -113,7 +113,8 @@ public void stop(boolean forceDisconnect) { logoutAllSessions(forceDisconnect); stopInitiators(); eventHandlingStrategy.stopDispatcherThreads(); - Session.unregisterSessions(getSessions()); + Session.unregisterSessions(getSessions(), true); + clearConnectorSessions(); } public void block() throws ConfigError, RuntimeError { diff --git a/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java b/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java index 06f207ed4..f0ce6cc3b 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java +++ b/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java @@ -119,6 +119,15 @@ protected void setSessions(Map sessions) { propertyChangeSupport.firePropertyChange(SESSIONS_PROPERTY, null, sessions); } + /** + * Will remove all Sessions from the SessionConnector's Session map. + * Please make sure that these Sessions were unregistered before via + * Session.unregisterSessions(). + */ + protected void clearConnectorSessions() { + this.sessions.clear(); + } + /** * Get the list of session managed by this connector. * diff --git a/quickfixj-core/src/main/java/quickfix/mina/initiator/AbstractSocketInitiator.java b/quickfixj-core/src/main/java/quickfix/mina/initiator/AbstractSocketInitiator.java index 3e9e0473c..b17ca5838 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/initiator/AbstractSocketInitiator.java +++ b/quickfixj-core/src/main/java/quickfix/mina/initiator/AbstractSocketInitiator.java @@ -77,9 +77,6 @@ protected AbstractSocketInitiator(SessionSettings settings, SessionFactory sessi protected void createSessionInitiators() throws ConfigError { try { - // QFJ698: clear() is needed on restart, otherwise the set gets filled up with - // more and more initiators which are not equal because the local port differs - initiators.clear(); createSessions(); SessionSettings settings = getSettings(); for (final Session session : getSessionMap().values()) { @@ -278,8 +275,9 @@ protected void startInitiators() { } protected void stopInitiators() { - for (final IoSessionInitiator initiator : initiators) { - initiator.stop(); + for (Iterator iterator = initiators.iterator(); iterator.hasNext();) { + iterator.next().stop(); + iterator.remove(); } super.stopSessionTimer(); } diff --git a/quickfixj-core/src/test/java/org/quickfixj/jmx/mbean/session/SessionAdminTest.java b/quickfixj-core/src/test/java/org/quickfixj/jmx/mbean/session/SessionAdminTest.java index 2352f6449..e5fcebc34 100644 --- a/quickfixj-core/src/test/java/org/quickfixj/jmx/mbean/session/SessionAdminTest.java +++ b/quickfixj-core/src/test/java/org/quickfixj/jmx/mbean/session/SessionAdminTest.java @@ -20,11 +20,12 @@ public class SessionAdminTest extends TestCase { public void testResetSequence() throws Exception { - Session session = SessionFactoryTestSupport.createSession(); - MockSessionAdmin admin = new MockSessionAdmin(session, null, null); - admin.resetSequence(25); - assertEquals(1, admin.sentMessages.size()); - assertEquals(25, admin.sentMessages.get(0).getInt(NewSeqNo.FIELD)); + try (Session session = SessionFactoryTestSupport.createSession()) { + MockSessionAdmin admin = new MockSessionAdmin(session, null, null); + admin.resetSequence(25); + assertEquals(1, admin.sentMessages.size()); + assertEquals(25, admin.sentMessages.get(0).getInt(NewSeqNo.FIELD)); + } } private class MockSessionAdmin extends SessionAdmin { diff --git a/quickfixj-core/src/test/java/quickfix/DefaultSessionFactoryTest.java b/quickfixj-core/src/test/java/quickfix/DefaultSessionFactoryTest.java index 0c305f303..a991f559b 100644 --- a/quickfixj-core/src/test/java/quickfix/DefaultSessionFactoryTest.java +++ b/quickfixj-core/src/test/java/quickfix/DefaultSessionFactoryTest.java @@ -19,6 +19,7 @@ package quickfix; +import java.io.IOException; import org.junit.Before; import org.junit.Test; import quickfix.field.ApplVerID; @@ -29,6 +30,7 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; +import org.junit.After; import static org.junit.Assert.*; public class DefaultSessionFactoryTest { @@ -45,6 +47,11 @@ public void setUp() throws Exception { new SLF4JLogFactory(new SessionSettings())); } + @After + public void tearDown() { + Session.unregisterSession(sessionID, true); + } + @Test public void testMinimalSettings() throws Exception { factory.create(sessionID, settings); @@ -86,29 +93,31 @@ public void testFixtDataDictionaryConfiguration() throws Exception { settings.setString(sessionID, Session.SETTING_APP_DATA_DICTIONARY, "FIX42.xml"); settings.setString(sessionID, Session.SETTING_APP_DATA_DICTIONARY + "." + FixVersions.BEGINSTRING_FIX40, "FIX40.xml"); - Session session = factory.create(sessionID, settings); - - DataDictionaryProvider provider = session.getDataDictionaryProvider(); - assertThat(provider.getSessionDataDictionary(sessionID.getBeginString()), - is(notNullValue())); + try (Session session = factory.create(sessionID, settings)) { - assertThat(provider.getApplicationDataDictionary(new ApplVerID(ApplVerID.FIX42)), - is(notNullValue())); - assertThat(provider.getApplicationDataDictionary(new ApplVerID(ApplVerID.FIX40)), - is(notNullValue())); + DataDictionaryProvider provider = session.getDataDictionaryProvider(); + assertThat(provider.getSessionDataDictionary(sessionID.getBeginString()), + is(notNullValue())); + + assertThat(provider.getApplicationDataDictionary(new ApplVerID(ApplVerID.FIX42)), + is(notNullValue())); + assertThat(provider.getApplicationDataDictionary(new ApplVerID(ApplVerID.FIX40)), + is(notNullValue())); + } } @Test public void testPreFixtDataDictionaryConfiguration() throws Exception { settings.setBool(sessionID, Session.SETTING_USE_DATA_DICTIONARY, true); - Session session = factory.create(sessionID, settings); + try (Session session = factory.create(sessionID, settings)) { - DataDictionaryProvider provider = session.getDataDictionaryProvider(); - assertThat(provider.getSessionDataDictionary(sessionID.getBeginString()), - is(notNullValue())); - assertThat(provider.getApplicationDataDictionary(new ApplVerID(ApplVerID.FIX42)), - is(notNullValue())); + DataDictionaryProvider provider = session.getDataDictionaryProvider(); + assertThat(provider.getSessionDataDictionary(sessionID.getBeginString()), + is(notNullValue())); + assertThat(provider.getApplicationDataDictionary(new ApplVerID(ApplVerID.FIX42)), + is(notNullValue())); + } } @Test @@ -181,13 +190,15 @@ public void testIncorrectTimeValues() throws Exception { @Test public void testTestRequestDelayMultiplier() throws Exception { settings.setString(sessionID, Session.SETTING_TEST_REQUEST_DELAY_MULTIPLIER, "0.37"); - Session session = factory.create(sessionID, settings); - assertEquals(0.37, session.getTestRequestDelayMultiplier(), 0); + try (Session session = factory.create(sessionID, settings)) { + assertEquals(0.37, session.getTestRequestDelayMultiplier(), 0); + } } private void createSessionAndAssertConfigError(String message, String pattern) { + Session session = null; try { - factory.create(sessionID, settings); + session = factory.create(sessionID, settings); fail(message); } catch (ConfigError e) { if (pattern != null) { @@ -196,6 +207,14 @@ private void createSessionAndAssertConfigError(String message, String pattern) { assertTrue("exception message not matched, expected: " + pattern + ", got: " + e.getMessage(), m.matches()); } + } finally { + if (session != null) { + try { + session.close(); + } catch (IOException ex) { + // ignore + } + } } } @@ -214,7 +233,8 @@ private void setUpDefaultSettings(SessionID sessionID) { @Test public void testReconnectIntervalInDefaultSession() throws Exception { settings.setString(sessionID, "ReconnectInterval", "2x5;3x15"); - factory.create(sessionID, settings); + Session session = factory.create(sessionID, settings); + session.close(); } @Test diff --git a/quickfixj-core/src/test/java/quickfix/FileLogTest.java b/quickfixj-core/src/test/java/quickfix/FileLogTest.java index 109964b64..cf524424c 100644 --- a/quickfixj-core/src/test/java/quickfix/FileLogTest.java +++ b/quickfixj-core/src/test/java/quickfix/FileLogTest.java @@ -202,14 +202,15 @@ public void testLogErrorWhenFilesystemRemoved() throws IOException { settings.setBool(sessionID, FileLogFactory.SETTING_INCLUDE_MILLIS_IN_TIMESTAMP, false); FileLogFactory factory = new FileLogFactory(settings); - Session session = new Session(new UnitTestApplication(), new MemoryStoreFactory(), + try (Session session = new Session(new UnitTestApplication(), new MemoryStoreFactory(), sessionID, new DefaultDataDictionaryProvider(), null, factory, - new DefaultMessageFactory(), 0); - Session.registerSession(session); - - FileLog log = (FileLog) session.getLog(); - log.close(); - log.logIncoming("test"); - // no stack overflow exception thrown + new DefaultMessageFactory(), 0)) { + Session.registerSession(session); + + FileLog log = (FileLog) session.getLog(); + log.close(); + log.logIncoming("test"); + // no stack overflow exception thrown + } } } diff --git a/quickfixj-core/src/test/java/quickfix/JdbcLogTest.java b/quickfixj-core/src/test/java/quickfix/JdbcLogTest.java index ec50a5da1..9c1d5147b 100644 --- a/quickfixj-core/src/test/java/quickfix/JdbcLogTest.java +++ b/quickfixj-core/src/test/java/quickfix/JdbcLogTest.java @@ -26,14 +26,25 @@ import javax.sql.DataSource; -import junit.framework.TestCase; - -public class JdbcLogTest extends TestCase { +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNotNull; +import static junit.framework.TestCase.assertTrue; +import static junit.framework.TestCase.fail; +import org.junit.After; +import org.junit.Test; + +public class JdbcLogTest { private JdbcLog log; private JdbcLogFactory logFactory; private Connection connection; private SessionID sessionID; + @After + public void tearDown() { + Session.unregisterSession(sessionID, true); + } + + @Test public void testLog() throws Exception { doLogTest(null); } @@ -60,6 +71,7 @@ private void doLogTest(DataSource dataSource) throws ClassNotFoundException, SQL assertEquals(0, getRowCount(connection, "event_log")); } + @Test public void testLogWithHeartbeatFiltering() throws Exception { setUpJdbcLog(false, null); @@ -83,6 +95,7 @@ public void testLogWithHeartbeatFiltering() throws Exception { * (such as we can't connect ot the DB, or the tables are missing) and doesn't try * to print failing exceptions recursively until the stack overflows */ + @Test public void testHandlesRecursivelyFailingException() throws Exception { setUpJdbcLog(false, null); diff --git a/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java b/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java index 48cad91c5..ebebb5530 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionDisconnectConcurrentlyTest.java @@ -258,51 +258,52 @@ public void onLogout(SessionID sessionId) { }; final SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX44, "SENDER", "TARGET"); - final Session session = new SessionFactoryTestSupport.Builder() + try (Session session = new SessionFactoryTestSupport.Builder() .setSessionId(sessionID) .setApplication(application) .setLogFactory(null) .setResetOnLogon(false) .setIsInitiator(true) - .build(); - final UnitTestResponder responder = new UnitTestResponder(); - session.setResponder(responder); - session.addStateListener(responder); - session.logon(); - session.next(); - - final Message logonRequest = new Message(responder.sentMessageData); - - final Message logonResponse = new DefaultMessageFactory().create(sessionID.getBeginString(), MsgType.LOGON); - logonResponse.setInt(EncryptMethod.FIELD, EncryptMethod.NONE_OTHER); - logonResponse.setInt(HeartBtInt.FIELD, logonRequest.getInt(HeartBtInt.FIELD)); - - final Message.Header header = logonResponse.getHeader(); - header.setString(BeginString.FIELD, sessionID.getBeginString()); - header.setString(SenderCompID.FIELD, sessionID.getSenderCompID()); - header.setString(TargetCompID.FIELD, sessionID.getTargetCompID()); - header.setInt(MsgSeqNum.FIELD, 1); - header.setUtcTimeStamp(SendingTime.FIELD, SystemTime.getLocalDateTime(), true); - - final PausableThreadPoolExecutor ptpe = new PausableThreadPoolExecutor(); - ptpe.pause(); - - for (int j=0; j<1000; j++) { - final Thread thread = new Thread(() -> { - try { - session.disconnect("No reason", false); - } catch (IOException e) { - e.printStackTrace(); - } - }, "disconnectThread"+j); - thread.setDaemon(true); - ptpe.submit(thread); + .build()) { + final UnitTestResponder responder = new UnitTestResponder(); + session.setResponder(responder); + session.addStateListener(responder); + session.logon(); + session.next(); + + final Message logonRequest = new Message(responder.sentMessageData); + + final Message logonResponse = new DefaultMessageFactory().create(sessionID.getBeginString(), MsgType.LOGON); + logonResponse.setInt(EncryptMethod.FIELD, EncryptMethod.NONE_OTHER); + logonResponse.setInt(HeartBtInt.FIELD, logonRequest.getInt(HeartBtInt.FIELD)); + + final Message.Header header = logonResponse.getHeader(); + header.setString(BeginString.FIELD, sessionID.getBeginString()); + header.setString(SenderCompID.FIELD, sessionID.getSenderCompID()); + header.setString(TargetCompID.FIELD, sessionID.getTargetCompID()); + header.setInt(MsgSeqNum.FIELD, 1); + header.setUtcTimeStamp(SendingTime.FIELD, SystemTime.getLocalDateTime(), true); + + final PausableThreadPoolExecutor ptpe = new PausableThreadPoolExecutor(); + ptpe.pause(); + + for (int j=0; j<1000; j++) { + final Thread thread = new Thread(() -> { + try { + session.disconnect("No reason", false); + } catch (IOException e) { + e.printStackTrace(); + } + }, "disconnectThread"+j); + thread.setDaemon(true); + ptpe.submit(thread); + } + + ptpe.resume(); + ptpe.awaitTermination(2, TimeUnit.SECONDS); + ptpe.shutdownNow(); + assertEquals(1, onLogoutCount.intValue()); } - - ptpe.resume(); - ptpe.awaitTermination(2, TimeUnit.SECONDS); - ptpe.shutdownNow(); - assertEquals(1, onLogoutCount.intValue()); } private class UnitTestResponder implements Responder, SessionStateListener { diff --git a/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java b/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java index 84acd529c..41543d6ea 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionDisconnectTest.java @@ -46,27 +46,26 @@ public void fromAdmin(final Message message, final SessionID sessionId) throws F super.fromAdmin(message, sessionId); } }; - final Session session = buildSession(application, storeMessageLatch, sentLogoutLatch); - - final MessageStore messageStore = session.getStore(); - checkNextSeqNums(messageStore, 1, 1); - - session.logon(); - - processOnSeparateThread(session::next); - assertTrue(String.format("Message not stored within %s secs", TIMEOUT_SECS), storeMessageLatch.await(TIMEOUT_SECS, TimeUnit.SECONDS)); - assertEquals(1, application.lastToAdminMessage().getHeader().getField(new MsgSeqNum()).getValue()); - checkNextSeqNums(messageStore, 1, 1); - - processOnSeparateThread(() -> { - storeMessageLatch.await(TIMEOUT_SECS, TimeUnit.SECONDS); - session.next(createLogonResponse()); - }); - assertTrue(String.format("Logon response not received within %s secs", TIMEOUT_SECS), receiveLogonResponseLatch.await(TIMEOUT_SECS, TimeUnit.SECONDS)); - assertTrue(String.format("Logout/SequenceReset not sent %s secs", TIMEOUT_SECS * 2), sentLogoutLatch.await(TIMEOUT_SECS * 2, TimeUnit.SECONDS)); - checkNextSeqNums(messageStore, 2, 2); - - session.close(); + try (Session session = buildSession(application, storeMessageLatch, sentLogoutLatch)) { + + final MessageStore messageStore = session.getStore(); + checkNextSeqNums(messageStore, 1, 1); + + session.logon(); + + processOnSeparateThread(session::next); + assertTrue(String.format("Message not stored within %s secs", TIMEOUT_SECS), storeMessageLatch.await(TIMEOUT_SECS, TimeUnit.SECONDS)); + assertEquals(1, application.lastToAdminMessage().getHeader().getField(new MsgSeqNum()).getValue()); + checkNextSeqNums(messageStore, 1, 1); + + processOnSeparateThread(() -> { + storeMessageLatch.await(TIMEOUT_SECS, TimeUnit.SECONDS); + session.next(createLogonResponse()); + }); + assertTrue(String.format("Logon response not received within %s secs", TIMEOUT_SECS), receiveLogonResponseLatch.await(TIMEOUT_SECS, TimeUnit.SECONDS)); + assertTrue(String.format("Logout/SequenceReset not sent %s secs", TIMEOUT_SECS * 2), sentLogoutLatch.await(TIMEOUT_SECS * 2, TimeUnit.SECONDS)); + checkNextSeqNums(messageStore, 2, 2); + } } private void checkNextSeqNums(final MessageStore messageStore, final int nextTarget, final int nextSender) throws IOException { diff --git a/quickfixj-core/src/test/java/quickfix/SessionResetTest.java b/quickfixj-core/src/test/java/quickfix/SessionResetTest.java index 77c79b537..f83cc7172 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionResetTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionResetTest.java @@ -32,59 +32,60 @@ public void testSessionResetDeadlock() throws Exception { final UnitTestApplication application = new UnitTestApplication(); final SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX44, "SENDER", "TARGET"); - final Session session = SessionFactoryTestSupport.createSession(sessionID, - application, true, false); - final UnitTestResponder responder = new UnitTestResponder(); - session.setResponder(responder); - session.addStateListener(responder); - session.logon(); - session.next(); - - assertFalse(responder.onResetCalled); - - final Message logonRequest = new Message(responder.sentMessageData); - final Message logonResponse = new DefaultMessageFactory().create( - sessionID.getBeginString(), MsgType.LOGON); - logonResponse.setInt(EncryptMethod.FIELD, EncryptMethod.NONE_OTHER); - logonResponse.setInt(HeartBtInt.FIELD, logonRequest.getInt(HeartBtInt.FIELD)); - - final Message.Header header = logonResponse.getHeader(); - header.setString(BeginString.FIELD, sessionID.getBeginString()); - header.setString(SenderCompID.FIELD, sessionID.getSenderCompID()); - header.setString(TargetCompID.FIELD, sessionID.getTargetCompID()); - header.setInt(MsgSeqNum.FIELD, 1); - header.setUtcTimeStamp(SendingTime.FIELD, SystemTime.getLocalDateTime(), true); - - Thread resetThread = new Thread(() -> { - try { - session.reset(); - } catch (IOException e) { - e.printStackTrace(); - } - }, "SessionReset"); - resetThread.setDaemon(true); - - Thread messageSender = new Thread(() -> { - for (int i = 2; i <= NUMBER_OF_ADMIN_MESSAGES; i++) { - session.send(createAdminMessage(i)); - } - }, "SessionSend"); - messageSender.setDaemon(true); - - // submit threads to pausable executor and try to let them start at the same time - PausableThreadPoolExecutor ptpe = new PausableThreadPoolExecutor(); - ptpe.pause(); - ptpe.submit(messageSender); - ptpe.submit(resetThread); - ptpe.resume(); - ptpe.awaitTermination(2, TimeUnit.SECONDS); - - ThreadMXBean bean = ManagementFactory.getThreadMXBean(); - long[] threadIds = bean.findDeadlockedThreads(); - assertNull("no threads should be deadlocked", threadIds); - assertTrue("session should have been reset", responder.onResetCalled); - - ptpe.shutdownNow(); + try (Session session = SessionFactoryTestSupport.createSession(sessionID, + application, true, false)) { + final UnitTestResponder responder = new UnitTestResponder(); + session.setResponder(responder); + session.addStateListener(responder); + session.logon(); + session.next(); + + assertFalse(responder.onResetCalled); + + final Message logonRequest = new Message(responder.sentMessageData); + final Message logonResponse = new DefaultMessageFactory().create( + sessionID.getBeginString(), MsgType.LOGON); + logonResponse.setInt(EncryptMethod.FIELD, EncryptMethod.NONE_OTHER); + logonResponse.setInt(HeartBtInt.FIELD, logonRequest.getInt(HeartBtInt.FIELD)); + + final Message.Header header = logonResponse.getHeader(); + header.setString(BeginString.FIELD, sessionID.getBeginString()); + header.setString(SenderCompID.FIELD, sessionID.getSenderCompID()); + header.setString(TargetCompID.FIELD, sessionID.getTargetCompID()); + header.setInt(MsgSeqNum.FIELD, 1); + header.setUtcTimeStamp(SendingTime.FIELD, SystemTime.getLocalDateTime(), true); + + Thread resetThread = new Thread(() -> { + try { + session.reset(); + } catch (IOException e) { + e.printStackTrace(); + } + }, "SessionReset"); + resetThread.setDaemon(true); + + Thread messageSender = new Thread(() -> { + for (int i = 2; i <= NUMBER_OF_ADMIN_MESSAGES; i++) { + session.send(createAdminMessage(i)); + } + }, "SessionSend"); + messageSender.setDaemon(true); + + // submit threads to pausable executor and try to let them start at the same time + PausableThreadPoolExecutor ptpe = new PausableThreadPoolExecutor(); + ptpe.pause(); + ptpe.submit(messageSender); + ptpe.submit(resetThread); + ptpe.resume(); + ptpe.awaitTermination(2, TimeUnit.SECONDS); + + ThreadMXBean bean = ManagementFactory.getThreadMXBean(); + long[] threadIds = bean.findDeadlockedThreads(); + assertNull("no threads should be deadlocked", threadIds); + assertTrue("session should have been reset", responder.onResetCalled); + + ptpe.shutdownNow(); + } } private Message createAdminMessage(int sequence) { diff --git a/quickfixj-core/src/test/java/quickfix/SessionTest.java b/quickfixj-core/src/test/java/quickfix/SessionTest.java index a6e6fe5c6..9d9ded035 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionTest.java @@ -53,6 +53,8 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.*; import static quickfix.SessionFactoryTestSupport.createSession; +import quickfix.field.CheckSum; +import quickfix.field.NextExpectedMsgSeqNum; /** * Note: most session tests are in the form of acceptance tests. @@ -80,17 +82,15 @@ public void testDisposalOfFileResources() throws Exception { final CloseableLog mockLog = mock(CloseableLog.class); stub(mockLogFactory.create(sessionID)).toReturn(mockLog); - final Session session = new Session(application, + try (Session session = new Session(application, mockMessageStoreFactory, sessionID, null, null, mockLogFactory, new DefaultMessageFactory(), 30, false, 30, UtcTimestampPrecision.MILLIS, true, false, false, false, false, false, true, false, 1.5, null, true, new int[] { 5 }, false, false, false, true, false, true, false, - null, true, 0, false, false); - - // Simulate socket disconnect - session.setResponder(null); - - session.close(); + null, true, 0, false, false)) { + // Simulate socket disconnect + session.setResponder(null); + } verify(mockMessageStore).close(); verifyNoMoreInteractions(mockMessageStore); @@ -123,22 +123,20 @@ public void testNondisposableFileResources() throws Exception { final Log mockLog = mock(Log.class); stub(mockLogFactory.create(sessionID)).toReturn(mockLog); - final Session session = new Session(application, + try (Session session = new Session(application, mockMessageStoreFactory, sessionID, null, null, mockLogFactory, new DefaultMessageFactory(), 30, false, 30, UtcTimestampPrecision.MILLIS, true, false, false, false, false, false, true, false, 1.5, null, true, new int[] { 5 }, false, false, false, true, false, true, false, - null, true, 0, false, false); - - // Simulate socket disconnect - session.setResponder(null); - - verifyNoMoreInteractions(mockMessageStore); - - verify(mockLog, atLeastOnce()).onEvent(anyString()); - verifyNoMoreInteractions(mockLog); - - session.close(); + null, true, 0, false, false)) { + // Simulate socket disconnect + session.setResponder(null); + + verifyNoMoreInteractions(mockMessageStore); + + verify(mockLog, atLeastOnce()).onEvent(anyString()); + verifyNoMoreInteractions(mockLog); + } } private interface CloseableMessageStore extends MessageStore, Closeable { @@ -154,38 +152,37 @@ public void testSessionWithoutValidateSequenceNumbers() throws Exception { final SessionID sessionID = new SessionID( FixVersions.BEGINSTRING_FIX44, "SENDER", "TARGET"); - final Session session = createSession(sessionID, application, true, - true, false); - - final UnitTestResponder responder = new UnitTestResponder(); - session.setResponder(responder); - - session.logon(); - session.next(); - - final Message logonRequest = new Message(responder.sentMessageData); - session.next(createLogonResponse(sessionID, logonRequest, 1)); - - assertEquals( - 1, - application.lastToAdminMessage().getHeader() - .getInt(MsgSeqNum.FIELD)); - assertEquals(2, session.getStore().getNextTargetMsgSeqNum()); - assertEquals(2, session.getStore().getNextSenderMsgSeqNum()); - - session.next(createHeartbeatMessage(1002)); - assertFalse(ResendRequest.MSGTYPE.equals(application - .lastToAdminMessage().getHeader().getString(MsgType.FIELD))); - - session.next(createHeartbeatMessage(1003)); - assertFalse(ResendRequest.MSGTYPE.equals(application - .lastToAdminMessage().getHeader().getString(MsgType.FIELD))); - - session.next(createHeartbeatMessage(1001)); - assertFalse(ResendRequest.MSGTYPE.equals(application - .lastToAdminMessage().getHeader().getString(MsgType.FIELD))); - - session.close(); + try (Session session = createSession(sessionID, application, true, + true, false)) { + + final UnitTestResponder responder = new UnitTestResponder(); + session.setResponder(responder); + + session.logon(); + session.next(); + + final Message logonRequest = new Message(responder.sentMessageData); + session.next(createLogonResponse(sessionID, logonRequest, 1)); + + assertEquals( + 1, + application.lastToAdminMessage().getHeader() + .getInt(MsgSeqNum.FIELD)); + assertEquals(2, session.getStore().getNextTargetMsgSeqNum()); + assertEquals(2, session.getStore().getNextSenderMsgSeqNum()); + + session.next(createHeartbeatMessage(1002)); + assertFalse(ResendRequest.MSGTYPE.equals(application + .lastToAdminMessage().getHeader().getString(MsgType.FIELD))); + + session.next(createHeartbeatMessage(1003)); + assertFalse(ResendRequest.MSGTYPE.equals(application + .lastToAdminMessage().getHeader().getString(MsgType.FIELD))); + + session.next(createHeartbeatMessage(1001)); + assertFalse(ResendRequest.MSGTYPE.equals(application + .lastToAdminMessage().getHeader().getString(MsgType.FIELD))); + } } // QFJ-703 @@ -265,23 +262,22 @@ public void testInferResetSeqNumAcceptedWithNonInitialSequenceNumber() final SessionID sessionID = new SessionID( FixVersions.BEGINSTRING_FIX44, "SENDER", "TARGET"); - final Session session = createSession(sessionID, application, true, - true); - - final UnitTestResponder responder = new UnitTestResponder(); - session.setResponder(responder); - - session.logon(); - session.next(); - - final Message logonRequest = new Message(responder.sentMessageData); - session.next(createLogonResponse(sessionID, logonRequest, 2)); - - assertTrue( - "Should not infer a reset when the sequence number is not one", - responder.disconnectCalled); - - session.close(); + try (Session session = createSession(sessionID, application, true, + true)) { + + final UnitTestResponder responder = new UnitTestResponder(); + session.setResponder(responder); + + session.logon(); + session.next(); + + final Message logonRequest = new Message(responder.sentMessageData); + session.next(createLogonResponse(sessionID, logonRequest, 2)); + + assertTrue( + "Should not infer a reset when the sequence number is not one", + responder.disconnectCalled); + } } @Test @@ -291,24 +287,23 @@ public void testInferResetSeqNumAccepted() throws Exception { final SessionID sessionID = new SessionID( FixVersions.BEGINSTRING_FIX44, "SENDER", "TARGET"); - final Session session = createSession(sessionID, application, true, - true); - - final UnitTestResponder responder = new UnitTestResponder(); - session.setResponder(responder); - - session.logon(); - session.next(); - - final Message logonRequest = new Message(responder.sentMessageData); - final Message logonResponse = createLogonResponse(sessionID, - logonRequest, 1); - session.next(logonResponse); - - assertFalse("Should not disconnect when an accepted reset is inferred", - responder.disconnectCalled); - - session.close(); + try (Session session = createSession(sessionID, application, true, + true)) { + + final UnitTestResponder responder = new UnitTestResponder(); + session.setResponder(responder); + + session.logon(); + session.next(); + + final Message logonRequest = new Message(responder.sentMessageData); + final Message logonResponse = createLogonResponse(sessionID, + logonRequest, 1); + session.next(logonResponse); + + assertFalse("Should not disconnect when an accepted reset is inferred", + responder.disconnectCalled); + } } @Test @@ -318,34 +313,33 @@ public void testUnsupportedVersion() throws Exception { final UnitTestApplication application = new UnitTestApplication(); final SessionID sessionID = new SessionID( FixVersions.BEGINSTRING_FIX44, "SENDER", "TARGET"); - final Session session = createSession(sessionID, application, true, - true); - - final UnitTestResponder responder = new UnitTestResponder(); - session.setResponder(responder); - - session.logon(); - session.next(); - - final Message logonRequest = new Message(responder.sentMessageData); - final Message logonResponse = createLogonResponse(sessionID, - logonRequest, 1); - session.next(logonResponse); - - final News newsMessage = createAppMessage(2); - // set a BeginString unsupported by the session - newsMessage.getHeader().setString(BeginString.FIELD, - FixVersions.BEGINSTRING_FIX40); - session.next(newsMessage); - final Message lastToAdminMessage = application.lastToAdminMessage(); - assertEquals(MsgType.LOGOUT, - lastToAdminMessage.getHeader().getString(MsgType.FIELD)); - assertEquals( - "Incorrect BeginString: Message version 'FIX.4.0' does not match the session version 'FIX.4.4'", - lastToAdminMessage.getString(Text.FIELD)); - assertTrue(responder.disconnectCalled); - - session.close(); + try (Session session = createSession(sessionID, application, true, + true)) { + + final UnitTestResponder responder = new UnitTestResponder(); + session.setResponder(responder); + + session.logon(); + session.next(); + + final Message logonRequest = new Message(responder.sentMessageData); + final Message logonResponse = createLogonResponse(sessionID, + logonRequest, 1); + session.next(logonResponse); + + final News newsMessage = createAppMessage(2); + // set a BeginString unsupported by the session + newsMessage.getHeader().setString(BeginString.FIELD, + FixVersions.BEGINSTRING_FIX40); + session.next(newsMessage); + final Message lastToAdminMessage = application.lastToAdminMessage(); + assertEquals(MsgType.LOGOUT, + lastToAdminMessage.getHeader().getString(MsgType.FIELD)); + assertEquals( + "Incorrect BeginString: Message version 'FIX.4.0' does not match the session version 'FIX.4.4'", + lastToAdminMessage.getString(Text.FIELD)); + assertTrue(responder.disconnectCalled); + } } // QFJ-650 @@ -353,39 +347,38 @@ public void testUnsupportedVersion() throws Exception { public void testLogoutOnMissingMsgSeqNum() throws Exception { final Application application = new UnitTestApplication(); - final Session session = setUpSession(application, false, - new UnitTestResponder()); - final SessionState state = getSessionState(session); - - assertEquals(1, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - - logonTo(session); - - assertEquals(2, state.getNextSenderMsgSeqNum()); - assertEquals(2, state.getNextTargetMsgSeqNum()); - - final TestRequest testRequest = (TestRequest) createAdminMessage(2); - session.next(testRequest); - - assertEquals(3, state.getNextSenderMsgSeqNum()); - assertEquals(3, state.getNextTargetMsgSeqNum()); - - testRequest.getHeader().removeField(MsgSeqNum.FIELD); - // this should disconnect the session due to the missing MsgSeqNum - session.next(testRequest); - assertFalse("Session should be disconnected", session.isLoggedOn()); - - // make sure that the target seq num has not been incremented - assertEquals(4, state.getNextSenderMsgSeqNum()); - assertEquals(3, state.getNextTargetMsgSeqNum()); - session.setResponder(new UnitTestResponder()); - logonTo(session, 3); - assertEquals(5, state.getNextSenderMsgSeqNum()); - assertEquals(4, state.getNextTargetMsgSeqNum()); - assertTrue("Session should be connected", session.isLoggedOn()); - - session.close(); + try (Session session = setUpSession(application, false, + new UnitTestResponder())) { + final SessionState state = getSessionState(session); + + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + logonTo(session); + + assertEquals(2, state.getNextSenderMsgSeqNum()); + assertEquals(2, state.getNextTargetMsgSeqNum()); + + final TestRequest testRequest = (TestRequest) createAdminMessage(2); + session.next(testRequest); + + assertEquals(3, state.getNextSenderMsgSeqNum()); + assertEquals(3, state.getNextTargetMsgSeqNum()); + + testRequest.getHeader().removeField(MsgSeqNum.FIELD); + // this should disconnect the session due to the missing MsgSeqNum + session.next(testRequest); + assertFalse("Session should be disconnected", session.isLoggedOn()); + + // make sure that the target seq num has not been incremented + assertEquals(4, state.getNextSenderMsgSeqNum()); + assertEquals(3, state.getNextTargetMsgSeqNum()); + session.setResponder(new UnitTestResponder()); + logonTo(session, 3); + assertEquals(5, state.getNextSenderMsgSeqNum()); + assertEquals(4, state.getNextTargetMsgSeqNum()); + assertTrue("Session should be connected", session.isLoggedOn()); + } } // QFJ-750 @@ -393,72 +386,70 @@ public void testLogoutOnMissingMsgSeqNum() throws Exception { public void testLogoutMsgSeqNumTooHighOrLow() throws Exception { final Application application = new UnitTestApplication(); - final Session session = setUpSession(application, false, - new UnitTestResponder()); - final SessionState state = getSessionState(session); - - assertEquals(1, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - - logonTo(session); - - assertEquals(2, state.getNextSenderMsgSeqNum()); - assertEquals(2, state.getNextTargetMsgSeqNum()); - - final TestRequest testRequest = (TestRequest) createAdminMessage(2); - session.next(testRequest); - - assertEquals(3, state.getNextSenderMsgSeqNum()); - assertEquals(3, state.getNextTargetMsgSeqNum()); - - logoutFrom(session, 100); - assertFalse("Session should be disconnected", session.isLoggedOn()); - - // make sure that the target seq num has not been incremented - assertEquals(4, state.getNextSenderMsgSeqNum()); - assertEquals(3, state.getNextTargetMsgSeqNum()); - session.setResponder(new UnitTestResponder()); - logonTo(session, 3); - assertEquals(5, state.getNextSenderMsgSeqNum()); - assertEquals(4, state.getNextTargetMsgSeqNum()); - assertTrue("Session should be connected", session.isLoggedOn()); - - logoutFrom(session, 1); - // make sure that the target seq num has not been incremented - assertEquals(6, state.getNextSenderMsgSeqNum()); - assertEquals(4, state.getNextTargetMsgSeqNum()); - - session.close(); + try (Session session = setUpSession(application, false, + new UnitTestResponder())) { + final SessionState state = getSessionState(session); + + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + logonTo(session); + + assertEquals(2, state.getNextSenderMsgSeqNum()); + assertEquals(2, state.getNextTargetMsgSeqNum()); + + final TestRequest testRequest = (TestRequest) createAdminMessage(2); + session.next(testRequest); + + assertEquals(3, state.getNextSenderMsgSeqNum()); + assertEquals(3, state.getNextTargetMsgSeqNum()); + + logoutFrom(session, 100); + assertFalse("Session should be disconnected", session.isLoggedOn()); + + // make sure that the target seq num has not been incremented + assertEquals(4, state.getNextSenderMsgSeqNum()); + assertEquals(3, state.getNextTargetMsgSeqNum()); + session.setResponder(new UnitTestResponder()); + logonTo(session, 3); + assertEquals(5, state.getNextSenderMsgSeqNum()); + assertEquals(4, state.getNextTargetMsgSeqNum()); + assertTrue("Session should be connected", session.isLoggedOn()); + + logoutFrom(session, 1); + // make sure that the target seq num has not been incremented + assertEquals(6, state.getNextSenderMsgSeqNum()); + assertEquals(4, state.getNextTargetMsgSeqNum()); + } } @Test public void testRejectMsgSeqNumTooHighOrLow() throws Exception { final Application application = new UnitTestApplication(); - final Session session = setUpSession(application, false, - new UnitTestResponder()); - final SessionState state = getSessionState(session); - - assertEquals(1, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - - logonTo(session); - - assertEquals(2, state.getNextSenderMsgSeqNum()); - assertEquals(2, state.getNextTargetMsgSeqNum()); - - processMessage(session, createReject(2, 100)); - assertEquals(3, state.getNextTargetMsgSeqNum()); - - // Reject with unexpected seqnum should not increment target seqnum - processMessage(session, createReject(50, 100)); - assertEquals(3, state.getNextTargetMsgSeqNum()); - - // Reject with unexpected seqnum should not increment target seqnum - processMessage(session, createReject(1, 100)); - assertEquals(3, state.getNextTargetMsgSeqNum()); - - session.close(); + try (Session session = setUpSession(application, false, + new UnitTestResponder())) { + final SessionState state = getSessionState(session); + + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + logonTo(session); + + assertEquals(2, state.getNextSenderMsgSeqNum()); + assertEquals(2, state.getNextTargetMsgSeqNum()); + + processMessage(session, createReject(2, 100)); + assertEquals(3, state.getNextTargetMsgSeqNum()); + + // Reject with unexpected seqnum should not increment target seqnum + processMessage(session, createReject(50, 100)); + assertEquals(3, state.getNextTargetMsgSeqNum()); + + // Reject with unexpected seqnum should not increment target seqnum + processMessage(session, createReject(1, 100)); + assertEquals(3, state.getNextTargetMsgSeqNum()); + } } /** @@ -481,28 +472,27 @@ public void testLogonIsFirstMessageOnAcceptor() throws Exception { // Session gets constructed, triggering a reset final UnitTestApplication application = new UnitTestApplication(); - final Session session = setUpFileStoreSession(application, false, - new UnitTestResponder(), settings, sessionID); - final SessionState state = getSessionState(session); - - assertEquals(1, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - - logonTo(session); - - // we should only answer with a Logon message - assertEquals(1, application.toAdminMessages.size()); - assertEquals(MsgType.LOGON, application.toAdminMessages.get(0) - .getHeader().getString(MsgType.FIELD)); - - // no reset should have been triggered by QF/J after the Logon attempt - assertEquals(0, application.sessionResets); - assertTrue("Session should be connected", session.isLoggedOn()); - - assertEquals(2, state.getNextSenderMsgSeqNum()); - assertEquals(2, state.getNextTargetMsgSeqNum()); - - session.close(); + try (Session session = setUpFileStoreSession(application, false, + new UnitTestResponder(), settings, sessionID)) { + final SessionState state = getSessionState(session); + + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + logonTo(session); + + // we should only answer with a Logon message + assertEquals(1, application.toAdminMessages.size()); + assertEquals(MsgType.LOGON, application.toAdminMessages.get(0) + .getHeader().getString(MsgType.FIELD)); + + // no reset should have been triggered by QF/J after the Logon attempt + assertEquals(0, application.sessionResets); + assertTrue("Session should be connected", session.isLoggedOn()); + + assertEquals(2, state.getNextSenderMsgSeqNum()); + assertEquals(2, state.getNextTargetMsgSeqNum()); + } } // QFJ-773 @@ -526,76 +516,75 @@ public void testLogonLogoutOnAcceptor() throws Exception { // Session gets constructed, triggering a reset final UnitTestApplication application = new UnitTestApplication(); final UnitTestResponder responder = new UnitTestResponder(); - final Session session = setUpFileStoreSession(application, false, - responder, settings, sessionID); - session.addStateListener(application); - final SessionState state = getSessionState(session); - - assertEquals(1, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - - logonTo(session); - - // we should only answer with a Logon message - assertEquals(1, application.toAdminMessages.size()); - assertEquals(MsgType.LOGON, application.toAdminMessages.get(0) - .getHeader().getString(MsgType.FIELD)); - - // no reset should have been triggered by QF/J after the Logon attempt - assertEquals(0, application.sessionResets); - assertTrue("Session should be connected", session.isLoggedOn()); - - assertEquals(2, state.getNextSenderMsgSeqNum()); - assertEquals(2, state.getNextTargetMsgSeqNum()); - - session.next(); - // increment time to force logout and reset - systemTimeSource.increment(3700000); - session.next(); - assertEquals(SystemTime.getDate(), state.getCreationTime()); - systemTimeSource.increment(10000); - session.next(); - systemTimeSource.increment(10000); - session.next(); - systemTimeSource.increment(10000); - session.next(); - systemTimeSource.increment(10000); - - // we should only reset once outside of the session time window - assertEquals(1, application.sessionResets); - assertFalse("Session should be disconnected", session.isLoggedOn()); - - assertEquals(1, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - - session.setResponder(responder); - // this should get rejected since we are outside of the session time - // window - logonTo(session); - assertFalse("Session should be disconnected", session.isLoggedOn()); - - // if we now logon to the session, it will be considered new - // and a reset will be done - session.setResponder(responder); - session.next(); - assertEquals(2, application.sessionResets); - systemTimeSource.increment(86100000); // jump one day but stay inside - // session time - session.next(); - logonTo(session); - assertTrue("Session should be connected", session.isLoggedOn()); - assertEquals(SystemTime.getDate(), state.getCreationTime()); - - // check that the creation time is not updated inside of the session - // time window - int delta = 60000; - systemTimeSource.increment(delta); - assertTrue(SystemTime.getDate().getTime() - - state.getCreationTime().getTime() == delta); - session.next(); - assertTrue("Session should be connected", session.isLoggedOn()); - - session.close(); + try (Session session = setUpFileStoreSession(application, false, + responder, settings, sessionID)) { + session.addStateListener(application); + final SessionState state = getSessionState(session); + + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + logonTo(session); + + // we should only answer with a Logon message + assertEquals(1, application.toAdminMessages.size()); + assertEquals(MsgType.LOGON, application.toAdminMessages.get(0) + .getHeader().getString(MsgType.FIELD)); + + // no reset should have been triggered by QF/J after the Logon attempt + assertEquals(0, application.sessionResets); + assertTrue("Session should be connected", session.isLoggedOn()); + + assertEquals(2, state.getNextSenderMsgSeqNum()); + assertEquals(2, state.getNextTargetMsgSeqNum()); + + session.next(); + // increment time to force logout and reset + systemTimeSource.increment(3700000); + session.next(); + assertEquals(SystemTime.getDate(), state.getCreationTime()); + systemTimeSource.increment(10000); + session.next(); + systemTimeSource.increment(10000); + session.next(); + systemTimeSource.increment(10000); + session.next(); + systemTimeSource.increment(10000); + + // we should only reset once outside of the session time window + assertEquals(1, application.sessionResets); + assertFalse("Session should be disconnected", session.isLoggedOn()); + + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + session.setResponder(responder); + // this should get rejected since we are outside of the session time + // window + logonTo(session); + assertFalse("Session should be disconnected", session.isLoggedOn()); + + // if we now logon to the session, it will be considered new + // and a reset will be done + session.setResponder(responder); + session.next(); + assertEquals(2, application.sessionResets); + systemTimeSource.increment(86100000); // jump one day but stay inside + // session time + session.next(); + logonTo(session); + assertTrue("Session should be connected", session.isLoggedOn()); + assertEquals(SystemTime.getDate(), state.getCreationTime()); + + // check that the creation time is not updated inside of the session + // time window + int delta = 60000; + systemTimeSource.increment(delta); + assertTrue(SystemTime.getDate().getTime() + - state.getCreationTime().getTime() == delta); + session.next(); + assertTrue("Session should be connected", session.isLoggedOn()); + } } @Test @@ -618,56 +607,55 @@ public void testStartOfInitiatorOutsideOfSessionTime() throws Exception { // Session gets constructed, triggering a reset final UnitTestApplication application = new UnitTestApplication(); - final Session session = setUpFileStoreSession(application, true, - new UnitTestResponder(), settings, sessionID); - session.addStateListener(application); - final SessionState state = getSessionState(session); - - assertEquals(1, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - - session.next(); - systemTimeSource.increment(10000); - session.next(); - systemTimeSource.increment(10000); - session.next(); - - // we should send no messages since we are outside of session time - assertEquals(0, application.toAdminMessages.size()); - // no reset should have been triggered by QF/J (since we were not logged - // on) - assertEquals(0, application.sessionResets); - assertEquals(1, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - - // increase time to be within session time - systemTimeSource.increment(1900000); - session.next(); - session.next(); - // we should have sent a Logon since the StartTime has been reached now - assertEquals(1, application.toAdminMessages.size()); - Message logon = application.toAdminMessages.get(0); - assertEquals(MsgType.LOGON, logon.getHeader().getString(MsgType.FIELD)); - assertEquals(2, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - Message createLogonResponse = createLogonResponse(new SessionID( - FixVersions.BEGINSTRING_FIX44, "TARGET", "SENDER"), logon, 1); - session.next(createLogonResponse); - assertTrue(session.isLoggedOn()); - assertEquals(1, application.sessionResets); - - // increase time to be out of session time - systemTimeSource.increment(1900000); - session.next(); - Message logout = application.lastToAdminMessage(); - assertEquals(MsgType.LOGOUT, logout.getHeader() - .getString(MsgType.FIELD)); - assertFalse(session.isLoggedOn()); - assertEquals(1, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - assertEquals(2, application.sessionResets); - - session.close(); + try (Session session = setUpFileStoreSession(application, true, + new UnitTestResponder(), settings, sessionID)) { + session.addStateListener(application); + final SessionState state = getSessionState(session); + + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + session.next(); + systemTimeSource.increment(10000); + session.next(); + systemTimeSource.increment(10000); + session.next(); + + // we should send no messages since we are outside of session time + assertEquals(0, application.toAdminMessages.size()); + // no reset should have been triggered by QF/J (since we were not logged + // on) + assertEquals(0, application.sessionResets); + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + // increase time to be within session time + systemTimeSource.increment(1900000); + session.next(); + session.next(); + // we should have sent a Logon since the StartTime has been reached now + assertEquals(1, application.toAdminMessages.size()); + Message logon = application.toAdminMessages.get(0); + assertEquals(MsgType.LOGON, logon.getHeader().getString(MsgType.FIELD)); + assertEquals(2, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + Message createLogonResponse = createLogonResponse(new SessionID( + FixVersions.BEGINSTRING_FIX44, "TARGET", "SENDER"), logon, 1); + session.next(createLogonResponse); + assertTrue(session.isLoggedOn()); + assertEquals(1, application.sessionResets); + + // increase time to be out of session time + systemTimeSource.increment(1900000); + session.next(); + Message logout = application.lastToAdminMessage(); + assertEquals(MsgType.LOGOUT, logout.getHeader() + .getString(MsgType.FIELD)); + assertFalse(session.isLoggedOn()); + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + assertEquals(2, application.sessionResets); + } } @Test @@ -692,30 +680,29 @@ public void testStartOfInitiatorInsideOfSessionTime() throws Exception { // Session gets constructed, triggering a reset final UnitTestApplication application = new UnitTestApplication(); - final Session session = setUpFileStoreSession(application, true, - new UnitTestResponder(), settings, sessionID); - final SessionState state = getSessionState(session); - - assertEquals(1, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - - session.next(); - systemTimeSource.increment(1000); - session.next(); - systemTimeSource.increment(1000); - session.next(); - - // we should have sent a Logon since we are inside of the SessionTime - assertEquals(1, application.toAdminMessages.size()); - assertEquals(MsgType.LOGON, application.toAdminMessages.get(0) - .getHeader().getString(MsgType.FIELD)); - // no reset should have been triggered by QF/J - assertEquals(0, application.sessionResets); - - assertEquals(2, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - - session.close(); + try (Session session = setUpFileStoreSession(application, true, + new UnitTestResponder(), settings, sessionID)) { + final SessionState state = getSessionState(session); + + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + session.next(); + systemTimeSource.increment(1000); + session.next(); + systemTimeSource.increment(1000); + session.next(); + + // we should have sent a Logon since we are inside of the SessionTime + assertEquals(1, application.toAdminMessages.size()); + assertEquals(MsgType.LOGON, application.toAdminMessages.get(0) + .getHeader().getString(MsgType.FIELD)); + // no reset should have been triggered by QF/J + assertEquals(0, application.sessionResets); + + assertEquals(2, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + } } @Test @@ -740,48 +727,47 @@ public void testSessionNotResetRightAfterLogonOnAcceptor() throws Exception { // Session gets constructed, triggering a reset final UnitTestApplication application = new UnitTestApplication(); - final Session session = setUpFileStoreSession(application, false, - new UnitTestResponder(), settings, sessionID); - session.addStateListener(application); - final SessionState state = getSessionState(session); - - assertEquals(1, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - - session.next(); - - // we should send no messages since we are outside of session time - assertEquals(0, application.toAdminMessages.size()); - // no reset should have been triggered by QF/J (since we were not logged on) - assertEquals(0, application.sessionResets); - assertEquals(1, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - - // increase time to be within session time - systemTimeSource.increment(5000); - // there should be a Logon but no subsequent reset - logonTo(session, 1); - // call next() to provoke SessionTime check which should NOT reset seqnums now - session.next(); - assertEquals(1, application.toAdminMessages.size()); - assertEquals(2, state.getNextSenderMsgSeqNum()); - assertEquals(2, state.getNextTargetMsgSeqNum()); - assertTrue(session.isLoggedOn()); - assertEquals(1, application.sessionResets); - - systemTimeSource.increment(5000); - session.disconnect("test", false); - systemTimeSource.increment(5000); - session.next(); - session.setResponder(new UnitTestResponder()); - - logonTo(session, 2); - session.next(); - - // check that no reset is done on next Logon - assertEquals(1, application.sessionResets); - - session.close(); + try (Session session = setUpFileStoreSession(application, false, + new UnitTestResponder(), settings, sessionID)) { + session.addStateListener(application); + final SessionState state = getSessionState(session); + + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + session.next(); + + // we should send no messages since we are outside of session time + assertEquals(0, application.toAdminMessages.size()); + // no reset should have been triggered by QF/J (since we were not logged on) + assertEquals(0, application.sessionResets); + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + // increase time to be within session time + systemTimeSource.increment(5000); + // there should be a Logon but no subsequent reset + logonTo(session, 1); + // call next() to provoke SessionTime check which should NOT reset seqnums now + session.next(); + assertEquals(1, application.toAdminMessages.size()); + assertEquals(2, state.getNextSenderMsgSeqNum()); + assertEquals(2, state.getNextTargetMsgSeqNum()); + assertTrue(session.isLoggedOn()); + assertEquals(1, application.sessionResets); + + systemTimeSource.increment(5000); + session.disconnect("test", false); + systemTimeSource.increment(5000); + session.next(); + session.setResponder(new UnitTestResponder()); + + logonTo(session, 2); + session.next(); + + // check that no reset is done on next Logon + assertEquals(1, application.sessionResets); + } } @Test @@ -807,51 +793,50 @@ public void testSessionNotResetRightAfterLogonOnInitiator() throws Exception { // Session gets constructed, triggering a reset final UnitTestApplication application = new UnitTestApplication(); UnitTestResponder responder = new UnitTestResponder(); - final Session session = setUpFileStoreSession(application, true, responder, settings, sessionID); - session.addStateListener(application); - final SessionState state = getSessionState(session); - - assertEquals(1, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - - session.next(); - - // we should send no messages since we are outside of session time - assertEquals(0, application.toAdminMessages.size()); - // no reset should have been triggered by QF/J (since we were not logged on) - assertEquals(0, application.sessionResets); - assertEquals(1, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - - // increase time to be almost within session time to check if session needs to be reset - // (will not reset since it is not yet within session time) - systemTimeSource.increment(4500); - session.next(); - // increase time further so that Logon is sent but reset is not done since last check - // of session time was done within one second - systemTimeSource.increment(600); - session.next(); - systemTimeSource.increment(1000); - session.next(createLogonResponse(new SessionID(FixVersions.BEGINSTRING_FIX44, "TARGET", "SENDER"), application.lastToAdminMessage(), 1)); - assertEquals(1, application.toAdminMessages.size()); - assertEquals(2, state.getNextSenderMsgSeqNum()); - assertEquals(2, state.getNextTargetMsgSeqNum()); - assertTrue(session.isLoggedOn()); - assertEquals(1, application.sessionResets); - - systemTimeSource.increment(5000); - session.disconnect("test", false); - systemTimeSource.increment(5000); - session.next(); - responder = new UnitTestResponder(); - session.setResponder(responder); - - session.next(); - session.next(createLogonResponse(new SessionID(FixVersions.BEGINSTRING_FIX44, "TARGET", "SENDER"), application.lastToAdminMessage(), 2)); - // check that no reset is done on next Logon - assertEquals(1, application.sessionResets); - - session.close(); + try (Session session = setUpFileStoreSession(application, true, responder, settings, sessionID)) { + session.addStateListener(application); + final SessionState state = getSessionState(session); + + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + session.next(); + + // we should send no messages since we are outside of session time + assertEquals(0, application.toAdminMessages.size()); + // no reset should have been triggered by QF/J (since we were not logged on) + assertEquals(0, application.sessionResets); + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + // increase time to be almost within session time to check if session needs to be reset + // (will not reset since it is not yet within session time) + systemTimeSource.increment(4500); + session.next(); + // increase time further so that Logon is sent but reset is not done since last check + // of session time was done within one second + systemTimeSource.increment(600); + session.next(); + systemTimeSource.increment(1000); + session.next(createLogonResponse(new SessionID(FixVersions.BEGINSTRING_FIX44, "TARGET", "SENDER"), application.lastToAdminMessage(), 1)); + assertEquals(1, application.toAdminMessages.size()); + assertEquals(2, state.getNextSenderMsgSeqNum()); + assertEquals(2, state.getNextTargetMsgSeqNum()); + assertTrue(session.isLoggedOn()); + assertEquals(1, application.sessionResets); + + systemTimeSource.increment(5000); + session.disconnect("test", false); + systemTimeSource.increment(5000); + session.next(); + responder = new UnitTestResponder(); + session.setResponder(responder); + + session.next(); + session.next(createLogonResponse(new SessionID(FixVersions.BEGINSTRING_FIX44, "TARGET", "SENDER"), application.lastToAdminMessage(), 2)); + // check that no reset is done on next Logon + assertEquals(1, application.sessionResets); + } } @Test @@ -861,73 +846,72 @@ public void testLogonIsAnsweredWithLogoutOnException() throws Exception { final SessionID sessionID = new SessionID( FixVersions.BEGINSTRING_FIX44, "SENDER", "TARGET"); UnitTestApplication application = new UnitTestApplication(); - Session session = SessionFactoryTestSupport.createSession(sessionID, application, - false, false, true, true, null); - UnitTestResponder responder = new UnitTestResponder(); - session.setResponder(responder); - session.logon(); - - session.next(); - Logon logonRequest = new Logon(); - setUpHeader(session.getSessionID(), logonRequest, true, 1); - logonRequest.setInt(HeartBtInt.FIELD, 30); - logonRequest.setString(EncryptMethod.FIELD, ""); - logonRequest.toString(); // calculate length and checksum - session.next(logonRequest); - // session should not be logged on due to empty EncryptMethod - assertFalse(session.isLoggedOn()); - - assertEquals(1, application.lastToAdminMessage().getHeader().getInt(MsgSeqNum.FIELD)); - assertEquals(MsgType.LOGOUT, application.lastToAdminMessage().getHeader().getString(MsgType.FIELD)); - assertEquals(2, session.getStore().getNextTargetMsgSeqNum()); - assertEquals(2, session.getStore().getNextSenderMsgSeqNum()); - - session.setResponder(responder); - session.logon(); - session.next(); - setUpHeader(session.getSessionID(), logonRequest, true, 2); - logonRequest.removeField(EncryptMethod.FIELD); - logonRequest.toString(); // calculate length and checksum - session.next(logonRequest); - // session should not be logged on due to missing EncryptMethod - assertFalse(session.isLoggedOn()); - - assertEquals(2, application.lastToAdminMessage().getHeader().getInt(MsgSeqNum.FIELD)); - assertEquals(MsgType.LOGOUT, application.lastToAdminMessage().getHeader().getString(MsgType.FIELD)); - assertEquals(3, session.getStore().getNextTargetMsgSeqNum()); - assertEquals(3, session.getStore().getNextSenderMsgSeqNum()); - - session.setResponder(responder); - session.logon(); - session.next(); - setUpHeader(session.getSessionID(), logonRequest, true, 3); - logonRequest.setString(EncryptMethod.FIELD, "A"); - logonRequest.toString(); // calculate length and checksum - session.next(logonRequest); - // session should not be logged on due to IncorrectDataFormat - assertFalse(session.isLoggedOn()); - - assertEquals(3, application.lastToAdminMessage().getHeader().getInt(MsgSeqNum.FIELD)); - assertEquals(MsgType.LOGOUT, application.lastToAdminMessage().getHeader().getString(MsgType.FIELD)); - assertEquals(4, session.getStore().getNextTargetMsgSeqNum()); - assertEquals(4, session.getStore().getNextSenderMsgSeqNum()); - - session.setResponder(responder); - session.logon(); - session.next(); - setUpHeader(session.getSessionID(), logonRequest, true, 3); - logonRequest.setString(EncryptMethod.FIELD, "99"); - logonRequest.toString(); // calculate length and checksum - session.next(logonRequest); - // session should not be logged on due to IncorrectTagValue - assertFalse(session.isLoggedOn()); - - assertEquals(4, application.lastToAdminMessage().getHeader().getInt(MsgSeqNum.FIELD)); - assertEquals(MsgType.LOGOUT, application.lastToAdminMessage().getHeader().getString(MsgType.FIELD)); - assertEquals(5, session.getStore().getNextTargetMsgSeqNum()); - assertEquals(5, session.getStore().getNextSenderMsgSeqNum()); - - session.close(); + try (Session session = SessionFactoryTestSupport.createSession(sessionID, application, + false, false, true, true, null)) { + UnitTestResponder responder = new UnitTestResponder(); + session.setResponder(responder); + session.logon(); + + session.next(); + Logon logonRequest = new Logon(); + setUpHeader(session.getSessionID(), logonRequest, true, 1); + logonRequest.setInt(HeartBtInt.FIELD, 30); + logonRequest.setString(EncryptMethod.FIELD, ""); + logonRequest.toString(); // calculate length and checksum + session.next(logonRequest); + // session should not be logged on due to empty EncryptMethod + assertFalse(session.isLoggedOn()); + + assertEquals(1, application.lastToAdminMessage().getHeader().getInt(MsgSeqNum.FIELD)); + assertEquals(MsgType.LOGOUT, application.lastToAdminMessage().getHeader().getString(MsgType.FIELD)); + assertEquals(2, session.getStore().getNextTargetMsgSeqNum()); + assertEquals(2, session.getStore().getNextSenderMsgSeqNum()); + + session.setResponder(responder); + session.logon(); + session.next(); + setUpHeader(session.getSessionID(), logonRequest, true, 2); + logonRequest.removeField(EncryptMethod.FIELD); + logonRequest.toString(); // calculate length and checksum + session.next(logonRequest); + // session should not be logged on due to missing EncryptMethod + assertFalse(session.isLoggedOn()); + + assertEquals(2, application.lastToAdminMessage().getHeader().getInt(MsgSeqNum.FIELD)); + assertEquals(MsgType.LOGOUT, application.lastToAdminMessage().getHeader().getString(MsgType.FIELD)); + assertEquals(3, session.getStore().getNextTargetMsgSeqNum()); + assertEquals(3, session.getStore().getNextSenderMsgSeqNum()); + + session.setResponder(responder); + session.logon(); + session.next(); + setUpHeader(session.getSessionID(), logonRequest, true, 3); + logonRequest.setString(EncryptMethod.FIELD, "A"); + logonRequest.toString(); // calculate length and checksum + session.next(logonRequest); + // session should not be logged on due to IncorrectDataFormat + assertFalse(session.isLoggedOn()); + + assertEquals(3, application.lastToAdminMessage().getHeader().getInt(MsgSeqNum.FIELD)); + assertEquals(MsgType.LOGOUT, application.lastToAdminMessage().getHeader().getString(MsgType.FIELD)); + assertEquals(4, session.getStore().getNextTargetMsgSeqNum()); + assertEquals(4, session.getStore().getNextSenderMsgSeqNum()); + + session.setResponder(responder); + session.logon(); + session.next(); + setUpHeader(session.getSessionID(), logonRequest, true, 3); + logonRequest.setString(EncryptMethod.FIELD, "99"); + logonRequest.toString(); // calculate length and checksum + session.next(logonRequest); + // session should not be logged on due to IncorrectTagValue + assertFalse(session.isLoggedOn()); + + assertEquals(4, application.lastToAdminMessage().getHeader().getInt(MsgSeqNum.FIELD)); + assertEquals(MsgType.LOGOUT, application.lastToAdminMessage().getHeader().getString(MsgType.FIELD)); + assertEquals(5, session.getStore().getNextTargetMsgSeqNum()); + assertEquals(5, session.getStore().getNextSenderMsgSeqNum()); + } } /** @@ -956,31 +940,30 @@ public void testLogonOutsideSessionTimeIsRejected() throws Exception { // Session gets constructed, triggering a reset final UnitTestApplication application = new UnitTestApplication(); - final Session session = setUpFileStoreSession(application, false, - new UnitTestResponder(), settings, sessionID); - final SessionState state = getSessionState(session); - - assertEquals(1, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - - logonTo(session); - // we should only answer with a Logout message - assertEquals(1, application.toAdminMessages.size()); - assertEquals(MsgType.LOGOUT, application.toAdminMessages.get(0) - .getHeader().getString(MsgType.FIELD)); - assertFalse("Session should not be connected", session.isLoggedOn()); - assertTrue(application.toAdminMessages.get(0).getString(Text.FIELD) - .contains("Logon attempt not within session time")); - // Normally, next() is called periodically; we only do it here to reset - // the seqNums. - // The seqNums should be reset because it was tried to establish a - // connection - // outside of the session schedule. - session.next(); - assertEquals(1, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - - session.close(); + try (Session session = setUpFileStoreSession(application, false, + new UnitTestResponder(), settings, sessionID)) { + final SessionState state = getSessionState(session); + + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + logonTo(session); + // we should only answer with a Logout message + assertEquals(1, application.toAdminMessages.size()); + assertEquals(MsgType.LOGOUT, application.toAdminMessages.get(0) + .getHeader().getString(MsgType.FIELD)); + assertFalse("Session should not be connected", session.isLoggedOn()); + assertTrue(application.toAdminMessages.get(0).getString(Text.FIELD) + .contains("Logon attempt not within session time")); + // Normally, next() is called periodically; we only do it here to reset + // the seqNums. + // The seqNums should be reset because it was tried to establish a + // connection + // outside of the session schedule. + session.next(); + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + } } // QFJ-357 @@ -1035,36 +1018,35 @@ public void testRejectLogon() throws Exception { final Application application = new UnitTestApplication() { @Override - public void fromAdmin(Message message, SessionID sessionId) - throws FieldNotFound, IncorrectDataFormat, - IncorrectTagValue, RejectLogon { - super.fromAdmin(message, sessionId); - throw new RejectLogon("FOR TEST"); - } - }; - - final Session session = setUpSession(application, false, - new UnitTestResponder()); - final SessionState state = getSessionState(session); - - assertEquals(1, state.getNextSenderMsgSeqNum()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - - logonTo(session); - - assertEquals(false, state.isLogonSent()); - assertEquals(false, state.isLogonReceived()); - assertEquals(false, state.isLogonAlreadySent()); - assertEquals(false, state.isLogonSendNeeded()); - assertEquals(false, state.isLogonTimedOut()); - assertEquals(false, state.isLogoutSent()); - assertEquals(false, state.isLogoutReceived()); - assertEquals(false, state.isLogoutTimedOut()); - - assertEquals(2, state.getNextSenderMsgSeqNum()); - assertEquals(2, state.getNextTargetMsgSeqNum()); + public void fromAdmin(Message message, SessionID sessionId) + throws FieldNotFound, IncorrectDataFormat, + IncorrectTagValue, RejectLogon { + super.fromAdmin(message, sessionId); + throw new RejectLogon("FOR TEST"); + } + }; - session.close(); + try (Session session = setUpSession(application, false, + new UnitTestResponder())) { + final SessionState state = getSessionState(session); + + assertEquals(1, state.getNextSenderMsgSeqNum()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + + logonTo(session); + + assertEquals(false, state.isLogonSent()); + assertEquals(false, state.isLogonReceived()); + assertEquals(false, state.isLogonAlreadySent()); + assertEquals(false, state.isLogonSendNeeded()); + assertEquals(false, state.isLogonTimedOut()); + assertEquals(false, state.isLogoutSent()); + assertEquals(false, state.isLogoutReceived()); + assertEquals(false, state.isLogoutTimedOut()); + + assertEquals(2, state.getNextSenderMsgSeqNum()); + assertEquals(2, state.getNextTargetMsgSeqNum()); + } } // QFJ-696 @@ -1107,49 +1089,47 @@ public void fromAdmin(Message message, SessionID sessionId) @Test // QFJ-339 public void testSendingTimeRejectBeforeLogon() throws Exception { - final Session session = setUpSession(new UnitTestApplication(), false, - new UnitTestResponder()); - - final Message message = new Logon(); - message.getHeader().setString(SenderCompID.FIELD, "SENDER"); - message.getHeader().setString(TargetCompID.FIELD, "TARGET"); - message.getHeader().setString(SendingTime.FIELD, - UtcTimestampConverter.convert(LocalDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC), UtcTimestampPrecision.SECONDS)); - message.getHeader().setInt(MsgSeqNum.FIELD, 1); - - final SessionStateListener mockStateListener = mock(SessionStateListener.class); - session.addStateListener(mockStateListener); - - session.next(message); - - verify(mockStateListener).onDisconnect(); - verifyNoMoreInteractions(mockStateListener); - - session.close(); + try (Session session = setUpSession(new UnitTestApplication(), false, + new UnitTestResponder())) { + + final Message message = new Logon(); + message.getHeader().setString(SenderCompID.FIELD, "SENDER"); + message.getHeader().setString(TargetCompID.FIELD, "TARGET"); + message.getHeader().setString(SendingTime.FIELD, + UtcTimestampConverter.convert(LocalDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC), UtcTimestampPrecision.SECONDS)); + message.getHeader().setInt(MsgSeqNum.FIELD, 1); + + final SessionStateListener mockStateListener = mock(SessionStateListener.class); + session.addStateListener(mockStateListener); + + session.next(message); + + verify(mockStateListener).onDisconnect(); + verifyNoMoreInteractions(mockStateListener); + } } @Test // QFJ-339 public void testCorruptLogonReject() throws Exception { - final Session session = setUpSession(new UnitTestApplication(), false, - new UnitTestResponder()); - - final Message message = new Logon(); - message.getHeader().setString(SenderCompID.FIELD, "SENDER"); - message.getHeader().setString(TargetCompID.FIELD, "TARGET"); - message.getHeader().setString(SendingTime.FIELD, - UtcTimestampConverter.convert(LocalDateTime.now(ZoneOffset.UTC), UtcTimestampPrecision.SECONDS)); - message.getHeader().setInt(MsgSeqNum.FIELD, 100); - - final SessionStateListener mockStateListener = mock(SessionStateListener.class); - session.addStateListener(mockStateListener); - - session.next(message); - - verify(mockStateListener).onDisconnect(); - verifyNoMoreInteractions(mockStateListener); - - session.close(); + try (Session session = setUpSession(new UnitTestApplication(), false, + new UnitTestResponder())) { + + final Message message = new Logon(); + message.getHeader().setString(SenderCompID.FIELD, "SENDER"); + message.getHeader().setString(TargetCompID.FIELD, "TARGET"); + message.getHeader().setString(SendingTime.FIELD, + UtcTimestampConverter.convert(LocalDateTime.now(ZoneOffset.UTC), UtcTimestampPrecision.SECONDS)); + message.getHeader().setInt(MsgSeqNum.FIELD, 100); + + final SessionStateListener mockStateListener = mock(SessionStateListener.class); + session.addStateListener(mockStateListener); + + session.next(message); + + verify(mockStateListener).onDisconnect(); + verifyNoMoreInteractions(mockStateListener); + } } @Test @@ -1179,28 +1159,27 @@ public void fromAdmin(Message message, SessionID sessionId) } }; - final Session session = setUpSession(application, false, - new UnitTestResponder()); - final SessionState state = getSessionState(session); - - logonTo(session); - assertEquals(2, state.getNextSenderMsgSeqNum()); - assertEquals(2, state.getNextTargetMsgSeqNum()); - - processMessage(session, createAppMessage(2)); - - assertEquals(2, state.getNextSenderMsgSeqNum()); - assertEquals(2, state.getNextTargetMsgSeqNum()); - - // To avoid resendRequest - state.setNextTargetMsgSeqNum(3); - - processMessage(session, createAdminMessage(3)); - - assertEquals(2, state.getNextSenderMsgSeqNum()); - assertEquals(3, state.getNextTargetMsgSeqNum()); - - session.close(); + try (Session session = setUpSession(application, false, + new UnitTestResponder())) { + final SessionState state = getSessionState(session); + + logonTo(session); + assertEquals(2, state.getNextSenderMsgSeqNum()); + assertEquals(2, state.getNextTargetMsgSeqNum()); + + processMessage(session, createAppMessage(2)); + + assertEquals(2, state.getNextSenderMsgSeqNum()); + assertEquals(2, state.getNextTargetMsgSeqNum()); + + // To avoid resendRequest + state.setNextTargetMsgSeqNum(3); + + processMessage(session, createAdminMessage(3)); + + assertEquals(2, state.getNextSenderMsgSeqNum()); + assertEquals(3, state.getNextTargetMsgSeqNum()); + } } // QFJ-271 @@ -1208,35 +1187,34 @@ public void fromAdmin(Message message, SessionID sessionId) public void testSequenceResetStackOverflow() throws Exception { final UnitTestApplication application = new UnitTestApplication(); - final Session session = setUpSession(application, false, - new UnitTestResponder()); - final SessionState state = getSessionState(session); - - logonTo(session, 1); - - assertTrue(session.isLoggedOn()); - assertEquals(2, state.getNextTargetMsgSeqNum()); - - for (int i = 2; i <= 41; i++) { - processMessage(session, createAppMessage(i)); - } - assertEquals(42, state.getNextTargetMsgSeqNum()); - - processMessage(session, createAppMessage(50)); - processMessage(session, createSequenceReset(51, 51, true)); - - for (int i = 42; i <= 49; i++) { - processMessage(session, createAppMessage(i)); + try (Session session = setUpSession(application, false, + new UnitTestResponder())) { + final SessionState state = getSessionState(session); + + logonTo(session, 1); + + assertTrue(session.isLoggedOn()); + assertEquals(2, state.getNextTargetMsgSeqNum()); + + for (int i = 2; i <= 41; i++) { + processMessage(session, createAppMessage(i)); + } + assertEquals(42, state.getNextTargetMsgSeqNum()); + + processMessage(session, createAppMessage(50)); + processMessage(session, createSequenceReset(51, 51, true)); + + for (int i = 42; i <= 49; i++) { + processMessage(session, createAppMessage(i)); + } + + assertEquals(51, state.getNextTargetMsgSeqNum()); + processMessage(session, createHeartbeatMessage(51)); + assertEquals(52, state.getNextTargetMsgSeqNum()); + assertTrue(session.isLoggedOn()); + assertFalse(state.isResendRequested()); + assertTrue(state.getQueuedSeqNums().isEmpty()); } - - assertEquals(51, state.getNextTargetMsgSeqNum()); - processMessage(session, createHeartbeatMessage(51)); - assertEquals(52, state.getNextTargetMsgSeqNum()); - assertTrue(session.isLoggedOn()); - assertFalse(state.isResendRequested()); - assertTrue(state.getQueuedSeqNums().isEmpty()); - - session.close(); } // QFJ-626 @@ -1245,45 +1223,44 @@ public void testResendMessagesWithIncorrectChecksum() throws Exception { final UnitTestApplication application = new UnitTestApplication(); final SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX44, "SENDER", "TARGET"); - final Session session = SessionFactoryTestSupport.createSession(sessionID, application, false, false, true, true, null); - UnitTestResponder responder = new UnitTestResponder(); - session.setResponder(responder); - final SessionState state = getSessionState(session); - - assertTrue(session.isUsingDataDictionary()); - - final Logon logonToSend = new Logon(); - setUpHeader(session.getSessionID(), logonToSend, true, 1); - logonToSend.setInt(HeartBtInt.FIELD, 30); - logonToSend.setInt(EncryptMethod.FIELD, EncryptMethod.NONE_OTHER); - logonToSend.toString(); // calculate length/checksum - session.next(logonToSend); - - session.send(createAppMessage(2)); - final News createAppMessage = createAppMessage(3); - createAppMessage.setString(11, "ÄÖÜäöü?ß"); - session.send(createAppMessage); - session.send(createAppMessage(4)); - session.send(createAppMessage(5)); - - // ugly hack: alter the store to get an invalid checksum - String toString = createAppMessage.toString(); - final String replace = toString.replace("10=", "10=1"); - state.set(3, replace); - - Message createResendRequest = createResendRequest(2, 1); - createResendRequest.toString(); // calculate length/checksum - processMessage(session, createResendRequest); - - Message createAdminMessage = createAdminMessage(3); - createAdminMessage.toString(); // calculate length/checksum - session.next(createAdminMessage); - - // all messages should have been resent - assertEquals(5, application.lastToAppMessage().header.getInt(MsgSeqNum.FIELD)); - assertFalse(state.isResendRequested()); - - session.close(); + try (Session session = SessionFactoryTestSupport.createSession(sessionID, application, false, false, true, true, null)) { + UnitTestResponder responder = new UnitTestResponder(); + session.setResponder(responder); + final SessionState state = getSessionState(session); + + assertTrue(session.isUsingDataDictionary()); + + final Logon logonToSend = new Logon(); + setUpHeader(session.getSessionID(), logonToSend, true, 1); + logonToSend.setInt(HeartBtInt.FIELD, 30); + logonToSend.setInt(EncryptMethod.FIELD, EncryptMethod.NONE_OTHER); + logonToSend.toString(); // calculate length/checksum + session.next(logonToSend); + + session.send(createAppMessage(2)); + final News createAppMessage = createAppMessage(3); + createAppMessage.setString(11, "ÄÖÜäöü?ß"); + session.send(createAppMessage); + session.send(createAppMessage(4)); + session.send(createAppMessage(5)); + + // ugly hack: alter the store to get an invalid checksum + String toString = createAppMessage.toString(); + final String replace = toString.replace("10=", "10=1"); + state.set(3, replace); + + Message createResendRequest = createResendRequest(2, 1); + createResendRequest.toString(); // calculate length/checksum + processMessage(session, createResendRequest); + + Message createAdminMessage = createAdminMessage(3); + createAdminMessage.toString(); // calculate length/checksum + session.next(createAdminMessage); + + // all messages should have been resent + assertEquals(5, application.lastToAppMessage().header.getInt(MsgSeqNum.FIELD)); + assertFalse(state.isResendRequested()); + } } // QFJ-493 @@ -1291,24 +1268,23 @@ public void testResendMessagesWithIncorrectChecksum() throws Exception { public void testGapFillSatisfiesResendRequest() throws Exception { final UnitTestApplication application = new UnitTestApplication(); - final Session session = setUpSession(application, false, - new UnitTestResponder()); - final SessionState state = getSessionState(session); - - session.setNextTargetMsgSeqNum(684); - logonTo(session, 687); - - assertTrue(state.isResendRequested()); - assertEquals(684, state.getNextTargetMsgSeqNum()); - processMessage(session, createResendRequest(688, 1)); - - processMessage(session, createSequenceReset(684, 688, true)); - - processMessage(session, createHeartbeatMessage(689)); - - assertFalse(state.isResendRequested()); - - session.close(); + try (Session session = setUpSession(application, false, + new UnitTestResponder())) { + final SessionState state = getSessionState(session); + + session.setNextTargetMsgSeqNum(684); + logonTo(session, 687); + + assertTrue(state.isResendRequested()); + assertEquals(684, state.getNextTargetMsgSeqNum()); + processMessage(session, createResendRequest(688, 1)); + + processMessage(session, createSequenceReset(684, 688, true)); + + processMessage(session, createHeartbeatMessage(689)); + + assertFalse(state.isResendRequested()); + } } // QFJ-673 @@ -1316,31 +1292,30 @@ public void testGapFillSatisfiesResendRequest() throws Exception { public void testResendRequestIsProcessedAndQueued() throws Exception { final UnitTestApplication application = new UnitTestApplication(); - final Session session = setUpSession(application, false, - new UnitTestResponder()); - final SessionState state = getSessionState(session); - - session.setNextSenderMsgSeqNum(1006); - logonTo(session, 6); - - assertTrue(state.isResendRequested()); - assertEquals(1, state.getNextTargetMsgSeqNum()); - processMessage(session, createResendRequest(7, 1005)); - assertEquals(1, state.getNextTargetMsgSeqNum()); - processMessage(session, createSequenceReset(1, 6, true)); - assertEquals(8, state.getNextTargetMsgSeqNum()); - // we need to satisfy the resendrequest of the opposing side - assertTrue(MsgType.SEQUENCE_RESET.equals(MessageUtils - .getMessageType(application.lastToAdminMessage().toString()))); - assertTrue(state.isResendRequested()); - processMessage(session, createHeartbeatMessage(8)); - assertFalse(state.isResendRequested()); - processMessage(session, createHeartbeatMessage(9)); - assertFalse(state.isResendRequested()); - assertTrue(session.isLoggedOn()); - assertEquals(10, state.getNextTargetMsgSeqNum()); - - session.close(); + try (Session session = setUpSession(application, false, + new UnitTestResponder())) { + final SessionState state = getSessionState(session); + + session.setNextSenderMsgSeqNum(1006); + logonTo(session, 6); + + assertTrue(state.isResendRequested()); + assertEquals(1, state.getNextTargetMsgSeqNum()); + processMessage(session, createResendRequest(7, 1005)); + assertEquals(1, state.getNextTargetMsgSeqNum()); + processMessage(session, createSequenceReset(1, 6, true)); + assertEquals(8, state.getNextTargetMsgSeqNum()); + // we need to satisfy the resendrequest of the opposing side + assertTrue(MsgType.SEQUENCE_RESET.equals(MessageUtils + .getMessageType(application.lastToAdminMessage().toString()))); + assertTrue(state.isResendRequested()); + processMessage(session, createHeartbeatMessage(8)); + assertFalse(state.isResendRequested()); + processMessage(session, createHeartbeatMessage(9)); + assertFalse(state.isResendRequested()); + assertTrue(session.isLoggedOn()); + assertEquals(10, state.getNextTargetMsgSeqNum()); + } } @Test @@ -1389,50 +1364,49 @@ public void testResendRequestMsgSeqNum() throws Exception { public void testSimultaneousResendRequests() throws Exception { final UnitTestApplication application = new UnitTestApplication(); - Session session = setUpSession(application, false, - new UnitTestResponder()); - SessionState state = getSessionState(session); - - assertEquals(1, state.getNextTargetMsgSeqNum()); - logonTo(session, 1); - assertEquals(2, state.getNextTargetMsgSeqNum()); - assertFalse(state.isResendRequested()); - assertTrue(session.isLoggedOn()); - - processMessage(session, createAppMessage(2)); - session.send(createAppMessage(2)); - assertFalse(state.isResendRequested()); - assertTrue(session.isLoggedOn()); - - processMessage(session, createAppMessage(3)); - session.send(createAppMessage(3)); - assertFalse(state.isResendRequested()); - assertTrue(session.isLoggedOn()); - - processMessage(session, createHeartbeatMessage(7)); - assertTrue(state.isResendRequested()); - assertTrue(session.isLoggedOn()); - processMessage(session, createResendRequest(8, 2)); - assertTrue(state.isResendRequested()); - assertTrue(session.isLoggedOn()); - - processMessage(session, createHeartbeatMessage(4)); - assertTrue(state.isResendRequested()); - processMessage(session, createHeartbeatMessage(5)); - assertTrue(state.isResendRequested()); - processMessage(session, createHeartbeatMessage(6)); - assertFalse(state.isResendRequested()); - assertTrue(session.isLoggedOn()); - - // we need to satisfy the resendrequest of the opposing side - assertTrue(MsgType.SEQUENCE_RESET.equals(MessageUtils - .getMessageType(application.lastToAdminMessage().toString()))); - assertEquals(9, state.getNextTargetMsgSeqNum()); - processMessage(session, createHeartbeatMessage(9)); - processMessage(session, createHeartbeatMessage(10)); - assertEquals(11, state.getNextTargetMsgSeqNum()); - - session.close(); + try (Session session = setUpSession(application, false, + new UnitTestResponder())) { + SessionState state = getSessionState(session); + + assertEquals(1, state.getNextTargetMsgSeqNum()); + logonTo(session, 1); + assertEquals(2, state.getNextTargetMsgSeqNum()); + assertFalse(state.isResendRequested()); + assertTrue(session.isLoggedOn()); + + processMessage(session, createAppMessage(2)); + session.send(createAppMessage(2)); + assertFalse(state.isResendRequested()); + assertTrue(session.isLoggedOn()); + + processMessage(session, createAppMessage(3)); + session.send(createAppMessage(3)); + assertFalse(state.isResendRequested()); + assertTrue(session.isLoggedOn()); + + processMessage(session, createHeartbeatMessage(7)); + assertTrue(state.isResendRequested()); + assertTrue(session.isLoggedOn()); + processMessage(session, createResendRequest(8, 2)); + assertTrue(state.isResendRequested()); + assertTrue(session.isLoggedOn()); + + processMessage(session, createHeartbeatMessage(4)); + assertTrue(state.isResendRequested()); + processMessage(session, createHeartbeatMessage(5)); + assertTrue(state.isResendRequested()); + processMessage(session, createHeartbeatMessage(6)); + assertFalse(state.isResendRequested()); + assertTrue(session.isLoggedOn()); + + // we need to satisfy the resendrequest of the opposing side + assertTrue(MsgType.SEQUENCE_RESET.equals(MessageUtils + .getMessageType(application.lastToAdminMessage().toString()))); + assertEquals(9, state.getNextTargetMsgSeqNum()); + processMessage(session, createHeartbeatMessage(9)); + processMessage(session, createHeartbeatMessage(10)); + assertEquals(11, state.getNextTargetMsgSeqNum()); + } } // QFJ-750 @@ -1440,38 +1414,37 @@ public void testSimultaneousResendRequests() throws Exception { public void testRemoveQueuedMessagesOnSequenceReset() throws Exception { final UnitTestApplication application = new UnitTestApplication(); - final Session session = setUpSession(application, false, - new UnitTestResponder()); - final SessionState state = getSessionState(session); - - final int from = 10; - int numberOfMsgs = 200; - int to = from + numberOfMsgs; - - logonTo(session, 1); - assertEquals(2, state.getNextTargetMsgSeqNum()); - for (int i = from; i < to; i++) { - processMessage(session, createAppMessage(i)); - } - for (int i = from; i < to; i++) { - assertTrue(state.getQueuedSeqNums().contains(i)); + try (Session session = setUpSession(application, false, + new UnitTestResponder())) { + final SessionState state = getSessionState(session); + + final int from = 10; + int numberOfMsgs = 200; + int to = from + numberOfMsgs; + + logonTo(session, 1); + assertEquals(2, state.getNextTargetMsgSeqNum()); + for (int i = from; i < to; i++) { + processMessage(session, createAppMessage(i)); + } + for (int i = from; i < to; i++) { + assertTrue(state.getQueuedSeqNums().contains(i)); + } + + assertTrue(state.getQueuedSeqNums().size() == numberOfMsgs); + assertTrue(application.fromAppMessages.isEmpty()); + // Create a sequence reset which will cause deletion of almost all + // messages + // from the sessionState queue since former messages are skipped. + // The remaining two messages will then be dequeued and processed by the + // app. + final int two = 2; + processMessage(session, createSequenceReset(2, to - two, true)); + assertTrue(application.fromAppMessages.size() == two); + assertFalse(state.isResendRequested()); + assertTrue(session.isLoggedOn()); + assertTrue(state.getQueuedSeqNums().isEmpty()); } - - assertTrue(state.getQueuedSeqNums().size() == numberOfMsgs); - assertTrue(application.fromAppMessages.isEmpty()); - // Create a sequence reset which will cause deletion of almost all - // messages - // from the sessionState queue since former messages are skipped. - // The remaining two messages will then be dequeued and processed by the - // app. - final int two = 2; - processMessage(session, createSequenceReset(2, to - two, true)); - assertTrue(application.fromAppMessages.size() == two); - assertFalse(state.isResendRequested()); - assertTrue(session.isLoggedOn()); - assertTrue(state.getQueuedSeqNums().isEmpty()); - - session.close(); } /** @@ -1487,21 +1460,20 @@ public void testNonLogonMessageNonFIXT() throws Exception { final ApplVerID applVerID = MessageUtils .toApplVerID(FixVersions.BEGINSTRING_FIX44); final UnitTestApplication application = new UnitTestApplication(); - final Session session = SessionFactoryTestSupport.createSession( - sessionID, application, true, false, true, true, null); - session.setResponder(new UnitTestResponder()); - - assertTrue(session.isUsingDataDictionary()); - assertEquals(applVerID, session.getTargetDefaultApplicationVersionID()); - session.next(); - session.next(); - Message createHeartbeatMessage = createHeartbeatMessage(1); - createHeartbeatMessage.toString(); // calculate checksum, length - processMessage(session, createHeartbeatMessage); - assertEquals(applVerID, session.getTargetDefaultApplicationVersionID()); - assertFalse(session.isLoggedOn()); - - session.close(); + try (Session session = SessionFactoryTestSupport.createSession( + sessionID, application, true, false, true, true, null)) { + session.setResponder(new UnitTestResponder()); + + assertTrue(session.isUsingDataDictionary()); + assertEquals(applVerID, session.getTargetDefaultApplicationVersionID()); + session.next(); + session.next(); + Message createHeartbeatMessage = createHeartbeatMessage(1); + createHeartbeatMessage.toString(); // calculate checksum, length + processMessage(session, createHeartbeatMessage); + assertEquals(applVerID, session.getTargetDefaultApplicationVersionID()); + assertFalse(session.isLoggedOn()); + } } /** @@ -1516,40 +1488,39 @@ public void testNonLogonMessageFIXT() throws Exception { final ApplVerID applVerID = MessageUtils .toApplVerID(FixVersions.FIX50SP2); final UnitTestApplication application = new UnitTestApplication(); - final Session session = SessionFactoryTestSupport.createSession( + try (Session session = SessionFactoryTestSupport.createSession( sessionID, application, true, false, true, true, - new DefaultApplVerID(ApplVerID.FIX50SP2)); - session.setResponder(new UnitTestResponder()); - - // construct example messages - final quickfix.fixt11.Heartbeat heartbeat = new quickfix.fixt11.Heartbeat(); - setUpHeader(session.getSessionID(), heartbeat, true, 1); - heartbeat.toString(); // calculate checksum, length - final quickfix.fixt11.Logon logon = new quickfix.fixt11.Logon(); - setUpHeader(session.getSessionID(), logon, true, 1); - logon.setInt(HeartBtInt.FIELD, 30); - logon.setInt(EncryptMethod.FIELD, EncryptMethod.NONE_OTHER); - logon.setString(DefaultApplVerID.FIELD, ApplVerID.FIX50SP2); - logon.toString(); // calculate checksum, length - - assertTrue(session.isUsingDataDictionary()); - assertNull(session.getTargetDefaultApplicationVersionID()); - session.next(); - session.next(); - session.next(heartbeat); - assertNull(session.getTargetDefaultApplicationVersionID()); - assertFalse(session.isLoggedOn()); - - // retry Logon - session.setResponder(new UnitTestResponder()); - session.next(); - session.next(); - assertNull(session.getTargetDefaultApplicationVersionID()); - session.next(logon); - assertEquals(applVerID, session.getTargetDefaultApplicationVersionID()); - assertTrue(session.isLoggedOn()); - - session.close(); + new DefaultApplVerID(ApplVerID.FIX50SP2))) { + session.setResponder(new UnitTestResponder()); + + // construct example messages + final quickfix.fixt11.Heartbeat heartbeat = new quickfix.fixt11.Heartbeat(); + setUpHeader(session.getSessionID(), heartbeat, true, 1); + heartbeat.toString(); // calculate checksum, length + final quickfix.fixt11.Logon logon = new quickfix.fixt11.Logon(); + setUpHeader(session.getSessionID(), logon, true, 1); + logon.setInt(HeartBtInt.FIELD, 30); + logon.setInt(EncryptMethod.FIELD, EncryptMethod.NONE_OTHER); + logon.setString(DefaultApplVerID.FIELD, ApplVerID.FIX50SP2); + logon.toString(); // calculate checksum, length + + assertTrue(session.isUsingDataDictionary()); + assertNull(session.getTargetDefaultApplicationVersionID()); + session.next(); + session.next(); + session.next(heartbeat); + assertNull(session.getTargetDefaultApplicationVersionID()); + assertFalse(session.isLoggedOn()); + + // retry Logon + session.setResponder(new UnitTestResponder()); + session.next(); + session.next(); + assertNull(session.getTargetDefaultApplicationVersionID()); + session.next(logon); + assertEquals(applVerID, session.getTargetDefaultApplicationVersionID()); + assertTrue(session.isLoggedOn()); + } } private void processMessage(Session session, Message message) @@ -1631,32 +1602,31 @@ public void fromApp(Message message, SessionID sessionId) } }; - final Session session = setUpSession(application, false, - new UnitTestResponder()); - logonTo(session); - - try { - session.next(createHeartbeatMessage(2)); // should increment target - // seqnum - session.next(createHeartbeatMessage(3)); // should increment target - // seqnum - session.next(createHeartbeatMessage(4)); // should increment target - // seqnum - assertEquals(5, session.getExpectedTargetNum()); - session.next(createAppMessage(5)); // should NOT increment target - // seqnum - fail("No error thrown"); - } catch (final Throwable t) { - assertEquals("java.lang.Error: TEST", t.getMessage()); - assertEquals(5, session.getExpectedTargetNum()); - assertEquals(2, session.getExpectedSenderNum()); - session.next(createHeartbeatMessage(5)); // should increment target - // seqnum - assertEquals(6, session.getExpectedTargetNum()); - assertEquals(2, session.getExpectedSenderNum()); + try (Session session = setUpSession(application, false, + new UnitTestResponder())) { + logonTo(session); + + try { + session.next(createHeartbeatMessage(2)); // should increment target + // seqnum + session.next(createHeartbeatMessage(3)); // should increment target + // seqnum + session.next(createHeartbeatMessage(4)); // should increment target + // seqnum + assertEquals(5, session.getExpectedTargetNum()); + session.next(createAppMessage(5)); // should NOT increment target + // seqnum + fail("No error thrown"); + } catch (final Throwable t) { + assertEquals("java.lang.Error: TEST", t.getMessage()); + assertEquals(5, session.getExpectedTargetNum()); + assertEquals(2, session.getExpectedSenderNum()); + session.next(createHeartbeatMessage(5)); // should increment target + // seqnum + assertEquals(6, session.getExpectedTargetNum()); + assertEquals(2, session.getExpectedSenderNum()); + } } - - session.close(); } // QFJ-572 @@ -1686,41 +1656,40 @@ public void fromApp(Message message, SessionID sessionId) } }; - final Session session = setUpSession(application, false, - new UnitTestResponder()); - session.setRejectMessageOnUnhandledException(true); - logonTo(session); - - try { - session.next(createAppMessage(2)); - assertEquals(3, session.getExpectedTargetNum()); - assertEquals(3, session.getExpectedSenderNum()); - assertEquals(MsgType.NEWS, application.lastFromAppMessage() - .getHeader().getString(MsgType.FIELD)); - assertEquals(MsgType.BUSINESS_MESSAGE_REJECT, application - .lastToAppMessage().getHeader().getString(MsgType.FIELD)); - - session.next(createHeartbeatMessage(3)); - assertEquals(4, session.getExpectedTargetNum()); - assertEquals(4, session.getExpectedSenderNum()); - assertEquals(MsgType.HEARTBEAT, application.lastFromAdminMessage() - .getHeader().getString(MsgType.FIELD)); - assertEquals(MsgType.REJECT, application.lastToAdminMessage() - .getHeader().getString(MsgType.FIELD)); - - session.next(createAdminMessage(4)); - assertEquals(5, session.getExpectedTargetNum()); - assertEquals(5, session.getExpectedSenderNum()); - assertEquals(MsgType.TEST_REQUEST, application - .lastFromAdminMessage().getHeader() - .getString(MsgType.FIELD)); - assertEquals(MsgType.HEARTBEAT, application.lastToAdminMessage() - .getHeader().getString(MsgType.FIELD)); - } catch (final Throwable t) { - fail("Error was thrown: " + t.getMessage()); + try (Session session = setUpSession(application, false, + new UnitTestResponder())) { + session.setRejectMessageOnUnhandledException(true); + logonTo(session); + + try { + session.next(createAppMessage(2)); + assertEquals(3, session.getExpectedTargetNum()); + assertEquals(3, session.getExpectedSenderNum()); + assertEquals(MsgType.NEWS, application.lastFromAppMessage() + .getHeader().getString(MsgType.FIELD)); + assertEquals(MsgType.BUSINESS_MESSAGE_REJECT, application + .lastToAppMessage().getHeader().getString(MsgType.FIELD)); + + session.next(createHeartbeatMessage(3)); + assertEquals(4, session.getExpectedTargetNum()); + assertEquals(4, session.getExpectedSenderNum()); + assertEquals(MsgType.HEARTBEAT, application.lastFromAdminMessage() + .getHeader().getString(MsgType.FIELD)); + assertEquals(MsgType.REJECT, application.lastToAdminMessage() + .getHeader().getString(MsgType.FIELD)); + + session.next(createAdminMessage(4)); + assertEquals(5, session.getExpectedTargetNum()); + assertEquals(5, session.getExpectedSenderNum()); + assertEquals(MsgType.TEST_REQUEST, application + .lastFromAdminMessage().getHeader() + .getString(MsgType.FIELD)); + assertEquals(MsgType.HEARTBEAT, application.lastToAdminMessage() + .getHeader().getString(MsgType.FIELD)); + } catch (final Throwable t) { + fail("Error was thrown: " + t.getMessage()); + } } - - session.close(); } private News createAppMessage(int sequence) { @@ -1758,9 +1727,9 @@ public void testSessionRegisteredCorrectly() throws Exception { new UnitTestApplication(), new MemoryStoreFactory(), new JdbcLogFactory(settings)); try { - final Session session = factory.create(sessionID, settings); - assertNotNull(session); - session.close(); + try (Session session = factory.create(sessionID, settings)) { + assertNotNull(session); + } } catch (final NullPointerException nex) { fail("Session not registering correctly so JdbcLog fails while printing an error: " + nex.getMessage()); @@ -1773,56 +1742,56 @@ public void testSessionRegisteredCorrectly() throws Exception { @Test public void testNonpersistedGapFill() throws Exception { final SessionID sessionID = new SessionID("FIX.4.4:SENDER->TARGET"); - final Session session = SessionFactoryTestSupport + try (Session session = SessionFactoryTestSupport .createNonpersistedSession(sessionID, - new UnitTestApplication(), false); - session.getStore().setNextTargetMsgSeqNum(200); - final SessionState state = ReflectionUtil.getField(session, "state", - SessionState.class); - state.setLogonReceived(true); - final ResendRequest resendRequest = new ResendRequest(); - resendRequest.getHeader().setField( - new SenderCompID(sessionID.getTargetCompID())); - resendRequest.getHeader().setField( - new TargetCompID(sessionID.getSenderCompID())); - resendRequest.getHeader().setField(new SendingTime(LocalDateTime.now(ZoneOffset.UTC))); - resendRequest.getHeader().setField(new MsgSeqNum(200)); - resendRequest.set(new BeginSeqNo(1)); - resendRequest.set(new EndSeqNo(100)); - session.next(resendRequest); - assertEquals(201, state.getNextTargetMsgSeqNum()); - session.close(); + new UnitTestApplication(), false)) { + session.getStore().setNextTargetMsgSeqNum(200); + final SessionState state = ReflectionUtil.getField(session, "state", + SessionState.class); + state.setLogonReceived(true); + final ResendRequest resendRequest = new ResendRequest(); + resendRequest.getHeader().setField( + new SenderCompID(sessionID.getTargetCompID())); + resendRequest.getHeader().setField( + new TargetCompID(sessionID.getSenderCompID())); + resendRequest.getHeader().setField(new SendingTime(LocalDateTime.now(ZoneOffset.UTC))); + resendRequest.getHeader().setField(new MsgSeqNum(200)); + resendRequest.set(new BeginSeqNo(1)); + resendRequest.set(new EndSeqNo(100)); + session.next(resendRequest); + assertEquals(201, state.getNextTargetMsgSeqNum()); + } } @Test // QFJ-457 public void testAcceptorRelogon() throws Exception { final UnitTestApplication application = new UnitTestApplication(); - final Session session = setUpSession(application, false, - new UnitTestResponder()); - - logonTo(session); - assertTrue(session.isEnabled()); - assertTrue(session.isLoggedOn()); - - session.logout(); - session.next(); - - final Message logout = new Logout(); - logout.getHeader().setString(SenderCompID.FIELD, "TARGET"); - logout.getHeader().setString(TargetCompID.FIELD, "SENDER"); - logout.getHeader().setString(SendingTime.FIELD, - UtcTimestampConverter.convert(LocalDateTime.now(ZoneOffset.UTC), UtcTimestampPrecision.SECONDS)); - logout.getHeader().setInt(MsgSeqNum.FIELD, 2); - session.next(logout); - - // session.reset(); - assertFalse(session.isLoggedOn()); - logonTo(session, 3); - Message lastToAdminMessage = application.lastToAdminMessage(); - assertFalse(Logout.MSGTYPE.equals(lastToAdminMessage.getHeader() - .getString(MsgType.FIELD))); - session.close(); + try (Session session = setUpSession(application, false, + new UnitTestResponder())) { + + logonTo(session); + assertTrue(session.isEnabled()); + assertTrue(session.isLoggedOn()); + + session.logout(); + session.next(); + + final Message logout = new Logout(); + logout.getHeader().setString(SenderCompID.FIELD, "TARGET"); + logout.getHeader().setString(TargetCompID.FIELD, "SENDER"); + logout.getHeader().setString(SendingTime.FIELD, + UtcTimestampConverter.convert(LocalDateTime.now(ZoneOffset.UTC), UtcTimestampPrecision.SECONDS)); + logout.getHeader().setInt(MsgSeqNum.FIELD, 2); + session.next(logout); + + // session.reset(); + assertFalse(session.isLoggedOn()); + logonTo(session, 3); + Message lastToAdminMessage = application.lastToAdminMessage(); + assertFalse(Logout.MSGTYPE.equals(lastToAdminMessage.getHeader() + .getString(MsgType.FIELD))); + } } @Test @@ -1830,52 +1799,51 @@ public void testAcceptorRelogon() throws Exception { public void testStateFlagsAreResetOnLogout() throws Exception { final UnitTestApplication application = new UnitTestApplication(); - final Session session = setUpSession(application, false, - new UnitTestResponder()); - final Message logout = new Logout(); - logout.getHeader().setString(SenderCompID.FIELD, "TARGET"); - logout.getHeader().setString(TargetCompID.FIELD, "SENDER"); - logout.getHeader().setString(SendingTime.FIELD, - UtcTimestampConverter.convert(LocalDateTime.now(ZoneOffset.UTC), UtcTimestampPrecision.SECONDS)); - logout.getHeader().setInt(MsgSeqNum.FIELD, 2); - - logonTo(session); - assertFalse(session.isLogoutSent()); - assertFalse(session.isLogoutReceived()); - assertTrue(session.isLogonReceived()); - assertTrue(session.isLogonSent()); - - /* - * Setting the responder to NULL here was formerly causing that the - * flags logoutReceived and logoutSent (amongst others) were not reset - * to false because the Session.disconnect() method returned too early - * since no responder was set anymore. - */ - session.setResponder(null); - session.next(logout); - - assertFalse(session.isLogoutReceived()); - assertFalse(session.isLogoutSent()); - assertFalse(session.isLogonReceived()); - assertFalse(session.isLogonSent()); - - session.setResponder(new UnitTestResponder()); - logonTo(session, 3); - assertFalse(session.isLogoutSent()); - assertFalse(session.isLogoutReceived()); - assertTrue(session.isLogonReceived()); - assertTrue(session.isLogonSent()); - - session.disconnect("Forced by UnitTest", true); - assertFalse(session.isLogoutReceived()); - assertFalse(session.isLogoutSent()); - assertFalse(session.isLogonReceived()); - assertFalse(session.isLogonSent()); - - // onLogout was called - assertTrue(application.logoutSessions.size() == 1); - - session.close(); + try (Session session = setUpSession(application, false, + new UnitTestResponder())) { + final Message logout = new Logout(); + logout.getHeader().setString(SenderCompID.FIELD, "TARGET"); + logout.getHeader().setString(TargetCompID.FIELD, "SENDER"); + logout.getHeader().setString(SendingTime.FIELD, + UtcTimestampConverter.convert(LocalDateTime.now(ZoneOffset.UTC), UtcTimestampPrecision.SECONDS)); + logout.getHeader().setInt(MsgSeqNum.FIELD, 2); + + logonTo(session); + assertFalse(session.isLogoutSent()); + assertFalse(session.isLogoutReceived()); + assertTrue(session.isLogonReceived()); + assertTrue(session.isLogonSent()); + + /* + * Setting the responder to NULL here was formerly causing that the + * flags logoutReceived and logoutSent (amongst others) were not reset + * to false because the Session.disconnect() method returned too early + * since no responder was set anymore. + */ + session.setResponder(null); + session.next(logout); + + assertFalse(session.isLogoutReceived()); + assertFalse(session.isLogoutSent()); + assertFalse(session.isLogonReceived()); + assertFalse(session.isLogonSent()); + + session.setResponder(new UnitTestResponder()); + logonTo(session, 3); + assertFalse(session.isLogoutSent()); + assertFalse(session.isLogoutReceived()); + assertTrue(session.isLogonReceived()); + assertTrue(session.isLogonSent()); + + session.disconnect("Forced by UnitTest", true); + assertFalse(session.isLogoutReceived()); + assertFalse(session.isLogoutSent()); + assertFalse(session.isLogonReceived()); + assertFalse(session.isLogonSent()); + + // onLogout was called + assertTrue(application.logoutSessions.size() == 1); + } } @Test @@ -1892,26 +1860,25 @@ public void testGenerateRejectAndTargetSeqNum() throws Exception { settings.setString(Session.SETTING_END_TIME, "00:00:00"); settings.setBool(Session.SETTING_CHECK_LATENCY, false); - Session session = new DefaultSessionFactory(new ApplicationAdapter(), + try (Session session = new DefaultSessionFactory(new ApplicationAdapter(), new MemoryStoreFactory(), new SLF4JLogFactory(settings)) - .create(sessionID, settings); - - session.setResponder(new UnitTestResponder()); - - session.next(); - session.setNextSenderMsgSeqNum(177); - session.setNextTargetMsgSeqNum(223); - String[] messages = { + .create(sessionID, settings)) { + + session.setResponder(new UnitTestResponder()); + + session.next(); + session.setNextSenderMsgSeqNum(177); + session.setNextTargetMsgSeqNum(223); + String[] messages = { "8=FIX.4.2\0019=0081\00135=A\00149=THEM\00156=US\001369=177\00152=20100908-17:59:30.551\00134=227\00198=0\001108=30\00110=36\001", "8=FIX.4.2\0019=0107\00135=z\001115=THEM\00149=THEM\00156=US\001369=177\00152=20100908-17:59:30.551\00134=228\001336=1\001340=2\00176=US\001439=USS\00110=133\001", "8=FIX.4.2\0019=0113\00135=4\00134=223\00143=Y\001122=20100908-17:59:30.642\00149=THEM\00156=US\001369=178\00152=20100908-17:59:30.642\001123=Y\00136=225\00110=110\001", "8=FIX.4.2\0019=0246\00135=8\001115=THEM\00134=225\00143=Y\001122=20100908-17:52:37.920\00149=THEM\00156=US\001369=178\00152=20100908-17:59:30.642\00137=10118506\00111=a00000052.1\00117=17537743\00120=0\001150=4\00139=4\00155=ETFC\00154=1\00138=500000\00144=0.998\00132=0\00131=0\001151=0\00114=0\0016=0\00160=20100908-17:52:37.920\00110=80\001" }; - for (String message : messages) - session.next(MessageUtils.parse(session, message)); - - assertEquals(226, session.getStore().getNextTargetMsgSeqNum()); - - session.close(); + for (String message : messages) + session.next(MessageUtils.parse(session, message)); + + assertEquals(226, session.getStore().getNextTargetMsgSeqNum()); + } } @Test @@ -1993,61 +1960,60 @@ private void testSequenceResetGapFillWithChunkSize(int chunkSize) boolean isInitiator = true, resetOnLogon = false, validateSequenceNumbers = true; - Session session = new Session(new UnitTestApplication(), + try (Session session = new Session(new UnitTestApplication(), new MemoryStoreFactory(), sessionID, null, null, new SLF4JLogFactory(new SessionSettings()), new DefaultMessageFactory(), isInitiator ? 30 : 0, false, 30, UtcTimestampPrecision.MILLIS, resetOnLogon, false, false, false, false, false, true, false, 1.5, null, validateSequenceNumbers, new int[] { 5 }, false, false, false, true, false, true, false, null, true, - chunkSize, false, false); - - UnitTestResponder responder = new UnitTestResponder(); - session.setResponder(responder); - final SessionState state = getSessionState(session); - - session.logon(); - session.next(); - - assertEquals(1, session.getStore().getNextTargetMsgSeqNum()); - - Message logonRequest = new Message(responder.sentMessageData); - - // Deliver Logon response with too high sequence 20 instead of 1. - session.next(createLogonResponse(sessionID, logonRequest, 20)); - - assertTrue(state.isResendRequested()); - // The expected target sequence should still be 1. - assertEquals(1, session.getStore().getNextTargetMsgSeqNum()); - - // Deliver the missing message #1. - session.next(createAppMessage(1)); - assertEquals(2, session.getStore().getNextTargetMsgSeqNum()); - - // Deliver the missing message #2. - session.next(createAppMessage(2)); - assertEquals(3, session.getStore().getNextTargetMsgSeqNum()); - - // Deliver SequenceReset-GapFill from 3 to 5 - session.next(createSequenceReset(3, 5, true)); - - // Deliver the missing message #5. - session.next(createAppMessage(5)); - /* - * The expected target sequence number should be 6 now. - */ - assertEquals(6, session.getStore().getNextTargetMsgSeqNum()); - assertTrue(session.isLoggedOn()); - assertTrue(state.isResendRequested()); - for (int i = 6; i <= 19; i++) { - session.next(createAppMessage(i)); + chunkSize, false, false)) { + + UnitTestResponder responder = new UnitTestResponder(); + session.setResponder(responder); + final SessionState state = getSessionState(session); + + session.logon(); + session.next(); + + assertEquals(1, session.getStore().getNextTargetMsgSeqNum()); + + Message logonRequest = new Message(responder.sentMessageData); + + // Deliver Logon response with too high sequence 20 instead of 1. + session.next(createLogonResponse(sessionID, logonRequest, 20)); + + assertTrue(state.isResendRequested()); + // The expected target sequence should still be 1. + assertEquals(1, session.getStore().getNextTargetMsgSeqNum()); + + // Deliver the missing message #1. + session.next(createAppMessage(1)); + assertEquals(2, session.getStore().getNextTargetMsgSeqNum()); + + // Deliver the missing message #2. + session.next(createAppMessage(2)); + assertEquals(3, session.getStore().getNextTargetMsgSeqNum()); + + // Deliver SequenceReset-GapFill from 3 to 5 + session.next(createSequenceReset(3, 5, true)); + + // Deliver the missing message #5. + session.next(createAppMessage(5)); + /* + * The expected target sequence number should be 6 now. + */ + assertEquals(6, session.getStore().getNextTargetMsgSeqNum()); + assertTrue(session.isLoggedOn()); + assertTrue(state.isResendRequested()); + for (int i = 6; i <= 19; i++) { + session.next(createAppMessage(i)); + } + assertFalse(state.isResendRequested()); + assertTrue(session.isLoggedOn()); + // seqnum 20 will be retrieved from the queue, so we should be at 21 now + assertEquals(21, session.getStore().getNextTargetMsgSeqNum()); } - assertFalse(state.isResendRequested()); - assertTrue(session.isLoggedOn()); - // seqnum 20 will be retrieved from the queue, so we should be at 21 now - assertEquals(21, session.getStore().getNextTargetMsgSeqNum()); - - session.close(); } @Test @@ -2153,31 +2119,30 @@ public void testMsgSeqNumTooHighWithDisconnectOnError() throws Exception { final boolean disconnectOnError = true; - Session session = new Session(new UnitTestApplication(), + try (Session session = new Session(new UnitTestApplication(), new MemoryStoreFactory(), sessionID, null, null, new SLF4JLogFactory(new SessionSettings()), new DefaultMessageFactory(), isInitiator ? 30 : 0, false, 30, UtcTimestampPrecision.MILLIS, resetOnLogon, false, false, false, false, false, true, false, 1.5, null, validateSequenceNumbers, new int[] { 5 }, false, disconnectOnError, false, true, false, true, false, - null, true, 0, false, false); - - UnitTestResponder responder = new UnitTestResponder(); - session.setResponder(responder); - - session.logon(); - session.next(); - - // Deliver Logon response with too high sequence number 100 - Message logonRequest = new Message(responder.sentMessageData); - session.next(createLogonResponse(sessionID, logonRequest, 100)); - - // Deliver application message with too high sequence number 101 - session.next(createAppMessage(101)); - // Check, if session is still connected. - assertEquals(true, session.hasResponder()); - - session.close(); + null, true, 0, false, false)) { + + UnitTestResponder responder = new UnitTestResponder(); + session.setResponder(responder); + + session.logon(); + session.next(); + + // Deliver Logon response with too high sequence number 100 + Message logonRequest = new Message(responder.sentMessageData); + session.next(createLogonResponse(sessionID, logonRequest, 100)); + + // Deliver application message with too high sequence number 101 + session.next(createAppMessage(101)); + // Check, if session is still connected. + assertEquals(true, session.hasResponder()); + } } @Test @@ -2190,26 +2155,26 @@ public void testTimestampPrecision() throws Exception { final boolean disconnectOnError = true; UnitTestApplication unitTestApplication = new UnitTestApplication(); - Session session = new Session(unitTestApplication, + try (Session session = new Session(unitTestApplication, new MemoryStoreFactory(), sessionID, null, null, new SLF4JLogFactory(new SessionSettings()), new DefaultMessageFactory(), isInitiator ? 30 : 0, false, 30, UtcTimestampPrecision.NANOS, resetOnLogon, false, false, false, false, false, true, false, 1.5, null, validateSequenceNumbers, new int[] { 5 }, false, disconnectOnError, false, true, false, true, false, - null, true, 0, false, false); - - UnitTestResponder responder = new UnitTestResponder(); - session.setResponder(responder); - - session.logon(); - session.next(); - String sendingTimeField = unitTestApplication.toAdminMessages.get(0).getHeader().getString(SendingTime.FIELD); - assertTrue("SendingTime should have NANOS precision (27 characters total)", sendingTimeField.length() == 27); - String substring = sendingTimeField.substring(sendingTimeField.lastIndexOf(".") + 1); - assertTrue("SendingTime should have NANOS precision (9 digits after dot)", substring.length() == 9); - Long.parseLong(substring); - session.close(); + null, true, 0, false, false)) { + + UnitTestResponder responder = new UnitTestResponder(); + session.setResponder(responder); + + session.logon(); + session.next(); + String sendingTimeField = unitTestApplication.toAdminMessages.get(0).getHeader().getString(SendingTime.FIELD); + assertTrue("SendingTime should have NANOS precision (27 characters total)", sendingTimeField.length() == 27); + String substring = sendingTimeField.substring(sendingTimeField.lastIndexOf(".") + 1); + assertTrue("SendingTime should have NANOS precision (9 digits after dot)", substring.length() == 9); + Long.parseLong(substring); + } } @Test diff --git a/quickfixj-core/src/test/java/quickfix/SocketAcceptorTest.java b/quickfixj-core/src/test/java/quickfix/SocketAcceptorTest.java index 6593d606a..01227d06d 100644 --- a/quickfixj-core/src/test/java/quickfix/SocketAcceptorTest.java +++ b/quickfixj-core/src/test/java/quickfix/SocketAcceptorTest.java @@ -45,6 +45,9 @@ * MultiAcceptorTest served as a template for this test. */ public class SocketAcceptorTest { + // store static Session count before the test to check cleanup + private static final int SESSION_COUNT = Session.numSessions(); + private final Logger log = LoggerFactory.getLogger(getClass()); private final SessionID acceptorSessionID = new SessionID(FixVersions.BEGINSTRING_FIX42, "ACCEPTOR", "INITIATOR"); @@ -63,13 +66,14 @@ public void cleanup() { @Test public void testRestartOfAcceptor() throws Exception { TestAcceptorApplication testAcceptorApplication = new TestAcceptorApplication(); + TestInitiatorApplication testInitiatorApplication = new TestInitiatorApplication(); ThreadMXBean bean = ManagementFactory.getThreadMXBean(); Acceptor acceptor = null; Initiator initiator = null; try { acceptor = createAcceptor(testAcceptorApplication); acceptor.start(); - initiator = createInitiator(); + initiator = createInitiator(testInitiatorApplication); assertNotNull("Session should be registered", lookupSession(acceptorSessionID)); @@ -84,7 +88,9 @@ public void testRestartOfAcceptor() throws Exception { checkThreads(bean, 2); testAcceptorApplication.waitForLogon(); - assertTrue("initiator should have logged on by now", acceptor.isLoggedOn()); + testInitiatorApplication.waitForLogon(); + assertTrue("acceptor should have logged on by now", acceptor.isLoggedOn()); + assertTrue("initiator should have logged on by now", initiator.isLoggedOn()); } finally { if (initiator != null) { try { @@ -101,6 +107,7 @@ public void testRestartOfAcceptor() throws Exception { } } assertEquals("application should receive logout", 1, testAcceptorApplication.logoutCounter); + assertEquals("application should receive logout", 1, testInitiatorApplication.logoutCounter); } } @@ -145,6 +152,44 @@ public void testDoubleStartOfAcceptor() throws Exception { } } + @Test + public void testSessionsAreCleanedUp() throws Exception { + Acceptor acceptor = null; + try { + TestAcceptorApplication testAcceptorApplication = new TestAcceptorApplication(); + acceptor = createAcceptor(testAcceptorApplication); + acceptor.start(); + assertEquals(1, acceptor.getSessions().size() ); + assertEquals(1 + SESSION_COUNT, Session.numSessions() ); + + } finally { + if (acceptor != null) { + acceptor.stop(true); + assertTrue("After stop() the Session count should not be higher than before the test", Session.numSessions() <= SESSION_COUNT ); + assertEquals("After stop() the Session count should be zero in Connector", 0, acceptor.getSessions().size() ); + } + } + } + + @Test + public void testSessionsAreCleanedUpOnThreadedSocketAcceptor() throws Exception { + Acceptor acceptor = null; + try { + TestAcceptorApplication testAcceptorApplication = new TestAcceptorApplication(); + acceptor = createAcceptorThreaded(testAcceptorApplication); + acceptor.start(); + assertEquals(1, acceptor.getSessions().size() ); + assertEquals(1 + SESSION_COUNT, Session.numSessions() ); + + } finally { + if (acceptor != null) { + acceptor.stop(true); + assertTrue("After stop() the Session count should not be higher than before the test", Session.numSessions() <= SESSION_COUNT ); + assertEquals("After stop() the Session count should be zero in Connector", 0, acceptor.getSessions().size() ); + } + } + } + private void checkThreads(ThreadMXBean bean, int expectedNum) { ThreadInfo[] dumpAllThreads = bean.dumpAllThreads(false, false); int qfjMPThreads = 0; @@ -196,9 +241,64 @@ public void fromAdmin(Message message, SessionID sessionId) throws FieldNotFound } } + private static class TestInitiatorApplication extends ApplicationAdapter { + + private final CountDownLatch logonLatch; + public volatile int logoutCounter = 0; + + public TestInitiatorApplication() { + logonLatch = new CountDownLatch(1); + } + + @Override + public void onLogon(SessionID sessionId) { + super.onLogon(sessionId); + logonLatch.countDown(); + } + + public void waitForLogon() { + try { + assertTrue("Logon timed out", logonLatch.await(10, TimeUnit.SECONDS)); + } catch (InterruptedException e) { + fail(e.getMessage()); + } + } + + @Override + public void fromAdmin(Message message, SessionID sessionId) throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, RejectLogon { + try { + if (MsgType.LOGOUT.equals(MessageUtils.getMessageType(message.toString()))) { + logoutCounter++; + } + } catch (InvalidMessage ex) { + // ignore + } + } + } + private Acceptor createAcceptor(TestAcceptorApplication testAcceptorApplication) throws ConfigError { + SessionSettings settings = createAcceptorSettings(); + + MessageStoreFactory factory = new MemoryStoreFactory(); + quickfix.LogFactory logFactory = new SLF4JLogFactory(new SessionSettings()); + return new SocketAcceptor(testAcceptorApplication, factory, settings, logFactory, + new DefaultMessageFactory()); + } + + private Acceptor createAcceptorThreaded(TestAcceptorApplication testAcceptorApplication) + throws ConfigError { + + SessionSettings settings = createAcceptorSettings(); + + MessageStoreFactory factory = new MemoryStoreFactory(); + quickfix.LogFactory logFactory = new SLF4JLogFactory(new SessionSettings()); + return new ThreadedSocketAcceptor(testAcceptorApplication, factory, settings, logFactory, + new DefaultMessageFactory()); + } + + private SessionSettings createAcceptorSettings() { SessionSettings settings = new SessionSettings(); HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "acceptor"); @@ -208,14 +308,10 @@ private Acceptor createAcceptor(TestAcceptorApplication testAcceptorApplication) settings.setString(acceptorSessionID, "SocketAcceptProtocol", ProtocolFactory.getTypeString(ProtocolFactory.VM_PIPE)); settings.setString(acceptorSessionID, "SocketAcceptPort", "10000"); settings.set(defaults); - - MessageStoreFactory factory = new MemoryStoreFactory(); - quickfix.LogFactory logFactory = new SLF4JLogFactory(new SessionSettings()); - return new SocketAcceptor(testAcceptorApplication, factory, settings, logFactory, - new DefaultMessageFactory()); + return settings; } - private Initiator createInitiator() throws ConfigError { + private Initiator createInitiator(TestInitiatorApplication testInitiatorApplication) throws ConfigError { SessionSettings settings = new SessionSettings(); HashMap defaults = new HashMap<>(); defaults.put("ConnectionType", "initiator"); @@ -233,8 +329,7 @@ private Initiator createInitiator() throws ConfigError { MessageStoreFactory factory = new MemoryStoreFactory(); quickfix.LogFactory logFactory = new SLF4JLogFactory(new SessionSettings()); - return new SocketInitiator(new ApplicationAdapter() { - }, factory, settings, logFactory, new DefaultMessageFactory()); + return new SocketInitiator(testInitiatorApplication, factory, settings, logFactory, new DefaultMessageFactory()); } } diff --git a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java index da790a484..aefc8bc7b 100644 --- a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java +++ b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java @@ -58,6 +58,8 @@ public class SocketInitiatorTest { private final Logger log = LoggerFactory.getLogger(getClass()); + // store static Session count before the test to check cleanup + private static final int SESSION_COUNT = Session.numSessions(); @Before public void setUp() throws Exception { @@ -376,8 +378,8 @@ private void doTestOfRestart(SessionID clientSessionID, ClientApplication client initiator.stop(); assertFalse(clientSession.isLoggedOn()); - assertTrue(initiator.getSessions().contains(clientSessionID)); - assertTrue(initiator.getSessions().size() == 1); + assertFalse(initiator.getSessions().contains(clientSessionID)); + assertTrue(initiator.getSessions().size() == 0); if (messageLog != null) { messageLogLength = messageLog.length(); assertTrue(messageLog.length() > 0); @@ -404,6 +406,8 @@ private void doTestOfRestart(SessionID clientSessionID, ClientApplication client serverThread.join(); } assertEquals("Client application should receive logout", 2, clientApplication.logoutCounter); + assertTrue("After stop() the Session count should not be higher than before the test", Session.numSessions() <= SESSION_COUNT ); + assertEquals("After stop() the Session count should be zero in Connector", 0, initiator.getSessions().size() ); } private void doTestOfStop(SessionID clientSessionID, ClientApplication clientApplication, diff --git a/quickfixj-core/src/test/java/quickfix/mina/SessionConnectorTest.java b/quickfixj-core/src/test/java/quickfix/mina/SessionConnectorTest.java index 7936d48bb..413b64e34 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/SessionConnectorTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/SessionConnectorTest.java @@ -19,7 +19,6 @@ package quickfix.mina; -import junit.framework.TestCase; import quickfix.Acceptor; import quickfix.ConfigError; import quickfix.DefaultSessionFactory; @@ -42,10 +41,16 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import org.junit.Test; -public class SessionConnectorTest extends TestCase { +public class SessionConnectorTest { private final List propertyChangeEvents = new ArrayList<>(); + @Test public void testConnector() throws Exception { SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX40, "TW", "ISLD"); SessionSettings settings = setUpSessionSettings(sessionID); @@ -88,6 +93,7 @@ public void testConnector() throws Exception { assertEquals(settings, connector.getSettings()); } + @Test public void testOneSessionLoggedOnOneSessionNotLoggedOne() throws Exception { SessionID sessionID1 = new SessionID(FixVersions.BEGINSTRING_FIX40, "TW", "ISLD"); SessionSettings settings = setUpSessionSettings(sessionID1); @@ -96,47 +102,50 @@ public void testOneSessionLoggedOnOneSessionNotLoggedOne() throws Exception { SessionConnector connector = new SessionConnectorUnderTest(settings, sessionFactory); - Session session1 = connector.createSession(sessionID1); - assertNotNull(session1); + try (Session session1 = connector.createSession(sessionID1)) { + assertNotNull(session1); - // test add/remove - SessionConnectorListener connectorListener = new SessionConnectorListener(); - connector.addPropertyChangeListener(connectorListener); - connector.removePropertyChangeListener(connectorListener); + // test add/remove + SessionConnectorListener connectorListener = new SessionConnectorListener(); + connector.addPropertyChangeListener(connectorListener); + connector.removePropertyChangeListener(connectorListener); - Map sessions = new HashMap<>(); - sessions.put(session1.getSessionID(), session1); - connector.setSessions(sessions); + Map sessions = new HashMap<>(); + sessions.put(session1.getSessionID(), session1); + connector.setSessions(sessions); - assertEquals(0, propertyChangeEvents.size()); + assertEquals(0, propertyChangeEvents.size()); - assertEquals(1, connector.getManagedSessions().size()); - assertEquals(session1, connector.getManagedSessions().get(0)); + assertEquals(1, connector.getManagedSessions().size()); + assertEquals(session1, connector.getManagedSessions().get(0)); - assertFalse(connector.isLoggedOn()); + assertFalse(connector.isLoggedOn()); - Field stateField = session1.getClass().getDeclaredField("state"); - stateField.setAccessible(true); - SessionState state = (SessionState) stateField.get(session1); + Field stateField = session1.getClass().getDeclaredField("state"); + stateField.setAccessible(true); + SessionState state = (SessionState) stateField.get(session1); - state.setLogonSent(true); - state.setLogonReceived(true); - assertTrue(connector.isLoggedOn()); + state.setLogonSent(true); + state.setLogonReceived(true); + assertTrue(connector.isLoggedOn()); - SessionID sessionID2 = new SessionID(FixVersions.BEGINSTRING_FIX40, "TW", "ISLD1"); - settings.setString(sessionID2, SessionFactory.SETTING_CONNECTION_TYPE, - SessionFactory.ACCEPTOR_CONNECTION_TYPE); - Session session2 = connector.createSession(sessionID2); - assertNotNull(session2); - sessions.put(session2.getSessionID(), session2); - assertFalse(connector.isLoggedOn()); - assertTrue(connector.anyLoggedOn()); + SessionID sessionID2 = new SessionID(FixVersions.BEGINSTRING_FIX40, "TW", "ISLD1"); + settings.setString(sessionID2, SessionFactory.SETTING_CONNECTION_TYPE, + SessionFactory.ACCEPTOR_CONNECTION_TYPE); + try (Session session2 = connector.createSession(sessionID2)) { + assertNotNull(session2); + sessions.put(session2.getSessionID(), session2); + assertFalse(connector.isLoggedOn()); + assertTrue(connector.anyLoggedOn()); + } + } } /** * Test that adding/removing dynamic sessions works correctly */ - public void testAddingRemovingDymaicSessions() throws Exception { + @Test + public void testAddingRemovingDynamicSessions() throws Exception { SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX40, "TW", "ISLD"); SessionID sessionID2 = new SessionID(FixVersions.BEGINSTRING_FIX40, "me", "you"); SessionSettings settings = setUpSessionSettings(sessionID); @@ -173,6 +182,9 @@ public void testAddingRemovingDymaicSessions() throws Exception { assertEquals(session2, connector.getManagedSessions().get(0)); connector.removeDynamicSession(session2.getSessionID()); assertEquals(0, connector.getManagedSessions().size()); + + session.close(); + session2.close(); } private SessionSettings setUpSessionSettings(SessionID sessionID) { diff --git a/quickfixj-core/src/test/java/quickfix/mina/ThreadPerSessionEventHandlingStrategyTest.java b/quickfixj-core/src/test/java/quickfix/mina/ThreadPerSessionEventHandlingStrategyTest.java index e1a286f1f..56afb4760 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/ThreadPerSessionEventHandlingStrategyTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/ThreadPerSessionEventHandlingStrategyTest.java @@ -122,54 +122,55 @@ public void fromAdmin(Message message, SessionID sessionId) throws FieldNotFound } }; - final Session session = setUpSession(sessionID, application); - - final Message message = new Logon(); - message.getHeader().setString(SenderCompID.FIELD, "ISLD"); - message.getHeader().setString(TargetCompID.FIELD, "TW"); - message.getHeader().setString(SendingTime.FIELD, - UtcTimestampConverter.convert(new Date(), false)); - message.getHeader().setInt(MsgSeqNum.FIELD, 1); - message.setInt(HeartBtInt.FIELD, 30); - - strategy.onMessage(session, message); - - // Wait for a received message - if (!latch.await(5, TimeUnit.SECONDS)) { - fail("Timeout"); - } - - assertEquals(1, application.fromAdminMessages.size()); - - final Thread[] threads = new Thread[1024]; - Thread.enumerate(threads); - - Thread dispatcherThread = null; - for (final Thread thread : threads) { - if (thread.getName().startsWith("QF/J Session dispatcher")) { - dispatcherThread = thread; - // Dispatcher threads are not daemon threads - assertThat(dispatcherThread.isDaemon(), is(false)); - break; + try (Session session = setUpSession(sessionID, application)) { + + final Message message = new Logon(); + message.getHeader().setString(SenderCompID.FIELD, "ISLD"); + message.getHeader().setString(TargetCompID.FIELD, "TW"); + message.getHeader().setString(SendingTime.FIELD, + UtcTimestampConverter.convert(new Date(), false)); + message.getHeader().setInt(MsgSeqNum.FIELD, 1); + message.setInt(HeartBtInt.FIELD, 30); + + strategy.onMessage(session, message); + + // Wait for a received message + if (!latch.await(5, TimeUnit.SECONDS)) { + fail("Timeout"); } - } - - // We should have found the dispatcher thread - assertThat(dispatcherThread, notNullValue()); - - // Stop the threads and then check the thread state - strategy.stopDispatcherThreads(); - - for (int i = 0; i < 10; i++) { - Thread.sleep(100); - if (!dispatcherThread.isAlive()) { - break; + + assertEquals(1, application.fromAdminMessages.size()); + + final Thread[] threads = new Thread[1024]; + Thread.enumerate(threads); + + Thread dispatcherThread = null; + for (final Thread thread : threads) { + if (thread.getName().startsWith("QF/J Session dispatcher")) { + dispatcherThread = thread; + // Dispatcher threads are not daemon threads + assertThat(dispatcherThread.isDaemon(), is(false)); + break; + } + } + + // We should have found the dispatcher thread + assertThat(dispatcherThread, notNullValue()); + + // Stop the threads and then check the thread state + strategy.stopDispatcherThreads(); + + for (int i = 0; i < 10; i++) { + Thread.sleep(100); + if (!dispatcherThread.isAlive()) { + break; + } } + + // Dispatcher thread should be dead + assertThat(dispatcherThread.isAlive(), is(false)); + assertNull(strategy.getDispatcher(sessionID)); } - - // Dispatcher thread should be dead - assertThat(dispatcherThread.isAlive(), is(false)); - assertNull(strategy.getDispatcher(sessionID)); } /** @@ -190,94 +191,97 @@ public void fromAdmin(Message message, SessionID sessionId) throws FieldNotFound } }; - final Session session = setUpSession(sessionID, application); - - final Message message = new Logon(); - message.getHeader().setString(SenderCompID.FIELD, "ISLD"); - message.getHeader().setString(TargetCompID.FIELD, "TW"); - message.getHeader().setString(SendingTime.FIELD, - UtcTimestampConverter.convert(new Date(), false)); - message.getHeader().setInt(MsgSeqNum.FIELD, 1); - message.setInt(HeartBtInt.FIELD, 30); - - strategy.onMessage(session, message); - - // Wait for a received message - if (!latch.await(5, TimeUnit.SECONDS)) { - fail("Timeout"); - } - - assertEquals(1, application.fromAdminMessages.size()); - - Thread[] threads = new Thread[1024]; - Thread.enumerate(threads); - - Thread dispatcherThread = null; - for (final Thread thread : threads) { - if (thread != null && thread.getName().startsWith("QF/J Session dispatcher")) { - dispatcherThread = thread; - // Dispatcher threads are not daemon threads - assertThat(dispatcherThread.isDaemon(), is(false)); - break; + try (Session session = setUpSession(sessionID, application)) { + + final Message message = new Logon(); + message.getHeader().setString(SenderCompID.FIELD, "ISLD"); + message.getHeader().setString(TargetCompID.FIELD, "TW"); + message.getHeader().setString(SendingTime.FIELD, + UtcTimestampConverter.convert(new Date(), false)); + message.getHeader().setInt(MsgSeqNum.FIELD, 1); + message.setInt(HeartBtInt.FIELD, 30); + + strategy.onMessage(session, message); + + // Wait for a received message + if (!latch.await(5, TimeUnit.SECONDS)) { + fail("Timeout"); } - } - - assertTrue(session.hasResponder()); - // QFJ-790: we do not check the state of the responder anymore - // but wait for the END_OF_STREAM message to stop the threads. - strategy.onMessage(session, EventHandlingStrategy.END_OF_STREAM); - - // sleep some time to let the thread stop - for (int i = 0; i < 20; i++) { - Thread.sleep(100); - if (!dispatcherThread.isAlive()) { - break; + + assertEquals(1, application.fromAdminMessages.size()); + + Thread[] threads = new Thread[1024]; + Thread.enumerate(threads); + + Thread dispatcherThread = null; + for (final Thread thread : threads) { + if (thread != null && thread.getName().startsWith("QF/J Session dispatcher")) { + dispatcherThread = thread; + // Dispatcher threads are not daemon threads + assertThat(dispatcherThread.isDaemon(), is(false)); + break; + } } - } - assertNull(strategy.getDispatcher(sessionID)); - - threads = new Thread[1024]; - Thread.enumerate(threads); - - dispatcherThread = null; - for (final Thread thread : threads) { - if (thread != null && thread.getName().startsWith("QF/J Session dispatcher")) { - dispatcherThread = thread; - // Dispatcher threads are not daemon threads - assertThat(dispatcherThread.isDaemon(), is(false)); - break; + + assertTrue(session.hasResponder()); + // QFJ-790: we do not check the state of the responder anymore + // but wait for the END_OF_STREAM message to stop the threads. + strategy.onMessage(session, EventHandlingStrategy.END_OF_STREAM); + + // sleep some time to let the thread stop + for (int i = 0; i < 20; i++) { + Thread.sleep(100); + if (!dispatcherThread.isAlive()) { + break; + } + } + assertNull(strategy.getDispatcher(sessionID)); + + threads = new Thread[1024]; + Thread.enumerate(threads); + + dispatcherThread = null; + for (final Thread thread : threads) { + if (thread != null && thread.getName().startsWith("QF/J Session dispatcher")) { + dispatcherThread = thread; + // Dispatcher threads are not daemon threads + assertThat(dispatcherThread.isDaemon(), is(false)); + break; + } } + + // the session dispatcher should be dead and hence not listed in the threads array + assertNull(dispatcherThread); + assertFalse(session.hasResponder()); } - - // the session dispatcher should be dead and hence not listed in the threads array - assertNull(dispatcherThread); - assertFalse(session.hasResponder()); } @Test public void testEventHandlingInterruptInRun() throws Exception { final SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX40, "TW", "ISLD"); - final Session session = setUpSession(sessionID); - final Message message = new Logon(); - message.setInt(HeartBtInt.FIELD, 30); - final ThreadPerSessionEventHandlingStrategyUnderTest strategy = new ThreadPerSessionEventHandlingStrategyUnderTest(); - - strategy.onMessage(session, message); - strategy.getNextMessageException = new InterruptedException("TEST"); - strategy.getDispatcher(sessionID).run(); + try (Session session = setUpSession(sessionID)) { + final Message message = new Logon(); + message.setInt(HeartBtInt.FIELD, 30); + final ThreadPerSessionEventHandlingStrategyUnderTest strategy = new ThreadPerSessionEventHandlingStrategyUnderTest(); + + strategy.onMessage(session, message); + strategy.getNextMessageException = new InterruptedException("TEST"); + strategy.getDispatcher(sessionID).run(); + } } @Test public void testEventHandlingRuntimeException() throws Exception { final SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX40, "TW", "ISLD"); - final Session session = setUpSession(sessionID); - final Message message = new Logon(); - message.setInt(HeartBtInt.FIELD, 30); - final ThreadPerSessionEventHandlingStrategyUnderTest strategy = new ThreadPerSessionEventHandlingStrategyUnderTest(); - - strategy.onMessage(session, message); - strategy.getNextMessageException = new NullPointerException("TEST"); - strategy.getDispatcher(sessionID).run(); + try (Session session = setUpSession(sessionID)) { + final Message message = new Logon(); + message.setInt(HeartBtInt.FIELD, 30); + final ThreadPerSessionEventHandlingStrategyUnderTest strategy = new ThreadPerSessionEventHandlingStrategyUnderTest(); + + strategy.onMessage(session, message); + strategy.getNextMessageException = new NullPointerException("TEST"); + strategy.getDispatcher(sessionID).run(); + } } // verify the assumption that this always returns null diff --git a/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java b/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java index 718b2882f..cbc444a19 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java @@ -43,7 +43,6 @@ import java.util.HashMap; import java.util.Properties; -import static junit.framework.TestCase.fail; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; @@ -65,28 +64,29 @@ public void testFIXTLogonAndApplVerID() throws Exception { final SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIXT11, "SENDER", "TARGET"); - final Session session = SessionFactoryTestSupport.createSession(sessionID, - new UnitTestApplication(), false); - stub(mockIoSession.getAttribute("QF_SESSION")).toReturn(null); // to create a new Session - - final HashMap acceptorSessions = new HashMap<>(); - acceptorSessions.put(sessionID, session); - final StaticAcceptorSessionProvider sessionProvider = createSessionProvider(acceptorSessions); - - final AcceptorIoHandler handler = new AcceptorIoHandler(sessionProvider, - new NetworkingOptions(new Properties()), mockEventHandlingStrategy); - - final DefaultApplVerID defaultApplVerID = new DefaultApplVerID(ApplVerID.FIX50SP2); - final Logon message = new Logon(new EncryptMethod(EncryptMethod.NONE_OTHER), - new HeartBtInt(30), defaultApplVerID); - message.getHeader().setString(TargetCompID.FIELD, sessionID.getSenderCompID()); - message.getHeader().setString(SenderCompID.FIELD, sessionID.getTargetCompID()); - message.getHeader().setField(new SendingTime(LocalDateTime.now())); - message.getHeader().setInt(MsgSeqNum.FIELD, 1); - - handler.processMessage(mockIoSession, message); - assertEquals(defaultApplVerID.getValue(), session.getTargetDefaultApplicationVersionID() - .getValue()); + try (Session session = SessionFactoryTestSupport.createSession(sessionID, + new UnitTestApplication(), false)) { + stub(mockIoSession.getAttribute("QF_SESSION")).toReturn(null); // to create a new Session + + final HashMap acceptorSessions = new HashMap<>(); + acceptorSessions.put(sessionID, session); + final StaticAcceptorSessionProvider sessionProvider = createSessionProvider(acceptorSessions); + + final AcceptorIoHandler handler = new AcceptorIoHandler(sessionProvider, + new NetworkingOptions(new Properties()), mockEventHandlingStrategy); + + final DefaultApplVerID defaultApplVerID = new DefaultApplVerID(ApplVerID.FIX50SP2); + final Logon message = new Logon(new EncryptMethod(EncryptMethod.NONE_OTHER), + new HeartBtInt(30), defaultApplVerID); + message.getHeader().setString(TargetCompID.FIELD, sessionID.getSenderCompID()); + message.getHeader().setString(SenderCompID.FIELD, sessionID.getTargetCompID()); + message.getHeader().setField(new SendingTime(LocalDateTime.now())); + message.getHeader().setInt(MsgSeqNum.FIELD, 1); + + handler.processMessage(mockIoSession, message); + assertEquals(defaultApplVerID.getValue(), session.getTargetDefaultApplicationVersionID() + .getValue()); + } } @Test @@ -115,26 +115,27 @@ private StaticAcceptorSessionProvider createSessionProvider(HashMap acceptorSessions = new HashMap<>(); - - AcceptorIoHandler handler = new AcceptorIoHandler(createSessionProvider(acceptorSessions), - new NetworkingOptions(new Properties()), mockEventHandlingStrategy); - - handler.processMessage(mockIoSession, logout); - - verify(mockIoSession).getAttribute("QF_SESSION"); - verify(mockEventHandlingStrategy).onMessage(qfSession, logout); + try (Session qfSession = SessionFactoryTestSupport.createSession()) { + stub(mockIoSession.getAttribute("QF_SESSION")).toReturn(qfSession); + + EventHandlingStrategy mockEventHandlingStrategy = mock(EventHandlingStrategy.class); + + Logout logout = new Logout(); + logout.getHeader() + .setString(SenderCompID.FIELD, qfSession.getSessionID().getSenderCompID()); + logout.getHeader() + .setString(TargetCompID.FIELD, qfSession.getSessionID().getTargetCompID()); + + HashMap acceptorSessions = new HashMap<>(); + + AcceptorIoHandler handler = new AcceptorIoHandler(createSessionProvider(acceptorSessions), + new NetworkingOptions(new Properties()), mockEventHandlingStrategy); + + handler.processMessage(mockIoSession, logout); + + verify(mockIoSession).getAttribute("QF_SESSION"); + verify(mockEventHandlingStrategy).onMessage(qfSession, logout); + } } @Test @@ -145,26 +146,27 @@ public void testMessageBeforeLogonWithKnownButUnboundSession() throws Exception EventHandlingStrategy mockEventHandlingStrategy = mock(EventHandlingStrategy.class); - Session qfSession = SessionFactoryTestSupport.createSession(); - - Logout logout = new Logout(); - logout.getHeader() - .setString(SenderCompID.FIELD, qfSession.getSessionID().getSenderCompID()); - logout.getHeader() - .setString(TargetCompID.FIELD, qfSession.getSessionID().getTargetCompID()); - - // Expect that onMessage will not be called - //mockEventHandlingStrategy.onMessage(qfSession, logout); - - HashMap acceptorSessions = new HashMap<>(); - acceptorSessions.put(qfSession.getSessionID(), qfSession); - AcceptorIoHandler handler = new AcceptorIoHandler(createSessionProvider(acceptorSessions), - new NetworkingOptions(new Properties()), mockEventHandlingStrategy); - - handler.processMessage(mockIoSession, logout); - - verify(mockIoSession).getAttribute("QF_SESSION"); - verifyNoMoreInteractions(mockEventHandlingStrategy); + try (Session qfSession = SessionFactoryTestSupport.createSession()) { + + Logout logout = new Logout(); + logout.getHeader() + .setString(SenderCompID.FIELD, qfSession.getSessionID().getSenderCompID()); + logout.getHeader() + .setString(TargetCompID.FIELD, qfSession.getSessionID().getTargetCompID()); + + // Expect that onMessage will not be called + //mockEventHandlingStrategy.onMessage(qfSession, logout); + + HashMap acceptorSessions = new HashMap<>(); + acceptorSessions.put(qfSession.getSessionID(), qfSession); + AcceptorIoHandler handler = new AcceptorIoHandler(createSessionProvider(acceptorSessions), + new NetworkingOptions(new Properties()), mockEventHandlingStrategy); + + handler.processMessage(mockIoSession, logout); + + verify(mockIoSession).getAttribute("QF_SESSION"); + verifyNoMoreInteractions(mockEventHandlingStrategy); + } } // QFJ-933 @@ -175,30 +177,28 @@ public void testLogonWithoutHeartBtInt() throws Exception { final SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIXT11, "SENDER", "TARGET"); - final Session session = SessionFactoryTestSupport.createSession(sessionID, - new UnitTestApplication(), false); - stub(mockIoSession.getAttribute("QF_SESSION")).toReturn(null); // to create a new Session - - final HashMap acceptorSessions = new HashMap<>(); - acceptorSessions.put(sessionID, session); - final StaticAcceptorSessionProvider sessionProvider = createSessionProvider(acceptorSessions); - - final AcceptorIoHandler handler = new AcceptorIoHandler(sessionProvider, - new NetworkingOptions(new Properties()), mockEventHandlingStrategy); - - final DefaultApplVerID defaultApplVerID = new DefaultApplVerID(ApplVerID.FIX50SP2); - final Logon message = new Logon(new EncryptMethod(EncryptMethod.NONE_OTHER), - new HeartBtInt(30), defaultApplVerID); - message.getHeader().setString(TargetCompID.FIELD, sessionID.getSenderCompID()); - message.getHeader().setString(SenderCompID.FIELD, sessionID.getTargetCompID()); - message.getHeader().setField(new SendingTime(LocalDateTime.now())); - message.getHeader().setInt(MsgSeqNum.FIELD, 1); - // remove HeartBtInt field and make sure there is no Exception - message.removeField(HeartBtInt.FIELD); - try { + try (Session session = SessionFactoryTestSupport.createSession(sessionID, + new UnitTestApplication(), false)) { + stub(mockIoSession.getAttribute("QF_SESSION")).toReturn(null); // to create a new Session + + final HashMap acceptorSessions = new HashMap<>(); + acceptorSessions.put(sessionID, session); + final StaticAcceptorSessionProvider sessionProvider = createSessionProvider(acceptorSessions); + + final AcceptorIoHandler handler = new AcceptorIoHandler(sessionProvider, + new NetworkingOptions(new Properties()), mockEventHandlingStrategy); + + final DefaultApplVerID defaultApplVerID = new DefaultApplVerID(ApplVerID.FIX50SP2); + final Logon message = new Logon(new EncryptMethod(EncryptMethod.NONE_OTHER), + new HeartBtInt(30), defaultApplVerID); + message.getHeader().setString(TargetCompID.FIELD, sessionID.getSenderCompID()); + message.getHeader().setString(SenderCompID.FIELD, sessionID.getTargetCompID()); + message.getHeader().setField(new SendingTime(LocalDateTime.now())); + message.getHeader().setInt(MsgSeqNum.FIELD, 1); + // remove HeartBtInt field and make sure there is no Exception + message.removeField(HeartBtInt.FIELD); handler.processMessage(mockIoSession, message); - } catch (Exception e) { - fail("No exception should be thrown! " + e); + // No exception should be thrown! } } diff --git a/quickfixj-core/src/test/java/quickfix/mina/acceptor/DynamicAcceptorSessionProviderTest.java b/quickfixj-core/src/test/java/quickfix/mina/acceptor/DynamicAcceptorSessionProviderTest.java index bde9c3a16..5cfbf482e 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/acceptor/DynamicAcceptorSessionProviderTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/acceptor/DynamicAcceptorSessionProviderTest.java @@ -81,37 +81,40 @@ protected void setUp() throws Exception { public void testSessionCreation() throws Exception { - Session session1 = provider.getSession(new SessionID("FIX.4.2", "SENDER", "SENDERSUB", - "SENDERLOC", "TARGET", "TARGETSUB", "TARGETLOC", null), null); - SessionID sessionID1 = session1.getSessionID(); - assertEquals("wrong FIX version", "FIX.4.2", sessionID1.getBeginString()); - assertEquals("wrong sender", "SENDER", sessionID1.getSenderCompID()); - assertEquals("wrong senderSub", "SENDERSUB", sessionID1.getSenderSubID()); - assertEquals("wrong senderLoc", "SENDERLOC", sessionID1.getSenderLocationID()); - assertEquals("wrong target", "TARGET", sessionID1.getTargetCompID()); - assertEquals("wrong targetSub", "TARGETSUB", sessionID1.getTargetSubID()); - assertEquals("wrong targetLoc", "TARGETLOC", sessionID1.getTargetLocationID()); - assertEquals("wrong setting", false, session1.getResetOnLogout()); - assertEquals("wrong setting", false, session1.getRefreshOnLogon()); - assertEquals("wrong setting", false, session1.getCheckCompID()); - - Session session2 = provider.getSession(new SessionID("FIX.4.4", "S1", "T"), null); - SessionID sessionID2 = session2.getSessionID(); - assertEquals("wrong FIX version", "FIX.4.4", sessionID2.getBeginString()); - assertEquals("wrong sender", "S1", sessionID2.getSenderCompID()); - assertEquals("wrong target", "T", sessionID2.getTargetCompID()); - assertEquals("wrong setting", true, session2.getResetOnLogout()); - assertEquals("wrong setting", false, session2.getRefreshOnLogon()); - assertEquals("wrong setting", true, session2.getCheckCompID()); - - Session session3 = provider.getSession(new SessionID("FIX.4.4", "X", "Y"), null); - SessionID sessionID3 = session3.getSessionID(); - assertEquals("wrong FIX version", "FIX.4.4", sessionID3.getBeginString()); - assertEquals("wrong sender", "X", sessionID3.getSenderCompID()); - assertEquals("wrong target", "Y", sessionID3.getTargetCompID()); - assertEquals("wrong setting", false, session3.getResetOnLogout()); - assertEquals("wrong setting", true, session3.getRefreshOnLogon()); - assertEquals("wrong setting", true, session3.getCheckCompID()); + try (Session session1 = provider.getSession(new SessionID("FIX.4.2", "SENDER", "SENDERSUB", + "SENDERLOC", "TARGET", "TARGETSUB", "TARGETLOC", null), null)) { + SessionID sessionID1 = session1.getSessionID(); + assertEquals("wrong FIX version", "FIX.4.2", sessionID1.getBeginString()); + assertEquals("wrong sender", "SENDER", sessionID1.getSenderCompID()); + assertEquals("wrong senderSub", "SENDERSUB", sessionID1.getSenderSubID()); + assertEquals("wrong senderLoc", "SENDERLOC", sessionID1.getSenderLocationID()); + assertEquals("wrong target", "TARGET", sessionID1.getTargetCompID()); + assertEquals("wrong targetSub", "TARGETSUB", sessionID1.getTargetSubID()); + assertEquals("wrong targetLoc", "TARGETLOC", sessionID1.getTargetLocationID()); + assertEquals("wrong setting", false, session1.getResetOnLogout()); + assertEquals("wrong setting", false, session1.getRefreshOnLogon()); + assertEquals("wrong setting", false, session1.getCheckCompID()); + } + + try (Session session2 = provider.getSession(new SessionID("FIX.4.4", "S1", "T"), null)) { + SessionID sessionID2 = session2.getSessionID(); + assertEquals("wrong FIX version", "FIX.4.4", sessionID2.getBeginString()); + assertEquals("wrong sender", "S1", sessionID2.getSenderCompID()); + assertEquals("wrong target", "T", sessionID2.getTargetCompID()); + assertEquals("wrong setting", true, session2.getResetOnLogout()); + assertEquals("wrong setting", false, session2.getRefreshOnLogon()); + assertEquals("wrong setting", true, session2.getCheckCompID()); + } + + try (Session session3 = provider.getSession(new SessionID("FIX.4.4", "X", "Y"), null)) { + SessionID sessionID3 = session3.getSessionID(); + assertEquals("wrong FIX version", "FIX.4.4", sessionID3.getBeginString()); + assertEquals("wrong sender", "X", sessionID3.getSenderCompID()); + assertEquals("wrong target", "Y", sessionID3.getTargetCompID()); + assertEquals("wrong setting", false, session3.getResetOnLogout()); + assertEquals("wrong setting", true, session3.getRefreshOnLogon()); + assertEquals("wrong setting", true, session3.getCheckCompID()); + } } private void setUpSettings(SessionID templateID, String key, String value) { @@ -137,9 +140,10 @@ public void testToString() throws Exception { public void testSimpleConstructor() throws Exception { provider = new DynamicAcceptorSessionProvider(settings, new SessionID("FIX.4.2", "ANY", "ANY"), application, messageStoreFactory, logFactory, messageFactory); - // Should actually throw an exception if it fails (see previous test) - assertNotNull(provider.getSession(new SessionID("FIX.4.2", "S", "T"), null)); + try (Session session = provider.getSession(new SessionID("FIX.4.2", "S", "T"), null)) { + assertNotNull(session); + } } /** @@ -150,16 +154,18 @@ public void testDynamicSessionIsAddedToSessionConnector() throws Exception { SessionID id1 = new SessionID("FIX.4.2", "me", "SENDERSUB", "SENDERLOC", "you", "TARGETSUB", "TARGETLOC", null); - provider.getSession(id1, connector); + Session session = provider.getSession(id1, connector); assertEquals(1, connector.sessions.size()); // try again with same sesionID - should still be 1 - provider.getSession(id1, connector); + session = provider.getSession(id1, connector); assertEquals(1, connector.sessions.size()); + session.close(); SessionID id2 = new SessionID("FIX.4.2", "SENDER2", "SENDERSUB", "SENDERLOC", "TARGET2", "TARGETSUB", "TARGETLOC", null); - provider.getSession(id2, connector); + Session session2 = provider.getSession(id2, connector); assertEquals(2, connector.sessions.size()); + session2.close(); } private static class MySessionConnector extends SessionConnector { From d6b9c26360883c5bf96b9e42274b46ebdffa9cfd Mon Sep 17 00:00:00 2001 From: Christoph John Date: Sun, 11 Mar 2018 00:36:48 +0100 Subject: [PATCH 155/165] removed MaxPermSize setting this is not supported anymore on JDK8 --- quickfixj-core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickfixj-core/pom.xml b/quickfixj-core/pom.xml index 65a58df01..ea8d2fdcb 100644 --- a/quickfixj-core/pom.xml +++ b/quickfixj-core/pom.xml @@ -383,7 +383,7 @@ org.apache.maven.plugins maven-surefire-plugin - -Xmx512m -XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true + -Xmx512m -Djava.net.preferIPv4Stack=true **/*Test.java ${acceptance.tests} From a00e6f45e7e4a91e6e164eee084e8bb2db834350 Mon Sep 17 00:00:00 2001 From: Marcin L Date: Mon, 12 Mar 2018 09:31:18 +0000 Subject: [PATCH 156/165] improving flaky ssl certificate test (#179) --- .../src/test/java/quickfix/mina/ssl/SSLCertificateTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 d2a06d544..0ca88ab29 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java @@ -545,11 +545,11 @@ public TestConnector(SessionSettings sessionSettings) throws ConfigError { private SessionConnector prepareConnector(SessionSettings sessionSettings) throws ConfigError { SessionConnector sessionConnector = createConnector(sessionSettings); - sessionConnector.setIoFilterChainBuilder(chain -> chain.addLast("SSL exception handler", new IoFilterAdapter() { + sessionConnector.setIoFilterChainBuilder(chain -> chain.addFirst("Exception handler", new IoFilterAdapter() { @Override public void exceptionCaught(NextFilter nextFilter, IoSession session, Throwable cause) throws Exception { - LOGGER.info("SSL exception", cause); + LOGGER.info("exceptionCaught", cause); exceptionThrownLatch.countDown(); nextFilter.exceptionCaught(session, cause); } From 95184ad18f4e02706a1951820e10d9422eed6a5c Mon Sep 17 00:00:00 2001 From: Christoph John Date: Tue, 13 Mar 2018 12:41:04 +0100 Subject: [PATCH 157/165] added trimStackTrace=false to surefire config to get complete stack trace in case of Exceptions during test run --- quickfixj-core/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/quickfixj-core/pom.xml b/quickfixj-core/pom.xml index ea8d2fdcb..e9aaf276d 100644 --- a/quickfixj-core/pom.xml +++ b/quickfixj-core/pom.xml @@ -384,6 +384,7 @@ maven-surefire-plugin -Xmx512m -Djava.net.preferIPv4Stack=true + false **/*Test.java ${acceptance.tests} From d9208531feb5ed8ef697d0792a8e144fff5e0842 Mon Sep 17 00:00:00 2001 From: Marcin L Date: Tue, 13 Mar 2018 13:51:49 +0000 Subject: [PATCH 158/165] QFJ-932 - data dictionary validation format independent (#180) --- .../main/java/quickfix/DataDictionary.java | 18 +- .../java/quickfix/DataDictionaryTest.java | 494 ++++++++++++++++++ 2 files changed, 509 insertions(+), 3 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/DataDictionary.java b/quickfixj-core/src/main/java/quickfix/DataDictionary.java index d41d9ffbf..99e991ab8 100644 --- a/quickfixj-core/src/main/java/quickfix/DataDictionary.java +++ b/quickfixj-core/src/main/java/quickfix/DataDictionary.java @@ -812,6 +812,18 @@ private void checkHasRequired(String msgType, FieldMap fields, boolean bodyOnly) } } + private int countElementNodes(NodeList nodes) { + int elementNodesCount = 0; + + for (int i = 0; i < nodes.getLength(); i++) { + if (nodes.item(i).getNodeType() == Node.ELEMENT_NODE) { + elementNodesCount++; + } + } + + return elementNodesCount; + } + private void read(String location) throws ConfigError { final InputStream inputStream = FileUtil.open(getClass(), location, URL, FILESYSTEM, CONTEXT_RESOURCE, CLASSLOADER_RESOURCE); @@ -885,7 +897,7 @@ private void load(InputStream inputStream) throws ConfigError { } final NodeList fieldNodes = fieldsNode.item(0).getChildNodes(); - if (fieldNodes.getLength() == 0) { + if (countElementNodes(fieldNodes) == 0) { throw new ConfigError("No fields defined"); } @@ -964,7 +976,7 @@ private void load(InputStream inputStream) throws ConfigError { } final NodeList messageNodes = messagesNode.item(0).getChildNodes(); - if (messageNodes.getLength() == 0) { + if (countElementNodes(messageNodes) == 0) { throw new ConfigError("No messages defined"); } @@ -1000,7 +1012,7 @@ public int getNumMessageCategories() { private void load(Document document, String msgtype, Node node) throws ConfigError { String name; final NodeList fieldNodes = node.getChildNodes(); - if (fieldNodes.getLength() == 0) { + if (countElementNodes(fieldNodes) == 0) { throw new ConfigError("No fields found: msgType=" + msgtype); } diff --git a/quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java b/quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java index 520361d94..968d017da 100644 --- a/quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java +++ b/quickfixj-core/src/test/java/quickfix/DataDictionaryTest.java @@ -228,6 +228,500 @@ public void testHeaderTrailerRequired() throws Exception { assertFalse("Unknown trailer field shows up as required", dd.isRequiredTrailerField(666)); } + @Test + public void testMessageWithNoChildren40() throws Exception { + String data = ""; + data += ""; + data += "

"; + data += " "; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += ""; + + expectedException.expect(ConfigError.class); + expectedException.expectMessage("No fields found: msgType=msg"); + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testMessageWithTextElement40() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += " "; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += "
"; + + expectedException.expect(ConfigError.class); + expectedException.expectMessage("No fields found: msgType=msg"); + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testMessagesWithNoChildren40() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += " "; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += "
"; + + expectedException.expect(ConfigError.class); + expectedException.expectMessage("No messages defined"); + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testMessagesWithTextElement40() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += " "; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += "
"; + + expectedException.expect(ConfigError.class); + expectedException.expectMessage("No messages defined"); + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testHeaderWithNoChildren40() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += ""; + + expectedException.expect(ConfigError.class); + expectedException.expectMessage("No fields found: msgType=HEADER"); + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testHeaderWithTextElement40() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += "
"; + + expectedException.expect(ConfigError.class); + expectedException.expectMessage("No fields found: msgType=HEADER"); + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testTrailerWithNoChildren40() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += " "; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += "
"; + + expectedException.expect(ConfigError.class); + expectedException.expectMessage("No fields found: msgType=TRAILER"); + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testTrailerWithTextElement40() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += " "; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += "
"; + + expectedException.expect(ConfigError.class); + expectedException.expectMessage("No fields found: msgType=TRAILER"); + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testFieldsWithNoChildren40() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += " "; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += "
"; + + expectedException.expect(ConfigError.class); + expectedException.expectMessage("No fields defined"); + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testFieldsWithTextElement40() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += " "; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += "
"; + + expectedException.expect(ConfigError.class); + expectedException.expectMessage("No fields defined"); + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testMessageWithNoChildren50() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += " "; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += "
"; + + expectedException.expect(ConfigError.class); + expectedException.expectMessage("No fields found: msgType=msg"); + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testMessageWithTextElement50() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += " "; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += "
"; + + expectedException.expect(ConfigError.class); + expectedException.expectMessage("No fields found: msgType=msg"); + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testMessagesWithNoChildren50() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += " "; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += "
"; + + expectedException.expect(ConfigError.class); + expectedException.expectMessage("No messages defined"); + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testMessagesWithTextElement50() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += " "; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += "
"; + + expectedException.expect(ConfigError.class); + expectedException.expectMessage("No messages defined"); + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testHeaderWithNoChildren50() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += ""; + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testHeaderWithTextElement50() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += "
"; + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testTrailerWithNoChildren50() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += " "; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += "
"; + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testTrailerWithTextElement50() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += " "; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += "
"; + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testFieldsWithNoChildren50() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += ""; + + expectedException.expect(ConfigError.class); + expectedException.expectMessage("No fields defined"); + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + + @Test + public void testFieldsWithTextElement50() throws Exception { + String data = ""; + data += ""; + data += "
"; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += " "; + data += ""; + + expectedException.expect(ConfigError.class); + expectedException.expectMessage("No fields defined"); + + new DataDictionary(new ByteArrayInputStream(data.getBytes())); + } + @Test public void testHeaderGroupField() throws Exception { DataDictionary dd = getDictionary(); From c14b77e30b4182e15f390d3635099fe77f50b654 Mon Sep 17 00:00:00 2001 From: Christoph John Date: Thu, 15 Mar 2018 09:35:53 +0100 Subject: [PATCH 159/165] QFJ-944 Misleading error message when receiving Logon with tag RawData(96) without RawDataLength(95) (#181) - improved error message --- quickfixj-core/src/main/java/quickfix/Message.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickfixj-core/src/main/java/quickfix/Message.java b/quickfixj-core/src/main/java/quickfix/Message.java index da6d44074..b458ae2ec 100644 --- a/quickfixj-core/src/main/java/quickfix/Message.java +++ b/quickfixj-core/src/main/java/quickfix/Message.java @@ -819,7 +819,7 @@ private StringField extractField(DataDictionary dataDictionary, FieldMap fields) try { fieldLength = fields.getInt(lengthField); } catch (final FieldNotFound e) { - throw new InvalidMessage("Tag " + e.field + " not found in " + messageData); + throw new InvalidMessage("Did not find length field " + e.field + " required to parse data field " + tag + " in " + messageData); } // since length is in bytes but data is a string, and it may also contain an SOH, From 980414b96cb39258f2d4ad8e54d8aaa9b28057c3 Mon Sep 17 00:00:00 2001 From: Christoph John Date: Mon, 19 Mar 2018 10:54:17 +0100 Subject: [PATCH 160/165] Update MINA to 2.0.17 (#177) (cherry picked from commit a06f31779d6455d40f15104f7c04d82efc3fe517) --- quickfixj-core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickfixj-core/pom.xml b/quickfixj-core/pom.xml index e9aaf276d..7874eace0 100644 --- a/quickfixj-core/pom.xml +++ b/quickfixj-core/pom.xml @@ -59,7 +59,7 @@ org.apache.mina mina-core - 2.0.16 + 2.0.17 org.slf4j From c25aff7bf67d4d8bca159cc1c0ade7bbd931d8fb Mon Sep 17 00:00:00 2001 From: Christoph John Date: Mon, 19 Mar 2018 11:05:32 +0100 Subject: [PATCH 161/165] QFJ-942: Observing hangs in dispose() on stop() (#178) * QFJ-942: Connectors sometimes hanging in call to dispose() when stop() was called - introduced SessionConnector.closeManagedSessionsAndDispose() which makes an effort to close all managed sessions and disposes the IoService - used new method in Acceptor, Initiator and TestConnection (used for acceptance tests) --- .../main/java/quickfix/mina/QueueTracker.java | 1 - .../java/quickfix/mina/SessionConnector.java | 31 +++++++++++++++++++ .../mina/acceptor/AbstractSocketAcceptor.java | 2 +- .../mina/initiator/IoSessionInitiator.java | 17 +++++++--- .../java/quickfix/SocketInitiatorTest.java | 8 ++--- .../test/acceptance/TestConnection.java | 16 +++------- 6 files changed, 52 insertions(+), 23 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/mina/QueueTracker.java b/quickfixj-core/src/main/java/quickfix/mina/QueueTracker.java index 3f47341bf..aa2928e5e 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/QueueTracker.java +++ b/quickfixj-core/src/main/java/quickfix/mina/QueueTracker.java @@ -1,7 +1,6 @@ package quickfix.mina; import java.util.Collection; -import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; interface QueueTracker { diff --git a/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java b/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java index f0ce6cc3b..eeeae51b0 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java +++ b/quickfixj-core/src/main/java/quickfix/mina/SessionConnector.java @@ -50,6 +50,8 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; +import org.apache.mina.core.future.CloseFuture; +import org.apache.mina.core.service.IoService; /** * An abstract base class for acceptors and initiators. Provides support for common functionality and also serves as an @@ -423,4 +425,33 @@ public void setIoFilterChainBuilder(IoFilterChainBuilder ioFilterChainBuilder) { protected IoFilterChainBuilder getIoFilterChainBuilder() { return ioFilterChainBuilder; } + + /** + * Closes all managed sessions of an Initiator/Acceptor. + * + * @param ioService Acceptor or Initiator implementation + * @param awaitTermination whether to wait for underlying ExecutorService to terminate + * @param logger used for logging WARNING when IoSession could not be closed + */ + public static void closeManagedSessionsAndDispose(IoService ioService, boolean awaitTermination, Logger logger) { + Map managedSessions = ioService.getManagedSessions(); + for (IoSession ioSession : managedSessions.values()) { + if (!ioSession.isClosing()) { + CloseFuture closeFuture = ioSession.closeNow(); + boolean completed = false; + try { + completed = closeFuture.await(1000, TimeUnit.MILLISECONDS); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + if (!completed) { + logger.warn("Could not close IoSession {}", ioSession); + } + } + } + if (!ioService.isDisposing()) { + ioService.dispose(awaitTermination); + } + } + } diff --git a/quickfixj-core/src/main/java/quickfix/mina/acceptor/AbstractSocketAcceptor.java b/quickfixj-core/src/main/java/quickfix/mina/acceptor/AbstractSocketAcceptor.java index 76ac1a287..c78e19fe3 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/acceptor/AbstractSocketAcceptor.java +++ b/quickfixj-core/src/main/java/quickfix/mina/acceptor/AbstractSocketAcceptor.java @@ -248,7 +248,7 @@ protected void stopAcceptingConnections() throws ConfigError { IoAcceptor ioAcceptor = ioIt.next(); SocketAddress localAddress = ioAcceptor.getLocalAddress(); ioAcceptor.unbind(); - ioAcceptor.dispose(true); + closeManagedSessionsAndDispose(ioAcceptor, true, log); log.info("No longer accepting connections on {}", localAddress); ioIt.remove(); } diff --git a/quickfixj-core/src/main/java/quickfix/mina/initiator/IoSessionInitiator.java b/quickfixj-core/src/main/java/quickfix/mina/initiator/IoSessionInitiator.java index c6d190ab1..e70e6325d 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/initiator/IoSessionInitiator.java +++ b/quickfixj-core/src/main/java/quickfix/mina/initiator/IoSessionInitiator.java @@ -50,11 +50,14 @@ import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class IoSessionInitiator { private final static long CONNECT_POLL_TIMEOUT = 2000L; private final ScheduledExecutorService executor; private final ConnectTask reconnectTask; + private final Logger log = LoggerFactory.getLogger(getClass()); private Future reconnectFuture; @@ -74,7 +77,7 @@ public IoSessionInitiator(Session fixSession, SocketAddress[] socketAddresses, reconnectTask = new ConnectTask(sslEnabled, socketAddresses, localAddress, userIoFilterChainBuilder, fixSession, reconnectIntervalInMillis, networkingOptions, eventHandlingStrategy, sslConfig, - proxyType, proxyVersion, proxyHost, proxyPort, proxyUser, proxyPassword, proxyDomain, proxyWorkstation); + proxyType, proxyVersion, proxyHost, proxyPort, proxyUser, proxyPassword, proxyDomain, proxyWorkstation, log); } catch (GeneralSecurityException e) { throw new ConfigError(e); } @@ -93,6 +96,7 @@ private static class ConnectTask implements Runnable { private final NetworkingOptions networkingOptions; private final EventHandlingStrategy eventHandlingStrategy; private final SSLConfig sslConfig; + private final Logger log; private IoSession ioSession; private long lastReconnectAttemptTime; @@ -116,7 +120,7 @@ public ConnectTask(boolean sslEnabled, SocketAddress[] socketAddresses, NetworkingOptions networkingOptions, EventHandlingStrategy eventHandlingStrategy, SSLConfig sslConfig, String proxyType, String proxyVersion, String proxyHost, int proxyPort, String proxyUser, String proxyPassword, String proxyDomain, - String proxyWorkstation) throws ConfigError, GeneralSecurityException { + String proxyWorkstation, Logger log) throws ConfigError, GeneralSecurityException { this.sslEnabled = sslEnabled; this.socketAddresses = socketAddresses; this.localAddress = localAddress; @@ -126,6 +130,7 @@ public ConnectTask(boolean sslEnabled, SocketAddress[] socketAddresses, this.networkingOptions = networkingOptions; this.eventHandlingStrategy = eventHandlingStrategy; this.sslConfig = sslConfig; + this.log = log; this.proxyType = proxyType; this.proxyVersion = proxyVersion; @@ -173,7 +178,7 @@ private void setupIoConnector() throws ConfigError, GeneralSecurityException { } if (ioConnector != null) { - ioConnector.dispose(); + SessionConnector.closeManagedSessionsAndDispose(ioConnector, true, log); } ioConnector = newConnector; } @@ -338,6 +343,9 @@ private void resetIoConnector() { connectFuture.cancel(); } connectFuture = null; + if (!ioSession.isClosing()) { + ioSession.closeNow(); + } ioSession = null; } catch (Throwable e) { LogUtil.logThrowable(fixSession.getLog(), "Exception during resetIoConnector call", e); @@ -361,7 +369,6 @@ synchronized void stop() { reconnectFuture.cancel(true); reconnectFuture = null; } - // QFJ-849: clean up resources of MINA connector - reconnectTask.ioConnector.dispose(); + SessionConnector.closeManagedSessionsAndDispose(reconnectTask.ioConnector, true, log); } } diff --git a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java index aefc8bc7b..f945a6767 100644 --- a/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java +++ b/quickfixj-core/src/test/java/quickfix/SocketInitiatorTest.java @@ -376,10 +376,11 @@ private void doTestOfRestart(SessionID clientSessionID, ClientApplication client Session clientSession = Session.lookupSession(clientSessionID); assertLoggedOn(clientApplication, clientSession); + clientApplication.setUpLogoutExpectation(); initiator.stop(); - assertFalse(clientSession.isLoggedOn()); + assertLoggedOut(clientApplication, clientSession); assertFalse(initiator.getSessions().contains(clientSessionID)); - assertTrue(initiator.getSessions().size() == 0); + assertTrue(initiator.getSessions().isEmpty()); if (messageLog != null) { messageLogLength = messageLog.length(); assertTrue(messageLog.length() > 0); @@ -482,9 +483,6 @@ private void assertLoggedOn(ClientApplication clientApplication, Session clientS } final boolean await = clientApplication.logonLatch.await(20, TimeUnit.SECONDS); - if (!await) { - ReflectionUtil.dumpStackTraces(); - } assertTrue("Expected logon did not occur", await); assertTrue("client session not logged in", clientSession.isLoggedOn()); } diff --git a/quickfixj-core/src/test/java/quickfix/test/acceptance/TestConnection.java b/quickfixj-core/src/test/java/quickfix/test/acceptance/TestConnection.java index de8303009..36fc4f040 100644 --- a/quickfixj-core/src/test/java/quickfix/test/acceptance/TestConnection.java +++ b/quickfixj-core/src/test/java/quickfix/test/acceptance/TestConnection.java @@ -48,6 +48,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; +import quickfix.mina.SessionConnector; public class TestConnection { private static final HashMap connectors = new HashMap<>(); @@ -85,27 +86,20 @@ public void connect(int clientId, int transportType, int port) throws IOException { IoConnector connector = connectors.get(Integer.toString(clientId)); if (connector != null) { - log.info("Disposing connector for clientId " + clientId); - connector.dispose(); + SessionConnector.closeManagedSessionsAndDispose(connector, true, log); } - if (transportType == ProtocolFactory.SOCKET) { - connector = new NioSocketConnector(); - } else if (transportType == ProtocolFactory.VM_PIPE) { - connector = new VmPipeConnector(); - } else { - throw new RuntimeException("Unsupported transport type: " + transportType); - } - connectors.put(Integer.toString(clientId), connector); - SocketAddress address; if (transportType == ProtocolFactory.SOCKET) { + connector = new NioSocketConnector(); address = new InetSocketAddress("localhost", port); } else if (transportType == ProtocolFactory.VM_PIPE) { + connector = new VmPipeConnector(); address = new VmPipeAddress(port); } else { throw new RuntimeException("Unsupported transport type: " + transportType); } + connectors.put(Integer.toString(clientId), connector); TestIoHandler testIoHandler = new TestIoHandler(); synchronized (ioHandlers) { From e3843366dc597c622deae39ab911836ee91bd7dd Mon Sep 17 00:00:00 2001 From: chrjohn Date: Thu, 29 Mar 2018 22:40:15 +0200 Subject: [PATCH 162/165] Fixed SLF4JLogTest. --- .../src/test/java/quickfix/SLF4JLogTest.java | 87 ++++++++++--------- 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/quickfixj-core/src/test/java/quickfix/SLF4JLogTest.java b/quickfixj-core/src/test/java/quickfix/SLF4JLogTest.java index 4df76477f..d3bc9e482 100644 --- a/quickfixj-core/src/test/java/quickfix/SLF4JLogTest.java +++ b/quickfixj-core/src/test/java/quickfix/SLF4JLogTest.java @@ -19,34 +19,34 @@ package quickfix; -import junit.framework.TestCase; import org.slf4j.Marker; import org.slf4j.spi.LocationAwareLogger; import java.util.ArrayList; -import java.util.Vector; +import java.util.List; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; +import org.junit.After; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import org.junit.Before; +import org.junit.Test; -public class SLF4JLogTest extends TestCase { - public SLF4JLogTest(String name) { - super(name); - } +public class SLF4JLogTest { - @Override - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { SystemTime.setTimeSource(new MockSystemTimeSource(System.currentTimeMillis())); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { SystemTime.setTimeSource(null); - super.tearDown(); } + @Test public void testLog() throws Exception { final SessionID sessionID = new SessionID("FIX.4.2", "SENDER" + System.currentTimeMillis(), "TARGET" + System.currentTimeMillis()); @@ -58,19 +58,19 @@ public void testLog() throws Exception { final String loggedText = "TEST123"; - setUpLoggerForTest(SLF4JLog.DEFAULT_EVENT_CATEGORY); + setUpLoggerForTest(SLF4JLog.DEFAULT_EVENT_CATEGORY, sessionID); log.onEvent(loggedText); assertMessageLogged(sessionID, SLF4JLog.DEFAULT_EVENT_CATEGORY, loggedText); - setUpLoggerForTest(SLF4JLog.DEFAULT_ERROR_EVENT_CATEGORY); + setUpLoggerForTest(SLF4JLog.DEFAULT_ERROR_EVENT_CATEGORY, sessionID); log.onErrorEvent(loggedText); assertMessageLogged(sessionID, SLF4JLog.DEFAULT_ERROR_EVENT_CATEGORY, loggedText); - setUpLoggerForTest(SLF4JLog.DEFAULT_INCOMING_MSG_CATEGORY); + setUpLoggerForTest(SLF4JLog.DEFAULT_INCOMING_MSG_CATEGORY, sessionID); log.onIncoming(loggedText); assertMessageLogged(sessionID, SLF4JLog.DEFAULT_INCOMING_MSG_CATEGORY, loggedText); - setUpLoggerForTest(SLF4JLog.DEFAULT_OUTGOING_MSG_CATEGORY); + setUpLoggerForTest(SLF4JLog.DEFAULT_OUTGOING_MSG_CATEGORY, sessionID); log.onOutgoing(loggedText); assertMessageLogged(sessionID, SLF4JLog.DEFAULT_OUTGOING_MSG_CATEGORY, loggedText); @@ -80,23 +80,24 @@ public void testLog() throws Exception { settings.setString(sessionID, SLF4JLogFactory.SETTING_OUTMSG_CATEGORY, "out"); log = factory.create(sessionID); - setUpLoggerForTest("event"); + setUpLoggerForTest("event", sessionID); log.onEvent(loggedText); assertMessageLogged(sessionID, "event", loggedText); - setUpLoggerForTest("errorEvent"); + setUpLoggerForTest("errorEvent", sessionID); log.onErrorEvent(loggedText); assertMessageLogged(sessionID, "errorEvent", loggedText); - setUpLoggerForTest("in"); + setUpLoggerForTest("in", sessionID); log.onIncoming(loggedText); assertMessageLogged(sessionID, "in", loggedText); - setUpLoggerForTest("out"); + setUpLoggerForTest("out", sessionID); log.onOutgoing(loggedText); assertMessageLogged(sessionID, "out", loggedText); } + @Test public void testLogHeartbeatFiltering() throws Exception { final SessionID sessionID = new SessionID("FIX.4.2", "SENDER" + System.currentTimeMillis(), "TARGET" + System.currentTimeMillis()); @@ -108,26 +109,27 @@ public void testLogHeartbeatFiltering() throws Exception { final String loggedText = "HEARTBEAT\00135=0\001"; - setUpLoggerForTest(SLF4JLog.DEFAULT_INCOMING_MSG_CATEGORY); + setUpLoggerForTest(SLF4JLog.DEFAULT_INCOMING_MSG_CATEGORY, sessionID); log.onIncoming(loggedText); assertMessageLogged(sessionID, SLF4JLog.DEFAULT_INCOMING_MSG_CATEGORY, loggedText); - setUpLoggerForTest(SLF4JLog.DEFAULT_OUTGOING_MSG_CATEGORY); + setUpLoggerForTest(SLF4JLog.DEFAULT_OUTGOING_MSG_CATEGORY, sessionID); log.onOutgoing(loggedText); assertMessageLogged(sessionID, SLF4JLog.DEFAULT_OUTGOING_MSG_CATEGORY, loggedText); settings.setBool(sessionID, SLF4JLogFactory.SETTING_LOG_HEARTBEATS, false); log = (SLF4JLog) factory.create(sessionID); - setUpLoggerForTest(SLF4JLog.DEFAULT_INCOMING_MSG_CATEGORY); + setUpLoggerForTest(SLF4JLog.DEFAULT_INCOMING_MSG_CATEGORY, sessionID); log.onIncoming(loggedText); assertMessageNotLogged(sessionID, SLF4JLog.DEFAULT_INCOMING_MSG_CATEGORY); - setUpLoggerForTest(SLF4JLog.DEFAULT_OUTGOING_MSG_CATEGORY); + setUpLoggerForTest(SLF4JLog.DEFAULT_OUTGOING_MSG_CATEGORY, sessionID); log.onOutgoing(loggedText); assertMessageNotLogged(sessionID, SLF4JLog.DEFAULT_OUTGOING_MSG_CATEGORY); } + @Test public void testLogFilteredByLevel() throws Exception { final SessionID sessionID = new SessionID("FIX.4.2", "SENDER" + System.currentTimeMillis(), "TARGET" + System.currentTimeMillis()); @@ -139,23 +141,23 @@ public void testLogFilteredByLevel() throws Exception { final String loggedText = "TEST123"; - setUpLoggerForTest(SLF4JLog.DEFAULT_EVENT_CATEGORY); - getTestHandler(SLF4JLog.DEFAULT_EVENT_CATEGORY).setLevel(Level.WARNING); + setUpLoggerForTest(SLF4JLog.DEFAULT_EVENT_CATEGORY, sessionID); + getTestHandler(SLF4JLog.DEFAULT_EVENT_CATEGORY, sessionID).setLevel(Level.WARNING); log.onEvent(loggedText); assertMessageNotLogged(sessionID, SLF4JLog.DEFAULT_EVENT_CATEGORY); - setUpLoggerForTest(SLF4JLog.DEFAULT_ERROR_EVENT_CATEGORY); - getTestHandler(SLF4JLog.DEFAULT_ERROR_EVENT_CATEGORY).setLevel(Level.SEVERE); + setUpLoggerForTest(SLF4JLog.DEFAULT_ERROR_EVENT_CATEGORY, sessionID); + getTestHandler(SLF4JLog.DEFAULT_ERROR_EVENT_CATEGORY, sessionID).setLevel(Level.SEVERE); log.onErrorEvent(loggedText); assertMessageNotLogged(sessionID, SLF4JLog.DEFAULT_EVENT_CATEGORY); - setUpLoggerForTest(SLF4JLog.DEFAULT_INCOMING_MSG_CATEGORY); - getTestHandler(SLF4JLog.DEFAULT_INCOMING_MSG_CATEGORY).setLevel(Level.WARNING); + setUpLoggerForTest(SLF4JLog.DEFAULT_INCOMING_MSG_CATEGORY, sessionID); + getTestHandler(SLF4JLog.DEFAULT_INCOMING_MSG_CATEGORY, sessionID).setLevel(Level.WARNING); log.onIncoming(loggedText); assertMessageNotLogged(sessionID, SLF4JLog.DEFAULT_INCOMING_MSG_CATEGORY); - setUpLoggerForTest(SLF4JLog.DEFAULT_OUTGOING_MSG_CATEGORY); - getTestHandler(SLF4JLog.DEFAULT_OUTGOING_MSG_CATEGORY).setLevel(Level.WARNING); + setUpLoggerForTest(SLF4JLog.DEFAULT_OUTGOING_MSG_CATEGORY, sessionID); + getTestHandler(SLF4JLog.DEFAULT_OUTGOING_MSG_CATEGORY, sessionID).setLevel(Level.WARNING); log.onOutgoing(loggedText); assertMessageNotLogged(sessionID, SLF4JLog.DEFAULT_OUTGOING_MSG_CATEGORY); } @@ -165,6 +167,7 @@ public void testLogFilteredByLevel() throws Exception { * the right wrapper function so that the appropriate calling location shows up * instead of our wrapper SLF4JLog class itself */ + @Test public void testLog4j_correctFQCN() throws Exception { final MyLog4JLog myLog4j = new MyLog4JLog(); final SLF4JLog slf4jLog = new MySLF4JLog(new SessionID("FIX.4.2", "sender", "target"), @@ -179,25 +182,25 @@ public void testLog4j_correctFQCN() throws Exception { } private void assertMessageNotLogged(SessionID sessionID, String categoryName) { - final TestHandler testHandler = getTestHandler(categoryName); + final TestHandler testHandler = getTestHandler(categoryName, sessionID); assertEquals(0, testHandler.records.size()); } private void assertMessageLogged(SessionID sessionID, String categoryName, String message) { - final TestHandler testHandler = getTestHandler(categoryName); + final TestHandler testHandler = getTestHandler(categoryName, sessionID); assertEquals(1, testHandler.records.size()); final LogRecord r = testHandler.records.get(0); if (r.getLoggerName() != null) { // The conditional is required because of a bug in SLF4J 1.0 // when used with JDK 1.4 logging. The wrapper does not pass // the logger name. - assertEquals(categoryName, r.getLoggerName()); + assertEquals(categoryName + sessionID + ": ", r.getLoggerName()); } - assertEquals(sessionID + ": " + message, r.getMessage()); + assertEquals(message, r.getMessage()); } - private TestHandler getTestHandler(String categoryName) { - final Logger logger = Logger.getLogger(categoryName); + private TestHandler getTestHandler(String categoryName, SessionID sessionID) { + final Logger logger = Logger.getLogger(categoryName + sessionID + ": "); TestHandler testHandler = null; final Handler[] handlers = logger.getHandlers(); for (final Handler handler : handlers) { @@ -210,8 +213,8 @@ private TestHandler getTestHandler(String categoryName) { return testHandler; } - private TestHandler setUpLoggerForTest(String category) { - final Logger logger = Logger.getLogger(category); + private TestHandler setUpLoggerForTest(String category, SessionID sessionID) { + final Logger logger = Logger.getLogger(category + sessionID + ": "); logger.setUseParentHandlers(false); final Handler[] handlers = logger.getHandlers(); for (final Handler handler : handlers) { @@ -258,8 +261,8 @@ protected void log(org.slf4j.Logger log, String text) { } private class MyLog4JLog extends DummySLF4JLogger implements LocationAwareLogger { - final Vector messages = new Vector<>(); - final Vector fqcns = new Vector<>(); + final List messages = new ArrayList<>(); + final List fqcns = new ArrayList<>(); public void log(Marker marker, String fqcn, int level, String message, Object[] params, Throwable t) { From 113630513f92c03db03e2a9da193789f03956d19 Mon Sep 17 00:00:00 2001 From: Christoph John Date: Sat, 31 Mar 2018 23:44:04 +0200 Subject: [PATCH 163/165] no-op change to trigger Travis build --- quickfixj-core/src/main/java/quickfix/Message.java | 1 + 1 file changed, 1 insertion(+) diff --git a/quickfixj-core/src/main/java/quickfix/Message.java b/quickfixj-core/src/main/java/quickfix/Message.java index 6054f77ca..cfd7d25fa 100644 --- a/quickfixj-core/src/main/java/quickfix/Message.java +++ b/quickfixj-core/src/main/java/quickfix/Message.java @@ -943,4 +943,5 @@ public static MsgType identifyType(String message) throws MessageParseError { } } + } From 556432134c896b2fe38b771f644a68a07cebec5c Mon Sep 17 00:00:00 2001 From: chrjohn Date: Wed, 2 May 2018 22:54:41 +0200 Subject: [PATCH 164/165] - changed logic to work also with incomplete messages, i.e. where BeginString etc have not been added yet - updated MessageTest - changed NumbersCache to only hold numbers up to 99999 since it should be sufficient for normal use cases - minor renaming --- .../src/main/java/quickfix/Message.java | 43 +++++++------------ .../src/main/java/quickfix/NumbersCache.java | 33 +++++--------- .../src/test/java/quickfix/MessageTest.java | 21 ++++++++- 3 files changed, 46 insertions(+), 51 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/Message.java b/quickfixj-core/src/main/java/quickfix/Message.java index af1016f40..b1f461b18 100644 --- a/quickfixj-core/src/main/java/quickfix/Message.java +++ b/quickfixj-core/src/main/java/quickfix/Message.java @@ -138,7 +138,7 @@ protected Context initialValue() { } }; - private static final boolean isStringEquivalent = CharsetSupport.isStringEquivalent(CharsetSupport.getCharsetInstance()); + private static final boolean IS_STRING_EQUIVALENT = CharsetSupport.isStringEquivalent(CharsetSupport.getCharsetInstance()); /** * Do not call this method concurrently while modifying the contents of the message. @@ -152,7 +152,7 @@ protected Context initialValue() { @Override public String toString() { Context context = stringContexts.get(); - if(isStringEquivalent) { // length & checksum can easily be calculated after message is built + if (IS_STRING_EQUIVALENT) { // length & checksum can easily be calculated after message is built header.setField(context.bodyLength); trailer.setField(context.checkSum); } else { @@ -164,7 +164,7 @@ public String toString() { header.calculateString(stringBuilder, null, null); calculateString(stringBuilder, null, null); trailer.calculateString(stringBuilder, null, null); - if(isStringEquivalent) { + if (IS_STRING_EQUIVALENT) { setBodyLength(stringBuilder); setChecksum(stringBuilder); } @@ -174,42 +174,29 @@ public String toString() { } } - private static final String beginStringField = String.valueOf(BeginString.FIELD); - private static final String separatorFix = String.valueOf('\001'); - private static final String bodyLengthField = separatorFix + String.valueOf(BodyLength.FIELD) + '='; - private static final String checkSumField = separatorFix + String.valueOf(CheckSum.FIELD) + '='; + private static final String SOH = String.valueOf('\001'); + private static final String BODY_LENGTH_FIELD = SOH + String.valueOf(BodyLength.FIELD) + '='; + private static final String CHECKSUM_FIELD = SOH + String.valueOf(CheckSum.FIELD) + '='; private static void setBodyLength(StringBuilder stringBuilder) { - int index = indexOf(stringBuilder, beginStringField, 0); - if(index != 0) - throw new IllegalArgumentException("Malformed FIX message"); - int bodyLengthIndex = getIndex(stringBuilder, bodyLengthField, 0); - index = getIndex(stringBuilder, separatorFix, bodyLengthIndex + 1); - int checkSumIndex = lastIndexOf(stringBuilder, checkSumField); - if(checkSumIndex < 0) - throw new IllegalArgumentException("Malformed FIX message"); - int length = checkSumIndex - index; - bodyLengthIndex += bodyLengthField.length(); + int bodyLengthIndex = indexOf(stringBuilder, BODY_LENGTH_FIELD, 0); + int sohIndex = indexOf(stringBuilder, SOH, bodyLengthIndex + 1); + int checkSumIndex = lastIndexOf(stringBuilder, CHECKSUM_FIELD); + int length = checkSumIndex - sohIndex; + bodyLengthIndex += BODY_LENGTH_FIELD.length(); stringBuilder.replace(bodyLengthIndex, bodyLengthIndex + 3, NumbersCache.get(length)); } private static void setChecksum(StringBuilder stringBuilder) { - int checkSumIndex = lastIndexOf(stringBuilder, checkSumField); + int checkSumIndex = lastIndexOf(stringBuilder, CHECKSUM_FIELD); int checkSum = 0; for(int i = checkSumIndex; i-- != 0;) checkSum += stringBuilder.charAt(i); - String checkSumValue = NumbersCache.get((checkSum + 1) % 256); - checkSumIndex += checkSumField.length(); + String checkSumValue = NumbersCache.get((checkSum + 1) & 0xFF); // better than sum % 256 since it avoids overflow issues + checkSumIndex += CHECKSUM_FIELD.length(); stringBuilder.replace(checkSumIndex + (3 - checkSumValue.length()), checkSumIndex + 3, checkSumValue); } - private static int getIndex(StringBuilder stringBuilder, String value, int fromIndex) { - int index = indexOf(stringBuilder, value, fromIndex); - if(index < 0) - throw new IllegalArgumentException("Malformed FIX message"); - return index; - } - // return index of a string in a stringbuilder without performing allocations private static int indexOf(StringBuilder source, String target, int fromIndex) { if (fromIndex >= source.length()) @@ -236,7 +223,7 @@ private static int indexOf(StringBuilder source, String target, int fromIndex) { } // return last index of a string in a stringbuilder without performing allocations - static int lastIndexOf(StringBuilder source, String target) { + private static int lastIndexOf(StringBuilder source, String target) { int rightIndex = source.length() - target.length(); int fromIndex = source.length(); if (fromIndex > rightIndex) diff --git a/quickfixj-core/src/main/java/quickfix/NumbersCache.java b/quickfixj-core/src/main/java/quickfix/NumbersCache.java index a3c72707a..1a3725884 100644 --- a/quickfixj-core/src/main/java/quickfix/NumbersCache.java +++ b/quickfixj-core/src/main/java/quickfix/NumbersCache.java @@ -22,40 +22,29 @@ import java.util.ArrayList; /** - * A cache for commonly used string representing numbers. - * Hold values from 0 to 999999 and from 1000 to 200 000 000 by step of 1000 + * A cache for commonly used strings representing numbers. + * Holds values from 0 to 99999. */ public final class NumbersCache { - private static final int littleNumbersLength = 1000000; - private static final int bigNumbersLength = 200000; - private static final int bigNumbersOffset = 1000; - private static final int bigNumbersMax = bigNumbersLength * bigNumbersOffset; - - public static final ArrayList littleNumbers; - public static final ArrayList bigNumbers; + private static final int LITTLE_NUMBERS_LENGTH = 100000; + private static final ArrayList LITTLE_NUMBERS; static { - littleNumbers = new ArrayList(littleNumbersLength); - bigNumbers = new ArrayList(bigNumbersLength); - for (int i = 0; i < littleNumbersLength; i++) - littleNumbers.add(Integer.toString(i)); - for (long i = 0; i < bigNumbersLength;) - bigNumbers.add(Long.toString(++i * bigNumbersOffset)); - + LITTLE_NUMBERS = new ArrayList<>(LITTLE_NUMBERS_LENGTH); + for (int i = 0; i < LITTLE_NUMBERS_LENGTH; i++) + LITTLE_NUMBERS.add(Integer.toString(i)); } /** - * Get the string representing the given number + * Get the String representing the given number * * @param i the long to convert * @return the String representing the long */ - public static String get(long i) { - if (i < littleNumbersLength) - return littleNumbers.get((int)i); - if (i <= bigNumbersMax && i % bigNumbersOffset == 0) - return bigNumbers.get((int)(i/bigNumbersOffset)-1); + public static String get(int i) { + if (i < LITTLE_NUMBERS_LENGTH) + return LITTLE_NUMBERS.get(i); return String.valueOf(i); } diff --git a/quickfixj-core/src/test/java/quickfix/MessageTest.java b/quickfixj-core/src/test/java/quickfix/MessageTest.java index 9368604d2..fbe200efd 100644 --- a/quickfixj-core/src/test/java/quickfix/MessageTest.java +++ b/quickfixj-core/src/test/java/quickfix/MessageTest.java @@ -19,6 +19,7 @@ package quickfix; +import java.lang.reflect.Modifier; import org.junit.Test; import org.quickfixj.CharsetSupport; import quickfix.field.Account; @@ -102,7 +103,14 @@ import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.Calendar; +import java.util.List; import java.util.TimeZone; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -240,14 +248,25 @@ public void testEmbeddedMessage() throws Exception { private void doTestMessageWithEncodedField(String charset, String text) throws Exception { CharsetSupport.setCharset(charset); + NewOrderSingle order = createNewOrderSingle(); + java.lang.reflect.Field declaredField = Message.class.getDeclaredField("IS_STRING_EQUIVALENT"); try { - NewOrderSingle order = createNewOrderSingle(); + // Some reflection magic to overwrite static final field in Message.class... + // We want to keep the field static final since its value does not change through + // the lifetime of the application but this test tests several charsets. + declaredField.setAccessible(true); + java.lang.reflect.Field modifiersField = java.lang.reflect.Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(declaredField, declaredField.getModifiers() & ~Modifier.FINAL); + declaredField.set(null, CharsetSupport.isStringEquivalent(CharsetSupport.getCharsetInstance())); + order.set(new EncodedTextLen(MessageUtils.length(CharsetSupport.getCharsetInstance(), text))); order.set(new EncodedText(text)); final Message msg = new Message(order.toString(), DataDictionaryTest.getDictionary()); assertEquals(charset + " encoded field", text, msg.getString(EncodedText.FIELD)); } finally { CharsetSupport.setCharset(CharsetSupport.getDefaultCharset()); + declaredField.set(null, CharsetSupport.isStringEquivalent(CharsetSupport.getCharsetInstance())); } } From 7f3c51e6ce8b9865c226e50d6515fae582a18681 Mon Sep 17 00:00:00 2001 From: chrjohn Date: Thu, 3 May 2018 00:22:24 +0200 Subject: [PATCH 165/165] trying to make unit test work --- .../src/main/java/quickfix/Message.java | 2 +- .../src/test/java/quickfix/MessageTest.java | 23 +++---------------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/Message.java b/quickfixj-core/src/main/java/quickfix/Message.java index b1f461b18..f227808d6 100644 --- a/quickfixj-core/src/main/java/quickfix/Message.java +++ b/quickfixj-core/src/main/java/quickfix/Message.java @@ -138,7 +138,7 @@ protected Context initialValue() { } }; - private static final boolean IS_STRING_EQUIVALENT = CharsetSupport.isStringEquivalent(CharsetSupport.getCharsetInstance()); + protected static boolean IS_STRING_EQUIVALENT = CharsetSupport.isStringEquivalent(CharsetSupport.getCharsetInstance()); /** * Do not call this method concurrently while modifying the contents of the message. diff --git a/quickfixj-core/src/test/java/quickfix/MessageTest.java b/quickfixj-core/src/test/java/quickfix/MessageTest.java index fbe200efd..2a6ea8150 100644 --- a/quickfixj-core/src/test/java/quickfix/MessageTest.java +++ b/quickfixj-core/src/test/java/quickfix/MessageTest.java @@ -19,7 +19,6 @@ package quickfix; -import java.lang.reflect.Modifier; import org.junit.Test; import org.quickfixj.CharsetSupport; import quickfix.field.Account; @@ -103,14 +102,7 @@ import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.Calendar; -import java.util.List; import java.util.TimeZone; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -249,24 +241,15 @@ public void testEmbeddedMessage() throws Exception { private void doTestMessageWithEncodedField(String charset, String text) throws Exception { CharsetSupport.setCharset(charset); NewOrderSingle order = createNewOrderSingle(); - java.lang.reflect.Field declaredField = Message.class.getDeclaredField("IS_STRING_EQUIVALENT"); + NewOrderSingle.IS_STRING_EQUIVALENT = CharsetSupport.isStringEquivalent(CharsetSupport.getCharsetInstance()); try { - // Some reflection magic to overwrite static final field in Message.class... - // We want to keep the field static final since its value does not change through - // the lifetime of the application but this test tests several charsets. - declaredField.setAccessible(true); - java.lang.reflect.Field modifiersField = java.lang.reflect.Field.class.getDeclaredField("modifiers"); - modifiersField.setAccessible(true); - modifiersField.setInt(declaredField, declaredField.getModifiers() & ~Modifier.FINAL); - declaredField.set(null, CharsetSupport.isStringEquivalent(CharsetSupport.getCharsetInstance())); - order.set(new EncodedTextLen(MessageUtils.length(CharsetSupport.getCharsetInstance(), text))); order.set(new EncodedText(text)); final Message msg = new Message(order.toString(), DataDictionaryTest.getDictionary()); assertEquals(charset + " encoded field", text, msg.getString(EncodedText.FIELD)); } finally { CharsetSupport.setCharset(CharsetSupport.getDefaultCharset()); - declaredField.set(null, CharsetSupport.isStringEquivalent(CharsetSupport.getCharsetInstance())); + NewOrderSingle.IS_STRING_EQUIVALENT = CharsetSupport.isStringEquivalent(CharsetSupport.getCharsetInstance()); } } @@ -279,7 +262,7 @@ public void testMessageWithEncodedField() throws Exception { doTestMessageWithEncodedField("ISO-2022-JP", text); doTestMessageWithEncodedField("Shift_JIS", text); doTestMessageWithEncodedField("GBK", text); - //doTestMessageWithEncodedField("UTF-16", text); // double-byte charset not supported yet +// doTestMessageWithEncodedField("UTF-16", text); // double-byte charset not supported yet } @Test