[QFJ-997] Http proxy doesnt reconnect upon lost fix session Created: 04/Dec/20  Updated: 26/Jan/22

Status: Open
Project: QuickFIX/J
Component/s: Build
Affects Version/s: 2.1.1
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Krys Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: http, initiator, proxy, reconnection


 Description   

Fix engine (initiator) doesnt reconnect upon the acceptor's restart when http proxy is being used. It keeps displaying "Pending connection not established after 270734 ms.", which is a consequence of not reconnecting at all. Is there any workaround for http proxy to trigger reconnection?

We have configured ReconnectInterval, ProxyType=http, ProxyVersion=1.1.

If we change proxy type to socks we are seeing the reconnect attempt due to /org/apache/mina/proxy/ProxyConnector.java:181, but would be nice to have the same functionality for http proxy. I also cant see any obvious way to set reconnectionNeeded variable that would potentially trigger the reconnection which i have tested by resetting it myself with a debugger.



 Comments   
Comment by Christoph John [ 05/Dec/20 ]

I am not aware of any special handling which could stop reconnecting from working only for http proxy... Could it be that the http connection is still considered "active" on the proxy? Could you please check that with "netstat" or some other tool which lists open sockets.
Could you please also create a stack dump when QFJ is in the state of "Pending connection not established..."

Comment by Krys [ 07/Dec/20 ]

Unlike http proxy, i am observing socks proxy reconnecting, probably due to this:

if (proxyIoSession.getRequest() instanceof SocksProxyRequest || proxyIoSession.isReconnectionNeeded())

{ return conFuture; }

Unless i need to configure http proxy with something else to get it reconnected.
we are not seeing any outbound connection in this scenario, although the same tcp port remains open.
In the state of "Pending connection...", there are two QFJ threads:

"QFJ Message Processor" #35 daemon prio=5 os_prio=0 tid=0x000000002b144800 nid=0xb090 waiting on condition [0x000000002fb8e000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)

  • parking to wait for <0x00000005d05d60d8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
    at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
    at quickfix.mina.QueueTrackers$1.poll(QueueTrackers.java:45)
    at quickfix.mina.SingleThreadedEventHandlingStrategy.getMessage(SingleThreadedEventHandlingStrategy.java:122)

"QFJ Timer" #34 daemon prio=5 os_prio=0 tid=0x000000002b144000 nid=0xa3a8 in Object.wait() [0x000000002f77f000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at org.apache.mina.core.future.DefaultIoFuture.await0(DefaultIoFuture.java:218)

  • locked <0x00000005d0640f10> (a org.apache.mina.core.future.DefaultConnectFuture)
    at org.apache.mina.core.future.DefaultIoFuture.awaitUninterruptibly(DefaultIoFuture.java:174)
    at quickfix.mina.initiator.IoSessionInitiator$ConnectTask.pollConnectFuture(IoSessionInitiator.java:232)
    at quickfix.mina.initiator.IoSessionInitiator$ConnectTask.run(IoSessionInitiator.java:207)
  • locked <0x00000005d05fdd80> (a quickfix.mina.initiator.IoSessionInitiator$ConnectTask)

QFJ Timer doesnt stop on breakpoints in IoSessionInitiator.ConnectTask#connect(), SocketChannelImpl#connect() or Net#connect() anymore.

Let me know if anything else would be useful to check.

Comment by Christoph John [ 14/Dec/20 ]

Unlike http proxy, i am observing socks proxy reconnecting, probably due to this:

if (proxyIoSession.getRequest() instanceof SocksProxyRequest || proxyIoSession.isReconnectionNeeded())
{ return conFuture; } 

Where is that code from? If that is from MINA then it could also be a MINA bug.

Comment by Krys [ 14/Dec/20 ]

That is right. it comes from MINA core: org.apache.mina.proxy.ProxyConnector#connect0:181

Comment by Christoph John [ 15/Dec/20 ]

So if I understood you right you could trigger the reconnection by setting isReconnectionNeeded to true in the debugger? If yes, then it should be a MINA bug, shouldn't it?

Comment by Krys [ 16/Dec/20 ]

Correct, when i set the re-connection needed with a debugger it does the job. In this case, we close this JIRA, right?

Comment by Christoph John [ 16/Dec/20 ]

It would be good if you could open a MINA issue and link to this issue. Let me know if I should open the issue against MINA. Thanks so far

Comment by Krys [ 14/Jan/21 ]

I would appreciate if you would open the issue with them.

Comment by Christoph John [ 26/Jan/22 ]

https://issues.apache.org/jira/browse/DIRMINA-1159





[QFJ-992] quickfixj 2.1.1 has dependency convergence error for org.apache.maven:maven-artifact:3.5.0 Created: 06/Mar/20  Updated: 09/Mar/20

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 2.1.1
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Andrew Peter Marlow Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: QuickfixJ


 Description   

the maven plugin enforcer shows that quickfixj has a dependency convergence error for org.apache.maven:maven-artifact:3.5.0. Here is the output:

Dependency convergence error for org.apache.maven:maven-artifact:3.5.0 paths to dependency are:
+-project-that-uses-quickfixj
+-org.quickfixj:quickfixj-all:2.1.1
+-org.quickfixj:quickfixj-codegenerator:2.1.1
+-org.apache.maven:maven-plugin-api:3.5.0
+-org.apache.maven:maven-artifact:3.5.0
and
+-project-that-uses-quickfixj
+-org.quickfixj:quickfixj-all:2.1.1
+-org.quickfixj:quickfixj-codegenerator:2.1.1
+-org.apache.maven:maven-project:2.2.1
+-org.apache.maven:maven-artifact-manager:2.2.1
+-org.apache.maven:maven-artifact:2.2.1
and
+-project-that-uses-quickfixj
+-org.quickfixj:quickfixj-all:2.1.1
+-org.quickfixj:quickfixj-codegenerator:2.1.1
+-org.apache.maven:maven-project:2.2.1
+-org.apache.maven:maven-artifact:2.2.1



 Comments   
Comment by Christoph John [ 06/Mar/20 ]

Thanks for the report. Under which cicrumstances does this cause an issue?

Comment by Andrew Peter Marlow [ 07/Mar/20 ]

The maven enforcer plugin is being used to report on inconsistent component versions. By default the plugin treats all such inconsistencies as errors, so by default such inconsistencies would make the build fail. This behaviour is configurable so it is possible just to get a report of the issues without making the build fail. But I want such inconsistencies to be flagged as serious issues because some of these inconsistencies involve components that show up on Black Duck security scans. The software I am working on is subject to a corporate decree that the software gets through Black Duck without raising any flags. This job is made harder when the number of flags raised is larger due to the same component appearing multiple times at different versions due to these dependency convergence errors.

My aim is to report any such dependency convergence errors that I find via enforcer. If they are then all fixed (there are only a few) then we could set the flag such that any such errors are fatal, so as to detect any regressions as soon as they occur. Without such fixes I will have to write a script that processes the enforcer output and checks any issues against a list of exceptions. This quickfixj issue would have to be such as exception. It just makes ultimate the job of dealing with Black Duck scans harder.

Comment by Christoph John [ 09/Mar/20 ]

Understood. If you would like you could also open a pull request on the quickfixj project on github. https://github.com/quickfix-j/quickfixj
I am also in favour of making the build fail on enforcer errors.





[QFJ-991] Add information about quickfixj-codegenerator maven plugin to documentation Created: 20/Feb/20  Updated: 08/Jun/20

Status: Open
Project: QuickFIX/J
Component/s: Documentation, Message Generation
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: Max Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

"Customizing Message Code Generation" article doesn't have information quickfixj-codegenerator.

Maven is standard de facto tool for building java application. And using of quickfixj-codegenerator is the most convenient way for using own dictionary.

So I suggest to add example of using this plugin for maven. Text may be like this:

If you are using the Maven build system, you can also use quickfixj-codegenerator:

<build>
<plugins>
<plugin>
<groupId>org.quickfixj</groupId>
<artifactId>quickfixj-codegenerator</artifactId>
<version>2.1.1</version>
<executions>
<execution>
<id>fixt11</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<dictFile>path/to/your/dictionary/file/FIXT11.xml</dictFile>
<packaging>quickfix.fixt11</packaging>
<fieldPackage>quickfix.field</fieldPackage>
</configuration>
</execution>
<execution>
<id>fix50sp2</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<dictFile>path/to/your/dictionary/file/FIX50SP2.modified.xml</dictFile>
<packaging>quickfix.fix50sp2</packaging>
<fieldPackage>quickfix.field</fieldPackage>
</configuration>
</execution>
[...]
</plugin>
[...]
</plugins>
</build>



 Comments   
Comment by Christoph John [ 08/Jun/20 ]

Good idea, maybe you could open a PR if you have the time.

Thanks





[QFJ-989] Acceptor Resetting the connection just after Login Created: 24/Dec/19  Updated: 28/Dec/19

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Anurag Ajmera Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Issue Links:
Relates
relates to QFJ-988 Session reset happens after logon Closed

 Description   

We are using fix acceptor (version 1.6.4). The acceptor resets the connection from initiators many times when logon is received. Can someone please help?

2019-12-01 23:10:00,712 |FIXT.1.1:SENDER->RECEIVER: 8=FIXT.1.1|9=74|35=A|56=SENDER|49=RECEIVER|52=20191201-23:10:00|34=1|108=60|98=0|1137=9|10=045|
2019-12-01 23:10:00,718 |FIXT.1.1:SENDER->RECEIVER: Accepting session FIXT.1.1:SENDER->RECEIVER from /(IP ADDRESS):(PORT)
2019-12-01 23:10:00,723 |FIXT.1.1:SENDER->RECEIVER: Acceptor heartbeat set to 60 seconds
2019-12-01 23:10:00,725 |FIXT.1.1:SENDER->RECEIVER: Setting DefaultApplVerID (1137=9) from Logon
2019-12-01 23:10:00,734 |FIXT.1.1:SENDER->RECEIVER: Refreshing message/state store at logon
2019-12-01 23:10:00,751 |FIXT.1.1:SENDER->RECEIVER: Received logon
2019-12-01 23:10:00,754 |FIXT.1.1:SENDER->RECEIVER: Responding to Logon request
2019-12-01 23:10:00,761 |FIXT.1.1:SENDER->RECEIVER: 8=FIXT.1.1|9=78|35=A|34=1|49=SENDER|52=20191201-23:10:00.761|56=RECEIVER|98=0|108=60|1137=9|10=253|
2019-12-01 23:10:04,859 |FIXT.1.1:SENDER->RECEIVER: Session state is not current; resetting FIXT.1.1:SENDER->RECEIVER
2019-12-01 23:10:04,865 |FIXT.1.1:SENDER->RECEIVER: 8=FIXT.1.1|9=59|35=5|34=2|49=SENDER|52=20191201-23:10:04.865|56=RECEIVER|10=155|
2019-12-01 23:10:04,877 |FIXT.1.1:SENDER->RECEIVER] Disconnecting: Session reset



 Comments   
Comment by Christoph John [ 24/Dec/19 ]

Do you only see this on FIXT.1.1 sessions or also on others?
And you are absolutely sure you are using version 1.6.4?

Comment by Anurag Ajmera [ 24/Dec/19 ]

Hi Christoph, yes we are using version 1.6.4 from maven repository. Also, we are seeing this issue in Fix version 4.4 as well.

Comment by Christoph John [ 24/Dec/19 ]

I am afraid I cannot help you unless you are able to reproduce this with a current QFJ version, i.e. 2.1 or 2.1.1.

Comment by Christoph John [ 28/Dec/19 ]

Could it be that your system is either heavily loaded or your QFJ process is constantly garbage collecting or something like that? Between the sending of the Logon reply and the "resetting session" message are four seconds delay?!

What is your StartTime and EndTime set to? Can you post the entry from your log where it says: "Session SENDER->RECEIVER schedule is "...





[QFJ-987] JPMS: Change field classes generation to resolve split package issue Created: 23/Sep/19  Updated: 05/Jun/20

Status: In Progress
Project: QuickFIX/J
Component/s: Message Generation
Affects Version/s: 2.1.1
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: Vlad Mureșan Assignee: Vlad Mureșan
Resolution: Unresolved Votes: 0
Labels: Message, QuickfixJ

Issue Links:
Duplicate
is duplicated by QFJ-985 Java Modules Closed

 Description   

The new module system available since JDK 9 does not allow duplicate packages on the module path.
As a result an application that depends on more than one messages version will have a split package issue, since quickfix.field exists in all quickfixj-messages-<version> jars.

The packaging needs to be changed in order to avoid duplicate packages used by different quickfixj modules.



 Comments   
Comment by Vlad Mureșan [ 23/Sep/19 ]

I analysed a little bit the situation and I see the following potential solutions:

  1. Generate a quickfixj-fields jar to be used as dependency by the other messages jars. This way the jar can be imported only once and split package issue is avoided.
    Advantage: avoid code duplication, avoid split package issue
  2. Generate  quickfix.<version>.fields packages instead of quickfix.fields. This means that each quickfixj-messages-<version> jar will have its own fields package and the component should make sure to consume the fields from its corresponding package.
    Disadvantage: the common fields between FIX versions will be generated once for each messages version jar, so there is some code duplication. However, this means that the messages between versions are completely decoupled between FIX versions.
    I don't know if this solution is feasible, since the impact is quite big (this won't be backward compatible for client applications already using the quickfix.fields package). As a workaround for this a quickfix.fields package can be generated in the messages-all jar.

I would go for first solution to also keep the impact as low as possible and avoid code duplication. What do you think?
Please let me know if you have other preferences. I'll wait for your feedback before doing any actual changes.

Cheers,
Vlad

Comment by Gili [ 24/Sep/19 ]

Hi Vlad,

I'm just an end-user. You discuss possible solutions, but can you explain outline the existing situation? I understand that modules cannot import the same package from multiple sources but it's not clear to me why the existing design exports the same packages/classes from multiple JARs. Can you please break that down? It would help us understand the proposed solutions and maybe even come up with others. Thank you.

Comment by Christoph John [ 25/Sep/19 ]

Hi Gili,

I have to admit that I don't recall exactly why the module structure was done this way. Maybe it was the easiest way at that time when we migrated the modules from Ant to Maven or to OSGi.

Cheers,
Chris.

Comment by Marcin L [ 02/Apr/20 ]

This is a tough one.

1) creating a separate module for fields

Seems like relatively easy solution, but I don't think there is much benefit of doing this one as the core structure problem remains. This might be only feasible to get JPMS working. BTW. Do you have a branch version (or module descriptors) of what you were trying to do?

2) each message module should has it's own version of fields

I agree with you. Even though this might be a duplication of fields I think this is the right way as this decouples fields for each version of FIX dictionaries.

  • fields are different (some are missing, some are added)
  • enum values for certain fields are different (mostly added as FIX version increases, but possibly they can be removed)

PROBLEM

quickfix-core code already depends on classes from quickfix.field package. Moreover, the code base is dependent (need to be available at run-time) on fields from different FIX versions all together e.g. SessionRejectReason (added in 4.2). They are somewhat "protected" by the code to use them only when specific FIX version is used - still they all need to be in class path at run-time.

This is the reason why code generator plugin generates fields in a very specific order as the code generator plugin does not override field classes that have been created. Currently this super set is assembled into each Maven module quickfixj-messages-fix**, so even if an application is dependent on quickfixj-messages-fix40 it will contain fields from different FIX versions such as SessionRejectReason, otherwise things will fail at run-time e.g.

quickfix.Message#parseBody
throw new FieldException(SessionRejectReason.TAG_SPECIFIED_OUT_OF_REQUIRED_ORDER, field.getTag());

I don't see an easy way of splitting this, but probably a way to go would be to abandon anaemic domain model and message modules would need to contain logic, so quickfix-core would delegate the logic depending on which version of FIX is being used. Also unit tests in quickfix-core are heavy dependent on fields and messages from different FIX versions.

Comment by Grigor Iliev [ 05/Jun/20 ]

I ran into same issue while trying to launch app from IDE. I was able to workaround it using the following maven configuration:

<dependency>
<groupId>org.quickfixj</groupId>
<artifactId>quickfixj-all</artifactId>
<version>2.1.1</version>
<exclusions>
<exclusion>
<groupId>org.quickfixj</groupId>
<artifactId>quickfixj-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.quickfixj</groupId>
<artifactId>quickfixj-messages-all</artifactId>
</exclusion>
<exclusion>
<groupId>org.quickfixj</groupId>
<artifactId>quickfixj-codegenerator</artifactId>
</exclusion>
<exclusion>
<groupId>org.quickfixj</groupId>
<artifactId>quickfixj-dictgenerator</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>2.1.3</version>
</dependency>

Note that quickfixj-all/pom.xml uses maven-shade-plugin to copy everything from quickfixj-core, quickfixj-messages-all, quickfixj-codegenerator and quickfixj-dictgenerator to single fat jar. Thus, dependencies to these jars are not need. Maybe quickfixj-all/pom.xml should be updated to use optional dependencies instead? I.e.

<dependency>
<groupId>org.quickfixj</groupId>
<artifactId>quickfixj-core</artifactId>
<version>$

{project.version}

</version>
<optional>true</optional>
</dependency>

But in this case transitive dependencies should be explicitly specified in quickfixj-all/pom.xml. I.e.

<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>2.1.3</version>
</dependency>

If quickfixj-all/pom.xml is updated in this way, the aforementioned workaround won't be needed.





[QFJ-982] Using the same dictionary file with different settings on different sessions causes problems Created: 02/Aug/19  Updated: 15/Jun/20

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: None
Fix Version/s: 3.0.0

Type: Bug Priority: Default
Reporter: Philip Whitehouse Assignee: Philip Whitehouse
Resolution: Unresolved Votes: 0
Labels: None

Issue Links:
Duplicate
is duplicated by QFJ-877 Multiple sessions with same dictionary Closed
Relates
relates to QFJ-981 Validation settings do not get applie... Closed

 Description   

[Affects all vaguely recent versions]

The DefaultSessionFactory stores a cache DataDictionary objects based on the file name of that object.

createDataDictionary fetches a DataDictionary object based on the file name and then applies settings to it based on the session.

Because it applies the settings to and returns the DataDictionary object in the cache, not a copy of it, when a different session uses a dictionary from the same file, it will also have the settings applied.

This means that configuration that's supposed to be session specific is not.

What we should do is instead have a `SessionDataDictionarySettings` object to encapsulate the settings. Then when using the data dictionary, pass in the relevant settings for the session the message is being validated for.

This would allow us to gain the advantages of reusing DataDictionary objects (lower memory usage) with the configuration settings required.

It will however likely involve API changes.



 Comments   
Comment by Christoph John [ 05/Aug/19 ]

Hi Philip Whitehouse,
funny, I also stumbled over this a few days ago while investigating https://github.com/quickfix-j/quickfixj/pull/224 / QFJ-981. Didn't get to investigate very far but IIRC the only settings that might differ are validation options

    checkFieldsOutOfOrder
    checkFieldsHaveValues
    checkUserDefinedFields
    checkUnorderedGroupFields
    allowUnknownMessageFields

so I thought I would just use the path plus the validation options as key for the cache in DefaultSessionFactory. Of course that means that there might be several DDs with different validation options. But on the other hand, I do not know if this really is a big downside. Of course depends how much sessions with the same dictionary and different validation options one might have in one VM.
Your proposed solution is of course a little more sophisticated since we would only have one instance of a DD, however as you said there might be API changes.

What do you think?
Thanks,
Chris.

Comment by Philip Whitehouse [ 14/Aug/19 ]

The problem with multiple copies of the same DataDictionary is that they are a massive memory hog given the size of them (especially once you add all the service packs).

I agree it's just the validation options however. My VMs generally run lots of sessions with the same dictionary so I'm keen to avoid an unexpected RAM usage increase from fixing the bug.

The other side to it is a proxy layer we have allowing you to live-reload the dictionary file to correct issues. I might try to upstream this at the same time.

This is likely to be something I have time to proof-of-concept relatively soon as currently the bug provides run-time unreliability on what will actually be applied to validate a given message.
Which is fairly ugly in terms of potential impact.

Comment by Christoph John [ 14/Aug/19 ]

OK, so did I understand you correctly that you are going to take a stab on this?
Or do you want me to do it?

Sorry, non-native english speaker here, so it's sometimes hard for me to get the nuances.

Thanks,
Chris.





[QFJ-974] Session+FileStore reset fails indefinitely when stream closed Created: 23/Apr/19  Updated: 06/Jun/21

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 2.1.1
Fix Version/s: None

Type: Bug Priority: Default
Reporter: amichair Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None


 Description   

If the FileStore stream is closed for any unexpected reason, the reset will fail indefinitely even if the original cause is fixed (or was just a transient error), since it will continue to try and flush/closed the failed stream, instead of truly resetting and opening a new one.

In our case the error was triggered by the disk being full (space was then freed up), but any reason for closing the stream could get the store stuck in this unrecoverable state. Perhaps the store reset mechanism should be made more robust so that it really tries to reset even in this unexpected state rather than require the application to be restarted manually.

quickfix.RuntimeError: java.io.IOException: Stream Closed
at quickfix.SessionState.reset(SessionState.java:384)
at quickfix.Session.resetState(Session.java:2624)
at quickfix.Session.nextLogon(Session.java:2116)
at quickfix.Session.next(Session.java:1026)
at quickfix.Session.next(Session.java:1204)
at quickfix.mina.ThreadPerSessionEventHandlingStrategy$MessageDispatchingThread.doRun(ThreadPerSessionEventHandlingStrategy.java:222)
at quickfix.mina.ThreadPerSessionEventHandlingStrategy$ThreadAdapter.run(ThreadPerSessionEventHandlingStrategy.java:146)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.IOException: Stream Closed
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:326)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at java.io.DataOutputStream.flush(DataOutputStream.java:123)
at java.io.FilterOutputStream.close(FilterOutputStream.java:158)
at quickfix.FileStore.close(FileStore.java:218)
at quickfix.FileStore.close(FileStore.java:209)
at quickfix.FileStore.closeAndDeleteFiles(FileStore.java:223)
at quickfix.FileStore.initialize(FileStore.java:101)
at quickfix.FileStore.reset(FileStore.java:405)
at quickfix.SessionState.reset(SessionState.java:382)
... 7 more Suppressed: java.io.IOException: Stream Closed
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:326)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at java.io.FilterOutputStream.close(FilterOutputStream.java:158)
at java.io.FilterOutputStream.close(FilterOutputStream.java:159)
... 13 more



 Comments   
Comment by Sergei [ 06/Jun/21 ]

13:35:17.885 QFJ Timer ERROR quickfix.SocketInitiator.run:356 - Error during timer processing
quickfix.RuntimeError: java.io.IOException: Stream Closed
at quickfix.SessionState.reset(SessionState.java:384)
at quickfix.Session.resetState(Session.java:2624)
at quickfix.Session.generateLogon(Session.java:2003)
at quickfix.Session.next(Session.java:1918)
at quickfix.mina.SessionConnector$SessionTimerTask.run(SessionConnector.java:350)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.IOException: Stream Closed
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:326)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at java.io.DataOutputStream.flush(DataOutputStream.java:123)
at java.io.FilterOutputStream.close(FilterOutputStream.java:158)
at quickfix.FileStore.close(FileStore.java:218)
at quickfix.FileStore.close(FileStore.java:209)
at quickfix.FileStore.closeAndDeleteFiles(FileStore.java:223)
at quickfix.FileStore.initialize(FileStore.java:101)
at quickfix.FileStore.reset(FileStore.java:405)
at quickfix.SessionState.reset(SessionState.java:382)
... 11 common frames omitted
Suppressed: java.io.IOException: Stream Closed
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:326)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at java.io.FilterOutputStream.close(FilterOutputStream.java:158)
at java.io.FilterOutputStream.close(FilterOutputStream.java:159)
... 17 common frames omitted

Same issue

What file might be the problem? - java.io.FileOutputStream.writeBytes





[QFJ-968] SessionState messageQueue causing out of memory exception Created: 06/Jan/19  Updated: 11/Jan/19

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 2.0.0
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Ryan Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Java 8



 Description   

The issues is based on my observation and investigation. Please correct me if I misunderstood it, thanks!

Scenario:

  • We use SocketInitiator to connect to vendor server and consume data.
  • ResendRequestChunkSize is set to 5000.
    Now assume our process is down for several hours, and 10 million messages are queued up on the vendor side. Once we get connected again, we will send about 2000 resend requests with batch size of 5000 to catch up to the latest message. In between of every two batches, vendor sends latest messages to us, which have much higher sequence number, and are added to the messageQueue in SessionState. They will not be processed until all the 10 million messages have been received by us, which means the memory will keep expanding during our "catching up" time. And this will eventually cause out of memory issue.

Proposed Solution:

Not limiting messageQueue size could be risky. My understanding is that messageQueue should only store temporary out of order messages, and if there are say 100,000 messages in it, there must be something wrong. Therefore options should be provided to discard newer messages instead of keep eating up the memory.

My proposal is to:

  1. Change LinkedHashMap to TreeMap. Even it may slow things down a little bit, O(lg n) should work fine given the size of messageQueue is normally very small. Even when it grows up, sequence number ordered entries should be beneficial.
  2. Update enqueue method to limit the size of messageQueue. If the queue is full, then add the new message and remove the entry with highest sequence number.
  3. Update dequeueMessagesUpTo method.

If you think this could work, I would be happy to submit a PR, thanks!



 Comments   
Comment by Christoph John [ 08/Jan/19 ]

I am not sure I understand fully: when you want to limit the queue size and discard messages if the queue is full, then why do you do a resend request for that many messages anyway? You could then just not do any resends (e.g. reset to seqnum 1)?

Apart from that: if you are transmitting millions of messages in a few hours then I am not sure if FIX is the right choice of protocol. I assume that some kind of volatile data is transmitted (e.g. market data) which in turn leads to the question why you need resends at all if the data is outdated in the meantime anyway.

Or did I misunderstand something?

Thanks,
Chris.

Comment by Ryan [ 09/Jan/19 ]

Hi Chris - Thank you for the reply! Let me try to give more details.

1. The reason we want to persist these messages is for future analysis. Normally the system works perfectly fine, but we want to handle the rarely happened situation where there is an issue and the system is down in the middle of the day. When that happens, we do need to send resend requests to catch up the outdated data.

2. My understanding is that there are two queues involved:

  • eventQueue in Session which is a bounded blocking queue
  • messageQueue in SessionState which is a map and not bounded

Every message has to go through the eventQueue, but only messages with higher seqNum will be put into messageQueue. Let's assume the batch size is 20 and consider the following event sequence:

  • initiator -> acceptor: expect 501, but seeing 10000, request resending of 501-520
  • acceptor -> initiator: resend 501-520, done
  • acceptor -> initiator: new messages 10001, 10002, 10003
  • initiator -> acceptor: request resending of 521-540
  • acceptor -> initiator: resend 521-540, done
  • acceptor -> initiator: new messages 10004, 10005
    ...

In the given sequence, messages 501-540 will be handled correctly, but 10001-10005 will be added to messageQueue and will not be touched until all messages 501-10000 have been requested and processed.

My proposal is to limit the size of the messageQueue (the map) to prevent the unbounded growing. For example if we set the limit to 4 messages, then the message 10005 and later messages will not be added to the messageQueue. When the initiator finishes handling messages 501-10004, it will expect 10005, but since it's discarded, initiator will try to request messages from 10005 to 10024 and move on.

This scenario will happen only when both of the following conditions are satisfied:

  • resend batch size is set.
  • new messages are coming in when the acceptor resends the messages.

Hope this better explained the scenario.

Thanks,
Ryan

Comment by Ryan [ 09/Jan/19 ]

BTW this is not a blocking issue for us, just want to report what we've observed during the development.

Comment by Christoph John [ 11/Jan/19 ]

Hi Ryan,

after thinking a little more about it I think it should work the way you said, i.e. if we limited the size of the queued messages QFJ will request them anyway as soon as it has dequeued all messages.

I have the following questions:
1. Why should this only be active when resend batch size is set? IMHO it could also happen that new messages are interleaved with resent messages. But of course that depends on how the counterparty has implemented their resend processing.
2. Why do you want to change the LinkedHashMap to TreeMap? Just because of the size limitation? Wouldn't a simple check if the allowed size has been reached (and then not queueing the message) be sufficient?
3. In the description you said "If the queue is full, then add the new message and remove the entry with highest sequence number." Why? I thought the idea was to not add the message?

Thanks,
Chris.

Comment by Christoph John [ 11/Jan/19 ]

Of course it will lead to massive number of messages since messages will be re-requested multiple times if the counterparty already sent them and we re-request them because we did not put them to the queue.

Comment by Ryan [ 11/Jan/19 ]

Hi Chris,

Let me pull the example sequence from above and try to explain my understanding:

  • initiator -> acceptor: expect 501, but seeing 10000, request resending of 501-520
  • acceptor -> initiator: resend 501-520, done
  • acceptor -> initiator: new messages 10001, 10002, 10003
  • initiator -> acceptor: request resending of 521-540
  • acceptor -> initiator: resend 521-540, done
  • acceptor -> initiator: new messages 10004, 10005
  • ...
    1. Totally agree that the limit can and should be applied for both batch and non-batch. Normally non-batch request won't cause this problem because of the acceptor logic. Let's take the same example, instead of using a batch of 20, if we send the resend request as 501-infinity, then messages 501-10000 will be added to the acceptor's send buffer. Now if new messages 10001-10005 appears on the acceptor side, they will only be appended to the end of the buffer, which means initiator will not see them until 501-10000 are received and processed. But if the acceptor takes another strategy of handling resend request, then non-batch may hit the same memory expanding problem. So I think you are right that we should limit the size of messageQueue in all cases.
    2 & 3. Generally speaking, we care more about the message sequence (MsgSeqNum) but not the insertion sequence. More specifically, let's assume the messageQueue is full with messages 10001-10004, and there is a temporary out of order message 542 coming in. Since we care more about 542 but not 10004 at this time, evicting 10004 would be the only option if we want to keep 542 and not expanding the queue size. By this way the TreeMap messageQueue will still work even after it's full.
    4. If the size limit is to be added, it should definitely be configurable so that user can choose between memory expanding and massive resend requests.

Thanks,
Ryan





[QFJ-962] FieldMap.setField(int key, Field<?> field) does not properly convert values Created: 15/Nov/18  Updated: 15/Jun/20

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 2.1.0
Fix Version/s: 3.0.0

Type: Bug Priority: Default
Reporter: amichair Assignee: Wojciech Zankowski
Resolution: Unresolved Votes: 0
Labels: None

Issue Links:
Relates
relates to QFJ-428 FieldMap.setField(int key, Field<?> f... Closed

 Description   

QFJ-428 made the generic setField(int key, Field<?> field) method public, claiming this will avoid having to use a switch statement and call each type-specific overload explicitly.

However, this is misleading and introduces a bug, since the two are not equivalent.

Specifically, the type-specific overloads do proper type conversions on the value, while the generic setField does not. For example, if you pass a DoubleField with a very large or small value, it will convert it into a string in scientific notation (with exponent) which is invalid in the FIX protocol, whereas calling the type-specific setField(DoubleField field) will properly use the DoubleConverter to convert it correctly.

When this method was non-public this was less of a problem, assuming its internal usages are correct (I don't know if this is the case, but assume it is). However making it public now creates a pitfall for anyone using this method in client code which will likely result in a bug on some data.

The solution would be to either implement it fully with proper type conversion (e.g. using the switch statement from QFJ-428), or at the very least, to add a javadoc to this method that warns about using it and clearly states that it does not do proper type conversion, so users will be able to decide whether this is what they really intend to do or not.



 Comments   
Comment by Christoph John [ 16/Nov/18 ]

Hi amichair,

maybe we should add the javadoc comment as you suggested and provide an additional method, say setFieldConverted(int key, Field<?> field) , so users can choose which method suits them best.

Cheers,
Chris.

Comment by Christoph John [ 16/Nov/18 ]

Briefly had a look at this. What about making Field abstract (According to a comment in the class it is only non-abstract to have JNI compatibility. But that was like 10 years ago.) and adding an abstract convertToString() method that does the necessary conversion in the subclasses? Example for BooleanField:

    @Override
    public String convertToString() {
        return BooleanConverter.convert(getValue());
    }

Then we can call in FieldMap:

    public void setField(int key, Field<?> field) {
        setString(key, field.convertToString());
    }

That way we can ensure that we always have a conversion method for a field and don't need a lengthy if-else statement.

What do you think?

Comment by amichair [ 22/Nov/18 ]

Encapsulating the converters inside the Field classes sounds like a good idea regardless of this issue or of Field being abstract

I have't delved into this one yet, but perhaps instead of convertToString, maybe toString itself should just do this properly?

Comment by Wojciech Zankowski [ 29/Jul/19 ]

Pull request created with implementation of the idea: https://github.com/quickfix-j/quickfixj/pull/226





[QFJ-954] sendRaw ignores return value of set call Created: 18/Sep/18  Updated: 18/Sep/18

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Philip Whitehouse Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

The documentation for MessageStore.set() says:

     * @return true is successful, false otherwise
     * @throws IOException IO error

However the return code is pointless. set is called by SessionState.set which is in turned called by Session.sendRaw, which does the following:

            if (num == 0) {
                final int msgSeqNum = header.getInt(MsgSeqNum.FIELD);
                if (persistMessages) {
                    state.set(msgSeqNum, messageString);
                }
                state.incrNextSenderMsgSeqNum();
            }
            return result;

So the return code is just pointless.

Throwing an exception on the other hand, does cause the return value of sendRaw (and hence Session.send to change.

Perhaps if it returns false Session.sendRaw should return false. (We may still want to call incrNextSenderMsgSeqNum however.)



 Comments   
Comment by Christoph John [ 18/Sep/18 ]

Hi Philip Whitehouse,

I am not entirely sure but I might be that the return code is a relict from the C++ implementation.
... digging through the code ...

Here is the comment of the Session.send() method:

   /**
     * Send a message to a counterparty. Sequence numbers and information about the sender
     * and target identification will be added automatically (or overwritten if that
     * information already is present).
     *
     * The returned status flag is included for
     * compatibility with the JNI API but it's usefulness is questionable.
     * In QuickFIX/J, the message is transmitted using asynchronous network I/O so the boolean
     * only indicates the message was successfully queued for transmission. An error could still
     * occur before the message data is actually sent.
     *
     * @param message the message to send
     * @return a status flag indicating whether the write to the network layer was successful.
     */

I think I already analyzed this some time ago. What I found more special was that the message is actually sent first and then persisted which might leave a little gap when there is a crash. The .NET and C++ implementations do persist first and send afterwards.

Chris.

Comment by Philip Whitehouse [ 18/Sep/18 ]

The comment about the return indicating a successful network write however is also broken however.

In the case of set throwing an IOException instead of returning false it will return false despite having already written to the network.

So it's definitely 'special'.

Comment by Christoph John [ 18/Sep/18 ]

You could turn on synchronous writes if you want to make sure that the message was really sent. But as you said, the usage of the return code is somewhat inconsistent.





[QFJ-947] Logout message with additional field is not logged Created: 26/Mar/18  Updated: 27/Mar/18

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.6.4
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Nikolai Kulakov Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Linux



 Description   

I came across a situation where a Logout messages that have some additional field are not logged anywhere, so it seems that the connection is breaking before the Logout message receiving. Only from our counterparty I found out that they are sending a Logout messages indeed, and my own network traffic analyzing confirmed it.
Logged messages:

8=FIX.4.2^A9=80^A35=A^A34=1^A49=fxw2^A52=20180326-14:16:20.879^A56=JLQD^A98=0^A108=30^A554=password^A10=215^A
8=FIX.4.2^A9=80^A35=A^A34=2^A49=fxw2^A52=20180326-14:16:23.840^A56=JLQD^A98=0^A108=30^A554=password^A10=207^A
...

Logged events:

<2018-03-26 10:16:19.751 -0400> <Session FIX.4.2:fxw2->JLQD:MARKET_DATA schedule is weekly, SUN 21:30:00-UTC - SUN 21:00:00-UTC (weekly, SUN 17:30:00-EDT - SUN 17:00:00-EDT)>
<2018-03-26 10:16:19.752 -0400> <Created session: FIX.4.2:fxw2->JLQD:MARKET_DATA>
<2018-03-26 10:16:19.833 -0400> <Configured socket addresses for session: [/some_ip:port]>
<2018-03-26 10:16:19.863 -0400> <MINA session created: local=/172.20.30.34:33369, class org.apache.mina.transport.socket.nio.NioSocketSession, remote=/some_ip:port>
<2018-03-26 10:16:20.882 -0400> <Initiated logon request>
<2018-03-26 10:16:20.885 -0400> <Disconnecting: Socket exception (/some_ip:port): java.io.IOException: Connection reset by peer>
<2018-03-26 10:16:22.888 -0400> <MINA session created: local=/172.20.30.34:33372, class org.apache.mina.transport.socket.nio.NioSocketSession, remote=/some_ip:port>
<2018-03-26 10:16:23.842 -0400> <Initiated logon request>
<2018-03-26 10:16:23.845 -0400> <Disconnecting: Socket exception (/some_ip:port): java.io.IOException: Connection reset by peer>
...

I read a pure network traffic and had seen that immediately after out Logon we actually receive the following Logout messages:

8=FIX.4.2^A9=0109^A35=5^A34=88^A49=JLQD^A52=20180326-14:16:20.886^A56=fxw2^A789=51^A58=MsgSeqNum too low, expecting 51 but received 1^A10=075^A
8=FIX.4.2^A9=0109^A35=5^A34=89^A49=JLQD^A52=20180326-14:16:23.846^A56=fxw2^A789=51^A58=MsgSeqNum too low, expecting 51 but received 2^A10=076^A
...

I think, this incoming Logout messages must be logged as well as our outcoming Logon messages, but this does not happen. I set logging level to the minimal possible values, but this did not help: there are no this Logout messages anywhere.
The additional tag 789 was added to FIX dictionary, so I think it should be processed correctly. But at any case, whether this Logout message valid or not, it should be presented in logs.
Thanks!



 Comments   
Comment by Nikolai Kulakov [ 26/Mar/18 ]

Of course, it would be great to see this Logout messages not only in the logs, but and in the quickfix.Application#fromAdmin as it usually happens - it allows us to handle this Logout message and set the expected sequence number (I already did this with some other counterparties).

Comment by Christoph John [ 26/Mar/18 ]

I think the problem is that the session is disconnected at 2018-03-26 10:16:20.885 (see event log) but the Logout message is coming in at 20180326-14:16:20.886 (SendingTime on message in your network log). This means the session is disconnected 1ms before the counterparty sends the Logout message (given that both your and the counterparty's clock is in sync).

This can't be a general problem because this kind of disconnection (message seqnum too low) happens quite often with some counterparties and the messages show up in the log files. I don't know of any occurrences with current QuickFIX/J versions.

So unless we can reproduce this in a unit test we cannot do anything about it.

Sorry, but I can only repeat my statement from the other issues: please please please write to the mailing list before opening possible "bug" tickets. That way we can clarify if there really is a bug before issues are opened which in the end is saving your and our time.

Thanks,
Chris.

Comment by Nikolai Kulakov [ 27/Mar/18 ]

Please, take a look to this network dump of the incoming messages (on the our side):

10:16:19.846538 IP some_ip.port > our_ip.port: Flags [S.], seq 28365822, ack 2573233766, win 32000, options [mss 1380,nop,wscale 8], length 0
        0x0000:  000c 2909 731b 001f 9edf 3ebf 0800 4500  ..).s.....>...E.
        0x0010:  0030 0000 4000 3406 90c8 cfef 1bda ac14  [email protected].........
        0x0020:  1e22 6204 8259 01b0 d3fe 9960 6e66 7012  ."b..Y.....`nfp.
        0x0030:  7d00 8f83 0000 0204 0564 0103 0308       }........d....
10:16:20.885507 IP some_ip.port > our_ip.port: Flags [P.], seq 1:134, ack 103, win 4096, length 133
        0x0000:  000c 2909 731b 001f 9edf 3ebf 0800 4500  ..).s.....>...E.
        0x0010:  00ad 0000 4000 3406 904b cfef 1bda ac14  [email protected]......
        0x0020:  1e22 6204 8259 01b0 d3ff 9960 6ecc 5018  ."b..Y.....`n.P.
        0x0030:  1000 216b 0000 383d 4649 582e 342e 3201  ..!k..8=FIX.4.2.
        0x0040:  393d 3031 3039 0133 353d 3501 3334 3d38  9=0109.35=5.34=8
        0x0050:  3801 3439 3d4a 4c51 4401 3532 3d32 3031  8.49=JLQD.52=201
        0x0060:  3830 3332 362d 3134 3a31 363a 3230 2e38  80326-14:16:20.8
        0x0070:  3836 0135 363d 6678 7732 0137 3839 3d35  86.56=fxw2.789=5
        0x0080:  3101 3538 3d4d 7367 5365 714e 756d 2074  1.58=MsgSeqNum.t
        0x0090:  6f6f 206c 6f77 2c20 6578 7065 6374 696e  oo.low,.expectin
        0x00a0:  6720 3531 2062 7574 2072 6563 6569 7665  g.51.but.receive
        0x00b0:  6420 3101 3130 3d30 3735 01              d.1.10=075.
10:16:20.885543 IP some_ip.port > our_ip.port: Flags [R.], seq 134, ack 103, win 0, length 0
        0x0000:  000c 2909 731b 001f 9edf 3ebf 0800 4500  ..).s.....>...E.
        0x0010:  0028 0000 4000 3406 90d0 cfef 1bda ac14  .([email protected].........
        0x0020:  1e22 6204 8259 01b0 d484 9960 6ecc 5014  ."b..Y.....`n.P.
        0x0030:  0000 3711 0000 0000 0000 0000            ..7.........
10:16:22.887575 IP some_ip.port > our_ip.33372: Flags [S.], seq 4175399090, ack 3053759955, win 32000, options [mss 1380,nop,wscale 8], length 0
        0x0000:  000c 2909 731b 001f 9edf 3ebf 0800 4500  ..).s.....>...E.
        0x0010:  0030 0000 4000 3406 90c8 cfef 1bda ac14  [email protected].........
        0x0020:  1e22 6204 825c f8df 88b2 b604 add3 7012  ."b..\........p.
        0x0030:  7d00 878b 0000 0204 0564 0103 0308       }........d....
10:16:23.845393 IP some_ip.port > our_ip.33372: Flags [P.], seq 1:134, ack 103, win 4096, length 133
        0x0000:  000c 2909 731b 001f 9edf 3ebf 0800 4500  ..).s.....>...E.
        0x0010:  00ad 0000 4000 3406 904b cfef 1bda ac14  [email protected]......
        0x0020:  1e22 6204 825c f8df 88b3 b604 ae39 5018  ."b..\.......9P.
        0x0030:  1000 1b6f 0000 383d 4649 582e 342e 3201  ...o..8=FIX.4.2.
        0x0040:  393d 3031 3039 0133 353d 3501 3334 3d38  9=0109.35=5.34=8
        0x0050:  3901 3439 3d4a 4c51 4401 3532 3d32 3031  9.49=JLQD.52=201
        0x0060:  3830 3332 362d 3134 3a31 363a 3233 2e38  80326-14:16:23.8
        0x0070:  3436 0135 363d 6678 7732 0137 3839 3d35  46.56=fxw2.789=5
        0x0080:  3101 3538 3d4d 7367 5365 714e 756d 2074  1.58=MsgSeqNum.t
        0x0090:  6f6f 206c 6f77 2c20 6578 7065 6374 696e  oo.low,.expectin
        0x00a0:  6720 3531 2062 7574 2072 6563 6569 7665  g.51.but.receive
        0x00b0:  6420 3201 3130 3d30 3736 01              d.2.10=076.
10:16:23.845427 IP some_ip.port > our_ip.33372: Flags [R.], seq 134, ack 103, win 0, length 0
        0x0000:  000c 2909 731b 001f 9edf 3ebf 0800 4500  ..).s.....>...E.
        0x0010:  0028 0000 4000 3406 90d0 cfef 1bda ac14  .([email protected].........
        0x0020:  1e22 6204 825c f8df 8938 b604 ae39 5014  ."b..\...8...9P.
        0x0030:  0000 2f19 0000 0000 0000 0000            ../.........
...

As I see, there are constantly repeating 3 records:

  1. Probably, a connect message.
  2. Then, about one second later, the Logout message.
  3. Then, immediately, one more message, probably disconnect.

I think that the time between our and the counterparty sides is not so good synchronized to rely on this (in fact, we have some problems with time synchronization on the used machine).
I guess, the problem may be in the too little delay between receiving the Logout and the disconnect messages. Also, it can be in the using of non-standard tag 789. Of course, it can be in something else, but it exists - that is the reason because I wrote this in the issues tracker, not to bother you, of course.

Thanks and my apologize if I'm using not the best procedure of issues notifying,
Nikolai.

Comment by Christoph John [ 27/Mar/18 ]

Hi Nikolai,
there is no need to apologize. I just wanted to stress the fact that it is hard to fix issues that cannot be reproduced reliably. We would need some kind of reproducable unit test to look deeper into this issue. I must admit that I never heard of this problem before but of course this does not mean that it is not possible to happen. May be related to a couple of things.

Thanks,
Chris.





[QFJ-946] Improve misleading error message during Logon Created: 21/Mar/18  Updated: 26/Mar/18

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.6.4
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: Nikolai Kulakov Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Linux



 Description   

It seems that the network connection between my company and our partner is very fast and the QuickFix/J engine suppose that their answering Logon message is coming before we send our Logon message:

8=FIX.4.2^A9=86^A35=A^A34=1^A49=fxw2^A52=20180321-14:09:01.447^A56=JLQD^A98=0^A108=30^A141=Y^A554=password^A10=253^A
8=FIX.4.2^A9=0065^A35=A^A34=317^A49=JLQD^A52=20180321-14:09:01.453^A56=fxw2^A98=0^A108=30^A10=119^A
8=FIX.4.2^A9=86^A35=A^A34=1^A49=fxw2^A52=20180321-14:09:04.413^A56=JLQD^A98=0^A108=30^A141=Y^A554=password^A10=249^A
8=FIX.4.2^A9=0065^A35=A^A34=318^A49=JLQD^A52=20180321-14:09:04.417^A56=fxw2^A98=0^A108=30^A10=123^A
8=FIX.4.2^A9=86^A35=A^A34=1^A49=fxw2^A52=20180321-14:09:07.413^A56=JLQD^A98=0^A108=30^A141=Y^A554=password^A10=252^A
8=FIX.4.2^A9=0065^A35=A^A34=319^A49=JLQD^A52=20180321-14:09:07.416^A56=fxw2^A98=0^A108=30^A10=126^A
etc

<2018-03-21 10:09:00.329 0400> <Session FIX.4.2:fxw2>JLQD:MARKET_DATA schedule is weekly, SUN 21:30:00-UTC - SUN 21:00:00-UTC (weekly, SUN 17:30:00-EDT - SUN 17:00:00-EDT)>
<2018-03-21 10:09:00.330 0400> <Created session: FIX.4.2:fxw2>JLQD:MARKET_DATA>
<2018-03-21 10:09:00.409 -0400> <Configured socket addresses for session: [/some_ip:port]>
<2018-03-21 10:09:00.444 -0400> <MINA session created: local=/172.20.30.34:57198, class org.apache.mina.transport.socket.nio.NioSocketSession, remote=/some_ip:port>
<2018-03-21 10:09:01.453 -0400> <Initiated logon request>
<2018-03-21 10:09:01.462 -0400> <Received logon>
<2018-03-21 10:09:01.462 -0400> <Disconnecting: Received logon response before sending request>
<2018-03-21 10:09:03.461 -0400> <MINA session created: local=/172.20.30.34:57200, class org.apache.mina.transport.socket.nio.NioSocketSession, remote=/some_ip:port>
<2018-03-21 10:09:04.417 -0400> <Initiated logon request>
<2018-03-21 10:09:04.421 -0400> <Received logon>
<2018-03-21 10:09:04.421 -0400> <Disconnecting: Received logon response before sending request>
<2018-03-21 10:09:06.468 -0400> <MINA session created: local=/172.20.30.34:57202, class org.apache.mina.transport.socket.nio.NioSocketSession, remote=/some_ip:port>
<2018-03-21 10:09:07.415 -0400> <Initiated logon request>
<2018-03-21 10:09:07.419 -0400> <Received logon>
<2018-03-21 10:09:07.419 -0400> <Disconnecting: Received logon response before sending request>
etc.

So, I do not see any way to establish the connection.



 Comments   
Comment by Nikolai Kulakov [ 21/Mar/18 ]

After further investigation of the problem, I guess that the problem is not in the speed of the connection, but in the fact that we set ResetSeqNumFlag=Y in the our Logon message but in the answering Logon message it is not presented (so, the priority of the problem can be lowered).

The code that is generating this error is in the method quickfix.Session#nextLogon:

        // Check for proper sequence reset response
        if (state.isResetSent() && !state.isResetReceived()) {
            disconnect("Received logon response before sending request", true);
        }

It can be a problem indeed, but the disconnect message seems totally misleading for me.
Also, I do not see any benefits to break down the connection in this case (we sent ResetSeqNumFlag but did not received it in the answer).

Comment by Christoph John [ 21/Mar/18 ]

I don't know but what sense does it make to reset the sequence numbers only on one side? So I guess the check might have a point. Unless I'm missing something.

Comment by Nikolai Kulakov [ 21/Mar/18 ]

Just a real situation: our partner is ready to reset the sequence number on the one side only. It seems that using ResetSeqNumFlag for this purpose it is not nice by FIX standards, but also it is a fact that this situation is not related with the "Received logon response before sending request".
Also, it is not clear for me why dropping down the connection is better than working.

Comment by Christoph John [ 21/Mar/18 ]

I think it does not make sense to open a bug ticket for every counterparty that does not conform to normal FIX standard.
If the counterparty wanted that you reset your sequence numbers I guess they should be sending you tag 141 in their Logon. At least IMHO.
Why are you sending 141? Does the counterparty require you to do so?

IMHO the best would be to direct such questions to the mailing list. Please post follow up questions and your answers there.
https://sourceforge.net/projects/quickfixj/lists/quickfixj-users

Thanks

Comment by Nikolai Kulakov [ 21/Mar/18 ]

John, I agree that it is no sence to open a bug ticket for a counetrparty that does not conform regular FIX standard (of course, I'll discuss this situation with them directly). But the ticket is about another thing and I'm really sorry if I'm describing it not clear.
The problem is that the engine is disconnecting with "Received logon response before sending request" when there is no such situation (logon response is coming after sending request).
Thank you for the patience.





[QFJ-930] FIXSettings not set for new DataDictionary objects created by DefaultDataDictionaryProvider Created: 18/Jul/17  Updated: 29/Jan/18

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.6.3
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Sachin Agrawal Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: File quickfix_930.rar    

 Description   

While DefaultSessionsFactory.processFixtDataDictionaries adds ApplicationDictionary to dataDictionaryProvider it uses beginStringQualifier only.

While method of MessageUtils
(Message parse(Session session, String messageString) throws InvalidMessage)

method used session,messageString both to get the ApplVerId. this results in mismatched key inside DefaultDataDictionaryProvider and DefaultDataDictionaryPovider need to create a new DataDictionary but FIX sesion settings are not set here at all, which are set by DefaultSessionsFactory while executing processFixtDataDictionaries inside createDataDictionary.

Please let me know in case this is intentional.



 Comments   
Comment by Christoph John [ 18/Jul/17 ]

I am sorry, but I cannot follow your description. Could you maybe describe the problem with some code examples or a unit test?
Thanks,
Chris.

Comment by Sachin Agrawal [ 19/Jul/17 ]

Thanks Chris for looking into,i now try to be more specific.

Please look into DeafultSessionFactory.processFixtDataDictionaries, we find following piece of code, please note here that toApplVerID is used to create the instance of ApplVerID before the applicationDictionary is added to the datadictionaryProvider.

final DataDictionary dd = createDataDictionary(sessionID, settings, key,
                            beginStringQualifier);
dataDictionaryProvider.addApplicationDictionary(MessageUtils.toApplVerID(beginStringQualifier), dd);

and createDataDictionary method reads the settings

private DataDictionary createDataDictionary(SessionID sessionID, SessionSettings settings,
            String settingsKey, String beginString) throws ConfigError, FieldConvertError {
        final String path = getDictionaryPath(sessionID, settings, settingsKey, beginString);
        final DataDictionary dataDictionary = getDataDictionary(path);

        if (settings.isSetting(sessionID, Session.SETTING_VALIDATE_FIELDS_OUT_OF_ORDER)) {
            dataDictionary.setCheckFieldsOutOfOrder(settings.getBool(sessionID,
                    Session.SETTING_VALIDATE_FIELDS_OUT_OF_ORDER));
        }

        if (settings.isSetting(sessionID, Session.SETTING_VALIDATE_FIELDS_HAVE_VALUES)) {
            dataDictionary.setCheckFieldsHaveValues(settings.getBool(sessionID,
                    Session.SETTING_VALIDATE_FIELDS_HAVE_VALUES));
        }

        if (settings.isSetting(sessionID, Session.SETTING_VALIDATE_UNORDERED_GROUP_FIELDS)) {        	
            boolean chkUnorderedGrpFields = settings.getBool(sessionID,
                    Session.SETTING_VALIDATE_UNORDERED_GROUP_FIELDS);
            settings.getLogger().error("Msg SttString "+Session.SETTING_VALIDATE_UNORDERED_GROUP_FIELDS +" value "+ chkUnorderedGrpFields +" dataDictionary " +dataDictionary.toString() +" beginString "+beginString);
			dataDictionary.setCheckUnorderedGroupFields(chkUnorderedGrpFields);
        }

        if (settings.isSetting(sessionID, Session.SETTING_VALIDATE_USER_DEFINED_FIELDS)) {
            dataDictionary.setCheckUserDefinedFields(settings.getBool(sessionID,
                    Session.SETTING_VALIDATE_USER_DEFINED_FIELDS));
        }

        if (settings.isSetting(sessionID, Session.SETTING_ALLOW_UNKNOWN_MSG_FIELDS)) {
            dataDictionary.setAllowUnknownMessageFields(settings.getBool(sessionID,
                    Session.SETTING_ALLOW_UNKNOWN_MSG_FIELDS));
        }

        return dataDictionary;
    }

Please note that DefaultDataDictionaryProvider uses ApplVerID as the key of the map.

While there is a method called MessageUtils.parse(Session session, String messageString), which uses getApplVerID(session, messageString) to create the ApplVerId and uses the same to fetch the applicationDictionary from dataDictionaryProvider.

MessageUtils.parse(Session session, String messageString)
.....
final String beginString = getStringField(messageString, BeginString.FIELD);
		final String msgType = getMessageType(messageString);

		ApplVerID applVerID;

		if (FixVersions.BEGINSTRING_FIXT11.equals(beginString))
		{
			applVerID = getApplVerID(session, messageString);
		}
		else
		{
			applVerID = toApplVerID(beginString);
		}
		final MessageFactory messageFactory = session.getMessageFactory();

		final DataDictionaryProvider ddProvider = session.getDataDictionaryProvider();
		final DataDictionary sessionDataDictionary = ddProvider == null ? null : ddProvider.getSessionDataDictionary(beginString);
		final DataDictionary applicationDataDictionary = ddProvider == null ? null : ddProvider.getApplicationDataDictionary(applVerID);
....

So when an application message is received a new DataDictionary is created by DefaultDataDictionaryProvider, look at method

 public DataDictionary getApplicationDataDictionary(ApplVerID applVerID) 

so the problem is that this new DataDictionary created by DefaultdataDictionaryProvider does not copy the FIX configurations i.e. settings. Hence even though the application dev has set the settings they are not picked while parsing messages.

Please ask further clarifications.

Thanks,
Sachin

Comment by Christoph John [ 19/Jul/17 ]

Hi,

I have changed https://github.com/quickfix-j/quickfixj/blob/master/quickfixj-core/src/test/java/quickfix/DefaultSessionFactoryTest.java (method testFixtDataDictionaryConfiguration) slightly to set "AllowUnknownMessageFields" to true.

 @Test
    public void testFixtDataDictionaryConfiguration() throws Exception {
        SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIXT11, "SENDER", "TARGET");
        setUpDefaultSettings(sessionID);
        settings.setBool(sessionID, Session.SETTING_USE_DATA_DICTIONARY, true);
        settings.setString(sessionID, Session.SETTING_TRANSPORT_DATA_DICTIONARY, "FIXT11.xml");
        settings.setString(sessionID, Session.SETTING_DEFAULT_APPL_VER_ID, "FIX.4.2");
        settings.setString(sessionID, Session.SETTING_APP_DATA_DICTIONARY, "FIX42.xml");
        settings.setString(sessionID, Session.SETTING_APP_DATA_DICTIONARY + "." + FixVersions.BEGINSTRING_FIX40, "FIX40.xml");
        settings.setString(sessionID, Session.SETTING_ALLOW_UNKNOWN_MSG_FIELDS, "Y");   // added

        Session session = factory.create(sessionID, settings);

        DataDictionaryProvider provider = session.getDataDictionaryProvider();
        assertThat(provider.getSessionDataDictionary(sessionID.getBeginString()),
                is(notNullValue()));
        final DataDictionary applicationDataDictionary = provider.getApplicationDataDictionary(new ApplVerID(ApplVerID.FIX42));

        assertThat(applicationDataDictionary,
                is(notNullValue()));
        assertThat(provider.getApplicationDataDictionary(new ApplVerID(ApplVerID.FIX40)),
                is(notNullValue()));
        
        System.err.println("XXXX " + provider.getSessionDataDictionary(sessionID.getBeginString()).isAllowUnknownMessageFields() );
        System.err.println("XXXX " + applicationDataDictionary.isAllowUnknownMessageFields() );
        
        quickfix.fixt11.Logon logon = new quickfix.fixt11.Logon(new EncryptMethod(EncryptMethod.NONE_OTHER), new HeartBtInt(30),
                new DefaultApplVerID(ApplVerID.FIX42));
        MessageUtils.parse(session, logon.toString());

This gives the following as output:

XXXX true
XXXX true

So the setting is picked up by both dictionaries.

Then I stepped into MessageUtils.parse(session, logon.toString()) with the debugger and could also see that the setting is true on the applicationDataDictionary.

So maybe I am taking a different code path than you? BTW I tested it on master, i.e. with version 1.7.0-SNAPSHOT.

Cheers,
Chris.

Comment by Sachin Agrawal [ 20/Jul/17 ]

Hi Chris,

I understand in your use case a new dictionary is never created, but there are some configurations in which a scenario occurs which creates a new dictionary by DefaultDataDictionaryProvider, then the settings will not be copied.
so to solve the problem we have 2 options

1) I correct the Fix configurations so that a new dictionary is never created.
2) Somehow set the session settings on each datadictionary created by DefaultDataDictionaryProvider

I see you are suggesting option 1.

--Regards,
Sachin

Comment by Christoph John [ 20/Jul/17 ]

Hi,

when there are such configurations then please give an example configuration. Otherwise I don't know how to reproduce the problem.

Thanks,
Chris.

Comment by Sachin Agrawal [ 29/Jan/18 ]

Attached is the zip src files with change

Add fix for correctly reading the settings in all the cases, i.e. whenever DataDictionary object is created from SessionFactory or MessageUtils.parse
    a) Update interface DataDictionaryProvider.java add DataDictionary getApplicationDataDictionary(SessionID sessionId, ApplVerID applVerID);
    b) Update DefaultDataDictionaryProvider
        1) add field SessionSettings
        2) add another constructor with SessionSettings, update old constructors to initialize field settings
        3) add implementation of new method getApplicationDataDictionary(SessionID sessionId, ApplVerID applVerID); which also readSettings\
        4) add public static method fillSettings
        5) add local method readSettings which calls static method fillsettings which is extracted from DefaultSessionFactory
    c) Update DefaultSessionFactory
        1) Update method create use new Constructor added for DefaultDataDictionaryProvider, pass settings.
        2) Update method createDataDictionary remove filling of settings locally and call DefaultDataDictionaryProvider.fillSettings instead
    d) Update MessageUtils, by updating method parse(Session session, String messageString) throws InvalidMessage so that appDataDictionary is fetched from ddProvider by also passing SessionID
    e) Update Session. next(Message message, boolean isProcessingQueuedMessages) throws FieldNotFound, RejectLogon, IncorrectDataFormat,
            IncorrectTagValue, UnsupportedMessageType, IOException, InvalidMessage, so that getApplicationDataDictionary is called with sessionID param as well.

Comment by Sachin Agrawal [ 29/Jan/18 ]

only improvement the changes i uploaded have is that whereever the DataDictionary object is created, the existing settings of  current session are always applied on DataDictionary created.

Comment by Christoph John [ 29/Jan/18 ]

Thanks for the file. Are you maybe able to generate a patch or even better open a pull request on github?
Thanks,
Chris.





[QFJ-918] Initiator failover funtion Created: 03/Apr/17  Updated: 03/Apr/17

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.6.3
Fix Version/s: None

Type: Other Priority: Default
Reporter: Cheng Guo Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: QuickfixJ
Environment:

Linux



 Description   

Hi,
I just learn the QuickFIXJ, and thinking if QuickFIXJ could support the below failover/ HA scenario, or if you could give me some suggestion for the custom dev?
We act as Initiator to connect to the external acceptor, as the Initiator, we want to deploy to two servers, one as the primary which is active, the other is the backup, and non-active.
Primary will be communicating with external acceptor, meanwhile, by HA module, the secondary sync with the primary at the seq number, msg, etc.. Once primary is down, secondary will take over the primary role, and connect to the external.
Checked the document, seems QuickFIX support the acceptor failover, but dont have the initiator case?
could you help let me know how address this? thanks.

by the way, i also developing to send the FIX msg to IBM MQ, could you suggest if QuickFIXJ has the persistence module/ api to store the un-delivery msg if MQ down, and then send out once MQ is up?



 Comments   
Comment by Christoph John [ 03/Apr/17 ]

You'll need to implement the HA functionality by yourself. You could use a database, synced file system or clustered in-memory cache to store the session information. But the whole failover decision has to be implemented by your application.

Since JIRA is the bug tracker you could ask on the mailing list whether anyone has already implemented something similar: https://lists.sourceforge.net/lists/listinfo/quickfixj-users
If you need production or implementation support please check: http://www.quickfixj.org/support/

Thanks,
Chris.





[QFJ-911] ResendRequests that fail to be sent are treated as sent Created: 03/Jan/17  Updated: 04/Jan/17

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Philip Whitehouse Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

https://github.com/quickfix-j/quickfixj/blob/629b801446431f06e0426aebcf669a2eca341a69/quickfixj-core/src/main/java/quickfix/Session.java#L2349

The return value from sendRaw() is ignored. If the message fails to send then we will still log that we have sent a resend request and (more crucially) still treat ourselves as having sent one for the purposes of whether we should send another.

At best this is merely misleading but I think it can actually cause problems in certain cases.



 Comments   
Comment by Christoph John [ 04/Jan/17 ]

Hmm, I can only quote the comment on the send method:

The returned status flag is included for compatibility with the JNI API but it's usefulness is questionable.
In QuickFIX/J, the message is transmitted using asynchronous network I/O so the boolean
only indicates the message was successfully queued for transmission. An error could still
occur before the message data is actually sent.

If the connection is broken, then the next incoming message on re-logon will trigger another ResendRequest anyway.
What do you think?





[QFJ-891] Upload release of BigDecimal versions to Maven or Sonatype central Created: 16/May/16  Updated: 15/Sep/16

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: 1.6.2
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: Igor Nemtsov Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None

Issue Links:
Duplicate
is duplicated by QFJ-904 Maven central repo releases don't sup... Closed

 Description   

In repositories of Maven and Sonatype centrals missing BigDecimal versions.



 Comments   
Comment by Christoph John [ 17/May/16 ]

This is currently maintained by marketcetera: http://repo.marketcetera.org/maven/quickfixj/quickfixj-core/

If you have any questions regarding this please write to the mailing list: https://lists.sourceforge.net/lists/listinfo/quickfixj-users





[QFJ-889] Leading zeros in int and float fields Created: 23/Apr/16  Updated: 28/Apr/16

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.6.0
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Roman Liverovskiy Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: QuickfixJ
Environment:

Fedora 23 x86_64, Windows 7 64 bit SP1



 Description   

I use quickfixj-examples-executor-1.6.0.jar as FIX 5.0 server.

Server does not respond on any client messages if there are leading zeros in int or float fields in client message, for example if there are leading zeros in sequnce number in message header (in login message or in heart beat message).
Server application outputs information about client conection on socket, but there is no any response on FIX message sent from client to server (there is no even an error message).
Leading zeros are permitted by FIX 5.0 protocol specification.



 Comments   
Comment by Christoph John [ 28/Apr/16 ]

Could you please attach some logs? Thanks





[QFJ-880] qfj doesn't send the next batch when ResendRequestChunkSize > 0 Created: 26/Feb/16  Updated: 10/Oct/18

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.6.0
Fix Version/s: None

Type: Other Priority: Default
Reporter: Xiaojun Zhang Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: CME, resend
Environment:

FIX4.2



 Description   

Quickfixj seems to send the 1st resend batch only after receiving a seq reset.

i.e.
ResendRequestChunkSize=10

15:28:37.142 [QFJ Message Processor] - fromAdmin PNPBBBN: 8=FIX.4.29=10735=134=44749=CME50=G52=20160225-20:28:37.22356=PNPBBBN57=DROPCOPY143=US,NY369=45621112=IDiky5miuo10=025

15:28:37.142 [QFJ Message Processor] - toAdmin PNPBBBN: 8=FIX.4.29=10735=034=4562249=PNPBBBN50=DropCopy52=20160225-20:28:37.14256=CME57=G142=US,NY143=CME112=IDiky5miuo10=004

I manually reduced the incoming seq no to 428
15:29:07.969 [Thread-30] - command: "fix PNPBBBN 428"

15:29:08.120 [QFJ Message Processor] - toAdmin PNPBBBN: 8=FIX.4.29=10535=234=4562449=PNPBBBN50=DropCopy52=20160225-20:29:08.12056=CME57=G142=US,NY143=CME7=42816=43710=188

15:29:08.148 [QFJ Message Processor] - fromAdmin PNPBBBN: 8=FIX.4.29=13635=434=42843=Y49=CME50=G52=20160225-20:29:08.25556=PNPBBBN57=DROPCOPY122=20160225-20:29:08.255143=US,NY369=4562436=449123=Y10=001

I expect quickfix to send the next batch (438-447) but it sent a normal heartbeat instead.

15:29:38.704 [QFJ Timer] - toAdmin PNPBBBN: 8=FIX.4.29=9235=034=4562549=PNPBBBN50=DropCopy52=20160225-20:29:38.70456=CME57=G142=US,NY143=CME10=069



 Comments   
Comment by Christoph John [ 26/Feb/16 ]

Sorry, this is a little hard to follow. I don't know about the command "fix PNPBBBN". Is this some custom stuff that you are executing? Actually, I would expect QFJ to send a Logout if it received too low a sequence number. The last log line is half an hour later than the log line before. What happened in between?

Actually, there are some unit tests around the chunked resend requests behaviour. But of course, this does not mean that there could be no bugs inside that portion of the code. But I cannot really follow your example. Do you have a unit test or some more concise steps which can be followed?

Comment by Xiaojun Zhang [ 26/Feb/16 ]

Sorry the log is a bit hard to read.
1. "fix PNPBBBN" is an admin command I created which calls session.setNextTargetMsgSeqNum() so I can manipulate the seq no to trigger the scenario.
2. The log started from 15:28:37 to 15:29:38. You can ignore the UTC time in the FIX message.
3. A simpler example is
1) both sides seq no started from 1.
2) for some reasons client didn't receive some messages
3) the next message client received was seq no 20
4) chunk size was set to 10. so client sent a resent request being=2 end =11
5) client received seq reset with GapFill=Y
6) client should send the next resend request begin=2 end=20 but it didn't

Hope this helps.

Comment by Xiaojun Zhang [ 26/Feb/16 ]

Sorry there was a typo in 6) client should send the next resend request begin=12 end=20 but it didn't

Comment by Christoph John [ 26/Feb/16 ]

If you look at the incoming sequence reset you see the field 36/NewSeqNo set to 449. So that is why there are no more messages resent. This should actually also be a message in your event log. Something along the lines of: "received sequence reset to 449."

Comment by Xiaojun Zhang [ 26/Feb/16 ]

Hmm i am reading the FIX doc.
The message in all situations specifies NewSeqNo <36> to reset as thevalue of the next sequence numberimmediately following the messages and/or sequence numbers being skipped.
It seems <36> just indicates the next seq no I will receive. Does it mean the whole gap has been filled? In order to send the next resend request what <36> should be?

Actually I was connecting to CME drop copy and encountered this issue.

Comment by Christoph John [ 26/Feb/16 ]

If you send a resend request and the counterparty sends SequenceReset with NewSeqNo = 449 then QFJ will continue with that incoming seqnum. That means that the gap has been filled up to that seqnum, yes. Probably there were only session messages in between, or messages that CME does not want to resend.

Comment by Christoph John [ 26/Feb/16 ]

NB: I think this belongs more onto the mailing list or with CME support than here. It's no bug after all.

Comment by Xiaojun Zhang [ 27/Feb/16 ]

Sorry I still don't quite understand the logic here.
Let's say the seq gap is 1-20 and chunk size is set to 10. Application messages are in 11-20 but NOT in 1-10. After QFJ sends the 1st resend request from 1 to 10 what NewSeqNo should be in SequenceReset?
I don't think it will be 11 because seq no shouldn't decrease.
If it is 21 QFJ will continue with 21 and lose all messages from 11 to 20.

If my understanding is not correct can you please give me an example how chunked resend should work? Appreciate your help.

Comment by Xiaojun Zhang [ 01/Mar/16 ]

If you don't think it is a bug I will add code in my Application class to override the logic. I just want to point out that current logic does NOT work for CME iLink and Drop Copy 4.0 which place a 2500 limit on resend request. QFJ would lose all messages after the first batch. It makes more sense to assume the corresponding chunk gap has been filled based on the sequence reset, not the whole gap.

Comment by Christoph John [ 01/Mar/16 ]

Sorry, I totally forgot about this one. What logic do you want to override? Actually, you do not need to override any of the session logic.

It seems <36> just indicates the next seq no I will receive. Does it mean the whole gap has been filled? In order to send the next resend request what <36> should be?

The NewSeqNo on a sequence reset is the next-to-be sequence number of the other communication side.

Let's say the seq gap is 1-20 and chunk size is set to 10. Application messages are in 11-20 but NOT in 1-10. After QFJ sends the 1st resend request from 1 to 10 what NewSeqNo should be in SequenceReset?

NewSeqNo should be 11.

I don't think it will be 11 because seq no shouldn't decrease.
If it is 21 QFJ will continue with 21 and lose all messages from 11 to 20.

Why does the seq no decrease? It is as follows: you connect to the counterparty. Your expected target seq no is 1. The other side comes in with 20. Now you send a resend request from 1-10.
You receive a SeqReset with NewSeqNo 11. Now your expected target seq no is 11. This is an increment to 1 and not a decrement.
You issue another ResendRequest for 11-20 and receive the app messages, each will increment your expected target seq no by 1.

I know that there are several users which use QFJ to connect to CME. The last issue around chunked resend requests I remember was QFJ-751 which was fixed in QF/J 1.6.0.

Please write a mail to the mailing list if you have further questions. https://lists.sourceforge.net/lists/listinfo/quickfixj-users
Or please attach a failing unit test so that I can reproduce the error.

Thanks.

Comment by John [ 07/Apr/16 ]

I can confirm that I am seeing the same behavior when connecting to the CME's Drop Copy 4.0. It appears this issue arises due to the way in which the CME increments tag 36 of SequenceReset messages and the way QuickFIX/J handles the sending of ResendRequest messages.

The following code is an excerpt from the Session class in the quickfix package which I believe is where the logic breaks down. It appears that QuickFIX/J will attempt to send chunks of ResendRequests depending upon when it receives incoming SequenceReset messages.The code below requires the value of the newSequence variable to be less than the EndSeqNo value defined in the range of messages that the client is supposed to fetch. This case fails and some ResendRequest messages will not be sent. Would it be safe to remove this logic from the if statement allowing subsequent RequestsRequests to be sent to the counterparty despite the fact that the newSequence value will be past the range of messages defined in the range variable? If so, the code would also need to be modified to not leverage the value of the newSequence variable when sending the ResendRequest to define the range of sequence numbers to send in the subsequent ResendRequest.

newSequence < range.getEndSeqNo()

private void nextSequenceReset(Message sequenceReset) throws IOException, RejectLogon,
FieldNotFound, IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType {
boolean isGapFill = false;
if (sequenceReset.isSetField(GapFillFlag.FIELD))

{ isGapFill = sequenceReset.getBoolean(GapFillFlag.FIELD) && validateSequenceNumbers; }

if (!verify(sequenceReset, isGapFill, isGapFill))

{ return; }

if (validateSequenceNumbers && sequenceReset.isSetField(NewSeqNo.FIELD)) {
final int newSequence = sequenceReset.getInt(NewSeqNo.FIELD);

getLog().onEvent(
"Received SequenceReset FROM: " + getExpectedTargetNum() + " TO: "
+ newSequence);
if (newSequence > getExpectedTargetNum()) {
state.setNextTargetMsgSeqNum(newSequence);
final ResendRange range = state.getResendRange();
if (range.isChunkedResendRequest()) {
if (newSequence >= range.getCurrentEndSeqNo()
&& newSequence < range.getEndSeqNo())

{ // If new seq no is beyond the range of the current chunk // and if we are not done with all resend chunks, // we send out a ResendRequest at once. // Alternatively, we could also wait for the next incoming message // which would trigger another resend. final String beginString = sequenceReset.getHeader().getString( BeginString.FIELD); sendResendRequest(beginString, range.getEndSeqNo() + 1, newSequence + 1, range.getEndSeqNo()); }

}
// QFJ-728: newSequence will be the seqnum of the next message so we
// delete all older messages from the queue since they are effectively skipped.
state.dequeueMessagesUpTo(newSequence);
} else if (newSequence < getExpectedTargetNum()) {

getLog().onErrorEvent(
"Invalid SequenceReset: newSequence=" + newSequence + " < expected="
+ getExpectedTargetNum());
if (resetOrDisconnectIfRequired(sequenceReset))

{ return; }

generateReject(sequenceReset, SessionRejectReason.VALUE_IS_INCORRECT,
NewSeqNo.FIELD);
}
}
}

Comment by Xiaojun Zhang [ 07/Apr/16 ]

John, I received your email. Do you have a non-personal email address? My corporate email doesn't allow sending to gmail, hotmail, etc.

Comment by Christoph John [ 08/Apr/16 ]

I very briefly read through http://www.cmegroup.com/confluence/display/EPICSANDBOX/Drop+Copy+Session+Layer+-+Resend+Request and I do not see anything that is contradictory to how QFJ interprets the NewSeqNo tag. However, it seems that CME is implementing something very custom. A test case would definitely help here.
One thing I noticed though, is that they mention "duplicate resend requests". Maybe you can try if the configuration SendRedundantResendRequests=Y helps in that case?

Comment by John [ 09/Apr/16 ]

Chrstoph,

What format would you prefer to see a test case in? I could provide the FIX messaging log so that it might be easier to see how the CME is increasing the sequence numbers in the SequenceReset messages they send in the middle of sending ResendRequest chunks past the end of the original ResendRequest range such that QuickFIX/J defines after logging on which causes some of the ResendRequest chunks to not be sent to the exchange.

As I mentioned in my earlier post, I believe the issue is in the code snippet I posted above where upon receiving SequenceReset messages QuickFIX/J will determine if a new ResendRequest chunk message needs to get sent out based on the following criteria in the nextSequenceReset method of the Session class by checking if newSequence < range.getEndSeqNo(). Since this fails, some ResendRequests fail to ever get sent out.

Say the defined ResendRequest range is 1-10000.
1) I send a ResendRequest for messages 1-2500. I receive these messages and then receive a SequenceReset to 2520 for example.
2) I then send a ResendRequest for messages 2501-5000. I receive these messages and then receive a SequenceReset to 5050.
3) I send a ResendRequest for messages 5001-7500. I receive these messages and then receive a SequenceReset of 11000.
At this point the newSequence < range.getEndSeqNo() test fails and QuickFIX/J never sends the final ResendRequest for messages 7501-10000. The FIX connection continues to receive real-time trades etc as per normal.

I would assume this to be custom logic that the CME is implementing on their end. I think the difference comes down to the fact that QuickFIX/J appears to rely more on the newSequence number that is received on an incoming SequenceReset message to dictate whether further ResendRequest chunks will be sent out and the CME may send out a SequenceReset message taking you past the originally defined EndSeqNo range.

I am not a FIX expert so I can't say if this solution would work but it seems that if the logic for sending chunks of ResendRequest messages is changed such that each of the ResendRequest chunk messages is defined immediately after the need for a ResendRequest arises and put into a queue (or some other object) QuickFIX/J could then pop the each ResendRequest message off the queue once it receives all of the messages for a given ResendRequest from the exchange and continue onto the next one and decouple itself in that way from the newSequenceNumber. This might ensure that any of the chunks of ResendRequest messages that need to get sent out don't get skipped. This might have negative implications as it might not be the standard logic for communicating via FIX however so it might not be a feasible solution however.

It would be really great if this functionality could be modified in QuickFIX/J as this is an extremely useful engine however for users attempting to use QuickFIX/J with CME's Drop Copy 4 this case will cause problems in a recovery scenario.

Comment by Christoph John [ 29/Apr/16 ]

Hi John,

yes, a message log would be a good starting point. From this I should hopefully be able to construct an automated test case.

Thanks, Chris.

Comment by Christoph John [ 26/Aug/16 ]

Hi John, Xiaojun Zhang: is there still the need to support this? Do you have any message logs?
Thanks, Chris.

Comment by John [ 01/Sep/16 ]

Hi Christoph John,

I can confirm that there is a need to support this functionality. To be clear, I was experiencing this issue when working with the 1.6.0 release of QuickFIX/J and have not tested with more recent releases. I don't have any message logs available currently aside from what Xiaojun posted earlier in this issue.

Thanks

Comment by Christoph John [ 01/Sep/16 ]

Hi John, OK, if this functionality was implemented could you test it against CME to verify if it works? Do they have some sort of certification test?

Comment by Dmitry Razumov [ 10/Oct/18 ]

Hey John
I know it's been two years, but did you pass the certification in the end?





[QFJ-874] Session Qualifier for acceptor sessions Created: 07/Jan/16  Updated: 03/Apr/16

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: 1.2.1
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: Kou Jun Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Hello,

i think, it would be a good idear, to have a session qualifier for acceptor sessions (ConnectionType=acceptor).
If you try to configure two acceptors in separate configuration files (Same fix-version, SenderCompId, TargetCompID) and the only difference is the port number, the configuration will not work if the Message store is in the same directory. They will both use the same message and eventlog files.

Regards
Thomas Hügel



 Comments   
Comment by Kou Jun [ 07/Jan/16 ]

My case is

there are 2 fix session both are acceptor,have separate file store. but the 2 session's fix-version, SenderCompId, TargetCompID are same,only the port number is different,I didn't use property file to config the session but config the 2 sessions in code.

receive message worked well!
but if I use Session.lookupSession(sessionID).send(message);
the 2 session's sessionID is same, so Session.lookupSession(sessionID) always return the session2.

Comment by Dmytro Semenov [ 21/Mar/16 ]

Can you use session qualifier field here? "SessionQualifier Additional qualifier to disambiguate otherwise identical sessions"

Also it will solve JMX problem if you have it. Both sessions will try to expose same MBean otherwise

Comment by Kou Jun [ 03/Apr/16 ]

A SessionQualifier can only be used with an initiator.





[QFJ-867] Thread handling after exiting QuickFIX Created: 06/Nov/15  Updated: 16/Nov/15

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.6.1
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Martin Vrábel Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: QuickfixJ
Environment:

Apache Tomcat 8 on Windows 10, Spring 4 web application



 Description   

Hi,

I stumbling over this thing over and over. When I stop my application I always get error messages in output about spawning a new thread during execution of application but failing to remove it when application stops:

```
06-Nov-2015 12:29:26.653 SEVERE [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@682d21a6]) and a value of type [quickfix.field.converter.UtcTimestampConverter] (value [quickfix.field.converter.UtcTimestampConverter@7f03e077]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
06-Nov-2015 12:29:26.654 SEVERE [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@682d21a6]) and a value of type [quickfix.field.converter.UtcTimestampConverter] (value [quickfix.field.converter.UtcTimestampConverter@6b6c6237]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
06-Nov-2015 12:29:26.654 SEVERE [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@682d21a6]) and a value of type [quickfix.field.converter.UtcTimestampConverter] (value [quickfix.field.converter.UtcTimestampConverter@2aca975d]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
06-Nov-2015 12:29:26.654 SEVERE [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@682d21a6]) and a value of type [quickfix.field.converter.UtcTimestampConverter] (value [quickfix.field.converter.UtcTimestampConverter@2bebb3b3]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
06-Nov-2015 12:29:26.655 SEVERE [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@682d21a6]) and a value of type [quickfix.field.converter.UtcTimestampConverter] (value [quickfix.field.converter.UtcTimestampConverter@4b8bfee1]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
```

It has something to do with `UtcTimestampConverter` but I have no idea why is it happening. I correctly shutdown all threads I manually start.



 Comments   
Comment by Christoph John [ 16/Nov/15 ]

Hmm, looks more like a false positive to me. But to be honest I never tried running QFJ in a managed environment or appserver.
http://stackoverflow.com/questions/28105803/tomcat8-memory-leak says that the ThreadLocals need to be removed but I think this is not done because it is expected that QFJ is ran in a stand-alone environment.

Comment by Martin Vrábel [ 16/Nov/15 ]

Would it be possible to call a method or something from outside of quickfix to manually shutdown all spawned threads when exiting my webapp?

Comment by Christoph John [ 16/Nov/15 ]

From what I understand from the output it does not have to do anything with threads but ThreadLocal variables that are still held. But AFAIK there is no built-in mechanism to clean them up.





[QFJ-863] In the quickfix version that we use (1.5.3b), an invalid checksum error does not result in a session reject Created: 12/Oct/15  Updated: 12/Oct/15

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.3
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Saurabh Desai Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

The scenario:

The initiator parses the following message with quickfix.MessageUtils.parse(), and sends it to the acceptor.

8=FIX.4.4|9=238|35=AE|31=1.35|32=1000|48=EURUSD|22=6|55=EURUSD|64=20131106|194=1.35|15011=1.33|15012=1.33|461=RCSXXX|487=2|571=1105200000001234|829=0|572=M1006050412587|552=1|54=1|37=SYS1:4545556002|11=SYS2:1006050412587|526=SSP:BDID001|453=2|448=a123456|447=D|452=3|802=2|523=5730607|803=10|523=5730606|803=15|1=123456-789|

It is not a valid FIX message, as we have 453<NoPartyIDs>=2, but there is only one group in the message. We would expect the acceptor to return a validation error, but instead the following happens:

1) An error message is logged:

2013-12-07 15:47:30,919 [SocketAcceptorIoProcessor-0.0] ERROR [] q.mina.acceptor.AcceptorIoHandler - Invalid message: Expected CheckSum=29, Received CheckSum=28 in 8=FIX.4.4?9=367?35=AE?34=82?49=SIDE1?52=20131207-14:47:30.618?56=SIDE2?22=6?31=1.35?32=1000?48=EURUSD?55=EURUSD?64=20131106?194=1.35?461=RCSXXX?487=2?571=1105200000001234?572=M1006050412587?829=0?15011=1.33?15012=1.33?552=1?54=1?37=SYS1:4545556002?11=SYS2:1006050412587?526=SSP:BDID001?453=2?448=a123456?447=D?452=3?802=2?523=5730607?803=10?523=5730606?803=15?1=123456-789?10=028?

2) The acceptor does not send any response and does not increase the message sequence count, either.

The suspect:

The acceptor validates the fix message with the checksum(String s) method of Message class. It calculates 29. But the checksum calculated on the initiator side is 28. The initiator calculates the checksum with a different method, which is called by the toString() method of Message class. This is the method which does the calculation (in FieldMap class) - my comments added:

int calculateTotal() {

int result = 0;
// JK: fields variable contains tags which are not group tags
for (final Field<?> field2 : fields.values()) {
final Field<?> field = field2;
if (field.getField() == CheckSum.FIELD || isGroupField(field.getField()))

{ continue; }

result += field.getTotal();
}

// JK: groups variable contains the group tags, but only the tag number (the key is Integer, not Field - why?)
final Iterator<Map.Entry<Integer, List<Group>>> iterator = groups.entrySet().iterator();
while (iterator.hasNext()) {
final Map.Entry<Integer, List<Group>> entry = iterator.next();
final List<Group> groupList = entry.getValue();
if (!groupList.isEmpty()) {
final IntField groupField = new IntField((entry.getKey()).intValue());
// JK: at this point we have 453=0, as this is a new field, no value yet
groupField.setValue(groupList.size());
// JK: now it is 453=1, because we have only one group
result += groupField.getTotal();
for (int i = 0; i < groupList.size(); i++)

{ final Group group = groupList.get(i); result += group.calculateTotal(); }

}
}

return result;
}

So the checksum will be the checksum of a different message actually, where 453=1.






[QFJ-860] Support newest EP (expansion pack) for FIX5.0SP2 Created: 20/Aug/15  Updated: 26/Aug/15

Status: Open
Project: QuickFIX/J
Component/s: Message Generation
Affects Version/s: 1.6.0
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: John Khouri Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: generation
Environment:

Java



 Description   

Some new messages were added in the EPs. E.g. PartyDetailsListRequest (35=CF).



 Comments   
Comment by Christoph John [ 20/Aug/15 ]

QFJ currently only supports FIX5.0 up to SP2. The message PartyDetailsListRequest is from EP105 (extentsion pack) so it is not yet supported by QFJ.

Comment by John Khouri [ 20/Aug/15 ]

Thanks! Do you know when the EP105 will be supported by QFJ?

Comment by Christoph John [ 26/Aug/15 ]

No, sorry. It will probably wait until someone volunteers to update the data dictionary accordingly.





[QFJ-859] Performance and latency improvements Created: 17/Aug/15  Updated: 18/Sep/17

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: None
Fix Version/s: 2.1-BETA

Type: Improvement Priority: Default
Reporter: Christoph John Assignee: Christoph John
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Charles Briquel submitted some performance related pull requests which should be integrated into the next version.

https://github.com/quickfix-j/quickfixj/pull/32
https://github.com/quickfix-j/quickfixj/pull/34
https://github.com/quickfix-j/quickfixj/pull/35
https://github.com/quickfix-j/quickfixj/pull/36
https://github.com/quickfix-j/quickfixj/pull/37
https://github.com/quickfix-j/quickfixj/pull/39
https://github.com/quickfix-j/quickfixj/pull/40
https://github.com/quickfix-j/quickfixj/pull/41
https://github.com/quickfix-j/quickfixj/pull/42






[QFJ-852] Missing synchronized blocks discovered in code review. Created: 01/Jul/15  Updated: 04/Jul/15

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.6.0
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Nathan Tippy Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: sequnece

Attachments: File quickfixjQFJ-852.patch    

 Description   

In the class Session in the following method

private boolean verify(Message msg, boolean checkTooHigh, boolean checkTooLow)

we find that synchronized (state.getLock()) is used to ensure atomic updates to the multiple fields in the state object. If this is needed then we must also check to ensure partial or dirty reads are avoided. This would happen any place that we call for more than one field of the state and assume the fields remain consistent with one another until we make a second or third request for other fields.

Directly after this same block the usage of isChunkedResendRequest, getCurrentEndSeqNo and getEndSeqNo run the risk of partial (dirty) reads because they are out side the sync.

This same problem also exists here where it may be the cause of other more serious issues.
private void nextSequenceReset(Message sequenceReset)

And to a a lesser degree in
private void doTargetTooHigh(Message msg)



 Comments   
Comment by Nathan Tippy [ 02/Jul/15 ]

For immediate use I apply this patch file to be safe. However this should be re-visited with a more elegant fix.

Comment by Christoph John [ 03/Jul/15 ]

Thanks for the patch!
Edit: did you encounter dirty read problems?

Comment by Nathan Tippy [ 04/Jul/15 ]

No I have not seen any problems but after discovery in code review I was uncomfortable running it without a fix.

I have not seen any negative consequences to applying the patch. So it was a defensive move.





[QFJ-847]  Transport Data Dict vs App Data Dict - settings not passed to App Data Dict Created: 19/May/15  Updated: 19/May/15

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.6.0
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Chris Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

N/a its in the java code



 Description   

The Quickfixj settings are not being passed to the ApplicationDataDictionary.

This seems to be because the transport dictionary is created via
DefaultSessionFactory.createDataDictionary.

Whereas the app DataDictionary is created in Default Data Dictionary
Provider, which does not seem to know about settings and so cannot pass them on.



 Comments   
Comment by Chris [ 19/May/15 ]

Not sure how best to address this - should the application DataDictionary be created when the Transport one is?

Or should the settings be made available to the DefaultDataDictionaryProvider class?





[QFJ-843] Some times QuickFix Message received on Fix session is processed first by Application thread and later by socket connection Processor Thread causing sequence error by later processing Created: 04/May/15  Updated: 07/May/15

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.3
Fix Version/s: None

Type: Bug Priority: Default
Reporter: anurag jain Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: sequnece, session


 Description   

Message on Fix session received by both Application thread (ProcessQ) and socket connection Processor Thread.
In below example Our Application Thread ProcessQ got the message with 34=158757 and later quickfix thread ScoketConnectionProcessor-0.0 Thread process the same message this happen only 4 time in a whole day.
But Due to this when quickfix's socketConnectionThread thread process the message and give it to QFJMessageProcessor thread to process further it encounters sequence rest error as a result session logged out triggers. In all the other scenarios ScoketConnectionProcessor process the message first and delegate the responsibility to QFJ Message Processor thread and later to application Thread i.e. ProcessQ

Please FInd application logs as below ..
2015-04-28 14:16:03,856 [ProcessQ] INFO quickfixj.msg.incoming - FIX.4.2:MDAQ_DEV2_SANDPIT_MD->ANZD_SANDPIT_MD: 8=FIX.4.2^A9=1500^A35=X^A34=158757^A49=ANZD_SANDPIT_MD^A52=20150428-06:16:03.814^A56=MDAQ_DEV2_SANDPIT_MD^A262=9^A268=26^A279=2^A269=0^A278=7usB0^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA0^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB1^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA1^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB2^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA2^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB3^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA3^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB4^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA4^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB5^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA5^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB6^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA6^A55=USD/CHF^A15=USD^A279=0^A269=0^A278=7utB0^A55=USD/CHF^A270=0.95388^A15=USD^A271=1000000^A346=1^A279=0^A269=1^A278=7utA0^A55=USD/CHF^A270=0.95413^A15=USD^A271=1000000^A346=1^A279=0^A269=0^A278=7utB1^A55=USD/CHF^A270=0.95385^A15=USD^A271=2000000^A346=1^A279=0^A269=1^A278=7utA1^A55=USD/CHF^A270=0.95416^A15=USD^A271=2000000^A346=1^A279=0^A269=0^A278=7utB2^A55=USD/CHF^A270=0.95382^A15=USD^A271=2000000^A346=1^A279=0^A269=1^A278=7utA2^A55=USD/CHF^A270=0.95419^A15=USD^A271=2000000^A346=1^A279=0^A269=0^A278=7utB3^A55=USD/CHF^A270=0.95380^A15=USD^A271=5000000^A346=1^A279=0^A269=1^A278=7utA3^A55=USD/CHF^A270=0.95421^A15=USD^A271=5000000^A346=1^A279=0^A269=0^A278=7utB4^A55=USD/CHF^A270=0.95377^A15=USD^A271=10000000^A346=1^A279=0^A269=1^A278=7utA4^A55=USD/CHF^A270=0.95424^A15=USD^A271=10000000^A346=1^A279=0^A269=0^A278=7utB5^A55=USD/CHF^A270=0.95374^A15=USD^A271=10000000^A346=1^A279=0^A269=1^A278=7utA5^A55=USD/CHF^A270=0.95427^A15=USD^A271=10000000^A346=1^A10=041^A
2015-04-28 14:16:03,856 [SocketConnectorIoProcessor-0.0] INFO quickfixj.msg.incoming - FIX.4.2:MDAQ_DEV2_SANDPIT_MD->ANZD_SANDPIT_MD: 8=FIX.4.2^A9=1500^A35=X^A34=158757^A49=ANZD_SANDPIT_MD^A52=20150428-06:16:03.814^A56=MDAQ_DEV2_SANDPIT_MD^A262=9^A268=26^A279=2^A269=0^A278=7usB0^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA0^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB1^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA1^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB2^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA2^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB3^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA3^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB4^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA4^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB5^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA5^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB6^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA6^A55=USD/CHF^A15=USD^A279=0^A269=0^A278=7utB0^A55=USD/CHF^A270=0.95388^A15=USD^A271=1000000^A346=1^A279=0^A269=1^A278=7utA0^A55=USD/CHF^A270=0.95413^A15=USD^A271=1000000^A346=1^A279=0^A269=0^A278=7utB1^A55=USD/CHF^A270=0.95385^A15=USD^A271=2000000^A346=1^A279=0^A269=1
^A278=7utA1^A55=USD/CHF^A270=0.95416^A15=USD^A271=2000000^A346=1^A279=0^A269=0^A278=7utB2^A55=USD/CHF^A270=0.95382^A15=USD^A271=2000000^A346=1^A279=0^A269=1^A278=7utA2^A55=USD/CHF^A270=0.95419^A15=USD^A271=2000000^A346=1^A279=0^A269=0^A278=7utB3^A55=USD/CHF^A270=0.95380^A15=USD^A271=5000000^A346=1^A279=0^A269=1^A278=7utA3^A55=USD/CHF^A270=0.95421^A15=USD^A271=5000000^A346=1^A279=0^A269=0^A278=7utB4^A55=USD/CHF^A270=0.95377^A15=USD^A271=10000000^A346=1^A279=0^A269=1^A278=7utA4^A55=USD/CHF^A270=0.95424^A15=USD^A271=10000000^A346=1^A279=0^A269=0^A278=7utB5^A55=USD/CHF^A270=0.95374^A15=USD^A271=10000000^A346=1^A279=0^A269=1^A278=7utA5^A55=USD/CHF^A270=0.95427^A15=USD^A271=10000000^A346=1^A10=041^A



 Comments   
Comment by anurag jain [ 04/May/15 ]

Please note that ProcessQ Thread is application thread which read objects from application Queue and not the the Quick Fix internal queue .

Comment by Christoph John [ 04/May/15 ]

When this happens, do you have to restart your application or does the problem correct itself? Are you starting/stopping your Initiator/Acceptor at certain times? This sounds a little like QFJ-825.
Would it be possible to create a stack dump with the program "jstack" once the error appears?

Comment by anurag jain [ 04/May/15 ]

Sorry rephrasing the above JIRA:

  • We noticed 2 threads logging the string --> "quickfixj.msg.incoming" at the same time. One of the threads to log this was SocketConnectorIoProcessor-0.0, Surprisingly the second thread which logs this is the ProcesQ thread
  • The ProcessQ thread is our own application thread so we are not sure how this could happen?
  • This does not seem to be a logging issue, we are using log4j2 as our logger. I say that because of the 2 consecutive messages received one after the other, Quickfix/J complains when the second message comes in:
    2015-04-28 14:16:03,857 [QFJ Message Processor] INFO  quickfixj.msg.outgoing - FIX.4.2:MDAQ_DEV2_SANDPIT_MD->ANZD_SANDPIT_MD: 8=FIX.4.2^A9=141^A35=5^A34=11955^A49=MDAQ_DEV2_SANDPIT_MD^A52=20150428-06:16:03.857^A56=ANZD_SANDPIT_MD^A58=MsgSeqNum too low, expecting 158758 but received 158757^A10=030^A
    

All the log files below:

2015-04-28 14:16:03,856 [ProcessQ] INFO quickfixj.msg.incoming - FIX.4.2:MDAQ_DEV2_SANDPIT_MD->ANZD_SANDPIT_MD: 8=FIX.4.2^A9=1500^A35=X^A34=158757^A49=ANZD_SANDPIT_MD^A52=20150428-06:16:03.814^A56=MDAQ_DEV2_SANDPIT_MD^A262=9^A268=26^A279=2^A269=0^A278=7usB0^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA0^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB1^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA1^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB2^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA2^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB3^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA3^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB4^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA4^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB5^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA5^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB6^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA6^A55=USD/CHF^A15=USD^A279=0^A269=0^A278=7utB0^A55=USD/CHF^A270=0.95388^A15=USD^A271=1000000^A346=1^A279=0^A269=1^A278=7utA0^A55=USD/CHF^A270=0.95413^A15=USD^A271=1000000^A346=1^A279=0^A269=0^A278=7utB1^A55=USD/CHF^A270=0.95385^A15=USD^A271=2000000^A346=1^A279=0^A269=1^A278=7utA1^A55=USD/CHF^A270=0.95416^A15=USD^A271=2000000^A346=1^A279=0^A269=0^A278=7utB2^A55=USD/CHF^A270=0.95382^A15=USD^A271=2000000^A346=1^A279=0^A269=1^A278=7utA2^A55=USD/CHF^A270=0.95419^A15=USD^A271=2000000^A346=1^A279=0^A269=0^A278=7utB3^A55=USD/CHF^A270=0.95380^A15=USD^A271=5000000^A346=1^A279=0^A269=1^A278=7utA3^A55=USD/CHF^A270=0.95421^A15=USD^A271=5000000^A346=1^A279=0^A269=0^A278=7utB4^A55=USD/CHF^A270=0.95377^A15=USD^A271=10000000^A346=1^A279=0^A269=1^A278=7utA4^A55=USD/CHF^A270=0.95424^A15=USD^A271=10000000^A346=1^A279=0^A269=0^A278=7utB5^A55=USD/CHF^A270=0.95374^A15=USD^A271=10000000^A346=1^A279=0^A269=1^A278=7utA5^A55=USD/CHF^A270=0.95427^A15=USD^A271=10000000^A346=1^A10=041^A


2015-04-28 14:16:03,856 [SocketConnectorIoProcessor-0.0] INFO quickfixj.msg.incoming - FIX.4.2:MDAQ_DEV2_SANDPIT_MD->ANZD_SANDPIT_MD: 8=FIX.4.2^A9=1500^A35=X^A34=158757^A49=ANZD_SANDPIT_MD^A52=20150428-06:16:03.814^A56=MDAQ_DEV2_SANDPIT_MD^A262=9^A268=26^A279=2^A269=0^A278=7usB0^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA0^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB1^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA1^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB2^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA2^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB3^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA3^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB4^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA4^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB5^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA5^A55=USD/CHF^A15=USD^A279=2^A269=0^A278=7usB6^A55=USD/CHF^A15=USD^A279=2^A269=1^A278=7usA6^A55=USD/CHF^A15=USD^A279=0^A269=0^A278=7utB0^A55=USD/CHF^A270=0.95388^A15=USD^A271=1000000^A346=1^A279=0^A269=1^A278=7utA0^A55=USD/CHF^A270=0.95413^A15=USD^A271=1000000^A346=1^A279=0^A269=0^A278=7utB1^A55=USD/CHF^A270=0.95385^A15=USD^A271=2000000^A346=1^A279=0^A269=1
^A278=7utA1^A55=USD/CHF^A270=0.95416^A15=USD^A271=2000000^A346=1^A279=0^A269=0^A278=7utB2^A55=USD/CHF^A270=0.95382^A15=USD^A271=2000000^A346=1^A279=0^A269=1^A278=7utA2^A55=USD/CHF^A270=0.95419^A15=USD^A271=2000000^A346=1^A279=0^A269=0^A278=7utB3^A55=USD/CHF^A270=0.95380^A15=USD^A271=5000000^A346=1^A279=0^A269=1^A278=7utA3^A55=USD/CHF^A270=0.95421^A15=USD^A271=5000000^A346=1^A279=0^A269=0^A278=7utB4^A55=USD/CHF^A270=0.95377^A15=USD^A271=10000000^A346=1^A279=0^A269=1^A278=7utA4^A55=USD/CHF^A270=0.95424^A15=USD^A271=10000000^A346=1^A279=0^A269=0^A278=7utB5^A55=USD/CHF^A270=0.95374^A15=USD^A271=10000000^A346=1^A279=0^A269=1^A278=7utA5^A55=USD/CHF^A270=0.95427^A15=USD^A271=10000000^A346=1^A10=041^A

2015-04-28 14:16:03,857 [QFJ Message Processor] INFO  quickfixj.msg.outgoing - FIX.4.2:MDAQ_DEV2_SANDPIT_MD->ANZD_SANDPIT_MD: 8=FIX.4.2^A9=141^A35=5^A34=11955^A49=MDAQ_DEV2_SANDPIT_MD^A52=20150428-06:16:03.857^A56=ANZD_SANDPIT_MD^A58=MsgSeqNum too low, expecting 158758 but received 158757^A10=030^A

Could you please tell us:

  • If this is a bug in 1.5.3 version of Quickfix/J?
  • We only notice this happening 4 times a day during peak load, 2000 market data messages a second
  • We did not seem to encounter this in 1.5.2
Comment by Christoph John [ 05/May/15 ]

Could you please answer my questions from the last comment?
As already said, the only thing I could imagine is that you are hitting QFJ-825. But to be sure I would need a stack dump.
Are you able to try without log4j2? It's probably not the problem, but just to be sure... Are you using asynchronous logging?

Comment by anurag jain [ 06/May/15 ]

Please find my answer here:

  • No we are not stopping are starting Initiator/Acceptor at certain times.
  • Also When this happened, we didn't restart the application as mention above due to this we get the sequence error as a result of that log-out has sent to target session after a while it connect back again as part of login retry attempts.
  • This is not happening daily basis, we are trying to reproduce the problem at our end if succeeds we will share the JStack's stack dump with you. However No luck so far.
  • We are using synchronous logging also this is unlikely to have log4j2 issue as its result in sequence error.
Comment by Christoph John [ 06/May/15 ]

OK, without the stack dump I cannot really tell anything. Just let me know once you have it.
More questions: are you using a ThreadedSocketAcceptor/Initiator? Or the default SocketAcceptor/Initiator? is there only one session that you have configured? Could you please post your session config?

And I guess you are certain that the counterparty did not just send the same message twice?

Comment by anurag jain [ 07/May/15 ]

1) We are using default Socket Initiator.
2) Have just one session .
3) Session config is as here
DataDictionary=config/FIX42.xml
ResetOnLogon=Y
ScreenLogShowOutgoing=N
FileLogHeartbeats=N
ResetOnDisconnect=Y
ScreenLogEvents=N
ConnectionType=initiator
SocketKeyStore=config/SummitInvt.pem
TargetCompID=ANZD_SANDPIT_MD
SenderCompID=MDAQ_DEV2_SANDPIT_MD
SocketConnectHost=1.x.x.x
ReconnectInterval=10
ScreenLogShowIncoming=N
SocketConnectPort=xxxx
SocketUseSSL=Y
FileStorePath=var/fix/fxlp
PersistMessages=N
EndTime=17:00:00
SocketKeyStorePassword=*******
TimeZone=America/New_York
StartTime=17:10:00
HeartBtInt=20
UseDataDictionary=Y
ResetOnLogout=Y
Username=TODO
e-mail=
SessionID= FIX.4.2:MDAQ_DEV2_SANDPIT_MD->ANZD_SANDPIT_MD

4)and yes there is no replay of same message from counter party .

Comment by Christoph John [ 07/May/15 ]

Hmm, now that I see that you are using SSL I am asking myself if it could be the same problem as in QFJ-745. However, there is not really much information to find the problem and the issue creator did not come back with answers.





[QFJ-828] Messages Log Contains Another Session's Messages Created: 19/Feb/15  Updated: 20/Feb/15

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: 1.5.3
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Rupert Webb Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: QuickfixJ
Environment:

Linux Server



 Description   

I had two quick fix sessions configured: CLIENT and CLIENT2. Our CLIENT2 session connected while no one connected to the CLIENT session. You can see this from the event logs:

::::::::::::::
FIX.4.2-LIME-CLIENT2.event.log
::::::::::::::
20150219-08:20:41: Session FIX.4.2:LIME->CLIENT schedule is daily, 05:00:00-UTC - 00:59:00-UTC
20150219-08:20:41: Created session: FIX.4.2:LIME->CLIENT

::::::::::::::
FIX.4.2-LIME-CLIENT2.event.log
::::::::::::::
20150219-08:20:41: Session FIX.4.2:LIME->CLIENT2 schedule is daily, 05:00:00-UTC - 00:59:00-UTC
20150219-08:20:41: Created session: FIX.4.2:LIME->CLIENT2
20150219-12:03:04: Accepting session FIX.4.2:LIME->CLIENT2 from /10.22.75.167:52406
20150219-12:03:04: Acceptor heartbeat set to 45 seconds
20150219-12:03:04: Received logon
20150219-12:03:04: Responding to Logon request
20150219-12:03:04: Received ResendRequest FROM: 1 TO: infinity
...

However, all the messages in CLIENT2's message log begin appearing in CLIENT's messages log:

::::::::::::::
FIX.4.2-LIME-CLIENT.messages.log
::::::::::::::
8=FIX.4.2|9=103|35=A|34=1|49=CLIENT2|52=20150219-12:03:04.175|56=LIME|98=0|108=45|553=USER2|554=DROPCOPY|10=165|
8=FIX.4.2|9=71|35=A|34=5998|49=LIME|52=20150219-12:03:04.185|56=CLIENT2|98=0|108=45|10=117|
8=FIX.4.2|9=65|35=2|34=2|49=CLIENT2|52=20150219-12:03:04.697|56=LIME|7=1|16=0|10=032|

::::::::::::::
FIX.4.2-LIME-CLIENT2.messages.log
::::::::::::::
8=FIX.4.2|9=103|35=A|34=1|49=CLIENT2|52=20150219-12:03:04.175|56=LIME|98=0|108=45|553=USER2|554=DROPCOPY|10=165|
8=FIX.4.2|9=71|35=A|34=5998|49=LIME|52=20150219-12:03:04.185|56=CLIENT2|98=0|108=45|10=117|
8=FIX.4.2|9=65|35=2|34=2|49=CLIENT2|52=20150219-12:03:04.697|56=LIME|7=1|16=0|10=032|

This only begin happening today. Here is the configuration:
[DEFAULT]
ConnectionType=acceptor
ReconnectInterval=60
SenderCompID=LIME
FileStorePath=fixstore-[4]-2015-02-19/
FileLogPath=fixlogs-[4]-2015-02-19/
ValidateFieldsOutOfOrder=N
ValidateFieldsHaveValues=N
ValidateIncomingMessage=N
AllowUnknownMsgFields=Y
UseDataDictionary=Y
StartTime=05:00:00
EndTime=00:59:00
BeginString=FIX.4.2
SocketAcceptPort=9003
SocketReuseAddress=Y
ValidateUserDefinedFields=N
PersistMessages=Y
CheckLatency= Y

[SESSION]
TargetCompID=CLIENT2
CheckPassword=Y
Password=PASS

[SESSION]
TargetCompID=CLIENT
CheckPassword=Y
Password=PASS



 Comments   
Comment by Christoph John [ 20/Feb/15 ]

Hi, some questions:

  • can you reproduce the problem or did it appear only once?
  • did you change something in the session settings before the problem appeared?
  • how do you use the FileLog? Are you creating it on your own?
Comment by Rupert Webb [ 20/Feb/15 ]

It does not appear to be reproducible. We did have exceptionally high disk load when it happened.

We did not make any changes to the session settings

We are using the default FileLog without any modifications.

As additional piece of information, this is the code that we use to send FIX messages:
public synchronized boolean sendMessage(Message message) throws SessionNotFound

{ return Session.sendToTarget(message); }

We also have multiple threads call this function.

I'll see if I try to reproduce it





[QFJ-819] Create XSD Schema for FIX dictionary files Created: 19/Nov/14  Updated: 17/Oct/17

Status: Reopened
Project: QuickFIX/J
Component/s: Engine, Message Generation
Affects Version/s: None
Fix Version/s: 2.1-BETA

Type: Improvement Priority: Default
Reporter: Stephen Flynn Assignee: Stephen Flynn
Resolution: Unresolved Votes: 1
Labels: None


 Description   

Fix xml dictionary documents (FIX44.xml etc) should have a defined schema (XSD).
The schema can be used for...
authoring customer fix data dictionaries.
(ii) validating documents at both build and runtime.
(iii) configuring the DataDictionary (via JAXB).

At the moment the DataDictionary.load() method pulls in an org.w3c.dom.Document instance and then iterates through it using hardwired node names doing some adhoc validation along the way. It would be much better to load a validated document as a type safe object and iterate through that.

The schema should fit the existing doc layout with as few changes as possible (probably a namespace declaration will be required).



 Comments   
Comment by praneeth thonupunoori [ 16/Oct/17 ]

Hi, any approximate ETA on this issue? it would help us a great deal if this is done. Thanks

Comment by Christoph John [ 17/Oct/17 ]

Hi praneeth thonupunoori,
no-one is working on this currently I'm afraid. So we cannot give an ETA.
Chris.





[QFJ-813] SessionConnector:waitForLogout()'s InterruptedException handling. Created: 11/Oct/14  Updated: 18/Sep/17

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.3
Fix Version/s: 2.1-BETA

Type: Improvement Priority: Default
Reporter: Francesco Lo Conte Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

When the executing thread is interrupted the waitForLogout() method catches it and prints and error to log.

I would like to suggest that the exception is either thrown or at least re-asserted so that higher level application code can handle it. Also I would like to suggest that nothing is printed to the log file.

This would:

  • Let higher level application code realize that an interruption has occurred.
  • Stop the engine as requested (if it's thrown).
  • Let higher level application code handler the interruption properly.
  • Let higher level application code decide what to print in the log file.

Currently after the interruption is requested there is no way to know whether the engine actually stopped.
Also the log file is polluted (in my opinion) with a stack dump whereas this is not an actual error condition.

I supposed a similar behavior would be desirable in all other equivalent places in the code.

I would be interested to hearing your opinion about it.

Many thanks.
Francesco Lo Conte



 Comments   
Comment by Christoph John [ 13/Oct/14 ]

So you propose to remove the logging and call Thread.currentThread().interrupt() instead?

Comment by Francesco Lo Conte [ 13/Oct/14 ]

Yes.

Alternatively, stop catching the InterruptedException and let it be thrown by the method. The impact would be:
On the SessionConnector class:

  • "protected void waitForLogout()" would change to "protected void waitForLogout(...) InterruptedException"
  • "protected void logoutAllSessions(...)" would change to "protected void logoutAllSessions(...) InterruptedException"
  • "public void stop(...)" would change to "public void stop(...) InterruptedException"
    On the Connector interface:
  • "void stop(...)" would change to "void stop(...) InterruptedException"

This would have repercussions on the Connector interface and break backward compatibility.
Re-asserting the interrupted state on the thread as you point out might be preferable as it would still provide a way for higher level code to detect the interruption and remain backward compatible.

Comment by Christoph John [ 16/Oct/14 ]

OK, then we should change it to "Thread.currentThread().interrupt()".
What about the usages in SingleThreadedEventHandlingStrategy and ThreadPerSessionEventHandlingStrategy. Is it also feasible to change it there?

Comment by Francesco Lo Conte [ 17/Nov/14 ]

SingleThreadedEventHandlingStrategy

40: I think 'isStopped' should be volatile because it is read and set by 2 different threads

50: } catch (InterruptedException e)

{ This is called from Mina's code so it should never happen anyway. So I think it's reasonable to throw a RuntimeException. An improved handling would be for onMessage(...) not to catch it and instead throw it so not to disrupt anything inside Mina (or the Transport layer in general) that might want to know about it. But it's probably not worth it changing the interface at this time. 79: }

catch (InterruptedException e)

{ // ignore }

No change. Can be ignored as this thread is never stopped. We don't even need a handle to it as its run() method just completes.

ThreadPerSessionEventHandlingStrategy

116: } catch (final InterruptedException e)

{ quickfixSession.getLog().onErrorEvent(e.toString()); }

This is called from Mina's code so it should never happen. So I think it's reasonable to just log an error in the session's log.
Please note though that the same in SingleThreadedEventHandlingStrategy throws a RuntimeException instead. Maybe we should go with 1 alternative for both. Either log something or throw a RuntimeException.
Same as before, an improved handling would be for enqueue(...) (and onMessage(...) that calls it) not to catch it and instead throw it so not to dirupt anything inside Mina (or the Transport layer in general) that might want to know about it. But it's probably not worth it changing the interface at this time.

137:
} catch (final InterruptedException e) {
LogUtil.logThrowable(quickfixSession.getSessionID(),
"Message dispatcher interrupted", e);
stopping = true;
As far as I can tell the dispatching threads (MessageDispatchingThread) are never stopped with Thread.stop() so the catch below will never happen (as the code stands now).
One might as well leave the code as it is in case in future Thread.stop() is called on the MessageDispatchingThread object (e.g. via getDispatcher(...) that can expose it to the outside).
Still I would add Thread.currentThread().interrupt() to the code in the catch block to reassert the thread status.

One suggestion: in both SingleThreadedEventHandlingStrategy and ThreadPerSessionEventHandlingStrategy there are thread that are instantiated.
They are then notified to stop using a volatile variable. I would suggest replacing this mechanism with one more 'natural' to thread semantic.
Whereas the loop should be: while (!Thread.currentThread().isInterrupted())

{...}

Then when they need to be stopped one simply calls myThread.stop().
The while loop will exit and any clean up can be carried out before the run() method returns.
At this stage though, as the code works, it wouldn't add any benefits.

Comment by Christoph John [ 15/Dec/14 ]

Hi Francesco,

thanks for your input.
During work on QFJ-790 I already changed the isStopped flag to volatile.

If it is OK with you I would put this issue to the next major release to resolve the remaining points.

Thanks,
Chris.





[QFJ-801] Validation fail on ClassCastException if using XML Created: 14/Jul/14  Updated: 14/Jul/14

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.3
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Benoit Xhenseval Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: validation
Environment:

Mac OSX


Attachments: Java Source File IOIValidation.java    

 Description   

It appears that the Message validation fails on a ClassCastException if the message contains the XmlDataLen tag.

Example:
https://gist.github.com/benoitx/e7da15dba9da133ac7b9

It seems that the validation code only expects StringField but the XmlDataLen is an IntField.

The output is:

Testing WITHOUT XML
8=FIXT.1.19=7935=649=Sender56=Target15=USD22=523=IOD-127=M28=N48=IBM.N54=255=IBM.N10=079
Testing WITH XML
8=FIXT.1.19=10335=649=Sender56=Target212=12213=<a>Hello</a>15=USD22=523=IOD-127=M28=N48=IBM.N54=255=IBM.N10=086
Exception in thread "main" java.lang.ClassCastException: quickfix.field.XmlDataLen cannot be cast to quickfix.StringField
	at quickfix.DataDictionary.iterate(DataDictionary.java:668)
	at quickfix.DataDictionary.validate(DataDictionary.java:653)
	at quickfix.DataDictionary.validate(DataDictionary.java:624)
	at quickfix.DataDictionary.validate(DataDictionary.java:606)
	at fixfun.IOIValidation.validateIoi(IOIValidation.java:45)
	at fixfun.IOIValidation.validateIoiWithXml(IOIValidation.java:37)
	at fixfun.IOIValidation.main(IOIValidation.java:78)


 Comments   
Comment by Benoit Xhenseval [ 14/Jul/14 ]

test case.

Comment by Christoph John [ 14/Jul/14 ]

It turned out that the setField( int, Field<?> ) method should rather not be used with non-String tags. Rather use setField( Field ), e.g.:
ioi.getHeader().setField(new XmlData(xml));
ioi.getHeader().setField(new XmlDataLen(xml.length()));

Of course, there should be means to prevent your original error. Either setField( int, Field<?> ) should convert the values (as setField( Field ) does) or the validate-method should not assume that all fields are Strings.





[QFJ-798] Refactor Session construction in test code Created: 13/Jun/14  Updated: 13/Jun/14

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.3
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: Andrzej Hajderek Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Currently to create some of the Session related test cases it is necessary to use constructs like this:

Session session = new Session(new UnitTestApplication(), new MemoryStoreFactory(),
sessionID, null, null, new ScreenLogFactory(true, true, true),
new DefaultMessageFactory(), isInitiator ? 30 : 0, false, 30, true, 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);

This kind of code turns from an asset into a liability pretty quickly, so the sooner it is rationalised the better. The Session constructor itself isn't very pretty either with its 30+ parameters.






[QFJ-797] Add a clean and safe mechanism to disconnect a session from within a call-back Created: 13/Jun/14  Updated: 13/Jun/14

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.3
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: Andrzej Hajderek Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Hi,

There is currently no clean and safe mechanism to completely stop and disconnect a session from within a call-back (e.g. when processing an incoming message inside fromApp()) with the effect that the session is immediately disconnected, no reject messages are sent back to the counter-party and no change to the session store is made.

Such a mechanism is useful for implementing failure handling scenarios, e.g. when a target database becomes suddenly unavailable, or the application needs to be shutdown in emergency. In such cases it's best to close the TCP socket immediately and keep the session state unchanged.

One could try to use something like SocketInitiatior.stop(true), but it's not generic (does not work for acceptors) and it results in a call to Session.disconnect(). Then, if Session.disconnect() is called from fromApp(), we get an immediate call to the onLogout() callback - a call is made from within the fromApp() call-back into the onLogout() call-back. This isn't a particularly safe scenario, especially when in most cases the onLogout() call is made by from QuickFIX/J threads.

Another solution is to throw a RuntimeException within the call-back method, but it's not reliable right now (QFJ-793, QFJ-795) and makes QuickFIX/J send an error message and the stack trace into the log.

I propose to add a special a subclass of RuntimeException, e.g. DisconnectSessionExcepion, which when thrown from a call-back method would notify QuickFIX/J that the session should be disconnected immediately. In such case only an informational message would be send to the log instead of error with a stack trace.

Regards,
Andrzej Hajderek






[QFJ-796] There is no mechanism to clear or update the data dictionary cache Created: 13/Jun/14  Updated: 13/Jun/14

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.3
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Andrzej Hajderek Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

A data dictionary file loaded into memory is cached without any option to reload the file after its contents has been updated. Worse - it's not even possible to clear the cache. This means that in order to use an updated data dictionary it is necessary to restart the application.

See: quickfix.DefaultSessionFactory.dictionaryCache






[QFJ-794] Misleading message logged when RuntimeException thrown within a call-back: "Rejecting message: ..." Created: 12/Jun/14  Updated: 23/Aug/16

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.3
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Andrzej Hajderek Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

This is in relation to QFJ-793.

When both settings RejectMessageOnUnhandledException and DisconnectOnError are set to Y and a RuntimeException is thrown within a call-back, QuickFIX/J will write to the log output messages like below:

<20140612-16:25:06, FIX.4.4:SENDER->TARGET, error> (Rejecting message: java.lang.RuntimeException: ... (with more details and the message)

2014-06-12 18:25:06 quickfix.Session disconnect

INFO: [FIX.4.4:SENDER->TARGET] Disconnecting: Auto disconnect

This is misleading because nothing is actually rejected (no reject message is sent back to the sender). The session is simply disconnected. I believe a slightly different wording should be used for this scenario, e.g "Failed to process message" instead of "Rejecting message".






[QFJ-793] When RuntimeException is thrown within a call-back and DisconnectOnError=Y the session does not get disconnected automatically Created: 12/Jun/14  Updated: 23/Aug/16

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.3
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Andrzej Hajderek Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: File SessionTest.java.add     File SessionTest.java.add.fixed    

 Description   

Hi,

When a RuntimeException is thrown within a call-back and the "DisconnectOnError" parameter is set to "Y" the session does not get disconnected automatically unless the "RejectMessageOnUnhandledException" parameter is also set to "Y". This dependency is not documented, but even if it was, it wouldn’t make too much sense.

It seems to be logical to understand an occurrence of a RuntimeException within a call-back as an error condition on its own, which should be sufficient to trigger the disconnection logic dictated by the "DisconnectOnError" parameter (regardless of any other settings).

Currently, if RejectMessageOnUnhandledException=N, the engine simply ignores the message for which the exception was thrown even though DisconnectOnError=Y (although it reports the exception as an “error” in the log).

Test code attached.

Please note that probably all call-backs exhibit the same behaviour, not just the fromApp() call-back used in the TestApp class. It is also possible that the “ResetOnError” parameter is treated in a similar manner.

Regards,
Andrzej Hajderek



 Comments   
Comment by Andrzej Hajderek [ 13/Jun/14 ]

Attached a fixed version of the test.





[QFJ-789] Fully support alternate encodings (charsets) Created: 09/Jun/14  Updated: 24/Nov/18

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: 1.6.0
Fix Version/s: None

Type: Bug Priority: Default
Reporter: amichair Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Issue Links:
Duplicate
is duplicated by QFJ-956 Checksum validation of incoming messa... Closed
Relates
is related to QFJ-684 Support for binary data (BytesField) ... Closed
is related to QFJ-38 FIX Message support double-byte charset. Closed
is related to QFJ-382 Foreign Language Support - Multibyte ... Closed

 Description   

QuickFIX/J currently has limited support for alternate encodings (charsets). While it is 'good enough' for some cases, it still has drawbacks - it is limited to charsets that are a superset of ASCII (in particular, double-byte encodings are not supported), the encoding can only be set globally via CharsetSupport and applies to all fields (which can generate non-compliant messages), the engine still uses Strings for the most part with some awkward and inefficient handling to make it properly support encoded bytes, etc.

It would be better to have proper encoding support all around - with ASCII used for all standard fields, the MessageEncoding field used per-message to specify the encoding used in its Encoded* fields (e.g. EncodedText), using bytes array (or ByteBuffer) instead of Strings for more efficient and direct manipulation, supporting arbitrary charsets (not only ASCII supersets), etc.

Suggestions, additional related requirements and protocol-compliance corrections are welcome.






[QFJ-784] quickfix.field package contains mix of various FIX versions Created: 26/May/14  Updated: 09/Jun/14

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: 1.5.3
Fix Version/s: None

Type: Bug Priority: Default
Reporter: amichair Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None

Issue Links:
Relates
is related to QFJ-781 Fix code generation for SP1/2 . Closed

 Description   

The FIX fields and messages classes are auto-generated from FIX spec xml files. Each FIX spec version has a corresponding jar created with its respective classes. The message package names contain the fix version (e.g. quickfix.fix44 package), so that a specific target version's messages can be used.

However, all field packages from all versions are simply named quickfix.field, so they cannot be targeted individually by code that needs them.

Worse, when all of these versioned packages are merged together into a single 'all' messages jar, the field classes overwrite each other in the quickfix.field package, which becomes a mix of classes from all versions. Seeing that the fields of newer versions are not entirely backwards-compatible with earlier versions (e.g. some field values/constants are renamed or removed), this package becomes compliant neither with the new versions or the old versions, and breaks existing client code when a new version is added (e.g. 5.0sp1/sp2) even if said code is intended to work only with and older spec version.

Worse still, the quickfix.field package is bundled not only in the quickfix-all jar but also in the quickfix-core jar, so they are not easily decoupled for users who want to select a specific target version jar to be used explicitly, or maintain a stable build unaffected by newer spec releases.

All these versions should ideally be decoupled from each other (and from core) in such a way that they can coexist in an application that must support multiple versions, and still remain compliant with each one of them independently.

These changes require additional research and have backward-compaibility implications. Currently the combined quickfix.field pakcage has the 5.0 spec classes trump all others (i.e. its classes take precedence when there are duplicates), to remain compatible with the previous release (even though new sp1/sp2 fields are added to the package as well).






[QFJ-782] Get rid of cyclic package dependencies Created: 15/May/14  Updated: 18/Sep/17

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: None
Fix Version/s: 2.1-BETA

Type: Improvement Priority: Default
Reporter: Christoph John Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Issue Links:
Requires
requires QFJ-499 Modify build system to use Maven Closed




[QFJ-780] QuickFixJ behavior for Acceptance test fix42/1a_ValidLogonMsgSeqNumTooHigh.def looks incorrect Created: 01/May/14  Updated: 23/Aug/16

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.3
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Tarun Bahadur Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

QuickFixJ behavior for Acceptance test fix42/1a_ValidLogonMsgSeqNumTooHigh.def looks incorrect

After a resend request is received from server subsequent messages should be ignored unless SequenceReset is received or messages replayed. In below test case the logout message is sent with sequence number 6, this should actually be ignored by the server and the test case should fail. This would require fixing both QuickFixJ behavior and the test case(probably logout should have MsgSeqNum=1).

from fix42/1a_ValidLogonMsgSeqNumTooHigh.def
...
E8=FIX.4.29=5835=234=249=ISLD52=00000000-00:00:00.00056=TW7=116=410=0
I8=FIX.4.235=534=649=TW52=<TIME>56=ISLD
...



 Comments   
Comment by Christoph John [ 05/May/14 ]

This is related to the QF/J-specific behaviour to always accept a Logout message regardless of the sequence number. But it probably would not hurt to change this in order to be more in line with the FIX spec.





[QFJ-771] Session and Settings JMX beans cannot be registered more than once. Created: 24/Jan/14  Updated: 23/Aug/16

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: 1.5.3
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Vladimir Tsanev Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: jmx


 Description   

I need to register, unregister and then register again a Connector - but then the session and settings beans do not appear.

I looked at the source and the problem seems that the SessionJmxExporter's cache with registered sessionId's is not cleared.
ConnectorAdmin registers sessions only if they are not cached by sessionExporter - so the second time session do not show up.



 Comments   
Comment by Christoph John [ 03/Feb/14 ]

How do you register your connector? Can't you simply unregister it prior to re-registering it? Briefly looking at the code it seems there is no unregister method in class org.quickfixj.jmx.JmxExporter.
But shouldn't it work to unregister the connector by yourself by calling jmxExporter.getMBeanServer().unregisterMBean( objectName )?

Comment by Vladimir Tsanev [ 06/Feb/14 ]

I do call jmxExporter.getMBeanServer().unregisterMBean(objectName);.

I will expand on my problem. I need to be able to add and remove sessions at runtime. To achieve this a have a connector per session (there are other reasons that prevents me to use add/remove dynamic sessions, but I think the problem would still be present).
If I want a session to go away I just stop the connector and unregister the bean.
If I want a session to come back some time later I create new settings and new connector instance, but when the session id is the same the session does not show up.

It is because when I unregister the connector the sessionObjectNames map in SessionJmxExporter is still containing entry for my session id.

I think the corresponding entry in SessionJmxExporter.sessionObjectNames should be removed either in ConnectorAdmin.postDeregister or SessionAdmin.postDeregister.

What do you think?

Comment by Christoph John [ 12/Feb/14 ]

OK, I also see in ConnectorAdmin.registerSessions() that the session is only registered if it is not already contained in the sessionObjectNames map. So, yes, your proposed solution to remove the entry in one of the postDeregister() methods should be OK.

Comment by Yukun Song [ 05/Nov/14 ]

I am using a customized DynamicAcceptorSessionProvider in 1.5.3 to create dynamic session with my own session configs instead of the static SessionSettings. Even though I call sessionConnector.removeDynamicSession(sessionID) before sessionConnector.addDynamicSession(session), the previous session is not destroyed. The behaviour includes but not limited to 1) the session jmx doesn't work (i.e. any operation has no effect), 2) the new session thread doesn't own the file handlers of the session store files, so that client can't connect with ResetSeqnum on when logon.

Will the proposed solution solve this issue? Has the solution been added to version 1.6.0? Has anyone been involved in fixing this issue?

Comment by Christoph John [ 05/Nov/14 ]

This issue is currently only planned in to be fixed for 1.6.0 but has not been fixed yet. Could you possibly supply a test case?





[QFJ-764] Create message class for XmlMessage (MsgType = 'n') Created: 11/Dec/13  Updated: 12/Dec/13

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: New Feature Priority: Default
Reporter: Isaac Levin Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Fix 4.4 defines XML Message (message type = 'n') that contains XmlData. There are XmlData and XmlDataLen classes in QuickFIX/J, but there is no actual class for XmlMessage. As a result calling MessageFactory.create(BEGIN_STRING, 'n') returns null



 Comments   
Comment by Christoph John [ 12/Dec/13 ]

I think the problem lies within the specification of the XmlMessage itself. In FIXimate (http://www.fixtradingcommunity.org/FIXimate/FIXimate3.0/) the MsgType n is only specified having a header and a trailer, but no body fields. When adding this information to the data dictionary and regenerating the code the MessageFactory returns a message but when adding fields and validating the message the error "No fields found" is thrown by the DataDictionary. So it seems that the XmlMessage cannot be completely supported.
Another point is that by definition of the FIXimate msgType n is an admin message but QuickFIX/J currently will not treat it as admin message (see MessageUtils.isAdminMessage()). I do not know if that will cause additional problems.





[QFJ-762] Message stores can become corrupted on acceptor/initiator shutdown Created: 09/Dec/13  Updated: 21/Apr/17

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Alexey Ermakov Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None

Issue Links:
Relates
relates to QFJ-552 Message Stores expected to be thread ... Open
is related to QFJ-923 FileStore is leaking file handles Closed

 Description   

Since MessageStore implementations aren't thread safe, all operations on them should be performed from the session thread only. However, all 4 acceptor and initiator implementations perform shutdown (and thus call Session.unregisterSessions) in the calling thread. Since that calls MessageStore.close(), it can easily lead to store corruption if, for example, FileStore.close() gets called while the session thread is in the middle of persisting a Logout response.



 Comments   
Comment by Constantin Florescu [ 20/Apr/17 ]

The same issue could be reproduced when the logon request is timing out.

There are 2 threads trying to do the same thing:
16:18:28.763 [QFJ Timer] INFO quickfix.FileStore - initialize() called from.
at quickfix.FileStore.initialize(FileStore.java:111) [quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.FileStore.reset(FileStore.java:465) [quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.SessionState.reset(SessionState.java:382) [quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.Session.resetState(Session.java:2503) [quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.Session.disconnect(Session.java:1968) [quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.Session.next(Session.java:1808) [quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.mina.SessionConnector$SessionTimerTask.run(SessionConnector.java:278) [quickfixj-core-1.6.2.jar:1.6.2]

And from:
16:18:28.788 [QFJ Message Processor] INFO quickfix.FileStore - initialize() called from.
at quickfix.FileStore.initialize(FileStore.java:111) [quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.FileStore.reset(FileStore.java:465) [quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.SessionState.reset(SessionState.java:382) [quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.Session.resetState(Session.java:2503) [quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.Session.disconnect(Session.java:1968) [quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.Session.next(Session.java:882) [quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.Session.next(Session.java:1109) [quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.mina.SingleThreadedEventHandlingStrategy$SessionMessageEvent.processMessage(SingleThreadedEventHandlingStrategy.java:144) [quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.mina.SingleThreadedEventHandlingStrategy.block(SingleThreadedEventHandlingStrategy.java:91) [quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.mina.SingleThreadedEventHandlingStrategy$1.run(SingleThreadedEventHandlingStrategy.java:125) [quickfixj-core-1.6.2.jar:1.6.2]

This causes unexpected behaviour and leaks File Descriptors.
Example:
ERROR [QFJ Timer] quickfix.SocketInitiator Error during timer processing
quickfix.RuntimeError: java.io.FileNotFoundException: [/..../Session].header (Too many open files)
at quickfix.SessionState.reset(SessionState.java:384) ~[quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.Session.resetState(Session.java:2499) ~[quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.Session.disconnect(Session.java:1967) ~[quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.Session.next(Session.java:1808) ~[quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.mina.SessionConnector$SessionTimerTask.run(SessionConnector.java:278) [quickfixj-core-1.6.2.jar:1.6.2]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_74]
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [?:1.8.0_74]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [?:1.8.0_74]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [?:1.8.0_74]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_74]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_74]
at java.lang.Thread.run(Thread.java:745) [?:1.8.0_74]
Caused by: java.io.FileNotFoundException: [/.../Session].header (Too many open files)
at java.io.FileOutputStream.open0(Native Method) ~[?:1.8.0_74]
at java.io.FileOutputStream.open(FileOutputStream.java:270) ~[?:1.8.0_74]
at java.io.FileOutputStream.<init>(FileOutputStream.java:213) ~[?:1.8.0_74]
at java.io.FileOutputStream.<init>(FileOutputStream.java:133) ~[?:1.8.0_74]
at quickfix.FileStore.initializeMessageIndex(FileStore.java:198) ~[quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.FileStore.initializeCache(FileStore.java:121) ~[quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.FileStore.initialize(FileStore.java:116) ~[quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.FileStore.reset(FileStore.java:442) ~[quickfixj-core-1.6.2.jar:1.6.2]
at quickfix.SessionState.reset(SessionState.java:382) ~[quickfixj-core-1.6.2.jar:1.6.2]
... 11 more





[QFJ-753] Banzai example wrong handling of replaced orders Created: 29/Aug/13  Updated: 29/Aug/13

Status: Open
Project: QuickFIX/J
Component/s: Examples
Affects Version/s: 1.5.3
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Marin Bonacci Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

After sending Cancel/Replace request with modified quantity, the target sends PENDING_REPLACE ExecutionReport, then REPLACE ExecutionReport with new quantity. The application does't update order quantity, and interprets first ExecutionReport as a fill.






[QFJ-745] "MsgSeqNum too high" error as result of "QFJ Message Processor" could parse income messages on SSL Connections Created: 23/May/13  Updated: 11/Jun/13

Status: Open
Project: QuickFIX/J
Component/s: Networking
Affects Version/s: 1.5.3
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Andrey Nalitkin Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: sequnece, ssl, testRequest
Environment:

CentOS release 5.9 (Final)
Linux dev99 2.6.18-348.6.1.el5 #1 SMP Tue May 21 15:29:55 EDT 2013 x86_64 x86_64 x86_64 GNU/Linux

java version "1.6.0_32"
Java(TM) SE Runtime Environment (build 1.6.0_32-b05)
Java HotSpot(TM) 64-Bit Server VM (build 20.7-b02, mixed mode)



 Description   

QFJ Message Processor thread could parse income message queue and

Name: QFJ Message Processor
State: RUNNABLE
Total blocked: 1 Total waited: 8,038

Stack trace:
quickfix.mina.AbstractIoHandler.messageReceived(AbstractIoHandler.java:104)
org.apache.mina.common.support.AbstractIoFilterChain$TailFilter.messageReceived(AbstractIoFilterChain.java:570)
org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
org.apache.mina.common.support.AbstractIoFilterChain.access$1100(AbstractIoFilterChain.java:53)
org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.messageReceived(AbstractIoFilterChain.java:648)
org.apache.mina.filter.codec.support.SimpleProtocolDecoderOutput.flush(SimpleProtocolDecoderOutput.java:58)
org.apache.mina.filter.codec.ProtocolCodecFilter.messageReceived(ProtocolCodecFilter.java:180)
org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
org.apache.mina.common.support.AbstractIoFilterChain.access$1100(AbstractIoFilterChain.java:53)
org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.messageReceived(AbstractIoFilterChain.java:648)
org.apache.mina.filter.support.SSLHandler.flushScheduledEvents(SSLHandler.java:275)
org.apache.mina.filter.SSLFilter.filterWrite(SSLFilter.java:512)
org.apache.mina.common.support.AbstractIoFilterChain.callPreviousFilterWrite(AbstractIoFilterChain.java:361)
org.apache.mina.common.support.AbstractIoFilterChain.access$1300(AbstractIoFilterChain.java:53)
org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.filterWrite(AbstractIoFilterChain.java:659)
org.apache.mina.filter.codec.ProtocolCodecFilter$ProtocolEncoderOutputImpl.doFlush(ProtocolCodecFilter.java:369)
org.apache.mina.filter.codec.support.SimpleProtocolEncoderOutput.flush(SimpleProtocolEncoderOutput.java:97)
org.apache.mina.filter.codec.ProtocolCodecFilter.filterWrite(ProtocolCodecFilter.java:215)
org.apache.mina.common.support.AbstractIoFilterChain.callPreviousFilterWrite(AbstractIoFilterChain.java:361)
org.apache.mina.common.support.AbstractIoFilterChain.access$1300(AbstractIoFilterChain.java:53)
org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.filterWrite(AbstractIoFilterChain.java:659)
org.apache.mina.common.support.AbstractIoFilterChain$TailFilter.filterWrite(AbstractIoFilterChain.java:587)
org.apache.mina.common.support.AbstractIoFilterChain.callPreviousFilterWrite(AbstractIoFilterChain.java:361)
org.apache.mina.common.support.AbstractIoFilterChain.fireFilterWrite(AbstractIoFilterChain.java:355)
org.apache.mina.transport.socket.nio.SocketSessionImpl.write0(SocketSessionImpl.java:166)
org.apache.mina.common.support.BaseIoSession.write(BaseIoSession.java:177)
org.apache.mina.common.support.BaseIoSession.write(BaseIoSession.java:168)
quickfix.mina.IoSessionResponder.send(IoSessionResponder.java:47)
quickfix.Session.send(Session.java:2483)

  • locked java.lang.String@73013e68
    quickfix.Session.sendRaw(Session.java:2414)
    quickfix.Session.generateHeartbeat(Session.java:1827)
    quickfix.Session.next(Session.java:1800)
    quickfix.Session.next(Session.java:1101)
    quickfix.mina.SingleThreadedEventHandlingStrategy$SessionMessageEvent.processMessage(SingleThreadedEventHandlingStrategy.java:114)
    quickfix.mina.SingleThreadedEventHandlingStrategy.block(SingleThreadedEventHandlingStrategy.java:77)
    quickfix.mina.SingleThreadedEventHandlingStrategy$1.run(SingleThreadedEventHandlingStrategy.java:94)
    java.lang.Thread.run(Thread.java:662)


 Comments   
Comment by Christoph John [ 24/May/13 ]

Please excuse me, could you please elaborate on what exactly the problem is? Thank you.

Comment by Andrey Nalitkin [ 24/May/13 ]

Problem in concurrent parsing and modification of incoming MsgSeqNum counter by 2 threads:
1. "QFJ Message Processor" thread
2. "SocketConnectorIoProcessor" thread

As result SocketConnectorIoProcessor "lose" messages, report error and request to resend

Comment by Christoph John [ 11/Jun/13 ]

Do you have some more information on this? Message logs maybe?
The stack trace only lists one thread. Do you also have a stack trace of the other involved threads?





[QFJ-743] JdbcLog doesn't take into consideration the sessionID to verify if a parameter is set like JdbcMessage does Created: 13/May/13  Updated: 06/Nov/15

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.3
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Leandro Garcia Herrera Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: JdbcLog, QuickfixJ, jdbc
Environment:

Windows 7, using JBoss and camel-quickfix


Attachments: Java Source File JdbcLog.java     Java Source File TemaJdbcLog.java    

 Description   

I'm trying to configure JdbcLogFactory dynamically passing a SessionSettings object as argument to constructor. All my configurations are under an especific session ID and I have no configurations under default session.

Looking at the source code of JdbcLog I was able to confirm that only the default session configurations are taken into consideration instead of checking first in session ID configurations informed via constructor, wich I was expecting.

The JdbcStore class does this verification by session ID and I think JdbcLog should work in the same way.



 Comments   
Comment by Christoph John [ 09/Jan/14 ]

Would it be OK for you to attach the patch to this ticket? I do not have the necessary rights to grant you SVN access but could integrate the patch shortly.

Comment by Leandro Garcia Herrera [ 06/Nov/15 ]

Hi, Christoph. Look if it helps. I've attached the patch as you requested.

Best regards.

Comment by Leandro Garcia Herrera [ 06/Nov/15 ]

bug fix





[QFJ-733] Provide customisable hooks into the core QuickFIX/J workflow Created: 11/Mar/13  Updated: 21/Mar/13

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.3
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: Ryan Lea Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: QuickfixJ, modules, performance


 Description   

Background:
I have been using QuickFIX for some time and found it a great library. As my usage has increased, I have become more aware that it's not necessarily GC-friendly. As such I'm in the process of extending the Message object to become more GC-friendly, but really a step away from the message type-safety that is currently present within QuickFIX/J.

In order to achieve my goal, I have made (what I consider) minor modifications to the core codebase to provide locatable service lookups where need be,

Improvement:
It would be great if QuickFIX/J was more customisable in the services that were able to be overriden/extended or generally customised. I've currently created a (very simple - based on http://martinfowler.com/articles/injection.html) ServiceLocator that prepares services with defaults (current 1.5.3 behaviour) that can be overriden with custom services on startup (if required).

The services that I have currently customised are:

  1. Message validation with the Data Dictionary
  2. Message creation from String (the FIXMessageDecoderFactory)
  3. Handling of FIX Messages within the abstract IoHandler (as it depends upon MINA passing it a String)

This approach seemed less intrusive than a DI framework, and perhaps a simpler fit into QuickFIX core. It provides the benefits of maintaining a library that can be used out of the box, whilst providing the capability of customisation where required or necessary.

I'd be mostly interested to know whether this (or something like it) would be considered as part of the roadmap with QuickFIX/J and how or whether I would be able to contribute.



 Comments   
Comment by Jörg Thönnes [ 15/Mar/13 ]

Dear Ryan,

we appreciate your idea and would like to consider it.
It is true the QF/J is quite monolithic and would greatly benefit from being split into more components.
E.g.

  • separate IO layer in order to allow to replace MINA by Netty, etc (QFJ-598)

But currently there is no roadmap what should be done.

But it would be good if you could start a page in QF/J Confluence to outline your thoughts
and perhaps attached some code.

Thanks, Jörg

Comment by Ryan Lea [ 21/Mar/13 ]

Hi Jorg,

Thanks for your feedback. I will certainly attach a patch once I've extracted out the pieces I need to.

Following that, I will look at creating a Confluence page as well (quite a few of the Confluence pages seem quite old as well I've noticed). Do you have a preference of which hierarchy you would like it placed in?

Ryan





[QFJ-729] Allow MessageCrackers to handle polymorphic Message types Created: 07/Feb/13  Updated: 07/Feb/13

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.3
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: S Raf Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

The MessageCracker expects an invoker to be registered for the specific actual Message type being processed. If an invoker exists for a supertype of the received Message, the invoker won't be called.

For those extending MessageCracker, the onMessage(quickfix.Message message, SessionID sessionID) method can be overridden to allow implementers to handle the most general quickfix.Message type (but not, for example, only quickfix.fix44.Message messages).

However, for those providing a delegate object to the MessageCracker, there is no option to provide a handler for a more general Message type to provide custom fallback logic.

The crack(..) method should look for invokers registered for the received Message's superclass(es), as well as its actual type, before resorting to the fallback onMessage call in MessageCracker.






[QFJ-725] Note that sequence numbers will be reset at 'StartTime' even if ResetOnLogon=N Created: 27/Dec/12  Updated: 12/Apr/13

Status: Open
Project: QuickFIX/J
Component/s: Documentation
Affects Version/s: None
Fix Version/s: None

Type: New Feature Priority: Default
Reporter: Jim Mulcahey Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: QuickfixJ


 Description   

When a new session is started based on the QF/J 'StartTime' configuration setting, the sequence numbers will be reset even if ResetOnLogon=N. The Configuration section in the User Manual does not make this clear, as 'StartTime' is only defined as..

"Time of day that this FIX session becomes activated"

It would help to have a note added in the Configuration section that the sequence numbers will be reset even if ResetOnLogon=N.



 Comments   
Comment by Jörg Thönnes [ 12/Apr/13 ]

A new FIX session is defined by resetting the numbers to 1. Or in other words: You cannot start a new session
without setting numbers back to 1.

The ResetOnLogon forces to reset the sequence numbers even if we are in the normal [StartTime, EndTime] frame.

So "Time of day that this FIX session becomes activated" should get "Time of day when the new FIX session starts".

Actually, the new FIX session starts some where in between the previous days EndTime and the todays StartTime.
And the engine really resets the sequence numbers if it detects that it is out of session time (e.g. after last days EndTime).

Comment by Jim Mulcahey [ 12/Apr/13 ]

Thanks for the clarification, Jörg. You can go ahead and close this ticket.





[QFJ-723] need complete validation in DataDictionary rather than just first failure Created: 20/Dec/12  Updated: 20/Dec/12

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: New Feature Priority: Default
Reporter: Vishal Arora Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Currently when DataDictionary.validate method is called over a FIX Message, it throws exception on first failure. We need to fail it last, listing all failures during validation. This is required for testing of our application, where we can't expect developers to fix one FIX validation failure to find next one.






[QFJ-670] CLONE - Session Qualifier or some other field Created: 05/Mar/12  Updated: 05/Mar/12

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Other Priority: Default
Reporter: Howard Andresier Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

I want to identify each session uniquely through my own Id (not version, sender or target_comp_id combination)

I mean onCreate gives a callback with SessionId, which gives a combination of version, sender_comp_id and target_compid. sessionQualifier helped in giving my own Id, but SessionQualifier is not supported with acceptor sessions, Is there some easy way I can identify the sessions with the my own id?



 Comments   
Comment by Howard Andresier [ 05/Mar/12 ]

Clone of QFJ-392, since I appear unable to re-open it.
Could someone give me the fix version where this was resolved? I too would like a qualifier for Acceptors.

Comment by Howard Andresier [ 05/Mar/12 ]

I see now also QFJ-207, which is closed with a 'Wont Fix'. Please disregard if that is still the case.





[QFJ-669] Initiator interprets logout response as logout request. Created: 02/Mar/12  Updated: 24/Jan/13

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: 1.5.2, 1.5.3
Fix Version/s: Future Releases

Type: Bug Priority: Default
Reporter: Bogdan Dornean Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Steps:
1.INITIATOR sends logout request.
2.ACCEPTOR sends logout response.
3.INITIATOR interprets received logout message as logout REQUEST
4.INITIATOR sends logout response.

INFO: Logging out all sessions
<20120302-14:43:55, FIX.4.2:INITIATOR->ACCEPTOR, event> (Initiated logout request)
<20120302-14:43:55, FIX.4.2:INITIATOR->ACCEPTOR, outgoing> (8=FIX.4.29=5535=534=5549=INITIATOR52=20120302-14:43:55.80556=ACCEPTOR10=100)
<20120302-14:43:55, FIX.4.2:INITIATOR->ACCEPTOR, incoming> (8=FIX.4.29=8135=552=20120302-14:43:55.80849=ACCEPTOR34=17156=INITIATOR58=At the opposite wish.10=242)
<20120302-14:43:55, FIX.4.2:INITIATOR->ACCEPTOR, event> (Received logout request)
<20120302-14:43:55, FIX.4.2:INITIATOR->ACCEPTOR, outgoing> (8=FIX.4.29=5535=534=5649=INITIATOR52=20120302-14:43:55.81356=ACCEPTOR10=100)
Mar 2, 2012 11:43:55 PM quickfix.Session disconnect
INFO: [FIX.4.2:INITIATOR->ACCEPTOR] Disconnecting: IO Session closed

<20120302-14:43:55, FIX.4.2:INITIATOR->ACCEPTOR, error> (Error Reading/Writing in MessageStore
java.io.IOException: Bad file descriptor
at java.io.RandomAccessFile.writeBytes(Native Method)
Mar 2, 2012 11:43:55 PM quickfix.mina.SessionConnector stopSessionTimer
at java.io.RandomAccessFile.write(RandomAccessFile.java:453)
INFO: SessionTimer canceled
at quickfix.FileStore.set(FileStore.java:409)
at quickfix.SessionState.set(SessionState.java:308)
at quickfix.Session.sendRaw(Session.java:2307)
at quickfix.Session.generateLogout(Session.java:1350)
at quickfix.Session.generateLogout(Session.java:1323)
at quickfix.Session.nextLogout(Session.java:1301)
at quickfix.Session.next(Session.java:965)
at quickfix.mina.SingleThreadedEventHandlingStrategy$SessionMessageEvent.processMessage(SingleThreadedEventHandlingStrategy.java:114)
at quickfix.mina.SingleThreadedEventHandlingStrategy.block(SingleThreadedEventHandlingStrategy.java:77)
at quickfix.mina.SingleThreadedEventHandlingStrategy$1.run(SingleThreadedEventHandlingStrategy.java:94)
at java.lang.Thread.run(Thread.java:619)

<20120302-14:43:55, FIX.4.2:INITIATOR->ACCEPTOR, event> (Sent logout response)
<20120302-14:43:55, FIX.4.2:INITIATOR->ACCEPTOR, error> (Error processing message: 8=FIX.4.29=8135=534=17149=ACCEPTOR52=20120302-14:43:55.80856=INITIATOR58=At the opposite wish.10=242
ava.io.IOException: Bad file descriptor
at java.io.RandomAccessFile.seek(Native Method)
at quickfix.FileStore.storeSequenceNumbers(FileStore.java:414)
at quickfix.FileStore.incrNextTargetMsgSeqNum(FileStore.java:307)
at quickfix.SessionState.incrNextTargetMsgSeqNum(SessionState.java:368)
at quickfix.Session.nextLogout(Session.java:1310)
at quickfix.Session.next(Session.java:965)
at quickfix.mina.SingleThreadedEventHandlingStrategy$SessionMessageEvent.processMessage(SingleThreadedEventHandlingStrategy.java:114)
at quickfix.mina.SingleThreadedEventHandlingStrategy.block(SingleThreadedEventHandlingStrategy.java:77)
at quickfix.mina.SingleThreadedEventHandlingStrategy$1.run(SingleThreadedEventHandlingStrategy.java:94)
at java.lang.Thread.run(Thread.java:619)



 Comments   
Comment by Krzysztof Szalast [ 14/Sep/12 ]

I also have this error. After second unnecessary LogOut, when I am sending LogOn, in field 34 is bad value (to high).

Scenario:
Me (initiator): Logout t34=204
Counterparty (acceptor): Logout t34=315
Me: Logout* t34=205 (counterparty don't receive this message, but my outgoing_seqnum is incremented)
Me: Logon t34=206, t789=316
Counterparty: t34=316, t789=205 (205 was second Logout*)
Me: SequenceReset t34=205, 36=207 <-- this message sould not be sent. This is side effect of Logout* (t34=205)

Very sorry for my English

Comment by Krzysztof Szalast [ 14/Sep/12 ]

I've resolved problem by add "synchronized" modifier to methods:
quickfix.Session::next()
quickfix.Session::next(Message)
ugly, but looks work properly.

Comment by Jörg Thönnes [ 24/Jan/13 ]

I could reproduce this issue. It seems to happen if there is a very low latency in the network connection between client and server (e.g. on the same host).

Two things happen very quickly:

  • Incoming Logout is processed before the sentLogout flag in the session state is set / published.
  • Shortly after that the socket is closed: "Disconnecting: IO Session closed"

QFJ tries to answer the Logout it considers as request and fails:

  • event : No responder, not sending message: 8=FIX.4.4|9=53|35=5|34=...

But this message is kept in the message store and leads to a ResendRequest at the next logon.

IHMO, syncing on next() is too brute-force. On the other hand, correcting the already complicated state handling is tricky.

Comment by Jörg Thönnes [ 24/Jan/13 ]

Lowering priority since this is a race condition in a very specific situation and does not affect general functionality.





[QFJ-659] Sequence number issues when acceptor sends a message immediately following logon response Created: 09/Jan/12  Updated: 09/Jan/12

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.4.0, 1.5.2
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Andrew Richards Assignee: Unassigned
Resolution: Unresolved Votes: 2
Labels: logon, sequnece


 Description   

I have an initiator connection to a foreign acceptor which has sequence number confusion on logon as the foreign acceptor sends a TestRequest immediately after the logon response.

It looks like the following is happening: Quickfix/J accepts both (Logon & TestRequest) messages. The and proceeds to check the sequence number of the Logon to make sure the session is valid. It does this via Session.isTargetTooHigh() which looks at the last message in the message store which is now 1 higher than is should be because the TestRequest has been received and stored. The "MsgSeqNum too high" is issued and the engine tries to recover. In some most circumstances, but not all it (with the engine in question) it can recover however it's not ideal.

The effect can be simulated (QuickFIX/J -> QuickFIX/J) by using and acceptor with the toAdmin below.

public void toAdmin(Message message, SessionID sessionID)
{
print("toAdmin", message, sessionID);

try {
Header header = message.getHeader();
if ( header.getField( new MsgType() ).valueEquals( MsgType.LOGON ) )

{ quickfix.fix44.TestRequest tst = new quickfix.fix44.TestRequest(new TestReqID("TEST")); Session.sendToTarget(tst, sessionID); }

}
catch (Exception e) {}
}

09-Jan-2012 08:49:19 INFO : Initialize
09-Jan-2012 08:49:50 INFO : FIX.4.4:CLIENT->SERVER: 8=FIX.4.49=5535=034=349=SERVER52=20120109-08:49:50.01356=CLIENT10=107
09-Jan-2012 08:49:50 SEVERE : FIX.4.4:CLIENT->SERVER: MsgSeqNum too high, expecting 2 but received 3: 8=FIX.4.49=5535=034=349=SERVER52=20120109-08:49:50.01356=CLIENT10=107
09-Jan-2012 08:49:50 INFO : FIX.4.4:CLIENT->SERVER: Enqueued at pos 3: 8=FIX.4.49=5535=034=349=SERVER52=20120109-08:49:50.01356=CLIENT10=107
09-Jan-2012 08:49:50 INFO : [toAdmin](FIX.4.4:CLIENT->SERVER)[2](MsgType:ResendRequest (2))
09-Jan-2012 08:49:50 INFO : FIX.4.4:CLIENT->SERVER: 8=FIX.4.49=6435=234=249=CLIENT52=20120109-08:49:50.01956=SERVER7=216=010=238
09-Jan-2012 08:49:50 INFO : FIX.4.4:CLIENT->SERVER: Sent ResendRequest FROM: 2 TO: 2
09-Jan-2012 08:49:50 INFO : FIX.4.4:CLIENT->SERVER: 8=FIX.4.49=9335=434=243=Y49=SERVER52=20120109-08:49:50.02556=CLIENT122=20120109-08:49:5036=4123=Y10=182
09-Jan-2012 08:49:50 INFO : FIX.4.4:CLIENT->SERVER: ResendRequest for messages FROM 2 TO 2 has been satisfied.
09-Jan-2012 08:49:50 INFO : [fromAdmin](FIX.4.4:CLIENT->SERVER)[2](MsgType:SequenceReset (4))
09-Jan-2012 08:49:50 INFO : FIX.4.4:CLIENT->SERVER: Received SequenceReset FROM: 2 TO: 4
09-Jan-2012 08:50:20 INFO : [toAdmin](FIX.4.4:CLIENT->SERVER)[3](MsgType:Heartbeat (0))
09-Jan-2012 08:50:20 INFO : FIX.4.4:CLIENT->SERVER: 8=FIX.4.49=5535=034=349=CLIENT52=20120109-08:50:20.21556=SERVER10=100
09-Jan-2012 08:50:20 INFO : FIX.4.4:CLIENT->SERVER: 8=FIX.4.49=5535=034=449=SERVER52=20120109-08:50:20.21856=CLIENT10=104
09-Jan-2012 08:50:20 INFO : [fromAdmin](FIX.4.4:CLIENT->SERVER)[4](MsgType:Heartbeat (0))






[QFJ-657] TestRequest should be sent before a Logout is sent. (Initiator) Created: 05/Dec/11  Updated: 06/Dec/11

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.0, 1.5.1
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: Ken Douglas Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: Logout, testRequest
Environment:

Windows 7 Ultimate, Java 6 u29
QuickFix J 1.5.1



 Description   

TestRequest should be sent before a Logout is sent (Initiator).
You may not agree this is a bug by the way but perhaps a feature not currently supported but the FIX Protocol recommends the following:-

[1] a TestRequest is sent and a hearbeat is expected to be sent in return
[2] NB No logout is sent until a heartbeat (with the TestRequest ID) is received.
[3] Once receive a logout is sent and waitfor Logout is carried out.
[4] then disconnect is done.

I have seen a question relating to this on the forum but this goes way back
http://quickfix-j.364392.n2.nabble.com/Log-file-rotation-td665743.html

Currently the way the reset() on the Session is done it does not allow you to fire a TestRequest off and wait for the hearbeat.

Any idea guys?

Thanks



 Comments   
Comment by Christoph John [ 06/Dec/11 ]

I think this would be a good improvement. BTW, the link to the forum thread is wrong. It leads to a discussion about log rotation.





[QFJ-625] Intermittent File Handle Issues While Generating Code Created: 29/Jul/11  Updated: 29/Jul/11

Status: Open
Project: QuickFIX/J
Component/s: Build
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Francois Auger Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: QuickfixJ, ant
Environment:

Windows 7 Professional x64 (latest updates)
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02, mixed mode)



 Description   

Intermittently, we're having the following error while running the default ant task:

[java] SEVERE: error during code generation
[java] quickfix.codegen.CodeGenerationException: java.io.FileNotFoundException: target\generated-sources\messages\quickfix\fix50\component\UnderlyingInstrument.java (The requested operation cannot be performed on a file with a user-mapped section open)

The following patch has worked so far:

Index: quickfixj-local/core/src/main/java/quickfix/codegen/MessageCodeGenerator.java
===================================================================
— quickfixj-local/core/src/main/java/quickfix/codegen/MessageCodeGenerator.java (revision xyz)
+++ quickfixj-local/core/src/main/java/quickfix/codegen/MessageCodeGenerator.java (working copy)
@@ -269,8 +269,11 @@
}

File outputFile = new File(outputFileName);

  • if (!task.isOverwrite() && outputFile.exists()) {
  • return;
    + if (outputFile.exists())
    Unknown macro: {+ if (!task.isOverwrite()) { + return; + }+ outputFile.delete(); }

DOMSource source = new DOMSource(document);

Thanks,
François






[QFJ-623] How do you change CompIDs, IP and port of a session at runtime? Created: 26/Jul/11  Updated: 19/Oct/11

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.0
Fix Version/s: None

Type: Other Priority: Default
Reporter: Andrew Niland Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: QuickfixJ
Environment:

java 1.6 on Windows



 Description   

How do you change CompIDs, IP and port of a session at runtime?

I would like to repoint the initiator engine to a different FIX server while the java app is still running.



 Comments   
Comment by Grant Birchmeier [ 26/Jul/11 ]

Did you try posting your question to the mailing list? This doesn't look like it should be a bug report.
http://quickfixj.org/support/

Comment by Laurent Danesi [ 19/Oct/11 ]

CompIDs are part of the SessionID, if you change them it is not the same Session anymore.
About the IP/port, you can specify multiple ip/port for the session and switch to them.

Regards,

Laurent DANESI





[QFJ-619] Late Resend Request causes sequence number mayhem : what happened? Created: 18/Jul/11  Updated: 18/Jul/11

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.4.0
Fix Version/s: None

Type: Other Priority: Default
Reporter: Nicolas Chaufette Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File trace.txt    

 Description   

Hello everyone,

A client seems to have a problem that I cannot reproduce. Basically, the third party asks for a resend request of a message sent 7 minutes earlier. During those 7 mintures, heartbeats have been exchanged and the sequence increased. When the Resend Request is received, this happens (look at the sequence numbers).
Is it a known bug in QuickFIX/J 1.4.0 ? fixed in 1.5.0 ?

Thanks, best regards,

Nicolas

<fix:trace logger="fix-engine-05301" timestamp="2011-07-05 13:30:40.704" level="Enabled" thread="QFJ Timer">
<fix:message length="79" way="outgoing"><![CDATA[8=FIX.4.4|9=57|35=0|34=260|49=NOYOBU|52=20110705-11:30:40.704|56=NOYOBU|10=215|]]></fix:message>
</fix:trace>

[... nothing of importance, just heartbeats in and out for 7 minutes...]

<fix:trace logger="fix-engine-05301" timestamp="2011-07-05 13:37:46.695" level="Enabled" thread="QFJ Timer">
<fix:message length="79" way="outgoing"><![CDATA[8=FIX.4.4|9=57|35=0|34=267|49=NOYOBU|52=20110705-11:37:46.695|56=NOYOBU|10=244|]]></fix:message>
</fix:trace>

[... here seqnum is 267, right? ...]

<fix:trace logger="fix-engine-05301" timestamp="2011-07-05 13:37:46.788" level="Enabled" thread="SocketConnectorIoProcessor-0.0">
<fix:message length="88" way="incoming"><![CDATA[8=FIX.4.4|9=0064|35=2|49=NOYOBU|56=NOYOBU|34=269|52=20110705-11:37:46|7=260|16=0|10=102|]]></fix:message>
</fix:trace>
<fix:trace logger="fix-engine-05301" timestamp="2011-07-05 13:37:46.788" level="Enabled" thread="QFJ Message Processor">
<fix:event length="45"><![CDATA[Received ResendRequest FROM: 260 TO: infinity]]></fix:event>
</fix:trace>

[... counterparty asks for 260, sent 7 minutes earlier ...]

<fix:trace logger="fix-engine-05301" timestamp="2011-07-05 13:37:47.185" level="Enabled" thread="QFJ Message Processor">
<fix:message length="119" way="outgoing"><![CDATA[8=FIX.4.4|9=97|35=4|34=260|43=Y|49=NOYOBU|52=20110705-11:37:47.185|56=NOYOBU|122=20110705-11:37:47|36=261|123=Y|10=150|]]></fix:message>
</fix:trace>
<fix:trace logger="fix-engine-05301" timestamp="2011-07-05 13:37:47.186" level="Enabled" thread="QFJ Message Processor">
<fix:event length="26"><![CDATA[Sent SequenceReset TO: 261]]></fix:event>
</fix:trace>

[... sending 260, reset to 261 ?? ...]

<fix:trace logger="fix-engine-05301" timestamp="2011-07-05 13:37:47.186" level="Enabled" thread="QFJ Message Processor">
<fix:message length="119" way="outgoing"><![CDATA[8=FIX.4.4|9=97|35=4|34=260|43=Y|49=NOYOBU|52=20110705-11:37:47.186|56=NOYOBU|122=20110705-11:37:47|36=267|123=Y|10=157|]]></fix:message>
</fix:trace>
<fix:trace logger="fix-engine-05301" timestamp="2011-07-05 13:37:47.186" level="Enabled" thread="QFJ Message Processor">
<fix:event length="26"><![CDATA[Sent SequenceReset TO: 267]]></fix:event>
</fix:trace>

[... sending 260 AGAIN, reset to 267 ????? ...]

<fix:trace logger="fix-engine-05301" timestamp="2011-07-05 13:38:46.819" level="Enabled" thread="SocketConnectorIoProcessor-0.0">
<fix:message length="77" way="incoming"><![CDATA[8=FIX.4.4|9=0053|35=0|49=NOYOBU|56=NOYOBU|34=270|52=20110705-11:38:46|10=121|]]></fix:message>
</fix:trace>
<fix:trace logger="fix-engine-05301" timestamp="2011-07-05 13:38:47.699" level="Enabled" thread="QFJ Timer">
<fix:message length="79" way="outgoing"><![CDATA[8=FIX.4.4|9=57|35=0|34=268|49=NOYOBU|52=20110705-11:38:47.698|56=NOYOBU|10=250|]]></fix:message>
</fix:trace>
<fix:trace logger="fix-engine-05301" timestamp="2011-07-05 13:38:47.831" level="Enabled" thread="SocketConnectorIoProcessor-0.0">
<fix:message length="88" way="incoming"><![CDATA[8=FIX.4.4|9=0064|35=2|49=NOYOBU|56=NOYOBU|34=271|52=20110705-11:38:47|7=261|16=0|10=098|]]></fix:message>
</fix:trace>

[... and it goes on and on and on and on...]

<fix:trace logger="fix-engine-05301" timestamp="2011-07-05 13:38:47.831" level="Enabled" thread="QFJ Message Processor">
<fix:event length="45"><![CDATA[Received ResendRequest FROM: 261 TO: infinity]]></fix:event>
</fix:trace>
<fix:trace logger="fix-engine-05301" timestamp="2011-07-05 13:38:48.187" level="Enabled" thread="QFJ Message Processor">
<fix:message length="119" way="outgoing"><![CDATA[8=FIX.4.4|9=97|35=4|34=261|43=Y|49=NOYOBU|52=20110705-11:38:48.187|56=NOYOBU|122=20110705-11:38:48|36=262|123=Y|10=158|]]></fix:message>
</fix:trace>
<fix:trace logger="fix-engine-05301" timestamp="2011-07-05 13:38:48.188" level="Enabled" thread="QFJ Message Processor">
<fix:event length="26"><![CDATA[Sent SequenceReset TO: 262]]></fix:event>
</fix:trace>
<fix:trace logger="fix-engine-05301" timestamp="2011-07-05 13:38:48.188" level="Enabled" thread="QFJ Message Processor">
<fix:message length="119" way="outgoing"><![CDATA[8=FIX.4.4|9=97|35=4|34=261|43=Y|49=NOYOBU|52=20110705-11:38:48.188|56=NOYOBU|122=20110705-11:38:48|36=268|123=Y|10=165|]]></fix:message>
</fix:trace>
<fix:trace logger="fix-engine-05301" timestamp="2011-07-05 13:38:48.188" level="Enabled" thread="QFJ Message Processor">
<fix:event length="26"><![CDATA[Sent SequenceReset TO: 268]]></fix:event>
</fix:trace>






[QFJ-610] java.io.IOException when using FileStore Created: 17/Jun/11  Updated: 17/Jun/11

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.0
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Daniel Clusin Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: QuickfixJ
Environment:

uname -a: Linux 2.6.9-34.ELsmp #1 SMP Fri Feb 24 16:56:28 EST 20 06 x86_64 x86_64 x86_64 GNU/Linux
Java VM: BEA JRockit(R) R27.6.0-50_o-100423-1.5.0_15-20080626-2104-linux-x86_64,BEA Systems, Inc.



 Description   

java.io.IOException: Bad file descriptor
at java.io.RandomAccessFile.seek(Native Method)
at quickfix.FileStore.storeSequenceNumbers(FileStore.java:403)
at quickfix.FileStore.incrNextSenderMsgSeqNum(FileStore.java:288)
at quickfix.SessionState.incrNextSenderMsgSeqNum(SessionState.java:350)
at quickfix.Session.sendRaw(Session.java:2177)
at quickfix.Session.generateHeartbeat(Session.java:1786)
at quickfix.Session.next(Session.java:1759)
at quickfix.Session.next(Session.java:1032)
at quickfix.mina.ThreadPerSessionEventHandlingStrategy$MessageDispatchingThread.run(ThreadPerSessionEventHandlingStrategy.java:119)

This occurred during a period of intermittent network disconnects. I did not see any forcible closes of the network sockets being done. Another time this occured is during a shutdown, after we called Initiator/Acceptor.stop

FIX.4.2:XXXX->XXXX: Error during message processing

quickfix.RuntimeError: java.io.IOException: Bad file descriptor
at quickfix.SessionState.reset(SessionState.java:373)
at quickfix.Session.resetState(Session.java:2193)
at quickfix.Session.nextLogout(Session.java:1279)
at quickfix.Session.next(Session.java:941)
at quickfix.mina.ThreadPerSessionEventHandlingStrategy$MessageDispatchingThread.run(ThreadPerSessionEventHandlingStrategy.java:119)

Caused by: java.io.IOException: Bad file descriptor
at java.io.RandomAccessFile.length(Native Method)
at quickfix.FileStore.initializeCache(FileStore.java:119)
at quickfix.FileStore.initialize(FileStore.java:111)
at quickfix.FileStore.reset(FileStore.java:436)
at quickfix.SessionState.reset(SessionState.java:370)
... 4 more






[QFJ-598] Make Quickfix/J transport layer pluggable in order to replace MINA by other IO frameworks as Netty or Grizzly Created: 06/May/11  Updated: 03/Sep/13

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: Andrei Pozolotin Assignee: Unassigned
Resolution: Unresolved Votes: 2
Labels: None


 Description   

Besides MINA there are some other Java IO frameworks as

In order to use them in the QF/J engine we need to create some API to make the IO framework pluggable.

Steps

  • Replace current MINA transport by hard-wired Netty transport:
  • Compare original code base with changed required to replace MINA by Netty:
    • In this way we could deduce some API requirements.
  • Replace MINA by Grizzly and refine API.
  • Also consider MINA 2.0 integration:
    • QFJ-664: Upgrade MINA from 1.1.8 to 2.0.4


 Comments   
Comment by Luca Burgazzoli [ 26/Feb/13 ]

Hi,
I think the modularity of the transport layer makes lot of sense thus I've create a little project that tries to integrate a netty based transport with quickfixj without have to change the quickfixj code itself (do not know if possible, I'll get it soon), you can find it on github:

http://github.com/lburgazzoli/lb-quickfixj

Comment by Jörg Thönnes [ 13/Mar/13 ]

In reply to comment #1:
> [...]
>
> http://github.com/lburgazzoli/lb-quickfixj

Sounds like a good start. Did you make some progress here?

Comment by Luca Burgazzoli [ 03/Sep/13 ]

Not so much progress here as I was busy on some other stuffs.

I'll start working again on it soon as on side project I've also did some test with reactor-tcp https://github.com/reactor/reactor as foundation for the communication layer and it works very well.

In my humble opinion it is time to:

  • define transport API
  • split transport from core




[QFJ-591] Can multiple SocketAcceptPort be mapped to one SocketConnectPort Created: 03/May/11  Updated: 03/May/11

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: Sasmit Sahu Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: QuickfixJ, session


 Description   

Hi,

We have a requirement where we have one SocketConnectPort, SenderCompID and TargetCompID three diffrent internal testing environment.We need atleast 3 distinct sessions to cater to each of our internal environment.But as we have only one SocketConnectPort, how can we create 3 distinct session with same SenderCompID and TargetCompID ?Is it possible map multiple SocketAcceptPort be mapped to one SocketConnectPort.Or is there some obvious way to solve this issue which I am missing.

Thanks in advance.



 Comments   
Comment by Steve Bate [ 03/May/11 ]

I you have 3 distinct sessions, you should have 3 distinct session identifiers. Each of the distinct sessions can connect to the same acceptor port.





[QFJ-587] Issues with session log files Created: 12/Apr/11  Updated: 27/Apr/11

Status: Open
Project: QuickFIX/J
Component/s: Build
Affects Version/s: 1.5.0
Fix Version/s: None

Type: Other Priority: Default
Reporter: Prabavathy Arumugam Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: QuickfixJ, sequnece, ses, session
Environment:

Solaris 10, webMethods Integration server 7.2



 Description   

I have a question on the session logs maintained by Quickfixj. We have FIX engine built on webMethods Integration servers and there are two instances of FIX engine running on two servers in parallel. The session log files are shared between the FIX engines so that the failover can be handled seamlessly. The FIX engines are configured to start up at 7:00 AM and they shut down at 7:00 PM. The session logs are not deleted at the end of the day as the Quickfixj can handle the session startup and shutdown on its own. We observed that sometimes when the session comes up in the morning, the sequence numbers starts at 1 but does not increment. That is, the FIX engine sends sequence no 1 to the client followed by sequence no reset message continuously, until the session log files are manually deleted and the FIX session is restarted. This happens at random, sometimes after being active for 3 days and sometimes after 15 days.

The logs look like,
2011-04-08 07:30:20,955|INFO|Admin Message sent to counter party: 8=FIX.4.49=5235=534=149=****52=20110408-11:30:20.95556=****10=062
2011-04-08 07:30:31,113|INFO|Admin Message sent to counter party: 8=FIX.4.49=5235=534=149=****52=20110408-11:30:31.11356=****10=050
2011-04-08 07:30:42,628|INFO|Admin Message sent to counter party: 8=FIX.4.49=5235=534=149=****52=20110408-11:30:42.62856=****10=063
2011-04-11 07:30:00,887|INFO|Admin Message sent to counter party: 8=FIX.4.49=5235=534=149=****52=20110411-11:30:00.88756=****10=058
2011-04-11 07:30:21,046|INFO|Admin Message sent to counter party: 8=FIX.4.49=5235=534=149=****52=20110411-11:30:21.04656=****10=048
2011-04-11 07:30:31,201|INFO|Admin Message sent to counter party: 8=FIX.4.49=5235=534=149=****52=20110411-11:30:31.20156=****10=042
2011-04-11 07:30:41,544|INFO|Admin Message sent to counter party: 8=FIX.4.49=5235=534=149=****52=20110411-11:30:41.54456=****10=053
2011-04-12 07:30:00,875|INFO|Admin Message sent to counter party: 8=FIX.4.49=5235=534=149=****52=20110412-11:30:00.87556=****10=056
2011-04-12 07:30:21,030|INFO|Admin Message sent to counter party: 8=FIX.4.49=5235=534=149=****52=20110412-11:30:21.02956=****10=050
2011-04-12 07:30:31,182|INFO|Admin Message sent to counter party: 8=FIX.4.49=5235=534=149=****52=20110412-11:30:31.18256=****10=051
2011-04-12 07:30:41,337|INFO|Admin Message sent to counter party: 8=FIX.4.49=5235=534=149=****52=20110412-11:30:41.33756=****10=054

Any suggestions or comments will be helpful. Is this a known issue? Or is there anything else that we can code for to avoid this? Thanks in advance.



 Comments   
Comment by Prabavathy Arumugam [ 27/Apr/11 ]

To update, We turned off the FIX engine on one of the instance and let it run on only one server. It ran fine for the past 20 days and we had the sequence number issue happen again today. That is the sequence number started at 1:00 today morning but it did not increment after that. We had to delete the session logs and restart the FIX engine. Is this a limitation in quickfixj framework? Is there a workaround that we can try?

Thanks!!





[QFJ-583] Session.forceStoreResync doesn't check persistMessages Created: 31/Mar/11  Updated: 31/Mar/11

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.0
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Dmitri Lenna Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Windows & Linux.



 Description   

We set the "ForceResync" to true and "PersistMessages" to false. Attempting connect to a target with a different sequence number, we get a logout message with the expected sequence number and the following is called:

(in Session.java):
private void forceStoreResync(int nextTargetMsgSeqNum, int nextSenderMsgSeqNum )

in that method, a heartbeat message is created for each missing sequence number and it's stored in the Message Store without checking if persisteMessage is true.

Is there a reason for this or this a bug? If it's a bug, I'd suggest this fix:

Line 1601:

  • if (actualSenderMsgSeqNum < nextSenderMsgSeqNum) {
    + if (actualSenderMsgSeqNum < nextSenderMsgSeqNum && persistMessages ) {

Thank you.






[QFJ-582] Converters improvement for better performance Created: 30/Mar/11  Updated: 29/May/17

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.0
Fix Version/s: Future Releases

Type: Improvement Priority: Default
Reporter: Abla Nait Assignee: Eric Deshayes
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Improve performance converters (double, int) and add tests to cover all cases.



 Comments   
Comment by Jörg Thönnes [ 30/Mar/11 ]

Hi Nait,

what kind of performance improvements you are planning. I have also some thoughts collected over the last years.

Cheers, Jörg

Comment by Abla Nait [ 30/Mar/11 ]

Remove Matcher in double converter and verify only if the first charater is not '+', other cases will be handled by parseDouble; and ditto for int converter.

Comment by Abla Nait [ 30/Mar/11 ]

Hi Jorg,
this is mainly very focused parsing improvements that we've done after some profiling and that we are integrating to the trunk (as part of the integration of our changes).

I let you open another JIRA for other or deeper improvements.
We could have some talks about it to share your thoughts with ours.

Regards,
Abla

Comment by Steve Bate [ 26/Apr/11 ]

As we discussed on the developer list, the current converter implementation is not FIX-compliant. The purpose for the Regex match to validate the input before passing it to Double for parsing. If this is causing significant performance issues then we may want to implement a fast double parsing function that validates while is parses/converts the string to a double. We should also add a unit test that shows the conversion fails for formats like "1e6" (scientific notation) which is not allowed by FIX.

Comment by Eric Deshayes [ 29/Apr/11 ]

As discussed previously, changes have been reverted.
Committed in integration branch in Rev#1025.

Comment by Eric Deshayes [ 20/May/11 ]

As discussed, some improvement on the converters could be done but they should not change the FIX compliance.

Changes have been reverted and performance improvements will be handled later.





[QFJ-577] tags ApplID [1180] + ApplSeqNum [1181] to synchronise at the application FIX.5.0 SP2 M3 Created: 24/Mar/11  Updated: 24/Mar/11

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: New Feature Priority: Default
Reporter: Soledad Calvo Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

I am analyzing whether I can use quickFixJ to handle messages with my Counterparty. My Counterparty has FIX.5.0 SP2 M3 and does not support ResendRequest message.

http://www.fixprotocol.org/FIXimate3.0/en/FIX.5.0SP1/body_49485355.html?find=ApplSeqNum

To synchronise at the application level whith it I must use the tags ApplID [1180] + ApplSeqNum [1181] instead of Resend Request and Sequence Reset messages. Is there any way, without update quickFixJ, to adapt to this behavior?






[QFJ-575] In configuration file, SocketAcceptPort property is inherited from the other session, not from "DEFAULT" Created: 11/Mar/11  Updated: 11/Mar/11

Status: Open
Project: QuickFIX/J
Component/s: Documentation
Affects Version/s: 1.5.0
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Leonid Ilyevsky Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

According to documentation, any [SESSION] section of the configuration file will inherit all properties from the [DEFAULT] section.
However, I noticed that this is not true for, at least, SocketAcceptPort property.
Let say, I define a few acceptor sessions, and I skip SocketAcceptPort in one of them. Then it takes it not from DEFAULT section, but rather from the other session definition that has the same SenderCompID .
It probably makes sense as a feature (though I am not 100% sure), but in the documentation I could not find the explanation of this behavior.






[QFJ-565] JMX session management does not work if there is a seqnum mismatch. Created: 10/Nov/10  Updated: 10/Nov/10

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: 1.5.0
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Kode Charlie Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

I am in a catch-22, it seems. I followed instructions here,

  http://www.quickfixj.org/quickfixj/usermanual/1.5.0/usage/jmx.html

in order to enable remote jconsole / JMX controls on my FIX session.
However, because there is a seqnum mismatch, no session appears in jconsole,
so I cannot set the sender-seqnum!

In summary: for remote jconsole / JMX controls to resolve a seqnum mismatch,
it would be helpful if the NextSenderMsgSeqNum could be set independently
of whether there is a current mismatch. Otherwise, the jconsole / JMX controls
are useless in this scenario.






[QFJ-564] Operating on (modifying) repeating groups Created: 10/Nov/10  Updated: 10/Nov/10

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.5.0
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: Addy Bhardwaj Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

N/A



 Description   

Currently if you want to add a value in a repeating group, there isn't a straightforward way of doing so. For instance,

//Just for illustration, if noSides group is read from TCR
TradeCaptureReport.NoSides noSidesGroup = new TradeCaptureReport.NoSides();
tradeCaptureReport.getGroup(1, noSidesGroup);

//add account information in TCR
noSidesGroup.set(new Account("accountA"));

This action doesn't modify the original TCR message as the group returned by getGroup() method is a copy of the actual group object.

Is there a reason for this behaviour? Also, I noticed that when we add a typed group object it is copied into a Group object and then stored in the underlying TreeMap of groups. The only reason I could find is that String to Object parsing doesn't create concrete group objects hence copy is required but I hoping there is another reason that I have overlooked.

ps: I have modified source code locally to improve this behaviour by

  • Removing the copy behaviour all together so concrete groups objects are kept in the message object
  • parsing string to QUICKFIXJ message object handles creation of concrete Groups as well.
    I am more than happy to provide a patch if it this functionality is desirable. It should surely help optimise the code by reducing copies and object creation.





[QFJ-558] Can no longer send messages to initiators that have not yet been started Created: 13/Sep/10  Updated: 16/Sep/10

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.4.0
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Rhys Yarranton Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File diff.txt     Text File diff.txt    

 Description   

We have some system states where we disable network connection but still may have messages that we wish to deliver to the gateway, i.e., message store, for future delivery to the counterparty when we re-enable the network connection. Our technique is to create a SocketAcceptor or SocketInitiator, but not to start it. Since we upgraded from QF/J 1.2.1 to QF/J 1.4.0, this is no longer working for initiators.

Traced this back to QFJ-354, revision number 874. QFJ-354 allows a SocketInitiator to be stopped and restarted. (Previously it could be stopped, but the only way to restart it was to recreate it.) As part of this change, they moved where the sessions are created out of the constructor. (Session creation is one way a session can be registered.) QFJ-354 was part of the 1.4.0 release. There was no similar change for acceptors.

I don't see any reason why the session creation cannot be moved back into the constructor. It does not interfere with the intent of QFJ-354.
Patch attached.

While in the neighbourhood, noticed the following two lines in the AbstractSocketInitiator constructor:

ByteBuffer.setAllocator(new SimpleByteBufferAllocator());
ByteBuffer.setUseDirectBuffers(false);

This should be some sort of static initialization. e.g., for applications that use Mina for their own purposes as well as QF/J, they may need control over the buffer type and allocator, and shouldn't have to worry about QF/J changing it on the fly.



 Comments   
Comment by Rhys Yarranton [ 16/Sep/10 ]

Updated diff includes mod to ThreadedSocketInitiator.java.





[QFJ-555] Problems with heartbeating in one session can obstruct heartbeating on other sessions Created: 01/Sep/10  Updated: 07/Jan/20

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.4.0
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Rhys Yarranton Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Issue Links:
Relates
relates to QFJ-291 Problems with initiator reconnect wil... Closed

 Description   

SessionConnector.scheduledExecutorService is a single-threaded executor, and is used by all sessions for heartbeating. If there is a problem in one session, it can impact other sessions.

This is really QFJ-291 again. QFJ-291 was stated in terms of initiator reconnects, and the fix to it targeted that specific scenario. However, we have just encountered this problem in production involving only heartbeats. Heartbeating seems innocuous, but in fact has most of the same vulnerabilities as sending any other message (logging, toAdmin etc.).



 Comments   
Comment by Christoph John [ 07/Jan/20 ]

This will be improved with https://github.com/quickfix-j/quickfixj/issues/254.





[QFJ-542] test targets wrong on installation page Created: 19/Jul/10  Updated: 19/Jul/10

Status: Open
Project: QuickFIX/J
Component/s: Documentation
Affects Version/s: 1.5.0
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Grant Birchmeier Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

On page http://www.quickfixj.org/quickfixj/usermanual/1.5.0/installation.html,

It says to use targets "test.unit" and "test.acceptance". These targets do not exist.

It appears that we are supposed to use the "test" target.






[QFJ-531] To set the number of logon attempts Created: 23/Jun/10  Updated: 23/Jun/10

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: Future Releases
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: Pranab Kumar Naik Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None
Environment:

Linux



 Description   

I was trying to set up the number of failed logon attempts after which the logon session would be created with a different host. The configuration does match with the interval between reconnects, but I thought it would be useful if the number of reconnect attempts may also be configurable from the config file. Or is there an option that I maybe missing ?






[QFJ-529] RTT benchmarking Created: 05/Jun/10  Updated: 05/Jun/10

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.4.0
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: Wayne Zhu Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

windows 7 professional 64 bits, multiple core Intel



 Description   

I have tested with a simple server and client setup using a single session in the same machine(tcp socket on local host). The client sent in new orders and got execution reports back. If the orders were sent at a high data rate for a period of 100-200ms, the round trip time for a new order and the corresponding report was not good.

My understanding is that there are two different threads in sending and receiving messages. What could be the reason causing QuickFix engine to slow down processing the incoming messages? Since there is no network overhead, it's most likely to be caused by the decoder and the way FIX message is constructed.






[QFJ-528] Message generator doesn't sanitize value descriptions before using them as identifiers. Created: 27/May/10  Updated: 27/May/10

Status: Open
Project: QuickFIX/J
Component/s: Message Generation
Affects Version/s: 1.4.0
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Serkan Kaba Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Windows 7 ıIBM JDK6



 Description   

Message generator uses enum value descriptions as constant names but doesn't sanitize them before using them as identifiers. Since the value is a free format string the generator produces invalid/uncompilable code.

I think the description tag value should be sanitized as a valid Java identifier before it's used.

Thanks in advance.

Serkan KABA






[QFJ-523] Couldn't get connection because we are at maximum connection count (10/10) and there are none available Created: 13/May/10  Updated: 13/May/10

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: 1.4.0
Fix Version/s: None

Type: Bug Priority: Default
Reporter: andrew M Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Windows server 2008 r2, jdk1.7.0_b89 x64 (I know...), 8 core machine.



 Description   

I'm seeing this error. It has only happened to me once so I can't reproduce it. Maybe same as this?
http://www.quickfixj.org/jira/browse/QFJ-313

java.io.IOException: Couldn't get connection because we are at maximum connection count (10/10) and there are none available
at quickfix.JdbcStore.storeSequenceNumbers(JdbcStore.java:286)
at quickfix.JdbcStore.setNextTargetMsgSeqNum(JdbcStore.java:272)
at quickfix.JdbcStore.incrNextTargetMsgSeqNum(JdbcStore.java:173)
at quickfix.SessionState.incrNextTargetMsgSeqNum(SessionState.java:359)
at quickfix.Session.next(Session.java:799)
at quickfix.mina.ThreadPerSessionEventHandlingStrategy$MessageDispatchingThread.run(ThreadPerSessionEventHandlingStrategy.java:85)
Caused by: java.sql.SQLException: Couldn't get connection because we are at maximum connection count (10/10) and there are none available
at org.logicalcobwebs.proxool.Prototyper.quickRefuse(Prototyper.java:309)
at org.logicalcobwebs.proxool.ConnectionPool.getConnection(ConnectionPool.java:152)
at org.logicalcobwebs.proxool.ProxoolDataSource.getConnection(ProxoolDataSource.java:97)
at quickfix.JdbcStore.storeSequenceNumbers(JdbcStore.java:279)
... 5 more






[QFJ-521] Support use of partial session ID for routing purposes Created: 10/May/10  Updated: 09/Jun/11

Status: Reopened
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.3.1, 1.3.2, 1.3.3, 1.4.0
Fix Version/s: None

Type: New Feature Priority: Default
Reporter: Rhys Yarranton Assignee: Grant Birchmeier
Resolution: Unresolved Votes: 1
Labels: None

Attachments: Text File diff3.txt    

 Description   

QFJ-272/1.3.1 added several fields to SessionID (SenderSubID, TargetSubID, SenderLocationID). These fields will be populated in MessageUtils.getReverseSessionID(...) if they are set in the Login message. They then form part of the session look-up in AbstractSocketAcceptor.StaticAcceptorSessionProvider.

In 1.2.1 and below, MessageUtils.getReverseSessionID included only the comp IDs, not the sub-IDs and SenderLocationID.

This breaks us in two ways. One is that we have been configuring our sessions by the comp IDs, which works well with the 1.2.1 code but mismatches with the 1.3.1+ code even if both sides get all their IDs right.

The other, and more important, is that several of our customer gateways will vary the SenderSubID and/or TargetSubID. For example, the FIX spec describes SenderSubID as being useful to distinguish between traders, and that messages not intended for a particular trader may optionally be flagged as ADMIN. It seems to me that the changes in QFJ-272 have resulted in a restrictions/obstacles beyond what was really intended by the spec, and certainly beyond what our customers will handle.

Fortunately there is a mechanism to provide your own AcceptorSessionProvider, which can be used to work around this issue. That said, the default behaviour is not ideal. Attached is a patch to replace StaticAcceptorSessionProvider with a new class, DefaultAcceptorProvider, which first tries a "strict" 1.3.1-style lookup, and if it fails, tries a 1.2.1-style lookup based on the Comp IDs only.

If the maintainers have an objection to the patch, I would suggest at the least that something like DefaultAcceptorProvider (plus instructions) be included in the distribution for those who cannot use StaticAcceptorSessionProvider.



 Comments   
Comment by Steve Bate [ 10/May/10 ]

The specifications include subID and locationID in information such as DeliverTo and OnBehalfOf, which are used for session routing. A route endpoint in this case is identified by CompID/SubID/LocationID in the originator sessionID and in the third-party routing cases. As you mentioned, I have seen the specification describe senderSubID as being useful to distinquish between traders, but this appears to me to still be in the context of message routing to a specific trader (or trading desk) within a broader organization (represented by the compID). Every counterparty I've worked with that used subIDs have used them for session identification and routing.

That said, from what I've seen on the FPL forums there was confusion in FIX 4.2 and before about the use of session ID fields for non-routing purposes. In FIX 4.3 and later, the Parties component is recommended for identifying traders outside the context of message routing.

I'm not the only one making the decision, but I'm open to to a feature that optionally ignores parts of the session ID for routing purposes.

Comment by Grant Birchmeier [ 19/Jul/10 ]

I am having similar issues as Rhys.

While reading the 4.4 spec to puzzle out my issues, I could not find where it says that SubID and LocationID should be used for anything substantial, let alone for message routing or session identification. Like Rhys, I'm not sure QFJ-272 is a correct interpretation. Such a change is not present in the latest QF/C++.

For now I'm integrating Rhys' patch into our local QF/J build, and being able to ignore the QFJ-272 additions is quite important for my company's usage.

Comment by Grant Birchmeier [ 19/Jul/10 ]

To integrate this patch into r958, DefaultAcceptorSessionProvider::getSession() needs a slight update to match an updated AcceptorSessionProvider interface:

  • public Session getSession(SessionID sessionID)
    + public Session getSession(SessionID sessionID, SessionConnector ignored)
Comment by Grant Birchmeier [ 12/Apr/11 ]

Committed to 1015

Comment by Jörg Thönnes [ 09/Jun/11 ]

Re-opening the issue to document the changes introduced
by this ticket.

IMHO, the handling of sub IDs and location IDs in QF/J deserves an extra section in the manual. There was some
ongoing discussion in the mailings lists and FPL forums
and it also not clear to me how QF/J handles this now.





[QFJ-517] CLONE -On checksum errors, include information on the problem section of the stream Created: 29/Apr/10  Updated: 29/Apr/10

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.2.1, 1.3.0, 1.3.1
Fix Version/s: 1.3.2

Type: Improvement Priority: Default
Reporter: Rhys Yarranton Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

If there is a checksum error an error is logged, but it does not include the problem section of stream. This would useful in determining if it was a garble, a problem with the counterparty's software or whatever.

A patch we've tried is to add the following snippet to FIXMessageDecoder.handleError(ByteBuffer, int, String, boolean), right before the "if(disconnect))":

int mark = buffer.position();
try {
StringBuilder sb = new StringBuilder(text);
sb.append("\nBuffer debug info: ").append(getBufferDebugInfo(buffer));
buffer.position(0);
sb.append("\nBuffer contents: ");
try

{ final byte[] array = new byte[buffer.limit()]; for(int i = 0; i < array.length; ++i) array[i] = buffer.get(); sb.append(new String(array, "ISO-8859-1")); }

catch (Exception e)

{ sb.append(buffer.getHexDump()); }

text = sb.toString();
} finally

{ buffer.position(mark); }

 Comments   
Comment by Rhys Yarranton [ 29/Apr/10 ]

This is not fixed in 1.4.0.





[QFJ-515] Broken Links in http://www.quickfixj.org/quickfixj/usermanual/ Created: 16/Apr/10  Updated: 16/Apr/10

Status: Open
Project: QuickFIX/J
Component/s: Documentation
Affects Version/s: 1.4.0
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Dale Wilson Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Any browser; any OS. I tried Chrome, FireFOX and IE8 on Windows 7



 Description   

The page at http://www.quickfixj.org/quickfixj/usermanual/ contain links that look like:

<a href="http://http://directory.apache.org/subprojects/mina/">MINA</a>)

Note that http:// appears twice twice.






[QFJ-511] persistance filter idea Created: 03/Mar/10  Updated: 04/Mar/10

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: Andre Mermegas Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File FilterExcludingSolicited.java     Text File MessageStorePersistanceFilter.java     Text File Session.java     Text File Session.java     Text File Session.java    

 Description   

ability to add a static persistance filter to Session. to avoid writing marketdata, other user defined criteria.



 Comments   
Comment by Andre Mermegas [ 03/Mar/10 ]

example usage.

Comment by Andre Mermegas [ 04/Mar/10 ]

2nd session, has a bugfix for forceresync getting messed up by sequence numbers from the message store, it should ignore it.

Comment by Andre Mermegas [ 04/Mar/10 ]

actually I guess you could just do this

if (forceResync && isPossibleDuplicate(msg))

{ return false; }
instead of
if (forceResync && (isAdminMessage(msgType) || isPossibleDuplicate(msg))) { return false; }




[QFJ-494] proected empty constructor for Sesson class Created: 29/Dec/09  Updated: 05/Apr/10

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.3.3
Fix Version/s: Future Releases

Type: Improvement Priority: Default
Reporter: Carlo Marchiori Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

n/a



 Description   

I'd like to create a wrapper implementation and subclass of the Session class.
This wrapper is by default stateless, delegating behaviour to a true Session object.
This is useful for example to start global transactions around the next methods.

Currently Session has two constructor that can only create 'true' Sessions.

An empty protected constructor may suffice.

In fact, it's not clear why there is a SessionFactory interface when actually one cannot modify or decorate the default Session implementation.



 Comments   
Comment by Steve Bate [ 05/Apr/10 ]

IIRC, the Session interface was requested by a user for some purpose related to Spring. It's currently used for unit test support as well.

We could potentially add an interface for Session, but have you considered using some form of AOP to implement the transaction hooks.





[QFJ-416] Support Header/Trailer field ordering in code generation Created: 16/Mar/09  Updated: 15/Oct/12

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.4.0
Fix Version/s: Future Releases

Type: Improvement Priority: Default
Reporter: Laurent Danesi Assignee: Laurent Danesi
Resolution: Unresolved Votes: 2
Labels: None

Issue Links:
Relates
relates to QFJ-512 How do I change the order of the head... Closed
Requires
requires QFJ-709 expose field order constructor for me... Resolved

 Description   

To fully support custom FIX dictionary, we should take care of header fields defined in XML dictionary.



 Comments   
Comment by Jörg Thönnes [ 16/Mar/09 ]

In reply to QFJ-416:
> To fully support custom FIX dictionary, we should take care of header fields
> defined in XML dictionary.

I would like to add that the ordering as defined in the data dictionary should be honoured.
Same applies to trailer fields.

Do you think this should be separate tickets?

Comment by Laurent Danesi [ 16/Mar/09 ]

Yes, please.

Comment by Steve Bate [ 16/Mar/09 ]

Ordering by default will lead to a potential performance hit for users that don't care about ordering.

Comment by Jörg Thönnes [ 16/Mar/09 ]

In reply to comment #3:
>
> Ordering by default will lead to a potential performance hit for users that
> don't care about ordering.

Yes, but at the moment it is not possible to generate ordered Header and Trailer fields since the FieldMap constructor is not exposed.

My suggestion is to expose the field order constructor and extend the message generation to honour the generator option to create ordered messages.

In addition, the field sort is generated for every single message instance, but could by generated by a factory to use a single instance for every message type.

Comment by Jörg Thönnes [ 16/Mar/09 ]

Sorry for the duplicate comments.

The JIRA version used by QuickFIX/J has a bug which triggers errors with my Eclipse Mylyn plugin. So I did not know that I already submitted the comment.

Comment by Steve Bate [ 05/Apr/10 ]

It appears the request is also to validate the ordering.

Comment by Phill Dixon [ 27/Sep/10 ]

To add a custom field to a Trailer I also found that I had to edit the quickfix.Message object as the Trailer class has a hardcoded field order and any tag added to it which did not appear resulted in an invalid tag error. This occured when sending the Logon message with the new custom field in the trailer. The DataDictionary xml file had been modified but was apparently ignored.

There is also a hardcoded case statement for isTrailerField which needs modifying.

It would be useful if the XML file was respected.





[QFJ-415] Use data dictionary to determine message category for admin messages Created: 16/Mar/09  Updated: 07/Apr/10

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.4.0
Fix Version/s: Future Releases

Type: Improvement Priority: Default
Reporter: Laurent Danesi Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

To fully support custom FIX dictionary, we should take care of msgcat to know if the message is an admin message or application message and not use hardcoded values.



 Comments   
Comment by Steve Bate [ 16/Mar/09 ]

The data dictionary is optional, so you'll need to handle the case of not having a data dictionary to determine admin vs. application messages.

Comment by Steve Bate [ 10/Jan/10 ]

In the absence of a data dictionary we can use the hardwired admin/app classifications but allow that to be overridden by the data dictionary.

Comment by Steve Bate [ 05/Apr/10 ]

I've looked at this and it's a bit tricky since there are several places in the code where we don't have a data dictionary and we must determine if the message is an application message or not. I've added predicates to the data dictionary to determine the category of the message, but more work is needed to convert the code to use every place.





[QFJ-405] Fields missing on resends Created: 26/Feb/09  Updated: 26/Feb/09

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.3.1
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Rhys Yarranton Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

In some circumstances fields may be omitted from re-sent messages.

We tracked this down to the following line in Session.parseMessage(String):
msg.fromString(messageData, dataDictionary, false);
In our case there was a repeating group used in outbound messages only that was not present in the data dictionary. Those fields silently disappeared.

So, a workaround is to edit the data dictionary. But given the silent misbehaviour, I would rate this a bug.

Probably could fix this by creating a subclass of Message that treats the body as an immutable string --> overrides to parseBody, calculateString, calculateLength and calculateTotal. Hopefully there is a more elegant solution.






[QFJ-400] Make scheduledExecutorService non-static Created: 03/Feb/09  Updated: 16/Feb/09

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.3.3
Fix Version/s: None

Type: New Feature Priority: Default
Reporter: Mihai Sardarescu Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Hello all,

In order to start our FIX connector, we have a "start" call from our middleware (there could be more than one FIX connectors started at different times on the same JVM). On this call, a logger is paased to the connector and all the log of the FIX connector should be dumped to this logger. The log of the QuickfixJ session is easily routed. However, the log messages from Mina and of the QuickfixJ initiators are more difficult to route. We use InheritableThreadLocal to pass the logger to all threads started by our FIX connector.
We encountered a problem due to the fact that the QuickfixJ SessionConnector uses a static executor service for executing SessionTimerTask tasks. Could you please change this to non-static?
For more details, please refer to thread: http://sourceforge.net/mailarchive/message.php?msg_name=1714.65.220.39.123.1208198497.squirrel%40webmail3.hrnoc.net

We expect our application to go in production very soon (at most 2 month for now).

Thank you,
Mihai



 Comments   
Comment by Steve Bate [ 05/Feb/09 ]

Please remind me why you weren't able to write a SLF4J logger implementation that delegates to the thread local logger provided by the middleware product. All logging from all threads goes through SLF4J so it seems that this would route those messages through the logger you provided.

Comment by Mihai Sardarescu [ 05/Feb/09 ]

Hi Steve,

In order to start the FIX connector, I get a start call from the middleware. On this call, a logger is passed to my code and I shall redirect all log message written by quickfixj and mina to this logger.

To do that I have used an InheritableThreadLocal that holds the middleware logger object in order to pass it to all the created by quickfixj and mina code. The loggers created by the slf4j are just proxies to the current thread middleware logger. I can thus redirect the quickfixj and mina log messages to the middleware log.

This technique does not work in case a static executor (or a static thread) is used. For example:
1. The FIX connector is started using the middleware logger LOGGER1. When loading of the quickfixj library, the static executor is initialized and the the logger attached to it is LOGGER1. All log messages written on this logger will be directed to the LOGGER1.
2. A second instance of the FIXConnector is started in the same JVM using LOGGER2. As the static executor was already initialized, the log written by quickfixj on the static executor will be also routed to LOGGER1 (and not to LOGGER2 as expected). This leads to potentials problems - what if the first instance of the FIXConnector is stopped and the LOGGER1 is closed by the middleware (etc.)

Also, I do not see the benefit of using a static scheduledExecutorService for all the initiators (which also uses a daemon worker thread). Wouldn't it be better to use a non-static executor that can be shutdown once the initiator is stopped?

Regards,
Mihai

Comment by Steve Bate [ 06/Feb/09 ]

Hello Mihai,

As we discussed before, the purpose of the static (singleton) executor is to minimize the number of threads used by QFJ for it's own purposes. The executor is shared among all initiators and acceptors.

I'm still not understanding why using a custom SLF4J implementation didn't work for you. If the custom logger implementation delegates to the /current/ middleware logger then it doesn't matter when the logger client actually retrieved the SLF4J logger instance. Actually, you could do this even without SLF4J by just implementing the QFJ Log interface. Your custom Log would delegate to the middleware logger. The middleware callback would modify the logger delegate in your Log implementation and everything that uses the Log implementation would automatically be using the new middleware logger. If the middleware logger is thread-local then that could also be supported with this approach.

I'm probably missing something, but this is my understanding at this point based on the information I have. Feel free to clarify any key issues I'm not seeing. I want to understand why this can't be done in the way I describe before changing the QFJ internals to support it.

Thanks,

Steve

Comment by Mihai Sardarescu [ 16/Feb/09 ]

Hi Steve,

The middleware provides a different logger object for each FIX connector. As I have one and only one QFJ session per connector, I have implemented a special QFJ logger that routes the log of one QFJ session to the middleware logger - this works fine and the log messages are routed to the correct logger.
However, I am missing the mina log and the low-level log of QFJ (the log that is written using slf4j). In fact, each FIX connector has its own initiator - the initiator is started upon the initialization of the connector and is stopped once the connector is destroyed. The problem is that once an initiator writes log messages from the static thread, there is no way to find out the which connector this initiator corresponds in order to route the log message to the correct logger.

To make it more clear: let's suppose I have two concurrent FIX connectors running in the same JVM having:

  • LOGGER1, LOGGER2 - the middleware loggers
  • INITIATOR1, INITIATOR2 - the initiators.
    INITIATOR1 logs something using the slf4j logger: log.debug("MESSAGE1") from the static thread THREAD1.
    INITIATOR2 logs something using the slf4j logger: log.debug("MESSAGE2") from the static thread THREAD1.
    There is no way to decide if the MESSAGE1 should be routed to LOGGER1 or LOGGER2 (the same applies for MESSAGE2). If the thread was non-static, then using inheritable thread locals could allow me to route the message to the right logger.

Thanks,
Mihai





[QFJ-394] SocketInitiator.stop(false) always waits sessions logoutTimeout before exit Created: 15/Jan/09  Updated: 03/Feb/10

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.3.3
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Alexey Utkin Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None


 Description   

SocketInitiator.stop(false) doesn't check sessions state. It always waits session logoutTimeout

It seems a bug in SessionConnection.waitForLogout()



 Comments   
Comment by Peter Franzen [ 03/Feb/10 ]

As far as I can tell, the problem lies in SessionConnection.waitForLogout().

If a session hasn't received its logout response when this method is entered
waitForLogout() keeps it in the local set of logged on sessions until the session's
logout timeout expires.

I noticed this problem when moving from 1.2.1 to 1.3.x, it seems to have been
introduced in version 1.3.

The solution would be to check if the session has been logged out each time
the sessions in the local logged on set are checked.

This could be achieved by changing the inner while loop in waitForLogout() to

while (sessionItr.hasNext()) {
Session session = sessionItr.next();
if (elapsed >= session.getLogoutTimeout() * 1000L) {
try

{ session.disconnect(); }

catch (IOException e)

{ log.error(e.getMessage(), e); }

}
if (!session.isLoggedOn())
sessionItr.remove();
}





[QFJ-373] Add a new validation configruation to bypass the data type check Created: 20/Nov/08  Updated: 26/Nov/08

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: None
Fix Version/s: None

Type: New Feature Priority: Default
Reporter: Alvin Wang Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Comments   
Comment by Steve Bate [ 26/Nov/08 ]

Can you be more specific about what you want in this feature? Thanks.

Comment by Alvin Wang [ 26/Nov/08 ]

For example, if there is a configuration called ValidateDateType=N in the configuration file, my QFJ server will not reject a message in which there is "867=100,0" rather than "867=100.0" because I do not care about tag 867.

thanks.





[QFJ-369] Send too many logout messages when continuely received messages which has BadTime or doBadCompID Created: 06/Nov/08  Updated: 06/Nov/08

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.3.3
Fix Version/s: None

Type: Bug Priority: Default
Reporter: Mike Gu Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Windows XP



 Description   

Send too many logout messages when continuely received messages which has BadTime or doBadCompID.
Session.java
private void doBadCompID(Message msg) throws IOException, FieldNotFound

{ generateReject(msg, SessionRejectReason.COMPID_PROBLEM, 0); generateLogout("Bad CompID"); }

private void doBadTime(Message msg) throws IOException, FieldNotFound

{ generateReject(msg, SessionRejectReason.SENDINGTIME_ACCURACY_PROBLEM, 0); generateLogout(); }

Before Send a logout message, should check the session statues. isLogoutSent()

private void doBadCompID(Message msg) throws IOException, FieldNotFound

{ generateReject(msg, SessionRejectReason.COMPID_PROBLEM, 0); if (!state.isLogoutSent()) generateLogout("Bad CompID"); }

private void doBadTime(Message msg) throws IOException, FieldNotFound

{ generateReject(msg, SessionRejectReason.SENDINGTIME_ACCURACY_PROBLEM, 0); if (!state.isLogoutSent()) generateLogout(); }




[QFJ-362] Enhance message and message_log table Created: 31/Oct/08  Updated: 05/Apr/10

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: None
Fix Version/s: Future Releases

Type: New Feature Priority: Default
Reporter: Alvin Wang Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

To faciliate user to monitor and manage FIX messages, I think we should add more columns into those 2 tables:

1. time (missing in messages_log)
2. message type
3. msgseqnum (missing in messages_log)
4. id (missing in messages)
5. isInbound (Y/N. Right now, sendercompid is the company and targetcompid is the counterparty. this is confusing from FIX message point of view and it is difficult to differentiate the direction)

Also I suggest to make column naming of these 2 tables be consistent to help developer to reuse code.



 Comments   
Comment by Steve Bate [ 05/Apr/10 ]

Just FYI, the messages table is for message resend and should not be used by anything other than the internal session functionality.





[QFJ-309] There is no need to store the messages in the message Queue when we use infinite range for resend request. Created: 06/May/08  Updated: 19/Dec/13

Status: Open
Project: QuickFIX/J
Component/s: None
Affects Version/s: 1.3.1
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: Mike Gu Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Windows xp, eclipse


Issue Links:
Relates
relates to QFJ-271 StackOverflowError trying to process ... Closed

 Description   

There is no need to store the messages in the message Queue when we use infinite range for resend request. Also there is no need to check the queue in the Session.next(Message) method when we use infinite range for resend request. That may cause the bug QFJ-271.






[QFJ-308] Fieldorder cannot be changed for NewOrderSingle, NewOrderMultiLeg, NewOrderCross Created: 28/Apr/08  Updated: 17/Jun/08

Status: Open
Project: QuickFIX/J
Component/s: Message Generation
Affects Version/s: 1.3.1
Fix Version/s: Future Releases

Type: Improvement Priority: Default
Reporter: Peter Reinhardt Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

The class NewOrderSingle does not allow to define a custom fieldorder, e.g. the constructor from the superclass Message(int[] fieldOrder) is not exposed.

I have a couple of extra fields my company uses, and currently I cannot change the order for these fields.



 Comments   
Comment by Steve Bate [ 03/May/08 ]

Have you considered creating a custom NewOrderSingle class with your company's field ordering and support for extra fields? You'd still need to add extra fields to the data dictionary for validation purposes. You can also generate all messages to have data dictionary-defined ordering. See the documentation on how to do that.

Comment by Peter Reinhardt [ 06/May/08 ]

Yes, that's possible.

I just have to make a copy of the NewOrderSingle class (and some of the other Order classes like NewOrderMultileg) class to support the additon of 2 custom fields. So I have to duplicate 99% of the code of the NewOrderSingle class to have custom ordering.

I think it would be much easier to expose the constructor.





[QFJ-278] method extractField(Group group, DataDictionary dataDictionary, FieldMap fields) don't check The length of "sohOffset" Created: 24/Dec/07  Updated: 01/Feb/08

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.2.1
Fix Version/s: Future Releases

Type: Bug Priority: Default
Reporter: CaiQi Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

In the class Message, method extractField(Group group, DataDictionary dataDictionary, FieldMap fields): The length of "sohOffset" is not checked. This will bring about full range of the message received as Message string out of range.

For all the field, if it is dataField, its length must be calculated by the former Field(Except for Tag 89/93). Because the data may contain a SOH.
For example, field 355 is dataField. Its length is in Field 354.
We must check the offset of the dataField is shorter than length of the message, and the offset's next char is SOH.

Add this code into Message.extractField():

//Judge if sohOffset's next char is '\001'.
if(messageData.indexOf('\001', sohOffset) != sohOffset)
throw new InvalidMessage("Wrong length of data field.");
//Judge if sohOffset is shorter than fields.
if(sohOffset > messageData.length())
throw new InvalidMessage("Wrong length of data field.");



 Comments   
Comment by CaiQi [ 24/Dec/07 ]

Initiator:send a message which is not comply with the protocol.
Acceptor:different problems occur.

For example, the dependances of fields. 354: the length of 355
354=10 355=123. The accptor will consider it that String out of range.
354=3 355=123. This is right.





[QFJ-277] if set "\001" in the StringField, it cause lots of problems Created: 24/Dec/07  Updated: 12/Jan/08

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.2.1
Fix Version/s: Future Releases

Type: Bug Priority: Default
Reporter: CaiQi Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

If "\001" is set in the string field by users, it can't be validated before sending. The field is considered as user expected. But it could be validated when received. There are three cases:

(1)Error incorrect format when Agent receives.
e.g. newOrderSingle.set(new Symbol("\001WAKEN"));
8=FIX.4.4_9=142_35=D_34=346_49=ICBC_50=operator001_52=20071128-03:03:37.140_56=XXX_212=346_11=123_38=1_40=2_44=1_54=1_55=WAKEN_60=20071128-11:03:37.125_10=XXX
Agent: [ERROR] quickfix.mina.acceptor.AcceptorIoHandler - Invalid message: bad tag format: For input string: "WAKEN_60"

e.g. newOrderSingle.set(new Symbol("WAK\001EN"));
8=FIX.4.4_9=142_35=D_34=329_49=ICBC_50=operator001_52=20071128-
03:00:50.875_56=XXX_212=329_11=123_38=1_40=2_44=1_54=1_55=WAK_EN_60=20071128-11:00:50.875_10=XXX_
Agent: [ERROR] quickfix.mina.acceptor.AcceptorIoHandler - Invalid message: bad tag format: For input string: "EN_60"

e.g. newOrderSingle.set(new Symbol("WAKEN\001"));
8=iMIX.1.0_9=142_35=D_34=365_49=ICBC_50=operator001_52=20071128-
03:06:13.671_56=XXX_212=365_11=123_38=1_40=2_44=1_54=1_55=WAKEN_60=20071128-11:06:13.671_10=XXX
Agent: [ERROR] quickfix.mina.acceptor.AcceptorIoHandler - Invalid message: bad tag format: For input string: "_60"

e.g. newOrderSingle.set(new Symbol("WAK\001=EN"));
8=iMIX.1.0_9=143_35=D_34=312_49=ICBC_50=operator001_52=20071128-
02:56:44.578_56=XXX_212=312_11=123_38=1_40=2_44=1_54=1_55=WAK_=EN_60=20071128-
10:56:44.562_10=XXX_
Agent:[ERROR] quickfix.mina.acceptor.AcceptorIoHandler - Invalid message: bad tag format: For input string: ""

(2)The message is rejected as expected.

e.g. newOrderSingle.set(new Symbol("WAK\001123=EN"));
8=iMIX.1.0_9=146_35=D_34=269_49=ICBC_50=operator001_52=20071128-
02:50:38.406_56=XXX_212=269_11=123_38=1_40=2_44=1_54=1_55=WAK_123=EN_60=20071128-
10:50:38.406_10=XXX_
Incorrect data format for value

e.g. newOrderSingle.set(new Symbol("\001123=EN"));
8=iMIX.1.0_9=143_35=D_34=248_49=ICBC_50=operator001_52=20071128-
02:49:02.406_56=XXX_212=248_11=123_38=1_40=2_44=1_54=1_55=_123=EN_60=20071128-
10:49:02.406_10=XXX_
Tag specified without a value

e.g. newOrderSingle.set(new Symbol("WAKEN\001123="));
8=iMIX.1.0_9=146_35=D_34=383_49=ICBC_50=operator001_52=20071128-
03:12:25.546_56=XXX_212=383_11=123_38=1_40=2_44=1_54=1_55=WAKEN_123=_60=20071128-
11:12:25.531_10=XXX_
Tag specified without a value

(3)The message is received successfully, but it is wrong. The result is critical. It will be used to attack the Server. This mustn't absolutely happen.
e.g. newOrderSingle.set(new Symbol("WAKEN\00110048=2"));
8=iMIX.1.0_9=149_35=D_34=449_49=ICBC_50=operator001_52=20071128-
03:21:47.031_56=XXX_212=449_11=123_38=1_40=2_44=1_54=1_55=WAKEN_10048=2_60=20071128-
11:21:47.015_10=XXX_

Solution 1
Encode the StringField at the Client, and decode at the Server. The encode and decode can be implemented in class StringField.
Fault:
In the FieldType "DATA", "\001" is permited. Its length is defined by the former field rather than by the position of "\001". So it is not affected by "\001". When encoded, its length will be changed. So the former field's value must be modified. To avoid this, a new class must be added instead of StringField. Make all
the "DATA" type extend StringField.

Solution 2
In the FIX protocol, the String field is not permit to be set as '\001'. So we can throw Exception directly or replace '\001' with ' ' in the StringField.
This can be implemented in class stringField. When construct a StringField except DATA fieldType, if find "\001", throw Exception directly or replace '\001' with ' '.
I think the solution 2 is better. The concisest method is to judge the DataField by tags. Now there are at least 3 pairs of DataField: 93/89, 95/96, 354/355.
Hard code is written:
if(field == 89||field == 96||field == 355)



 Comments   
Comment by Steve Bate [ 08/Jan/08 ]

If I understand your concern correctly, this is more of a FIX protocol issue than a QuickFIX/J issue.On the QFJ side, we can validate
that a value of a String field doesn't contain a "\001". However, this doesn't stop the possibility of "server attacks". From the perspective
of the receiving engine, a "\001" is a field delimeter and the message will be parsed accordingly. Even if we validate the StringFields, your
counterparty can send whatever FIX message string they want with whatever fields they want so you must validate those anyway in your application
code.

Comment by Steve Bate [ 11/Jan/08 ]

This is more involved than I thought it would be. The data fields are based on StringField so I need to think more about to provide validation for String versus data fields.





[QFJ-242] Check for presence of conditionally required fields (OpenFIX) Created: 19/Sep/07  Updated: 02/Feb/08

Status: Open
Project: QuickFIX/J
Component/s: Engine
Affects Version/s: 1.2.1
Fix Version/s: Future Releases

Type: New Feature Priority: Default
Reporter: Graham Miller Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

We are filing this because of a failing OpenFIX test, but we actually believe that the test itself is broken, so I won't describe the interaction here.

It would be nice if QuickFIX/J could check for the presence of conditionally required fields in messages when doing validation with a data dictionary. An example: In an execution report, we have the following description of ExpireDate and ExpireTime:

432 ExpireDate C Conditionally required if TimeInForce (59) = GTD and ExpireTime (126) is not specified.
126 ExpireTime C Conditionally required if TimeInForce (59) = GTD and ExpireDate (432) is not specified.

QuickFIX/J should reject a message if 59=6 but the message is missing both 432 and 126.

Other than that, this request is pretty open-ended. Clearly there would need to be some language for expressing these conditional requirements in the data dictionary, but we would have to think about what that would look like.






[QFJ-234] Add documetation to kinds of SSL certs supported for SSL connectivity Created: 31/Aug/07  Updated: 06/Oct/07

Status: Open
Project: QuickFIX/J
Component/s: Documentation
Affects Version/s: 1.2.1
Fix Version/s: Future Releases

Type: Task Priority: Default
Reporter: Toli Kuznets Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Need to add more documentation specifying the exact format of SSL certs that are necessary to be in the keystore for SSL connectivity to work.

Seems like the PKCS#12 is the format that needs to be in the keystore, but perhaps there are others.



 Comments   
Comment by Gregg Freeman [ 31/Aug/07 ]

I believe that the keystore is it's own "special" java format, and easily accepts DER encoded certificates/keys. However, PKCS#12, which is the only format that windows supports for private key encoded certificates, isn't readable by the standard java keytool utility.

The following worked for me to use a private key PKCS12 certificate:
Import the root certificate into a keystore using the java keytool utility (keytool -import -file xxxx -keystore xxxxx)
Import the intermediate certificate (if you have one) just as you did the root certificate (using the same keystore file).
For PKCS#12 certificates, the easiest thing to do is to download the jwsdwp 2.0 (as of Sept 07) and use the pkcs12import.bat utility to import the PKCS#12 certificate into the same keystore.

Make the keystore file available on the classpath.
Change the SSL settings in the session.properties to include the keystore, keystore password, and SSL setting = on.

For connections that can use a self-signed certificate, it's much easier.
Use the keytool to generate a key using the following command:
keytool -genkey -alias <anything> -keystore <keystorefilename>

Follow the prompts, change your session.properties, and make the keystore available on the classpath & you're all good.





[QFJ-216] Support recursive custom group definitions in the code generator Created: 27/Jul/07  Updated: 27/Apr/11

Status: Open
Project: QuickFIX/J
Component/s: Message Generation
Affects Version/s: 1.2.1
Fix Version/s: Future Releases

Type: New Feature Priority: Default
Reporter: Lev Grevnin Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

windows XP/java 1.5_06



 Description   

Suppose I have the following xml message definition

<message name="FirmPrice" msgtype="UN020" msgcat="app">
<field name="Symbol" required="Y"/>
<field name="Size" required="Y"/>
<group name="NoPriceEntries" required="Y">
<component name="PriceComponent" required="Y"/>
</group>
<group name="NoLegEntries" required="N">
<component name="LegComponent" required="N"/>
</group>
</message>

...

<component name="LegComponent">
<field name="Size" required="Y"/>
<field name="Symbol" required="Y"/>
<group name="NoPriceEntries" required="Y">
<component name="PriceComponent" required="Y"/>
</group>
</component>

The message generation creates a MessageFactory.java which has the following snippet of code in it:

if("UN020".equals(msgType)) {
switch(correspondingFieldID)

{ case liquidity.quickfix.fields.NoPriceEntries.FIELD: return new liquidity.quickfix.messages.FirmPrice.NoPriceEntries(); case liquidity.quickfix.fields.NoLegEntries.FIELD: return new liquidity.quickfix.messages.FirmPrice.NoLegEntries(); case liquidity.quickfix.fields.NoPriceEntries.FIELD: return new liquidity.quickfix.messages.FirmPrice.NoLegEntries.NoPriceEntries(); }

}

This cannot compile, obviously, as it has a duplicate case label. So, it seems like the usage of a field in both, the enclosing message and the nested component is not handled properly by the generated code.

Looks like this is due to "NoPriceEntries" appearing twice: once in the main body of the message, and once in the subcomponent "LegComponent".



 Comments   
Comment by Steve Bate [ 16/Aug/07 ]

Toli, any ideas on what we should do about this issue? The only idea I have is to have a second group generation method that accepts a list of message and group fields to identify the specific nested group to create.

Comment by Toli Kuznets [ 17/Aug/07 ]

Steve,

This bug is a case of a group appearing twice in a message, once inside a "top-level" and then once again in a nested subgroup.

If QFJ were to support this case, it'll probably make sense to make it available for any deep level of nesting, right?
That becomes a much more complicated problem, right? For every level of nesting you need to keep passing some additional arguments in to be able to reconstruct how all of this is related, correct?

What does the FIX spec say about that? Can you have same groups showing up multiple times in different nested subgroups? I couldn't see the spec specifically disallowing it, so my guess is that this is allowed and we need to support it?

A message specification is a hierarchical tree, with different fields appearing in different locations. Are the group fieldIDs treated as unique IDs that specify their location? (kind of like the <id> tag in HTML?)
Looks like we are trying to flatten out a hierarchical structure that has is indexed by field names/ids. We are only specifying a fieldID per field, and it seems that it follows a built-in assumption that having only 1 fieldID is enough to specify the position of the field inside the hierarchy of the message specification.
If you have a message with repeating field names at different level of nesting, then they'll cause a collision when flattened out - which is what we are seeing with this bug.

Sounds like we may need to pass all the information/context about the level of nesting into the factory message in order to able to create the groups at the right level of nesting...

A workaround would certainly be to create more specific field types or change the name of some sub-group. Maybe create a NoPriceEntriesPerLeg ? This would be a straight-forward short-term workaround.

Comment by Lev Grevnin [ 27/Nov/07 ]

Hi. Did anyone manage to have a look at this? Is it still an issue?

Comment by Lev Grevnin [ 20/Dec/07 ]

Yes, indeed, it appears the quickfix 1.3.0 still suffers from this problem. It would be really nice to correct it.

Comment by Steve Bate [ 26/Apr/11 ]

I don't know if the specification prohibits it, but apparently there are no standard FIX group definitions that contain a repeating group of the same type (recursive group definition). Therefore, I changed this from a bug to a feature request and dropped the priority. I'm curious about whether the message parser will handle the recursive groups.

Comment by Eric Deshayes [ 27/Apr/11 ]

As it is a new feature that would have some impact on the generated classes (and therefore not be backward compatible), it is descoped from the 1.5.1 release.





Generated at Thu Apr 25 09:36:08 UTC 2024 using JIRA 7.5.2#75007-sha1:9f5725bb824792b3230a5d8716f0c13e296a3cae.