Index: core/src/test/java/quickfix/SessionScheduleTest.java =================================================================== --- core/src/test/java/quickfix/SessionScheduleTest.java (revision 796) +++ core/src/test/java/quickfix/SessionScheduleTest.java (working copy) @@ -383,13 +383,16 @@ doIsSessionTimeTest(schedule, false, 2003, 5, 5, 16, 30, 0, tz); } + /** Need to use a US/Eastern timzone explicitly instead of EST/EDT because of + * daylight-savings time considerations. + */ public void testSettingsWithoutStartEndDayWithTimeZoneInTime() throws Exception { SessionSettings settings = new SessionSettings(); - settings.setString(Session.SETTING_START_TIME, "01:00:00 EST"); + settings.setString(Session.SETTING_START_TIME, "01:00:00 US/Eastern"); settings.setString(Session.SETTING_END_TIME, "15:00:00 US/Central"); SessionID sessionID = new SessionID("FIX.4.2", "SENDER", "TARGET"); SessionSchedule schedule = new SessionSchedule(settings, sessionID); - TimeZone tz = TimeZone.getTimeZone("EST"); + TimeZone tz = TimeZone.getTimeZone("US/Eastern"); doIsSessionTimeTest(schedule, false, 2002, 5, 5, 0, 59, 0, tz); doIsSessionTimeTest(schedule, true, 2002, 7, 5, 14, 30, 0, tz); Index: core/src/test/java/quickfix/BigDecimalFieldTest.java =================================================================== --- core/src/test/java/quickfix/BigDecimalFieldTest.java (revision 0) +++ core/src/test/java/quickfix/BigDecimalFieldTest.java (revision 0) @@ -0,0 +1,56 @@ +package quickfix; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import java.math.BigDecimal; +import java.lang.reflect.Constructor; + +import quickfix.field.Price; +import quickfix.fix42.NewOrderSingle; + +/** + * Conditionally test that BigDecimals are handled correctly if we've generated + * the message fields with BigDecimal support + * + * @author toli + * @version $Id$ + */ + +public class BigDecimalFieldTest extends TestCase { + public BigDecimalFieldTest(String inName) { + super(inName); + } + + public static Test suite() { + return new TestSuite(BigDecimalFieldTest.class); + } + + /** Verify that the round-tripping of BigDecimals works with messages + * Run the real test inside the testcase only if we have a BigDecimal-ized fields, + * ie if we have a constructor taking a BigDecimal. + */ + public void testBigDecimalRoundTripping() throws Exception { + // check to see if we have a BigDecimal constructor + try { + Constructor cons = Price.class.getConstructor(BigDecimal.class); + + BigDecimal originalPrice = new BigDecimal("10.3000"); + assertEquals(4, originalPrice.scale()); + Message message = new NewOrderSingle(); + message.setField(cons.newInstance (new BigDecimal("10.3000"))); + BigDecimal extractedPrice = message.getDecimal(Price.FIELD); + assertEquals(4, extractedPrice.scale()); + assertEquals(new BigDecimal("10.3000"), extractedPrice); + String newOrderString = message.toString(); + Message rehydratedMessage = new Message(newOrderString); + BigDecimal rehydratedPrice = rehydratedMessage.getDecimal(Price.FIELD); + assertEquals(new BigDecimal("10.3000"), rehydratedPrice); + assertEquals(4, rehydratedPrice.scale()); + } catch(NoSuchMethodException ex) { + // we are using doubles only. this isn't the testcase we are looking for + // skip the test + } + } +} Property changes on: core/src/test/java/quickfix/BigDecimalFieldTest.java ___________________________________________________________________ Name: svn:keywords + Id version Index: core/src/test/java/quickfix/MessageTest.java =================================================================== --- core/src/test/java/quickfix/MessageTest.java (revision 796) +++ core/src/test/java/quickfix/MessageTest.java (working copy) @@ -988,7 +988,7 @@ assertEquals("AllocACC2", field.getValue()); assertTrue(i.hasNext()); field = (StringField) i.next(); - assertEquals("2020.2", field.getValue()); + assertEquals("2020.20", field.getValue()); assertTrue(!i.hasNext()); try { @@ -1012,9 +1012,9 @@ private void assertAllocation(String accountId, Object shares) { if (accountId.equals("AllocACC1")) { - assertTrue(equals(1010.10, shares)); + assertEquals("got shares: " + shares, 0, new BigDecimal("1010.10").compareTo(new BigDecimal(shares.toString()))); } else if (accountId.equals("AllocACC2")) { - assertTrue(equals(2020.20, shares)); + assertEquals("got shares: " + shares, 0, new BigDecimal("2020.20").compareTo(new BigDecimal(shares.toString()))); } else { fail("Unknown account"); } @@ -1033,10 +1033,10 @@ private NewOrderSingle.NoAllocs setUpGroups(Message message) { NewOrderSingle.NoAllocs numAllocs = new NewOrderSingle.NoAllocs(); numAllocs.set(new AllocAccount("AllocACC1")); - numAllocs.set(new AllocShares(1010.10)); + numAllocs.setField(new StringField(AllocShares.FIELD, "1010.10")); message.addGroup(numAllocs); - numAllocs.set(new AllocAccount("AllocACC2")); - numAllocs.set(new AllocShares(2020.20)); + numAllocs.setField(new AllocAccount("AllocACC2")); + numAllocs.setField(new StringField(AllocShares.FIELD, "2020.20")); message.addGroup(numAllocs); return numAllocs; } Index: core/src/main/java/quickfix/field/converter/DecimalConverter.java =================================================================== --- core/src/main/java/quickfix/field/converter/DecimalConverter.java (revision 796) +++ core/src/main/java/quickfix/field/converter/DecimalConverter.java (working copy) @@ -26,12 +26,12 @@ public class DecimalConverter { /** * Converts a double to a string with no padding. - * @param d the double to convert - * @return the formatted String representing the double. + * @param d the BigDecimal to convert + * @return the formatted String representing the incoming decimal. * @see #convert(BigDecimal, int) */ public static String convert(BigDecimal d) { - return convert(d, 0); + return d.toPlainString(); } /** Index: core/src/main/java/quickfix/FieldMap.java =================================================================== --- core/src/main/java/quickfix/FieldMap.java (revision 796) +++ core/src/main/java/quickfix/FieldMap.java (working copy) @@ -168,7 +168,7 @@ } public void setDecimal(int field, BigDecimal value) { - setDecimal(field, value, 0); + setField(new StringField(field, DecimalConverter.convert(value))); } public void setDecimal(int field, BigDecimal value, int padding) { Index: core/src/main/doc/usermanual/usage/secure_communications.html =================================================================== --- core/src/main/doc/usermanual/usage/secure_communications.html (revision 796) +++ core/src/main/doc/usermanual/usage/secure_communications.html (working copy) @@ -13,7 +13,7 @@

This technique relies on the MINA SSL I/O filter. To use SSL, you must include -the mina-filter-ssl-1.0.1-sources.jar library +the mina-filter-ssl-1.1.0-sources.jar library in your application's classpath.

Index: core/src/main/doc/usermanual/installation.html =================================================================== --- core/src/main/doc/usermanual/installation.html (revision 796) +++ core/src/main/doc/usermanual/installation.html (working copy) @@ -162,6 +162,29 @@ To enable this feature pass a -Dgenerator.decimal option on the command line when running the generate.code Ant target. +

Command-line Switches

+There are various command-line switches you can pass to ant to modify the produced behavior: + + + + + + + + + + + + + + + + +
SwitchDescriptionDefault
-Dgenerator.decimalGenerate BigDecimal vs doubles fieldsfalse
-Dskip.jalopySkip Java class reformatting during code generation false
+

+ For example, in order to generate fields with BigDecimals and skip Jalopy message reformatting:
+ant -Dgenerator.decimal=true -Dskip.jalopy=true clean test +

Eclipse IDE support:

The QuickFIX/J developers also use Eclipse to build the software. There is a project definition in the top-level directory of the checked out CVS workspace. @@ -181,32 +204,32 @@ <dependency> <groupId>quickfixj</groupId> <artifactId>quickfixj-core</artifactId> - <version>1.2.1</version> + <version>1.3.1</version> </dependency> <dependency> <groupId>quickfixj</groupId> <artifactId>quickfixj-msg-fix40</artifactId> - <version>1.2.1</version> + <version>1.3.1</version> </dependency> <dependency> <groupId>quickfixj</groupId> <artifactId>quickfixj-msg-fix41</artifactId> - <version>1.2.1</version> + <version>1.3.1</version> </dependency> <dependency> <groupId>quickfixj</groupId> <artifactId>quickfixj-msg-fix42</artifactId> - <version>1.2.1</version> + <version>1.3.1</version> </dependency> <dependency> <groupId>quickfixj</groupId> <artifactId>quickfixj-msg-fix43</artifactId> - <version>1.2.1</version> + <version>1.3.1</version> </dependency> <dependency> <groupId>quickfixj</groupId> <artifactId>quickfixj-msg-fix44</artifactId> - <version>1.2.1</version> + <version>1.3.1</version> </dependency> <dependency> <groupId>org.apache.mina</groupId> Index: examples/src/main/java/quickfix/examples/banzai/BanzaiApplication.java =================================================================== --- examples/src/main/java/quickfix/examples/banzai/BanzaiApplication.java (revision 796) +++ examples/src/main/java/quickfix/examples/banzai/BanzaiApplication.java (working copy) @@ -23,6 +23,8 @@ import java.util.HashSet; import java.util.Observable; import java.util.Observer; +import java.math.BigDecimal; +import java.math.MathContext; import javax.swing.SwingUtilities; @@ -203,23 +205,23 @@ return; } - double fillSize = 0; + BigDecimal fillSize = BigDecimal.ZERO; try { LastShares lastShares = new LastShares(); message.getField(lastShares); - fillSize = lastShares.getValue(); + fillSize = new BigDecimal(""+lastShares.getValue()); } catch (FieldNotFound e) { // FIX 4.0 LeavesQty leavesQty = new LeavesQty(); message.getField(leavesQty); - fillSize = order.getQuantity() - leavesQty.getValue(); + fillSize = new BigDecimal(order.getQuantity()).subtract(new BigDecimal(""+leavesQty.getValue())); } - if (fillSize > 0) { - order.setOpen((int)(order.getOpen() - fillSize)); - order.setExecuted((int) message.getField(new CumQty()).getValue()); - order.setAvgPx(message.getField(new AvgPx()).getValue()); + if (fillSize.compareTo(BigDecimal.ZERO) > 0) { + order.setOpen(order.getOpen() - (int) Double.parseDouble(fillSize.toPlainString())); + order.setExecuted(new Integer(message.getString(CumQty.FIELD))); + order.setAvgPx(new Double(message.getString(AvgPx.FIELD))); } OrdStatus ordStatus = (OrdStatus) message.getField(new OrdStatus()); @@ -245,12 +247,12 @@ orderTableModel.updateOrder(order, message.getField(new ClOrdID()).getValue()); observableOrder.update(order); - if (fillSize > 0) { + if (fillSize.compareTo(BigDecimal.ZERO) > 0) { Execution execution = new Execution(); execution.setExchangeID(sessionID + message.getField(new ExecID()).getValue()); execution.setSymbol(message.getField(new Symbol()).getValue()); - execution.setQuantity((int) fillSize); - execution.setPrice(message.getField(new LastPx()).getValue()); + execution.setQuantity((int) Double.parseDouble(fillSize.toPlainString())); + execution.setPrice(new Double(message.getString(LastPx.FIELD))); Side side = (Side) message.getField(new Side()); execution.setSide(FIXSideToSide(side)); executionTableModel.addExecution(execution); Index: examples/src/main/java/quickfix/examples/executor/Application.java =================================================================== --- examples/src/main/java/quickfix/examples/executor/Application.java (revision 796) +++ examples/src/main/java/quickfix/examples/executor/Application.java (working copy) @@ -22,6 +22,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.math.BigDecimal; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -70,11 +71,7 @@ initializeValidOrderTypes(settings); initializeMarketDataProvider(settings); - if (settings.isSetting(ALWAYS_FILL_LIMIT_KEY)) { - alwaysFillLimitOrders = settings.getBool(ALWAYS_FILL_LIMIT_KEY); - } else { - alwaysFillLimitOrders = false; - } + alwaysFillLimitOrders = settings.isSetting(ALWAYS_FILL_LIMIT_KEY) && settings.getBool(ALWAYS_FILL_LIMIT_KEY); } private void initializeMarketDataProvider(SessionSettings settings) throws ConfigError, FieldConvertError { @@ -160,10 +157,12 @@ private boolean isOrderExecutable(Message order, Price price) throws FieldNotFound { if (order.getChar(OrdType.FIELD) == OrdType.LIMIT) { - double limitPrice = order.getDouble(Price.FIELD); + BigDecimal limitPrice = new BigDecimal(order.getString(Price.FIELD)); char side = order.getChar(Side.FIELD); - return (side == Side.BUY && price.getValue() <= limitPrice) - || ((side == Side.SELL || side == Side.SELL_SHORT) && price.getValue() >= limitPrice); + BigDecimal thePrice = new BigDecimal(""+ price.getValue()); + + return (side == Side.BUY && thePrice.compareTo(limitPrice) <= 0) + || ((side == Side.SELL || side == Side.SELL_SHORT) && thePrice.compareTo(limitPrice) >= 0); } return true; }