├── .gitignore ├── AGENTS.md ├── LICENSE ├── README.adoc ├── account.ad ├── account ├── README.adoc ├── img │ └── Chronicle-Services-Diagram.png ├── pom.xml ├── prompts │ ├── improve-code.adoc │ ├── improve-test-data.adoc │ └── requirements.adoc └── src │ ├── main │ └── java │ │ └── run │ │ └── chronicle │ │ └── account │ │ ├── AccountManagerBenchmarkMain.java │ │ ├── AccountManagerClientMain.java │ │ ├── AccountManagerGatewayMain.java │ │ ├── AccountManagerServiceMain.java │ │ ├── api │ │ ├── AccountManagerIn.java │ │ ├── AccountManagerOut.java │ │ ├── CreateAccountOut.java │ │ └── TransferOut.java │ │ ├── benchmark-results.txt │ │ ├── domain │ │ └── AccountService.java │ │ ├── dto │ │ ├── AbstractEvent.java │ │ ├── CheckPoint.java │ │ ├── CreateAccount.java │ │ ├── CreateAccountFailed.java │ │ ├── OnCreateAccount.java │ │ ├── OnTransfer.java │ │ ├── Transfer.java │ │ └── TransferFailed.java │ │ ├── impl │ │ └── AccountManagerImpl.java │ │ └── util │ │ ├── ErrorListener.java │ │ └── LogsAccountManagerOut.java │ └── test │ ├── java │ └── run │ │ └── chronicle │ │ └── account │ │ ├── AccountsTest.java │ │ ├── domain │ │ └── AccountServiceTest.java │ │ ├── dto │ │ ├── CreateAccountFailedTest.java │ │ ├── CreateAccountTest.java │ │ ├── OnCreateAccountTest.java │ │ ├── OnTransferTest.java │ │ ├── TransferFailedTest.java │ │ └── TransferTest.java │ │ ├── impl │ │ └── AccountManagerImplTest.java │ │ └── util │ │ └── LogsAccountManagerOutTest.java │ └── resources │ └── account │ ├── bard-gen │ ├── _setup.yaml │ ├── in.yaml │ ├── out-missing-field-amount.yaml │ ├── out-missing-field-balance.yaml │ ├── out-missing-field-reference.yaml │ ├── out-set-field-amount=-1.yaml │ ├── out-set-field-amount=NaN.yaml │ ├── out-set-field-balance=-1.yaml │ ├── out-set-field-balance=NaN.yaml │ └── out.yaml │ ├── bard-jinja │ ├── in.yaml │ ├── out-missing-field-balance.yaml │ ├── out-missing-field-name.yaml │ ├── out-missing-field-reference.yaml │ ├── out-missing-field-sender.yaml │ ├── out-missing-field-sendingTime.yaml │ ├── out-missing-field-target.yaml │ ├── out-set-field-balance=-1.yaml │ ├── out-set-field-balance=NaN.yaml │ ├── out-set-field-target=no-vault.yaml │ └── out.yaml │ ├── copilot │ ├── _setup.yaml │ ├── in.yaml │ ├── out-missing-field-balance.yaml │ ├── out-missing-field-name.yaml │ ├── out-missing-field-reference.yaml │ ├── out-missing-field-sendingTime.yaml │ ├── out-msg-0-duplicated.yaml │ ├── out-set-field-balance=-1.yaml │ ├── out-set-field-balance=NaN.yaml │ └── out.yaml │ ├── gpt-gen │ ├── _setup.yaml │ ├── in.yaml │ ├── out-missing-field-balance.yaml │ ├── out-missing-field-name.yaml │ ├── out-missing-field-reference.yaml │ ├── out-missing-field-sendingTime.yaml │ ├── out-set-field-balance=-1.yaml │ ├── out-set-field-balance=NaN.yaml │ └── out.yaml │ ├── gpt-jinja │ ├── in.yaml │ ├── out-account_simple.yaml │ ├── out-missing-field-account.yaml │ ├── out-missing-field-balance.yaml │ ├── out-missing-field-from.yaml │ ├── out-missing-field-name.yaml │ ├── out-missing-field-reference.yaml │ ├── out-missing-field-sendingTime.yaml │ ├── out-missing-field-to.yaml │ └── out.yaml │ ├── mixed │ ├── _setup.yaml │ ├── in.yaml │ ├── out-missing-field-reference.yaml │ └── out.yaml │ ├── o1-pro │ ├── README.adoc │ ├── _setup.yaml │ ├── in.yaml │ ├── out-missing-field-from.yaml │ ├── out-missing-field-name.yaml │ ├── out-missing-field-reference.yaml │ ├── out-missing-field-sendingTime.yaml │ ├── out-set-field-balance=-1.yaml │ ├── out-set-field-balance=NaN.yaml │ └── out.yaml │ ├── simple-gen │ ├── _setup.yaml │ ├── in.yaml │ ├── out-missing-field-amount.yaml │ ├── out-missing-field-currency.yaml │ ├── out-missing-field-reference.yaml │ ├── out-missing-field-sendingTime.yaml │ ├── out-missing-field-to.yaml │ ├── out-missing-msg-0.yaml │ ├── out-missing-msg-1.yaml │ ├── out-set-field-amount=-1.yaml │ ├── out-set-field-amount=NaN.yaml │ ├── out-set-field-currency=.yaml │ └── out.yaml │ ├── simple │ ├── _setup.yaml │ ├── in.yaml │ ├── out-account_bard-gen.yaml │ ├── out-account_simple-gen.yaml │ ├── out-missing-field-account.yaml │ ├── out-missing-field-amount.yaml │ ├── out-missing-field-balance.yaml │ ├── out-missing-field-currency.yaml │ ├── out-missing-field-from.yaml │ ├── out-missing-field-name.yaml │ ├── out-missing-field-reference.yaml │ ├── out-missing-field-sender.yaml │ ├── out-missing-field-sendingTime.yaml │ ├── out-missing-field-target.yaml │ ├── out-missing-field-to.yaml │ ├── out-missing-msg-0.yaml │ ├── out-msg-0-duplicated.yaml │ ├── out-set-field-amount=-1.yaml │ ├── out-set-field-amount=NaN.yaml │ ├── out-set-field-balance=-1.yaml │ ├── out-set-field-balance=NaN.yaml │ ├── out-set-field-currency=.yaml │ ├── out-set-field-target=no-vault.yaml │ └── out.yaml │ └── waterfall │ ├── _setup.yaml │ ├── in.yaml │ ├── out-missing-field-reference.yaml │ ├── out-missing-field-sendingTime.yaml │ ├── out-set-field-amount=-1.yaml │ ├── out-set-field-amount=NaN.yaml │ └── out.yaml ├── architecture.adoc ├── benchmarks ├── README.adoc ├── pom.xml ├── src │ └── main │ │ └── java │ │ ├── chronicle │ │ └── queue │ │ │ └── benchmark │ │ │ ├── LatencyDistributionMain.java │ │ │ ├── Main.java │ │ │ └── ThroughputMain.java │ │ └── run │ │ └── chronicle │ │ └── staged │ │ ├── IFacadeAll.java │ │ ├── IFacadeBase.java │ │ ├── IFacadeSon.java │ │ └── StagedPerformanceMain.java └── system.properties ├── docs └── images │ ├── hello-world-fig1.png │ ├── hello-world-fig2.png │ ├── hello-world-fig3.png │ └── source │ └── hello-world-fig1.svg ├── event-routing ├── pom.xml └── src │ ├── main │ ├── adoc │ │ └── event-routing-requirements.adoc │ └── java │ │ └── run │ │ └── chronicle │ │ └── routing │ │ ├── inout │ │ ├── ViaThreeFive.java │ │ ├── api │ │ │ ├── Value.java │ │ │ ├── ValueMessage.java │ │ │ ├── ViaIn.java │ │ │ ├── ViaOut.java │ │ │ └── package-info.java │ │ └── package-info.java │ │ └── out │ │ ├── SifterImpl.java │ │ ├── api │ │ ├── AllOut.java │ │ ├── Even.java │ │ ├── EvenIn.java │ │ ├── SifterIn.java │ │ ├── SifterOut.java │ │ ├── Triple.java │ │ ├── TripleIn.java │ │ └── package-info.java │ │ └── package-info.java │ └── test │ ├── java │ └── run │ │ └── chronicle │ │ └── routing │ │ ├── inout │ │ ├── ViaThreeFiveTest.java │ │ └── api │ │ │ └── ViaOutTextMethodWriter.java │ │ └── out │ │ └── SifterImplTest.java │ └── resources │ ├── sifter │ ├── in.yaml │ └── out.yaml │ ├── three-five-values │ ├── in.yaml │ └── out.yaml │ └── three-five │ ├── in.yaml │ └── out.yaml ├── hello-world ├── README.adoc ├── pom.xml └── src │ ├── main │ ├── adoc │ │ └── hello-world-requirements.adoc │ ├── hello-world-requirements.adoc │ ├── java │ │ └── event │ │ │ └── driven │ │ │ └── program │ │ │ ├── AddsExclamation.java │ │ │ ├── DirectWithExclamationMain.java │ │ │ ├── RecordInputAsYamlMain.java │ │ │ ├── RecordInputToConsoleMain.java │ │ │ ├── ReplayOutputMain.java │ │ │ ├── SaysInput.java │ │ │ ├── SaysOutput.java │ │ │ ├── api │ │ │ └── Says.java │ │ │ └── package-info.java │ └── resources │ │ └── says.yaml │ └── test │ ├── java │ └── event │ │ └── driven │ │ └── program │ │ └── AddsExclamationTest.java │ └── resources │ └── says │ ├── in.yaml │ └── out.yaml ├── images ├── AddJDK.png ├── Clone.png ├── JDKhome.png ├── OutputMain.png ├── Two-hop-latency.png ├── directory.png ├── gitpack.png ├── homegit.png ├── lotsafiles.png ├── queue.png ├── runin.png ├── runout.png ├── sayhello.png └── setJDK.png ├── md-pipeline ├── README.adoc ├── pom.xml └── src │ ├── main │ └── java │ │ └── org │ │ └── trading │ │ ├── AggregatorImpl.java │ │ ├── ExchangeSimulatorImpl.java │ │ ├── OMSImpl.java │ │ ├── Runner.java │ │ ├── StrategyImpl.java │ │ ├── api │ │ ├── AggregatorIn.java │ │ ├── AggregatorOut.java │ │ ├── All.java │ │ ├── OMSIn.java │ │ ├── OMSOut.java │ │ └── package-info.java │ │ ├── dto │ │ ├── BuySell.java │ │ ├── MarketDataIncrement.java │ │ ├── MarketDataSnapshot.java │ │ ├── NewOrderSingle.java │ │ └── package-info.java │ │ └── package-info.java │ └── test │ ├── java │ └── org │ │ └── trading │ │ ├── AggregatorTest.java │ │ └── StrategyTest.java │ └── resources │ ├── aggregator │ ├── in.yaml │ └── out.yaml │ └── strategy │ ├── in.yaml │ └── out.yaml ├── message-history-demo ├── README.adoc ├── pom.xml └── src │ └── main │ └── java │ └── town │ └── lost │ └── processor │ └── events │ ├── AbstractEvent.java │ ├── BridgeMain.java │ ├── DumpDecodedMain.java │ ├── DumpOutMain.java │ ├── EventOne.java │ ├── EventTwo.java │ ├── EventWithHistory.java │ ├── Events.java │ └── PublisherMain.java ├── messages-with-text ├── README.adoc ├── pom.xml └── src │ └── main │ └── java │ └── run │ └── chronicle │ └── queue │ ├── Message.java │ ├── MessageMain.java │ └── Messages.java ├── order-processor.ad ├── order-processor ├── README.adoc ├── pom.xml └── src │ ├── main │ ├── adoc │ │ ├── oms-api-requirements.adoc │ │ ├── oms-requirements.adoc │ │ ├── selected-fix-4.2.adoc │ │ └── test-requirements.adoc │ └── java │ │ └── town │ │ └── lost │ │ └── oms │ │ ├── OMSBenchmarkMain.java │ │ ├── OMSImpl.java │ │ ├── OrderAdderMain.java │ │ ├── OrderViewerMain.java │ │ ├── api │ │ ├── ErrorListener.java │ │ ├── OMSIn.java │ │ ├── OMSOut.java │ │ └── package-info.java │ │ └── dto │ │ ├── AbstractEvent.java │ │ ├── CancelAll.java │ │ ├── CancelOrderRequest.java │ │ ├── Ccy.java │ │ ├── ExecutionReport.java │ │ ├── NewOrderSingle.java │ │ ├── OrderCancelReject.java │ │ ├── OrderType.java │ │ ├── Side.java │ │ ├── TimeInForce.java │ │ ├── ValidateUtil.java │ │ └── package-info.java │ └── test │ ├── java │ └── town │ │ └── lost │ │ └── oms │ │ ├── OMSImplEdgeCaseTest.java │ │ └── OMSImplTest.java │ └── resources │ ├── cancelAll │ ├── in.yaml │ ├── out-missing-field-clOrdID.yaml │ ├── out-set-field-clOrdID=__.yaml │ ├── out-set-field-sendingTime=__.yaml │ └── out.yaml │ ├── cancelOrderRequest │ ├── in.yaml │ ├── out-missing-field-sender.yaml │ ├── out-missing-field-side.yaml │ ├── out-missing-field-target.yaml │ ├── out-set-field-sendingTime=__.yaml │ └── out.yaml │ ├── newOrderSingle │ ├── in.yaml │ ├── out-missing-field-account.yaml │ ├── out-missing-field-clOrdID.yaml │ ├── out-missing-field-currency.yaml │ ├── out-missing-field-ordType.yaml │ ├── out-missing-field-orderQty.yaml │ ├── out-missing-field-price.yaml │ ├── out-missing-field-sender.yaml │ ├── out-missing-field-sendingTime.yaml │ ├── out-missing-field-side.yaml │ ├── out-missing-field-symbol.yaml │ ├── out-missing-field-target.yaml │ ├── out-missing-field-timeInForce.yaml │ ├── out-missing-field-transactTime.yaml │ ├── out-set-field-clOrdID=__.yaml │ ├── out-set-field-ordType=__.yaml │ ├── out-set-field-orderQty=-1.yaml │ ├── out-set-field-orderQty=NaN.yaml │ ├── out-set-field-price=-1.yaml │ ├── out-set-field-price=NaN.yaml │ ├── out-set-field-sendingTime=__.yaml │ ├── out-set-field-side=__.yaml │ ├── out-set-field-symbol=__.yaml │ └── out.yaml │ └── newOrderSingleEquity │ ├── in.yaml │ ├── out-missing-field-account.yaml │ ├── out-missing-field-clOrdID.yaml │ ├── out-missing-field-ordType.yaml │ ├── out-missing-field-orderQty.yaml │ ├── out-missing-field-price.yaml │ ├── out-missing-field-sender.yaml │ ├── out-missing-field-sendingTime.yaml │ ├── out-missing-field-side.yaml │ ├── out-missing-field-symbol.yaml │ ├── out-missing-field-target.yaml │ ├── out-missing-field-timeInForce.yaml │ ├── out-missing-field-transactTime.yaml │ ├── out-missing-msg-0.yaml │ ├── out-msg-0-duplicated.yaml │ ├── out-newOrderSingleEquity.yaml │ ├── out-set-field-clOrdID=__.yaml │ ├── out-set-field-ordType=__.yaml │ ├── out-set-field-orderQty=-1.yaml │ ├── out-set-field-orderQty=NaN.yaml │ ├── out-set-field-price=-1.yaml │ ├── out-set-field-price=NaN.yaml │ ├── out-set-field-sendingTime=__.yaml │ ├── out-set-field-side=__.yaml │ ├── out-set-field-symbol=__.yaml │ └── out.yaml ├── pom.xml ├── reference.adoc ├── simple-avro-example ├── pom.xml └── src │ └── main │ ├── java │ └── net │ │ └── openhft │ │ └── chronicle │ │ └── queue │ │ └── simple │ │ └── avro │ │ ├── AvroHelper.java │ │ ├── InputMain.java │ │ └── OutputMain.java │ └── resources │ └── user.avsc ├── simple-input ├── README.adoc ├── pom.xml └── src │ └── main │ └── java │ └── net │ └── openhft │ └── chronicle │ └── queue │ └── simple │ └── input │ ├── InputMain.java │ ├── OutputMain.java │ ├── PrintQueueMain.java │ └── package-info.java ├── simple-translator ├── pom.xml └── src │ ├── main │ └── java │ │ └── net │ │ └── openhft │ │ └── chronicle │ │ └── queue │ │ └── simple │ │ └── translator │ │ ├── InputMain.java │ │ ├── MessageConsumer.java │ │ ├── OutputMain.java │ │ ├── PrintQueueMain.java │ │ ├── SimpleTranslator.java │ │ ├── TranslatorMain.java │ │ └── package-info.java │ └── test │ └── java │ └── net │ └── openhft │ └── chronicle │ └── queue │ └── simple │ └── translator │ ├── SimpleTranslator2Test.java │ └── SimpleTranslatorTest.java └── usage-and-tests.adoc /.gitignore: -------------------------------------------------------------------------------- 1 | # Temporarily exclude these files from aide to make the token size manageable 2 | #account/ 3 | #order-processor/ 4 | 5 | ### How to update 6 | # This is copied from OpenHFT/.gitignore 7 | # update the original and run OpenHFT/update_gitignore.sh 8 | 9 | ### Compiled class file 10 | *.class 11 | 12 | ### Package Files 13 | *.jar 14 | *.war 15 | *.ear 16 | 17 | ### Log file 18 | *.log 19 | 20 | ### IntelliJ 21 | *.iml 22 | *.ipr 23 | *.iws 24 | .idea 25 | .attach_pid* 26 | 27 | ### Virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 28 | hs_err_pid* 29 | 30 | ### Maven template 31 | target/ 32 | pom.xml.tag 33 | pom.xml.releaseBackup 34 | pom.xml.versionsBackup 35 | pom.xml.next 36 | release.properties 37 | 38 | ### Eclipse template 39 | *.pydevproject 40 | .metadata 41 | .gradle 42 | bin/ 43 | tmp/ 44 | *.tmp 45 | *.bak 46 | *.swp 47 | *~.nib 48 | local.properties 49 | .classpath 50 | .project 51 | .settings/ 52 | .loadpath 53 | 54 | ### Queue files 55 | *.cq4t 56 | *.cq4 -------------------------------------------------------------------------------- /account/img/Chronicle-Services-Diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/account/img/Chronicle-Services-Diagram.png -------------------------------------------------------------------------------- /account/src/main/java/run/chronicle/account/AccountManagerGatewayMain.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.account; 2 | 3 | import net.openhft.chronicle.core.io.InvalidMarshallableException; 4 | import net.openhft.chronicle.wire.channel.ChronicleGatewayMain; 5 | 6 | import java.io.IOException; 7 | 8 | /** 9 | * This class acts as the main entry point for the AccountManagerGateway, 10 | * which extends the ChronicleGatewayMain class. 11 | */ 12 | public class AccountManagerGatewayMain extends ChronicleGatewayMain { 13 | 14 | /** 15 | * Constructor for AccountManagerGatewayMain. 16 | * 17 | * @param url The URL for the ChronicleGateway. 18 | * @throws InvalidMarshallableException Thrown if the gateway URL is invalid. 19 | */ 20 | public AccountManagerGatewayMain(String url) throws InvalidMarshallableException { 21 | super(url); 22 | } 23 | 24 | /** 25 | * Main method to start the gateway. 26 | * 27 | * @param args The command line arguments. Optionally, the first argument can be the gateway URL. 28 | * @throws IOException If an IO error occurs during gateway initialization. 29 | * @throws InvalidMarshallableException Thrown if the gateway URL is invalid. 30 | */ 31 | public static void main(String... args) throws IOException, InvalidMarshallableException { 32 | // The main() method in ChronicleGatewayMain expects a factory method for creating the gateway 33 | // and a URL as arguments. If no command-line arguments are given, an empty string is used as the URL. 34 | main(AccountManagerGatewayMain.class, AccountManagerGatewayMain::new, args.length == 0 ? "" : args[0]) 35 | .run(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /account/src/main/java/run/chronicle/account/api/AccountManagerOut.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2022 chronicle.software 3 | * 4 | * https://chronicle.software 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package run.chronicle.account.api; 20 | 21 | import run.chronicle.account.dto.CheckPoint; 22 | 23 | /** 24 | * This interface extends both the CreateAccountOut and TransferOut interfaces. 25 | * It provides methods to manage account operations including account creation, 26 | * transfers, and checkpoint handling. 27 | */ 28 | public interface AccountManagerOut extends CreateAccountOut, TransferOut { 29 | 30 | /** 31 | * This method initiates a checkpoint operation. 32 | * 33 | * @param checkPoint a CheckPoint object encapsulating the details of the 34 | * checkpoint that started the following state dump. 35 | */ 36 | void startCheckpoint(CheckPoint checkPoint); 37 | 38 | /** 39 | * This method concludes a checkpoint operation. 40 | * 41 | * @param checkPoint a CheckPoint object encapsulating the details of the 42 | * checkpoint that started the previous state dump. 43 | */ 44 | void endCheckpoint(CheckPoint checkPoint); 45 | } 46 | -------------------------------------------------------------------------------- /account/src/main/java/run/chronicle/account/api/CreateAccountOut.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2022 chronicle.software 3 | * 4 | * https://chronicle.software 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package run.chronicle.account.api; 20 | 21 | import run.chronicle.account.dto.CreateAccountFailed; 22 | import run.chronicle.account.dto.OnCreateAccount; 23 | import run.chronicle.account.util.ErrorListener; 24 | 25 | /** 26 | * This interface extends the ErrorListener interface. It is used to define methods related to 27 | * account creation. This includes notifying about the creation of an account and handling failures 28 | * during account creation. 29 | */ 30 | public interface CreateAccountOut extends ErrorListener { 31 | 32 | /** 33 | * Method to notify about the creation of an account. 34 | * 35 | * @param onCreateAccount an object of type OnCreateAccount which encapsulates the details of 36 | * the created account. 37 | */ 38 | void onCreateAccount(OnCreateAccount onCreateAccount); 39 | 40 | /** 41 | * Method to handle failures during account creation. 42 | * 43 | * @param createAccountFailed an object of type CreateAccountFailed which encapsulates the 44 | * details of the account creation failure. 45 | */ 46 | void createAccountFailed(CreateAccountFailed createAccountFailed); 47 | } 48 | -------------------------------------------------------------------------------- /account/src/main/java/run/chronicle/account/api/TransferOut.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2022 chronicle.software 3 | * 4 | * https://chronicle.software 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package run.chronicle.account.api; 20 | 21 | import net.openhft.chronicle.bytes.MethodId; 22 | import run.chronicle.account.dto.OnTransfer; 23 | import run.chronicle.account.dto.TransferFailed; 24 | import run.chronicle.account.util.ErrorListener; 25 | 26 | /** 27 | * This interface extends the ErrorListener interface. It is used to define methods related to 28 | * money transfers between accounts. This includes notifying about a successful transfer and 29 | * handling failures during a transfer. 30 | */ 31 | public interface TransferOut extends ErrorListener { 32 | 33 | /** 34 | * Method to notify about a successful transfer. 35 | * 36 | * @param onTransfer an object of type OnTransfer which encapsulates the details of the 37 | * successful transfer. 38 | */ 39 | @MethodId('T') 40 | void onTransfer(OnTransfer onTransfer); 41 | 42 | /** 43 | * Method to handle failures during a transfer. 44 | * 45 | * @param transferFailed an object of type TransferFailed which encapsulates the details of 46 | * the transfer failure. 47 | */ 48 | void transferFailed(TransferFailed transferFailed); 49 | } 50 | -------------------------------------------------------------------------------- /account/src/main/java/run/chronicle/account/benchmark-results.txt: -------------------------------------------------------------------------------- 1 | -Xmx64m -Dthroughput=100000 -DrunTime=30 -Dbuffered=false -Durl=tcp://localhost:1248 -DaccountForCoordinatedOmission=false 2 | -------------------------------- SUMMARY (end to end) us ------------------------------------------- 3 | Percentile run1 run2 run3 run4 run5 % Variation 4 | 50.0: 10.99 10.99 11.02 11.02 10.99 0.19 5 | 90.0: 18.02 17.89 15.70 11.22 11.12 28.86 6 | 99.0: 20.96 19.94 15.86 15.86 15.79 14.89 7 | 99.7: 34.11 21.02 16.11 15.92 15.89 17.73 8 | 99.9: 42.18 22.62 16.67 16.34 16.18 21.00 9 | 99.97: 2021.38 26.08 18.21 17.44 17.25 25.45 10 | 99.99: 5480.45 60.48 44.48 22.82 47.68 52.39 11 | 99.997: 6938.62 332.29 426.50 80.26 451.07 75.49 12 | worst: 7593.98 728.06 820.22 303.62 838.66 54.02 13 | 14 | Windows 11 laptop, i7-1360P, Java 11 15 | -Dthroughput=20000 -Durl=internal:// 16 | -------------------------------- SUMMARY (end to end) us ------------------------------------------- 17 | Percentile run1 run2 run3 run4 run5 % Variation 18 | 50.0: 1.60 1.70 1.60 1.60 1.60 3.84 19 | 90.0: 2.10 2.10 2.10 2.10 2.00 3.16 20 | 99.0: 23.39 22.62 22.18 20.70 17.12 17.65 21 | 99.7: 155.90 168.19 191.74 177.92 170.24 8.54 22 | 99.9: 857.09 723.97 824.32 816.13 764.93 8.46 23 | 24 | -Dthroughput=20000 25 | -------------------------------- SUMMARY (end to end) us ------------------------------------------- 26 | Percentile run1 run2 run3 run4 run5 % Variation 27 | 50.0: 24.93 24.67 24.93 24.80 24.93 0.69 28 | 90.0: 37.95 35.26 38.34 35.52 35.14 5.72 29 | 99.0: 1198.08 250.62 1243.14 469.50 477.70 72.53 30 | -------------------------------------------------------------------------------- /account/src/main/java/run/chronicle/account/dto/CheckPoint.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2022 chronicle.software 3 | * 4 | * https://chronicle.software 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package run.chronicle.account.dto; 19 | 20 | 21 | /** 22 | * The {@code CheckPoint} class represents a request to produce a snapshot 23 | * (or "dump") of the entire current system state at a given moment in time. 24 | * This includes all accounts and their balances, ensuring that the state 25 | * can be recorded for audit, recovery, or analysis. 26 | *

27 | * A valid {@code CheckPoint} event must have all these fields set; validation 28 | * is performed automatically when the event is processed. 29 | * 30 | *

Usage example: 31 | *

{@code
32 |  * CheckPoint cp = new CheckPoint()
33 |  *     .sender(gw2Id)
34 |  *     .target(vaultId)
35 |  *     .sendingTime(SystemTimeProvider.CLOCK.currentTimeNanos());
36 |  * }
37 | */ 38 | public class CheckPoint extends AbstractEvent { 39 | // The CheckPoint event leverages the common fields and validation logic provided by AbstractEvent. 40 | } 41 | -------------------------------------------------------------------------------- /account/src/main/java/run/chronicle/account/util/ErrorListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2022 chronicle.software 3 | * 4 | * https://chronicle.software 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package run.chronicle.account.util; 19 | 20 | /** 21 | * A functional interface for handling critical JVM-level errors in the system. 22 | * Implementations can define custom error-handling strategies such as logging, 23 | * triggering alerts, or performing cleanup and shutdown procedures. 24 | *

25 | * Using a replicated queue, this can be done on another machine to avoid 26 | * the impact of GC or IO the monitoring system might have. 27 | * 28 | *

Example usage: 29 | *

30 |  * public class LoggingErrorListener implements ErrorListener {
31 |  *     public void jvmError(String msg) {
32 |  *         // Log the error to monitoring system, a file, or console
33 |  *         logger.error(msg);
34 |  *     }
35 |  * }
36 | * 37 | *

By providing different {@code ErrorListener} implementations, the system 38 | * can adapt to various environments (production vs. development) or integrate 39 | * with different error-handling frameworks. 40 | */ 41 | @FunctionalInterface 42 | public interface ErrorListener { 43 | 44 | /** 45 | * Handles a critical JVM-level error. 46 | *

47 | * Implementations may choose to: 48 | *

53 | * 54 | * @param msg a human-readable message providing details about the encountered JVM error. 55 | */ 56 | void jvmError(String msg); 57 | } 58 | -------------------------------------------------------------------------------- /account/src/test/resources/account/bard-gen/_setup.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # This operation creates an account for Alice with account number 101013. 3 | createAccount: { 4 | sender: gw1, 5 | target: vault, 6 | sendingTime: 2023-01-20T10:00:00, 7 | name: alice, 8 | account: 13, 9 | currency: EUR, 10 | balance: 15 11 | } 12 | ... 13 | --- 14 | # This operation creates an account for Bob with account number 101025. 15 | createAccount: { 16 | sender: gw1, 17 | target: vault, 18 | sendingTime: 2023-01-20T10:00:01, 19 | name: bob, 20 | account: 101025, 21 | currency: EUR, 22 | balance: 1000 23 | } 24 | ... 25 | --- 26 | # This operation represents a transfer of 10 EUR from Alice to Bob. 27 | transfer: { 28 | sender: gw2, 29 | target: vault, 30 | sendingTime: 2023-01-20T10:01:00, 31 | from: 101013, 32 | to: 101025, 33 | currency: EUR, 34 | amount: 10, 35 | reference: Dog food 36 | } 37 | ... 38 | --- 39 | # This operation attempts to make a transfer from a non-existent account to Bob. 40 | # This operation will fail due to the 'from' account not existing. 41 | transfer: { 42 | sender: gw2, 43 | target: vault, 44 | sendingTime: 2023-01-20T10:02:00, 45 | from: 1, 46 | to: 101025, 47 | currency: EUR, 48 | amount: 10, 49 | reference: Junk food 50 | } 51 | ... 52 | --- 53 | # This operation attempts to transfer 10 EUR from Alice to a non-existent account. 54 | # This operation will fail due to the 'to' account not existing. 55 | transfer: { 56 | sender: gw2, 57 | target: vault, 58 | sendingTime: 2023-01-20T10:03:00, 59 | from: 101013, 60 | to: 9999, 61 | currency: EUR, 62 | amount: 10, 63 | reference: Cat food 64 | } 65 | ... 66 | -------------------------------------------------------------------------------- /account/src/test/resources/account/bard-gen/in.yaml: -------------------------------------------------------------------------------- 1 | { # Generated by Bard #} 2 | --- 3 | # This operation creates an account for Charlie with account number 101037. 4 | createAccount: { 5 | sender: gw1, 6 | target: vault, 7 | sendingTime: 2023-01-20T10:00:02, 8 | name: charlie, 9 | account: 101037, 10 | currency: EUR, 11 | balance: 50 12 | } 13 | ... 14 | --- 15 | # This operation attempts to make a transfer from Alice to Charlie. 16 | # This operation will succeed. 17 | transfer: { 18 | sender: gw2, 19 | target: vault, 20 | sendingTime: 2023-01-20T10:04:00, 21 | from: 101013, 22 | to: 101037, 23 | currency: EUR, 24 | amount: 5, 25 | reference: New shoes 26 | } 27 | ... 28 | --- 29 | # This operation attempts to make a transfer from Bob to Charlie. 30 | # This operation will succeed. 31 | transfer: { 32 | sender: gw2, 33 | target: vault, 34 | sendingTime: 2023-01-20T10:05:00, 35 | from: 101025, 36 | to: 101037, 37 | currency: EUR, 38 | amount: 10, 39 | reference: New bike 40 | } 41 | ... 42 | --- 43 | # This operation requests a checkpoint. 44 | # Checkpoints are typically used to dump or save the state of the system at a certain point in time. 45 | # In this case, it will dump all the accounts. 46 | checkPoint: { 47 | sender: gw2, 48 | target: vault, 49 | sendingTime: 2023-01-20T11:00:00, 50 | } 51 | ... 52 | -------------------------------------------------------------------------------- /account/src/test/resources/account/bard-gen/out-set-field-balance=-1.yaml: -------------------------------------------------------------------------------- 1 | # This operation creates an account for Charlie with account number 101037. 2 | # override balance: 50 to balance: -1 3 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: balance must be positive or zero" 4 | ... 5 | # This operation attempts to make a transfer from Alice to Charlie. 6 | # This operation will succeed. 7 | --- 8 | transferFailed: { 9 | sender: vault, 10 | target: gw2, 11 | sendingTime: 2023-01-21T11:00:05, 12 | transfer: { 13 | sender: gw2, 14 | target: vault, 15 | sendingTime: 2023-01-20T10:04:00, 16 | from: 101013, 17 | to: 101037, 18 | currency: EUR, 19 | amount: 5.0, 20 | reference: New shoes 21 | }, 22 | reason: from account doesn't exist 23 | } 24 | ... 25 | # This operation attempts to make a transfer from Bob to Charlie. 26 | # This operation will succeed. 27 | --- 28 | transferFailed: { 29 | sender: vault, 30 | target: gw2, 31 | sendingTime: 2023-01-21T11:00:06, 32 | transfer: { 33 | sender: gw2, 34 | target: vault, 35 | sendingTime: 2023-01-20T10:05:00, 36 | from: 101025, 37 | to: 101037, 38 | currency: EUR, 39 | amount: 10.0, 40 | reference: New bike 41 | }, 42 | reason: to account doesn't exist 43 | } 44 | ... 45 | # This operation requests a checkpoint. 46 | # Checkpoints are typically used to dump or save the state of the system at a certain point in time. 47 | # In this case, it will dump all the accounts. 48 | --- 49 | startCheckpoint: { 50 | sender: gw2, 51 | target: vault, 52 | sendingTime: 2023-01-20T11:00:00 53 | } 54 | ... 55 | onCreateAccount: { 56 | sender: vault, 57 | target: gw1, 58 | sendingTime: 2023-01-21T11:00:07, 59 | createAccount: { 60 | sender: gw1, 61 | target: vault, 62 | sendingTime: 2023-01-20T10:00:00, 63 | name: alice, 64 | account: 13, 65 | currency: EUR, 66 | balance: 15.0, 67 | overdraft: 0.0 68 | } 69 | } 70 | ... 71 | onCreateAccount: { 72 | sender: vault, 73 | target: gw1, 74 | sendingTime: 2023-01-21T11:00:08, 75 | createAccount: { 76 | sender: gw1, 77 | target: vault, 78 | sendingTime: 2023-01-20T10:00:01, 79 | name: bob, 80 | account: 101025, 81 | currency: EUR, 82 | balance: 1E3, 83 | overdraft: 0.0 84 | } 85 | } 86 | ... 87 | endCheckpoint: { 88 | sender: gw2, 89 | target: vault, 90 | sendingTime: 2023-01-20T11:00:00 91 | } 92 | ... 93 | -------------------------------------------------------------------------------- /account/src/test/resources/account/bard-jinja/in.yaml: -------------------------------------------------------------------------------- 1 | {# Generated by Bard #} 2 | --- 3 | # This operation creates 10 accounts. 4 | {% for i in range(10, 20) %} 5 | createAccount: { 6 | sender: gw1, 7 | target: vault, 8 | sendingTime: 2023-01-20T10:00:{{ i }}, 9 | name: "account_{{ i }}", 10 | account: {{ i }}, 11 | currency: EUR, 12 | balance: 100 13 | } 14 | {% endfor %} 15 | ... 16 | --- 17 | # This operation creates 10 transfers between the accounts. 18 | {% for i in range(10, 20) %} 19 | transfer: { 20 | sender: {{ i }}, 21 | target: {{ i + 1 }}, 22 | sendingTime: 2023-01-20T10:00: + {{ i }}, 23 | currency: EUR, 24 | amount: 10, 25 | reference: "transfer_{{ i }}" 26 | } 27 | {% endfor %} 28 | ... 29 | -------------------------------------------------------------------------------- /account/src/test/resources/account/bard-jinja/out-missing-field-name.yaml: -------------------------------------------------------------------------------- 1 | # This operation creates 10 accounts. 2 | # missing name: "account_10", 3 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: name must be set and not empty" 4 | ... 5 | # This operation creates 10 transfers between the accounts. 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 7 | ... 8 | -------------------------------------------------------------------------------- /account/src/test/resources/account/bard-jinja/out-missing-field-sender.yaml: -------------------------------------------------------------------------------- 1 | # This operation creates 10 accounts. 2 | # missing sender: gw1, 3 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sender must be set" 4 | ... 5 | # This operation creates 10 transfers between the accounts. 6 | # missing sender: 10, 7 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sender must be set" 8 | ... 9 | -------------------------------------------------------------------------------- /account/src/test/resources/account/bard-jinja/out-missing-field-sendingTime.yaml: -------------------------------------------------------------------------------- 1 | # This operation creates 10 accounts. 2 | # missing sendingTime: 2023-01-20T10:00:10, 3 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 4 | ... 5 | # This operation creates 10 transfers between the accounts. 6 | # missing sendingTime: 2023-01-20T10:00: + 10, 7 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 8 | ... 9 | -------------------------------------------------------------------------------- /account/src/test/resources/account/bard-jinja/out-missing-field-target.yaml: -------------------------------------------------------------------------------- 1 | # This operation creates 10 accounts. 2 | # missing target: vault, 3 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: target must be set" 4 | ... 5 | # This operation creates 10 transfers between the accounts. 6 | # missing target: 11, 7 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: target must be set" 8 | ... 9 | -------------------------------------------------------------------------------- /account/src/test/resources/account/bard-jinja/out-set-field-balance=-1.yaml: -------------------------------------------------------------------------------- 1 | # This operation creates 10 accounts. 2 | # override balance: 100 to balance: -1 3 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: balance must be positive or zero" 4 | ... 5 | # This operation creates 10 transfers between the accounts. 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 7 | ... 8 | -------------------------------------------------------------------------------- /account/src/test/resources/account/copilot/_setup.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # This operation creates an account for Alice with account number 101013. 3 | createAccount: { 4 | sender: gw1, 5 | target: vault, 6 | sendingTime: 2023-01-20T10:00:00, 7 | name: alice, 8 | account: 101013, 9 | currency: EUR, 10 | balance: 15 11 | } 12 | ... 13 | --- 14 | # This operation creates an account for Bob with account number 101025. 15 | createAccount: { 16 | sender: gw1, 17 | target: vault, 18 | sendingTime: 2023-01-20T10:00:01, 19 | name: bob, 20 | account: 101025, 21 | currency: EUR, 22 | balance: 1000 23 | } 24 | ... 25 | --- 26 | # This operation represents a transfer of 10 EUR from Alice to Bob. 27 | transfer: { 28 | sender: gw2, 29 | target: vault, 30 | sendingTime: 2023-01-20T10:01:00, 31 | from: 101013, 32 | to: 101025, 33 | currency: EUR, 34 | amount: 10, 35 | reference: Dog food 36 | } 37 | ... 38 | --- 39 | # This operation attempts to make a transfer from a non-existent account to Bob. 40 | # This operation will fail due to the 'from' account not existing. 41 | transfer: { 42 | sender: gw2, 43 | target: vault, 44 | sendingTime: 2023-01-20T10:02:00, 45 | from: 1, 46 | to: 101025, 47 | currency: EUR, 48 | amount: 10, 49 | reference: Junk food 50 | } 51 | ... 52 | --- 53 | # This operation attempts to transfer 10 EUR from Alice to a non-existent account. 54 | # This operation will fail due to the 'to' account not existing. 55 | transfer: { 56 | sender: gw2, 57 | target: vault, 58 | sendingTime: 2023-01-20T10:03:00, 59 | from: 101013, 60 | to: 9999, 61 | currency: EUR, 62 | amount: 10, 63 | reference: Cat food 64 | } 65 | ... 66 | --- 67 | # This operation requests a checkpoint. 68 | # Checkpoints are typically used to dump or save the state of the system at a certain point in time. 69 | # In this case, it will dump all the accounts. 70 | checkPoint: { 71 | sender: gw2, 72 | target: vault, 73 | sendingTime: 2023-01-20T11:00:00, 74 | } 75 | ... 76 | -------------------------------------------------------------------------------- /account/src/test/resources/account/gpt-gen/_setup.yaml: -------------------------------------------------------------------------------- 1 | # This is GPT-4 generated 2 | -------------------------------------------------------------------------------- /account/src/test/resources/account/gpt-gen/in.yaml: -------------------------------------------------------------------------------- 1 | { # Generated by GPT-4 #} 2 | --- 3 | # This operation creates an account for Charlie with account number 101045. 4 | # The 'sender' is 'gw1' and the 'target' is 'vault'. 5 | # The 'currency' for Charlie's account is EUR and the initial account 'balance' is 5000. 6 | createAccount: { 7 | sender: gw1, 8 | target: vault, 9 | sendingTime: 2023-01-20T10:05:00, 10 | name: charlie, 11 | account: 101045, 12 | currency: EUR, 13 | balance: 5000 14 | } 15 | --- 16 | # This operation creates an account for Dania with account number 101055. 17 | # The 'sender' is 'gw1' and the 'target' is 'vault'. 18 | # The 'currency' for Dania's account is EUR and the initial account 'balance' is 3500. 19 | createAccount: { 20 | sender: gw1, 21 | target: vault, 22 | sendingTime: 2023-01-20T10:05:01, 23 | name: Dania, 24 | account: 101055, 25 | currency: EUR, 26 | balance: 3500 27 | } 28 | --- 29 | # This operation represents a transfer of 500 EUR from Charlie to Dania. 30 | # The 'sender' is 'gw2' and the 'target' is 'vault'. 31 | transfer: { 32 | sender: gw2, 33 | target: vault, 34 | sendingTime: 2023-01-20T10:06:00, 35 | from: 101045, 36 | to: 101055, 37 | currency: EUR, 38 | amount: 500, 39 | reference: Grocery Shopping 40 | } 41 | --- 42 | # This operation attempts to make a transfer from a non-existent account to Charlie. 43 | # This operation will likely fail due to the 'from' account not existing. 44 | transfer: { 45 | sender: gw2, 46 | target: vault, 47 | sendingTime: 2023-01-20T10:07:00, 48 | from: 2, 49 | to: 101045, 50 | currency: EUR, 51 | amount: 500, 52 | reference: Unexpected Income 53 | } 54 | --- 55 | # This operation attempts to transfer 1000 EUR from Dania to a non-existent account. 56 | # This operation will likely fail due to the 'to' account not existing. 57 | transfer: { 58 | sender: gw2, 59 | target: vault, 60 | sendingTime: 2023-01-20T10:08:00, 61 | from: 101055, 62 | to: 9998, 63 | currency: EUR, 64 | amount: 1000, 65 | reference: Charity Donation 66 | } 67 | --- 68 | # This operation requests a checkpoint. 69 | # It will dump all the accounts. 70 | checkPoint: { 71 | sender: gw2, 72 | target: vault, 73 | sendingTime: 2023-01-20T11:05:00, 74 | } 75 | -------------------------------------------------------------------------------- /account/src/test/resources/account/gpt-gen/out-missing-field-sendingTime.yaml: -------------------------------------------------------------------------------- 1 | # This operation creates an account for Charlie with account number 101045. 2 | # The 'sender' is 'gw1' and the 'target' is 'vault'. 3 | # The 'currency' for Charlie's account is EUR and the initial account 'balance' is 5000. 4 | # missing sendingTime: 2023-01-20T10:05:00, 5 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 6 | ... 7 | # This operation creates an account for Dania with account number 101055. 8 | # The 'sender' is 'gw1' and the 'target' is 'vault'. 9 | # The 'currency' for Dania's account is EUR and the initial account 'balance' is 3500. 10 | # missing sendingTime: 2023-01-20T10:05:01, 11 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 12 | ... 13 | # This operation represents a transfer of 500 EUR from Charlie to Dania. 14 | # The 'sender' is 'gw2' and the 'target' is 'vault'. 15 | # missing sendingTime: 2023-01-20T10:06:00, 16 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 17 | ... 18 | # This operation attempts to make a transfer from a non-existent account to Charlie. 19 | # This operation will likely fail due to the 'from' account not existing. 20 | # missing sendingTime: 2023-01-20T10:07:00, 21 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 22 | ... 23 | # This operation attempts to transfer 1000 EUR from Dania to a non-existent account. 24 | # This operation will likely fail due to the 'to' account not existing. 25 | # missing sendingTime: 2023-01-20T10:08:00, 26 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 27 | ... 28 | # This operation requests a checkpoint. 29 | # It will dump all the accounts. 30 | # missing sendingTime: 2023-01-20T11:05:00, 31 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 32 | ... 33 | -------------------------------------------------------------------------------- /account/src/test/resources/account/gpt-jinja/in.yaml: -------------------------------------------------------------------------------- 1 | {# Generated by GPT-4 #} 2 | --- 3 | # Starting from account number 10, we create 10 new accounts 4 | {% for i in range(10, 20) %} 5 | createAccount: { 6 | sender: gw1, 7 | target: vault, 8 | sendingTime: "2023-01-21T10:{{ i }}:00", 9 | name: "user{{ i }}", 10 | account: {{ i }}, 11 | currency: EUR, 12 | balance: 1000 13 | } 14 | {% endfor %} 15 | ... 16 | --- 17 | # Starting from account number 10, we initiate 10 transfers to the next account 18 | {% for i in range(10, 20-1) %} {# -1 because the last account won't have a next account to transfer to #} 19 | transfer: { 20 | sender: gw2, 21 | target: vault, 22 | sendingTime: "2023-01-21T11:{{ i }}:00", 23 | from: {{ i }}, 24 | to: {{ i|add(1) }}, 25 | currency: EUR, 26 | amount: 100, 27 | reference: Transfer {{ i }} to {{ i|add(1) }} 28 | } 29 | {% endfor %} 30 | ... -------------------------------------------------------------------------------- /account/src/test/resources/account/gpt-jinja/out-missing-field-sendingTime.yaml: -------------------------------------------------------------------------------- 1 | # Starting from account number 10, we create 10 new accounts 2 | # missing sendingTime: "2023-01-21T10:10:00", 3 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 4 | ... 5 | # Starting from account number 10, we initiate 10 transfers to the next account 6 | # missing sendingTime: "2023-01-21T11:10:00", 7 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 8 | ... 9 | -------------------------------------------------------------------------------- /account/src/test/resources/account/mixed/_setup.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is an operation to create an account for Alice with account number 101013. 3 | createAccount: { 4 | sender: gw1, 5 | target: vault, 6 | sendingTime: 2023-01-20T10:00:00, 7 | name: alice, 8 | account: 101013, 9 | currency: EUR, 10 | balance: 15 11 | } 12 | ... 13 | --- 14 | # This is another operation to create an account, this time for Bob with account number 101025. 15 | createAccount: { 16 | sender: gw1, 17 | target: vault, 18 | sendingTime: 2023-01-20T10:00:01, 19 | name: bob, 20 | account: 101025, 21 | currency: USD, 22 | balance: 1000 23 | } 24 | ... 25 | -------------------------------------------------------------------------------- /account/src/test/resources/account/mixed/in.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is a transfer operation where Alice (represented by account 101013) sends 10 EUR to Bob (represented by account 101025) 3 | transfer: { 4 | sender: gw2, 5 | target: vault, 6 | sendingTime: 2023-01-20T10:01:00, 7 | from: 101013, 8 | to: 101025, 9 | currency: EUR, 10 | amount: 10, 11 | reference: Dog food, 12 | } 13 | ... 14 | --- 15 | # This is another transfer operation where Alice (represented by account 101013) sends 10 USD to Bob (represented by account 101025). 16 | transfer: { 17 | sender: gw2, 18 | target: vault, 19 | sendingTime: 2023-01-20T10:02:00, 20 | from: 101013, 21 | to: 101025, 22 | currency: USD, 23 | amount: 10, 24 | reference: Dog food, 25 | } 26 | ... 27 | -------------------------------------------------------------------------------- /account/src/test/resources/account/mixed/out-missing-field-reference.yaml: -------------------------------------------------------------------------------- 1 | # This is a transfer operation where Alice (represented by account 101013) sends 10 EUR to Bob (represented by account 101025) 2 | # missing reference: Dog food, 3 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: reference must be set" 4 | ... 5 | # This is another transfer operation where Alice (represented by account 101013) sends 10 USD to Bob (represented by account 101025). 6 | # missing reference: Dog food, 7 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: reference must be set" 8 | ... 9 | -------------------------------------------------------------------------------- /account/src/test/resources/account/mixed/out.yaml: -------------------------------------------------------------------------------- 1 | # This is a transfer operation where Alice (represented by account 101013) sends 10 EUR to Bob (represented by account 101025) 2 | --- 3 | transferFailed: { 4 | sender: vault, 5 | target: gw2, 6 | sendingTime: 2023-01-21T11:00:02, 7 | transfer: { 8 | sender: gw2, 9 | target: vault, 10 | sendingTime: 2023-01-20T10:01:00, 11 | from: 101013, 12 | to: 101025, 13 | currency: EUR, 14 | amount: 10.0, 15 | reference: Dog food 16 | }, 17 | reason: to account currency doesn't match 18 | } 19 | ... 20 | # This is another transfer operation where Alice (represented by account 101013) sends 10 USD to Bob (represented by account 101025). 21 | --- 22 | transferFailed: { 23 | sender: vault, 24 | target: gw2, 25 | sendingTime: 2023-01-21T11:00:03, 26 | transfer: { 27 | sender: gw2, 28 | target: vault, 29 | sendingTime: 2023-01-20T10:02:00, 30 | from: 101013, 31 | to: 101025, 32 | currency: USD, 33 | amount: 10.0, 34 | reference: Dog food 35 | }, 36 | reason: from account currency doesn't match 37 | } 38 | ... 39 | -------------------------------------------------------------------------------- /account/src/test/resources/account/o1-pro/_setup.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Create an account for Alice (101013) with 15 EUR initial balance. 3 | # Rationale: Alice is used in transfer scenarios that require a known starting balance. 4 | createAccount: { 5 | sender: gw1, 6 | target: vault, 7 | sendingTime: 2023-01-20T10:00:00, 8 | name: alice, 9 | account: 101013, 10 | currency: EUR, 11 | balance: 15 12 | } 13 | ... 14 | --- 15 | # Create an account for Bob (101025) with 1000 USD initial balance. 16 | # Rationale: Bob's account is in a different currency (USD) to test currency mismatch failures. 17 | createAccount: { 18 | sender: gw1, 19 | target: vault, 20 | sendingTime: 2023-01-20T10:00:01, 21 | name: bob, 22 | account: 101025, 23 | currency: USD, 24 | balance: 1000 25 | } 26 | 27 | --- 28 | # Create an account for Charlie (101040) with 50 EUR initial balance. 29 | # Rationale: Charlie has an EUR account to test successful EUR-to-EUR transfers. 30 | createAccount: { 31 | sender: gw1, 32 | target: vault, 33 | sendingTime: 2023-01-20T10:00:02, 34 | name: charlie, 35 | account: 101040, 36 | currency: EUR, 37 | balance: 50 38 | } 39 | -------------------------------------------------------------------------------- /account/src/test/resources/account/o1-pro/in.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Scenario: Valid EUR-to-EUR Transfer (Alice -> Charlie) 3 | # Alice (101013) has 15 EUR, Charlie (101040) has 50 EUR. 4 | # Transfer 10 EUR from Alice to Charlie should succeed. 5 | transfer: { 6 | sender: gw2, 7 | target: vault, 8 | sendingTime: 2023-01-20T10:01:00, 9 | from: 101013, 10 | to: 101040, 11 | currency: EUR, 12 | amount: 10, 13 | reference: Groceries Payment 14 | } 15 | ... 16 | --- 17 | # Scenario: Currency Mismatch Transfer (Alice -> Bob) 18 | # Attempting a transfer of 10 EUR to Bob who holds a USD account. 19 | # This should fail due to currency mismatch. 20 | transfer: { 21 | sender: gw2, 22 | target: vault, 23 | sendingTime: 2023-01-20T10:02:00, 24 | from: 101013, 25 | to: 101025, 26 | currency: EUR, 27 | amount: 10, 28 | reference: "Dog food" 29 | } 30 | 31 | --- 32 | # Scenario: Invalid Create Account 33 | # Attempt to create an account with a negative initial balance (-20). 34 | # This should fail with a createAccountFailed event. 35 | createAccount: { 36 | sender: gw2, 37 | target: vault, 38 | sendingTime: 2023-01-20T10:03:00, 39 | name: "derek", 40 | account: 101050, 41 | currency: EUR, 42 | balance: -20 43 | } 44 | 45 | --- 46 | # Scenario: Non-Existent Account Transfer 47 | # Attempting to transfer 5 EUR from a non-existent account (999999) to Charlie (101040). 48 | # This should fail with reason "accountNotFound". 49 | transfer: { 50 | sender: gw2, 51 | target: vault, 52 | sendingTime: 2023-01-20T10:04:00, 53 | from: 999999, 54 | to: 101040, 55 | currency: EUR, 56 | amount: 5, 57 | reference: "Mystery Sender" 58 | } 59 | 60 | --- 61 | # Scenario: Insufficient Funds Transfer 62 | # After the first successful transfer, Alice has 5 EUR left (15 - 10 = 5). 63 | # Attempting to transfer 100 EUR from Alice to Charlie should fail with "insufficientFunds". 64 | transfer: { 65 | sender: gw2, 66 | target: vault, 67 | sendingTime: 2023-01-20T10:05:00, 68 | from: 101013, 69 | to: 101040, 70 | currency: EUR, 71 | amount: 100, 72 | reference: "Big Purchase" 73 | } 74 | 75 | --- 76 | # Scenario: Checkpoint 77 | # Requesting a checkpoint after all operations. 78 | # Expected output: startCheckpoint, onCreateAccount events for all existing accounts, 79 | # and endCheckpoint, reflecting the final state of known accounts. 80 | checkPoint: { 81 | sender: gw2, 82 | target: vault, 83 | sendingTime: 2023-01-20T11:00:00 84 | } 85 | -------------------------------------------------------------------------------- /account/src/test/resources/account/o1-pro/out-missing-field-sendingTime.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Valid EUR-to-EUR Transfer (Alice -> Charlie) 2 | # Alice (101013) has 15 EUR, Charlie (101040) has 50 EUR. 3 | # Transfer 10 EUR from Alice to Charlie should succeed. 4 | # missing sendingTime: 2023-01-20T10:01:00, 5 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 6 | ... 7 | # Scenario: Currency Mismatch Transfer (Alice -> Bob) 8 | # Attempting a transfer of 10 EUR to Bob who holds a USD account. 9 | # This should fail due to currency mismatch. 10 | # missing sendingTime: 2023-01-20T10:02:00, 11 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 12 | ... 13 | # Scenario: Invalid Create Account 14 | # Attempt to create an account with a negative initial balance (-20). 15 | # This should fail with a createAccountFailed event. 16 | # missing sendingTime: 2023-01-20T10:03:00, 17 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 18 | ... 19 | # Scenario: Non-Existent Account Transfer 20 | # Attempting to transfer 5 EUR from a non-existent account (999999) to Charlie (101040). 21 | # This should fail with reason "accountNotFound". 22 | # missing sendingTime: 2023-01-20T10:04:00, 23 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 24 | ... 25 | # Scenario: Insufficient Funds Transfer 26 | # After the first successful transfer, Alice has 5 EUR left (15 - 10 = 5). 27 | # Attempting to transfer 100 EUR from Alice to Charlie should fail with "insufficientFunds". 28 | # missing sendingTime: 2023-01-20T10:05:00, 29 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 30 | ... 31 | # Scenario: Checkpoint 32 | # Requesting a checkpoint after all operations. 33 | # Expected output: startCheckpoint, onCreateAccount events for all existing accounts, 34 | # and endCheckpoint, reflecting the final state of known accounts. 35 | # missing sendingTime: 2023-01-20T11:00:00 36 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 37 | ... 38 | -------------------------------------------------------------------------------- /account/src/test/resources/account/simple-gen/_setup.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Create an account for Alice with account number 101013. 3 | createAccount: { 4 | sender: gw1, 5 | target: vault, 6 | sendingTime: 2023-01-20T09:00:00, 7 | name: alice, 8 | account: 101013, 9 | currency: EUR, 10 | balance: 1000, 11 | overdraft: 100 12 | } 13 | ... 14 | 15 | --- 16 | 17 | # Create an account for Bob with account number 101025. 18 | createAccount: { 19 | sender: gw1, 20 | target: vault, 21 | sendingTime: 2023-01-20T09:05:00, 22 | name: bob, 23 | account: 101025, 24 | currency: EUR, 25 | balance: 500, 26 | overdraft: 100 27 | } 28 | ... 29 | 30 | --- 31 | 32 | # Create an account for Charlie with account number 101037. 33 | createAccount: { 34 | sender: gw1, 35 | target: vault, 36 | sendingTime: 2023-01-20T09:10:00, 37 | name: charlie, 38 | account: 101037, 39 | currency: USD, 40 | balance: 2000, 41 | overdraft: 100 42 | } 43 | ... 44 | 45 | --- 46 | 47 | # Create an account for Diana with account number 101049. 48 | createAccount: { 49 | sender: gw1, 50 | target: vault, 51 | sendingTime: 2023-01-20T09:15:00, 52 | name: diana, 53 | account: 101049, 54 | currency: GBP, 55 | balance: 1500, 56 | overdraft: 100 57 | } 58 | ... 59 | -------------------------------------------------------------------------------- /account/src/test/resources/account/simple/_setup.yaml: -------------------------------------------------------------------------------- 1 | # no setup required 2 | -------------------------------------------------------------------------------- /account/src/test/resources/account/simple/in.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # This operation creates an account for Alice with account number 101013. 3 | createAccount: { 4 | sender: gw1, 5 | target: vault, 6 | sendingTime: 2023-01-20T10:00:00, 7 | name: alice, 8 | account: 101013, 9 | currency: EUR, 10 | balance: 15, 11 | overdraft: 10 12 | } 13 | ... 14 | --- 15 | # This operation creates an account for Bob with account number 101025. 16 | createAccount: { 17 | sender: gw1, 18 | target: vault, 19 | sendingTime: 2023-01-20T10:00:01, 20 | name: bob, 21 | account: 101025, 22 | currency: EUR, 23 | balance: 1000, 24 | overdraft: 100 25 | } 26 | ... 27 | --- 28 | # This operation represents a transfer of 10 EUR from Alice to Bob. 29 | transfer: { 30 | sender: gw2, 31 | target: vault, 32 | sendingTime: 2023-01-20T10:01:00, 33 | from: 101013, 34 | to: 101025, 35 | currency: EUR, 36 | amount: 10, 37 | reference: Dog food 38 | } 39 | ... 40 | --- 41 | # This operation attempts to make a transfer from a non-existent account to Bob. 42 | # This operation will fail due to the 'from' account not existing. 43 | transfer: { 44 | sender: gw2, 45 | target: vault, 46 | sendingTime: 2023-01-20T10:02:00, 47 | from: 1, 48 | to: 101025, 49 | currency: EUR, 50 | amount: 10, 51 | reference: Junk food 52 | } 53 | ... 54 | --- 55 | # This operation attempts to transfer 10 EUR from Alice to a non-existent account. 56 | # This operation will fail due to the 'to' account not existing. 57 | transfer: { 58 | sender: gw2, 59 | target: vault, 60 | sendingTime: 2023-01-20T10:03:00, 61 | from: 101013, 62 | to: 9999, 63 | currency: EUR, 64 | amount: 10, 65 | reference: Cat food 66 | } 67 | ... 68 | --- 69 | # This operation requests a checkpoint. 70 | # Checkpoints are typically used to dump or save the state of the system at a certain point in time. 71 | # In this case, it will dump all the accounts. 72 | checkPoint: { 73 | sender: gw2, 74 | target: vault, 75 | sendingTime: 2023-01-20T11:00:00, 76 | } 77 | ... 78 | -------------------------------------------------------------------------------- /account/src/test/resources/account/simple/out-missing-field-balance.yaml: -------------------------------------------------------------------------------- 1 | jvmError: "Unhandled Exception net.openhft.chronicle.core.io.InvalidMarshallableException: balance must be positive or zero" 2 | ... 3 | -------------------------------------------------------------------------------- /account/src/test/resources/account/simple/out-missing-field-currency.yaml: -------------------------------------------------------------------------------- 1 | # This operation creates an account for Alice with account number 101013. 2 | # missing currency: EUR, 3 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: currency must be set" 4 | ... 5 | # This operation creates an account for Bob with account number 101025. 6 | # missing currency: EUR, 7 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: currency must be set" 8 | ... 9 | # This operation represents a transfer of 10 EUR from Alice to Bob. 10 | # missing currency: EUR, 11 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: currency must be set" 12 | ... 13 | # This operation attempts to make a transfer from a non-existent account to Bob. 14 | # This operation will fail due to the 'from' account not existing. 15 | # missing currency: EUR, 16 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: currency must be set" 17 | ... 18 | # This operation attempts to transfer 10 EUR from Alice to a non-existent account. 19 | # This operation will fail due to the 'to' account not existing. 20 | # missing currency: EUR, 21 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: currency must be set" 22 | ... 23 | # This operation requests a checkpoint. 24 | # Checkpoints are typically used to dump or save the state of the system at a certain point in time. 25 | # In this case, it will dump all the accounts. 26 | --- 27 | startCheckpoint: { 28 | sender: gw2, 29 | target: vault, 30 | sendingTime: 2023-01-20T11:00:00 31 | } 32 | ... 33 | endCheckpoint: { 34 | sender: gw2, 35 | target: vault, 36 | sendingTime: 2023-01-20T11:00:00 37 | } 38 | ... 39 | -------------------------------------------------------------------------------- /account/src/test/resources/account/simple/out-missing-field-sender.yaml: -------------------------------------------------------------------------------- 1 | # This operation creates an account for Alice with account number 101013. 2 | # missing sender: gw1, 3 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sender must be set" 4 | ... 5 | # This operation creates an account for Bob with account number 101025. 6 | # missing sender: gw1, 7 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sender must be set" 8 | ... 9 | # This operation represents a transfer of 10 EUR from Alice to Bob. 10 | # missing sender: gw2, 11 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sender must be set" 12 | ... 13 | # This operation attempts to make a transfer from a non-existent account to Bob. 14 | # This operation will fail due to the 'from' account not existing. 15 | # missing sender: gw2, 16 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sender must be set" 17 | ... 18 | # This operation attempts to transfer 10 EUR from Alice to a non-existent account. 19 | # This operation will fail due to the 'to' account not existing. 20 | # missing sender: gw2, 21 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sender must be set" 22 | ... 23 | # This operation requests a checkpoint. 24 | # Checkpoints are typically used to dump or save the state of the system at a certain point in time. 25 | # In this case, it will dump all the accounts. 26 | # missing sender: gw2, 27 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sender must be set" 28 | ... 29 | -------------------------------------------------------------------------------- /account/src/test/resources/account/simple/out-missing-field-sendingTime.yaml: -------------------------------------------------------------------------------- 1 | # This operation creates an account for Alice with account number 101013. 2 | # missing sendingTime: 2023-01-20T10:00:00, 3 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 4 | ... 5 | # This operation creates an account for Bob with account number 101025. 6 | # missing sendingTime: 2023-01-20T10:00:01, 7 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 8 | ... 9 | # This operation represents a transfer of 10 EUR from Alice to Bob. 10 | # missing sendingTime: 2023-01-20T10:01:00, 11 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 12 | ... 13 | # This operation attempts to make a transfer from a non-existent account to Bob. 14 | # This operation will fail due to the 'from' account not existing. 15 | # missing sendingTime: 2023-01-20T10:02:00, 16 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 17 | ... 18 | # This operation attempts to transfer 10 EUR from Alice to a non-existent account. 19 | # This operation will fail due to the 'to' account not existing. 20 | # missing sendingTime: 2023-01-20T10:03:00, 21 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 22 | ... 23 | # This operation requests a checkpoint. 24 | # Checkpoints are typically used to dump or save the state of the system at a certain point in time. 25 | # In this case, it will dump all the accounts. 26 | # missing sendingTime: 2023-01-20T11:00:00, 27 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 28 | ... 29 | -------------------------------------------------------------------------------- /account/src/test/resources/account/simple/out-missing-field-target.yaml: -------------------------------------------------------------------------------- 1 | # This operation creates an account for Alice with account number 101013. 2 | # missing target: vault, 3 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: target must be set" 4 | ... 5 | # This operation creates an account for Bob with account number 101025. 6 | # missing target: vault, 7 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: target must be set" 8 | ... 9 | # This operation represents a transfer of 10 EUR from Alice to Bob. 10 | # missing target: vault, 11 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: target must be set" 12 | ... 13 | # This operation attempts to make a transfer from a non-existent account to Bob. 14 | # This operation will fail due to the 'from' account not existing. 15 | # missing target: vault, 16 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: target must be set" 17 | ... 18 | # This operation attempts to transfer 10 EUR from Alice to a non-existent account. 19 | # This operation will fail due to the 'to' account not existing. 20 | # missing target: vault, 21 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: target must be set" 22 | ... 23 | # This operation requests a checkpoint. 24 | # Checkpoints are typically used to dump or save the state of the system at a certain point in time. 25 | # In this case, it will dump all the accounts. 26 | # missing target: vault, 27 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: target must be set" 28 | ... 29 | -------------------------------------------------------------------------------- /account/src/test/resources/account/simple/out-set-field-currency=.yaml: -------------------------------------------------------------------------------- 1 | # This operation creates an account for Alice with account number 101013. 2 | # override currency: EUR to currency: 3 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: currency must be set" 4 | ... 5 | # This operation creates an account for Bob with account number 101025. 6 | # override currency: EUR to currency: 7 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: currency must be set" 8 | ... 9 | # This operation represents a transfer of 10 EUR from Alice to Bob. 10 | # override currency: EUR to currency: 11 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: currency must be set" 12 | ... 13 | # This operation attempts to make a transfer from a non-existent account to Bob. 14 | # This operation will fail due to the 'from' account not existing. 15 | # override currency: EUR to currency: 16 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: currency must be set" 17 | ... 18 | # This operation attempts to transfer 10 EUR from Alice to a non-existent account. 19 | # This operation will fail due to the 'to' account not existing. 20 | # override currency: EUR to currency: 21 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: currency must be set" 22 | ... 23 | # This operation requests a checkpoint. 24 | # Checkpoints are typically used to dump or save the state of the system at a certain point in time. 25 | # In this case, it will dump all the accounts. 26 | --- 27 | startCheckpoint: { 28 | sender: gw2, 29 | target: vault, 30 | sendingTime: 2023-01-20T11:00:00 31 | } 32 | ... 33 | endCheckpoint: { 34 | sender: gw2, 35 | target: vault, 36 | sendingTime: 2023-01-20T11:00:00 37 | } 38 | ... 39 | -------------------------------------------------------------------------------- /account/src/test/resources/account/waterfall/_setup.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # This operation is creating an account for Alice with 15 EUR. 3 | createAccount: { 4 | sender: gw1, 5 | target: vault, 6 | sendingTime: 2023-01-20T10:00:00, 7 | name: alice, 8 | account: 101013, 9 | currency: EUR, 10 | balance: 15 11 | } 12 | ... 13 | --- 14 | # This operation is creating an account for Bob with 10 EUR 15 | createAccount: { 16 | sender: gw1, 17 | target: vault, 18 | sendingTime: 2023-01-20T10:00:01, 19 | name: bob, 20 | account: 101025, 21 | currency: EUR, 22 | balance: 10 23 | } 24 | ... 25 | --- 26 | # This operation is creating an account for Cate with 10 EUR. 27 | createAccount: { 28 | sender: gw1, 29 | target: vault, 30 | sendingTime: 2023-01-20T10:00:02, 31 | name: cate, 32 | account: 101037, 33 | currency: EUR, 34 | balance: 10 35 | } 36 | ... 37 | -------------------------------------------------------------------------------- /account/src/test/resources/account/waterfall/in.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # This operation represents a transfer 10 EUR from Alice to Bob. 3 | transfer: { 4 | sender: gw2, 5 | target: vault, 6 | sendingTime: 2023-01-20T10:03:00, 7 | from: 101013, 8 | to: 101025, 9 | currency: EUR, 10 | amount: 10, 11 | reference: Dog food 12 | } 13 | ... 14 | --- 15 | # This operation represents a transfer 20 EUR from Bob to Cate. 16 | transfer: { 17 | sender: gw2, 18 | target: vault, 19 | sendingTime: 2023-01-20T10:04:00, 20 | from: 101025, 21 | to: 101037, 22 | currency: EUR, 23 | amount: 20, 24 | reference: Coffee 25 | } 26 | ... 27 | -------------------------------------------------------------------------------- /account/src/test/resources/account/waterfall/out-missing-field-reference.yaml: -------------------------------------------------------------------------------- 1 | # This operation represents a transfer 10 EUR from Alice to Bob. 2 | # missing reference: Dog food 3 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: reference must be set" 4 | ... 5 | # This operation represents a transfer 20 EUR from Bob to Cate. 6 | # missing reference: Coffee 7 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: reference must be set" 8 | ... 9 | -------------------------------------------------------------------------------- /account/src/test/resources/account/waterfall/out-missing-field-sendingTime.yaml: -------------------------------------------------------------------------------- 1 | # This operation represents a transfer 10 EUR from Alice to Bob. 2 | # missing sendingTime: 2023-01-20T10:03:00, 3 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 4 | ... 5 | # This operation represents a transfer 20 EUR from Bob to Cate. 6 | # missing sendingTime: 2023-01-20T10:04:00, 7 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime must be set" 8 | ... 9 | -------------------------------------------------------------------------------- /account/src/test/resources/account/waterfall/out-set-field-amount=-1.yaml: -------------------------------------------------------------------------------- 1 | # This operation represents a transfer 10 EUR from Alice to Bob. 2 | # override amount: 10 to amount: -1 3 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: amount must be positive" 4 | ... 5 | # This operation represents a transfer 20 EUR from Bob to Cate. 6 | # override amount: 20 to amount: -1 7 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: amount must be positive" 8 | ... 9 | -------------------------------------------------------------------------------- /account/src/test/resources/account/waterfall/out-set-field-amount=NaN.yaml: -------------------------------------------------------------------------------- 1 | # This operation represents a transfer 10 EUR from Alice to Bob. 2 | # override amount: 10 to amount: NaN 3 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: amount must be positive" 4 | ... 5 | # This operation represents a transfer 20 EUR from Bob to Cate. 6 | # override amount: 20 to amount: NaN 7 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: amount must be positive" 8 | ... 9 | -------------------------------------------------------------------------------- /account/src/test/resources/account/waterfall/out.yaml: -------------------------------------------------------------------------------- 1 | # This operation represents a transfer 10 EUR from Alice to Bob. 2 | --- 3 | onTransfer: { 4 | sender: vault, 5 | target: gw2, 6 | sendingTime: 2023-01-21T11:00:03, 7 | transfer: { 8 | sender: gw2, 9 | target: vault, 10 | sendingTime: 2023-01-20T10:03:00, 11 | from: 101013, 12 | to: 101025, 13 | currency: EUR, 14 | amount: 10.0, 15 | reference: Dog food 16 | } 17 | } 18 | ... 19 | # This operation represents a transfer 20 EUR from Bob to Cate. 20 | --- 21 | onTransfer: { 22 | sender: vault, 23 | target: gw2, 24 | sendingTime: 2023-01-21T11:00:04, 25 | transfer: { 26 | sender: gw2, 27 | target: vault, 28 | sendingTime: 2023-01-20T10:04:00, 29 | from: 101025, 30 | to: 101037, 31 | currency: EUR, 32 | amount: 20.0, 33 | reference: Coffee 34 | } 35 | } 36 | ... 37 | -------------------------------------------------------------------------------- /benchmarks/README.adoc: -------------------------------------------------------------------------------- 1 | = Benchmark 2 | Peter Lawrey 3 | 4 | Simple throughput and latency benchmarks for Chronicle Queue. 5 | 6 | == ThroughputMain 7 | 8 | .Results for -Dsize=60 on Ubuntu i7-10710U CPU @ 1.10GHz 9 | ---- 10 | Writing 140,500,273 messages took 5.025 seconds, at a rate of 27,959,000 per second 11 | Reading 140,500,273 messages took 6.619 seconds, at a rate of 21,226,000 per second 12 | ---- 13 | 14 | .Results for -Dsize=200 on Ubuntu i7-10710U CPU @ 1.10GHz 15 | ---- 16 | Writing 44,039,331 messages took 5.017 seconds, at a rate of 8,778,000 per second 17 | Reading 44,039,331 messages took 2.846 seconds, at a rate of 15,472,000 per second 18 | ---- 19 | 20 | .Results for -Dsize=500 on Ubuntu i7-10710U CPU @ 1.10GHz 21 | ---- 22 | Writing 23,068,441 messages took 5.076 seconds, at a rate of 4,544,000 per second 23 | Reading 23,068,441 messages took 2.728 seconds, at a rate of 8,456,000 per second 24 | ---- 25 | 26 | == LatencyDistributionMain 27 | 28 | This is the time from the message sent to the time the message was received. 29 | 30 | .Results for -Dsize=60 -Dthroughput=100000 on Ubuntu i7-10710U CPU @ 1.10GHz 31 | ---- 32 | in: 50/90 97/99 99.7/99.9 99.97/99.99 99.997/99.999 - worst 33 | was 0.251 / 0.273 0.293 / 0.385 0.650 / 0.962 1.93 / 20.4 22.6 / 36.5 - 218 34 | ---- 35 | 36 | NOTE: `sudo cpupower frequency-set -g performance` was used. -------------------------------------------------------------------------------- /benchmarks/src/main/java/run/chronicle/staged/IFacadeAll.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.staged; 2 | 3 | import net.openhft.chronicle.values.Array; 4 | 5 | public interface IFacadeAll extends IFacadeSon { 6 | @Array(length = 42) 7 | void setTimestampAt(int i, long v); 8 | 9 | long getTimestampAt(int i); 10 | } 11 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/run/chronicle/staged/IFacadeBase.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.staged; 2 | 3 | import net.openhft.chronicle.bytes.Byteable; 4 | 5 | @SuppressWarnings("rawtypes") 6 | interface IFacadeBase extends Byteable { 7 | short getValue0(); 8 | 9 | void setValue0(short value); 10 | 11 | byte getValue1(); 12 | 13 | void setValue1(byte value); 14 | 15 | byte getValue2(); 16 | 17 | void setValue2(byte value); 18 | 19 | int getValue3(); 20 | 21 | void setValue3(int value); 22 | 23 | short getValue4(); 24 | 25 | void setValue4(short value); 26 | 27 | boolean getValue5(); 28 | 29 | void setValue5(boolean value); 30 | 31 | boolean getValue6(); 32 | 33 | void setValue6(boolean value); 34 | 35 | short getValue7(); 36 | 37 | void setValue7(short value); 38 | 39 | short getValue8(); 40 | 41 | void setValue8(short value); 42 | 43 | long getValue9(); 44 | 45 | void setValue9(long value); 46 | 47 | long getValue10(); 48 | 49 | void setValue10(long value); 50 | 51 | long getValue11(); 52 | 53 | void setValue11(long value); 54 | 55 | long getValue12(); 56 | 57 | void setValue12(long value); 58 | 59 | long getValue13(); 60 | 61 | void setValue13(long value); 62 | 63 | long getValue14(); 64 | 65 | void setValue14(long value); 66 | 67 | long getValue15(); 68 | 69 | void setValue15(long value); 70 | 71 | short getValue16(); 72 | 73 | void setValue16(short value); 74 | 75 | short getValue17(); 76 | 77 | void setValue17(short value); 78 | 79 | short getValue18(); 80 | 81 | void setValue18(short value); 82 | } 83 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/run/chronicle/staged/IFacadeSon.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.staged; 2 | 3 | import net.openhft.chronicle.values.MaxUtf8Length; 4 | 5 | interface IFacadeSon extends IFacadeBase { 6 | long getValue19(); 7 | 8 | void setValue19(long value); 9 | 10 | int getValue20(); 11 | 12 | void setValue20(int value); 13 | 14 | int getValue21(); 15 | 16 | void setValue21(int value); 17 | 18 | double getValue22(); 19 | 20 | void setValue22(double value); 21 | 22 | String getValue23(); 23 | 24 | void setValue23(@MaxUtf8Length(10) String value); 25 | 26 | int getValue24(); 27 | 28 | void setValue24(int value); 29 | 30 | double getValue25(); 31 | 32 | void setValue25(double value); 33 | 34 | int getValue26(); 35 | 36 | void setValue26(int value); 37 | 38 | double getValue27(); 39 | 40 | void setValue27(double value); 41 | 42 | double getValue28(); 43 | 44 | void setValue28(double value); 45 | 46 | double getValue29(); 47 | 48 | void setValue29(double value); 49 | 50 | double getValue30(); 51 | 52 | void setValue30(double value); 53 | 54 | double getValue31(); 55 | 56 | void setValue31(double value); 57 | 58 | double getValue32(); 59 | 60 | void setValue32(double value); 61 | } 62 | -------------------------------------------------------------------------------- /benchmarks/system.properties: -------------------------------------------------------------------------------- 1 | # Tracing if resources are closed/released correctly. 2 | jvm.resource.tracing=false 3 | # for profiling 4 | jvm.safepoint.enabled=true 5 | -------------------------------------------------------------------------------- /docs/images/hello-world-fig1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/docs/images/hello-world-fig1.png -------------------------------------------------------------------------------- /docs/images/hello-world-fig2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/docs/images/hello-world-fig2.png -------------------------------------------------------------------------------- /docs/images/hello-world-fig3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/docs/images/hello-world-fig3.png -------------------------------------------------------------------------------- /event-routing/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | run.chronicle 9 | chronicle-queue-demo 10 | 1.0-SNAPSHOT 11 | ../pom.xml 12 | 13 | 14 | event-routing 15 | OpenHFT/${project.parent.artifactId}/${project.artifactId} 16 | 17 | -------------------------------------------------------------------------------- /event-routing/src/main/java/run/chronicle/routing/inout/api/Value.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.routing.inout.api; 2 | 3 | import net.openhft.chronicle.wire.SelfDescribingMarshallable; 4 | 5 | /** 6 | * Represents a simple DTO with a numeric value 'val'. 7 | * We can route these messages based on val's properties 8 | * (e.g., divisible by 3, negative, etc.). 9 | */ 10 | public class Value extends SelfDescribingMarshallable { 11 | 12 | // This is the encapsulated long value 13 | private long val; 14 | 15 | /** 16 | * This is a constructor for the Value class. 17 | * It initialises the val instance variable with the provided value. 18 | * 19 | * @param val A long value to set as the initial value for this instance 20 | */ 21 | public Value(long val) { 22 | this.val = val; 23 | } 24 | 25 | /** 26 | * Returns the numeric value of this message. 27 | */ 28 | public long val() { 29 | return val; 30 | } 31 | 32 | /** 33 | * (Optional) Allows updating the numeric value. 34 | */ 35 | public Value val(long newVal) { 36 | this.val = newVal; 37 | return this; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /event-routing/src/main/java/run/chronicle/routing/inout/api/ValueMessage.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.routing.inout.api; 2 | 3 | /** 4 | * Describes the contract for any class that handles 5 | * a 'Value' message. The system will call `value(...)` 6 | * whenever a new message is received or processed. 7 | */ 8 | public interface ValueMessage { 9 | 10 | /** 11 | * This is a method contract for sending a {@link Value} message. 12 | * Any class implementing this interface will provide its own implementation of this method. 13 | * 14 | * @param value the {@code Value} object that will be the content of the message 15 | */ 16 | void value(Value value); 17 | } 18 | -------------------------------------------------------------------------------- /event-routing/src/main/java/run/chronicle/routing/inout/api/ViaIn.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.routing.inout.api; 2 | 3 | /** 4 | * An interface for specifying a route ("via") and obtaining 5 | * an input source ("in"). 6 | * 7 | * Typically, you'd call via("someName") to define a route, 8 | * then in() to start reading from that route as a ValueMessage. 9 | * 10 | * @param the type returned by the {@code via} method 11 | * @param the type returned by the {@code in} method 12 | */ 13 | public interface ViaIn { 14 | 15 | /** 16 | * This method is expected to be implemented to provide a specific route or way. 17 | * 18 | * @param name The name of the route or way. 19 | * @return An instance of type V representing the specific route or way. 20 | */ 21 | V via(String name); 22 | 23 | /** 24 | * This method is expected to be implemented to provide an input source. 25 | * 26 | * @return An instance of type I representing the input source. 27 | */ 28 | I in(); 29 | } 30 | -------------------------------------------------------------------------------- /event-routing/src/main/java/run/chronicle/routing/inout/api/ViaOut.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.routing.inout.api; 2 | 3 | /** 4 | * An interface for specifying a route ("via") and obtaining 5 | * an output destination ("out"). 6 | * 7 | * Typically, you'd call via("someName") to define a route, 8 | * then out() to get a ValueMessage for writing messages. 9 | * 10 | * @param the type returned by the {@code via} method 11 | * @param the type returned by the {@code out} method 12 | */ 13 | public interface ViaOut { 14 | 15 | /** 16 | * This method is expected to be implemented to provide a specific route or path. 17 | * 18 | * @param name the name of the route 19 | * @return an instance of type {@code V} representing the specified route 20 | */ 21 | V via(String name); 22 | 23 | /** 24 | * This method is expected to be implemented to provide an output destination. 25 | * 26 | * @return an instance of type {@code O} representing the output destination 27 | */ 28 | O out(); 29 | } 30 | 31 | -------------------------------------------------------------------------------- /event-routing/src/main/java/run/chronicle/routing/inout/api/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Provides interfaces and classes for routing messages in and out using a Chronicle-based infrastructure. 3 | * 4 | *

This package includes:

5 | *
    6 | *
  • {@link run.chronicle.routing.inout.api.Value}: A class that encapsulates a long value, providing methods for retrieval.
  • 7 | *
  • {@link run.chronicle.routing.inout.api.ValueMessage}: An interface defining a contract for sending {@code Value} messages.
  • 8 | *
  • {@link run.chronicle.routing.inout.api.ViaIn}: An interface for specifying a route ("via") and obtaining an input source ("in").
  • 9 | *
  • {@link run.chronicle.routing.inout.api.ViaOut}: An interface for specifying a route ("via") and obtaining an output destination ("out").
  • 10 | *
11 | * 12 | *

The goal of this package is to offer a flexible and extensible means of routing messages in various formats and protocols, supporting different input/output strategies.

13 | * 14 | * @since 2023-07-29 15 | */ 16 | package run.chronicle.routing.inout.api; 17 | 18 | -------------------------------------------------------------------------------- /event-routing/src/main/java/run/chronicle/routing/inout/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package, run.chronicle.routing.inout, includes classes related to handling, routing, and processing 3 | * messages from multiple sources and routing them to multiple destinations. 4 | * 5 | *

This package includes:

6 | *
    7 | *
  • {@link run.chronicle.routing.inout.ViaThreeFive}: Routes {@link run.chronicle.routing.inout.api.ValueMessage} messages 8 | * from multiple sources to multiple destinations. Implements {@link run.chronicle.routing.inout.api.ViaIn} 9 | * and {@link run.chronicle.routing.inout.api.ValueMessage}, providing functionality for named routing paths 10 | * and handling of {@code ValueMessage} objects.
  • 11 | *
12 | * 13 | * - ViaThreeFive: A class that takes messages from multiple sources and routes them to multiple sources. 14 | * This class implements the ViaIn<ValueMessage, ValueMessage> and ValueMessage interfaces, 15 | * providing functionality for a named routing path and the handling of ValueMessage objects. 16 | * 17 | * The goal of this package is to provide an efficient and extensible framework for managing the flow of 18 | * messages in a system with multiple inputs and outputs. 19 | * 20 | * @since 2023-07-29 21 | */ 22 | package run.chronicle.routing.inout; 23 | -------------------------------------------------------------------------------- /event-routing/src/main/java/run/chronicle/routing/out/SifterImpl.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.routing.out; 2 | 3 | import run.chronicle.routing.inout.api.Value; 4 | import run.chronicle.routing.out.api.Even; 5 | import run.chronicle.routing.out.api.SifterIn; 6 | import run.chronicle.routing.out.api.SifterOut; 7 | import run.chronicle.routing.out.api.Triple; 8 | 9 | /** 10 | * SifterImpl checks if val is even or divisible by 3 (or both), 11 | * then routes to different destinations. For example: 12 | * - Even -> 'evens()' 13 | * - Multiple of 3 -> 'triples()' 14 | * 15 | * * The SifterImpl class is an implementation of the SifterIn interface. 16 | * This class implements the logic for processing a Value object. 17 | * The Value object is processed based on whether its val property is an even number or divisible by 3. 18 | */ 19 | public class SifterImpl implements SifterIn { 20 | 21 | // The SifterOut object for outputting the processed values 22 | private final SifterOut so; 23 | 24 | // Even object to process even values 25 | private final Even even = new Even(); 26 | 27 | // Triple object to process values divisible by 3 28 | private final Triple triple = new Triple(); 29 | 30 | /** 31 | * Constructor for the SifterImpl class. 32 | * This initialises the SifterOut object used for outputting the processed values. 33 | * 34 | * @param so A SifterOut object to be used for outputting the processed values 35 | */ 36 | public SifterImpl(SifterOut so) { 37 | this.so = so; 38 | } 39 | 40 | /** 41 | * Implementation of the value method from the SifterIn interface. 42 | * This method processes a Value object. 43 | * If the val property of the Value object is an even number, it is processed as an Even object. 44 | * If the val property of the Value object is divisible by 3, it is processed as a Triple object. 45 | * Regardless of the above conditions, the Value object is always output using the SifterOut object. 46 | * 47 | * @param value A Value object to be processed 48 | */ 49 | @Override 50 | public void value(Value value) { 51 | if (value.val() % 2 == 0) 52 | so.evens() 53 | .even(even.val(value.val())); 54 | if (value.val() % 3 == 0) 55 | so.triples() 56 | .triple(triple.val(value.val())); 57 | so.out().value(value); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /event-routing/src/main/java/run/chronicle/routing/out/api/AllOut.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.routing.out.api; 2 | 3 | import run.chronicle.routing.inout.api.Value; 4 | 5 | /** 6 | * This is an AllOut interface. 7 | * It provides a contract for any class that wants to send a value message using the 'value' method. 8 | * The purpose of this interface is to encapsulate the process of sending a value in a message. 9 | * The value being sent is an instance of the Value class from the run.chronicle.routing.inout.api package. 10 | */ 11 | public interface AllOut { 12 | 13 | /** 14 | * This method provides a contract for sending a Value message. 15 | * Any class implementing this interface will provide its own implementation of this method. 16 | * 17 | * @param value A Value object that will be the content of the message 18 | */ 19 | void value(Value value); 20 | } 21 | -------------------------------------------------------------------------------- /event-routing/src/main/java/run/chronicle/routing/out/api/Even.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.routing.out.api; 2 | 3 | import net.openhft.chronicle.wire.SelfDescribingMarshallable; 4 | 5 | /** 6 | * This is the Even class extending SelfDescribingMarshallable. 7 | * It encapsulates a long value providing methods for setting and retrieving this value. 8 | * The class is designed to follow the builder pattern with the 'val' method returning the current instance. 9 | */ 10 | public class Even extends SelfDescribingMarshallable { 11 | 12 | // This is the encapsulated long value 13 | private long val; 14 | 15 | /** 16 | * This is a getter for the val instance variable. 17 | * It returns the current long value of this Even object. 18 | * 19 | * @return The current long value of this Even object 20 | */ 21 | public long val() { 22 | return val; 23 | } 24 | 25 | /** 26 | * This is a setter for the val instance variable. 27 | * It sets the provided long value to the val instance variable and returns the current instance. 28 | * This method is part of the builder pattern allowing chained method calls. 29 | * 30 | * @param value The new long value to be set 31 | * @return The current instance of the Even class 32 | */ 33 | public Even val(long value) { 34 | this.val = value; 35 | return this; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /event-routing/src/main/java/run/chronicle/routing/out/api/EvenIn.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.routing.out.api; 2 | 3 | /** 4 | * This is an EvenIn interface. 5 | * It provides a contract for classes that need to process an Even object. 6 | * The purpose of this interface is to encapsulate the operation on an Even object. 7 | */ 8 | public interface EvenIn { 9 | 10 | /** 11 | * This method provides a contract for processing an Even object. 12 | * Any class implementing this interface will need to provide its own implementation of this method. 13 | * 14 | * @param even An Even object to be processed 15 | */ 16 | void even(Even even); 17 | } 18 | -------------------------------------------------------------------------------- /event-routing/src/main/java/run/chronicle/routing/out/api/SifterIn.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.routing.out.api; 2 | 3 | import run.chronicle.routing.inout.api.Value; 4 | 5 | /** 6 | * This is a SifterIn interface. 7 | * It provides a contract for any class that needs to process a Value object. 8 | * The purpose of this interface is to encapsulate the operation on a Value object. 9 | * 10 | * @since 2023-07-29 11 | */ 12 | public interface SifterIn { 13 | 14 | /** 15 | * This method provides a contract for processing a Value object. 16 | * Any class implementing this interface will provide its own implementation of this method. 17 | * 18 | * @param value A Value object to be processed 19 | */ 20 | void value(Value value); 21 | } 22 | -------------------------------------------------------------------------------- /event-routing/src/main/java/run/chronicle/routing/out/api/SifterOut.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.routing.out.api; 2 | 3 | /** 4 | * This is a SifterOut interface. 5 | * It provides a contract for classes that need to manage the output to various destinations. 6 | * It has methods for obtaining output routes for 'All', 'Even', and 'Triple' type messages. 7 | */ 8 | public interface SifterOut { 9 | 10 | /** 11 | * This method provides a contract for getting the output route for 'All' type messages. 12 | * Any class implementing this interface will provide its own implementation of this method. 13 | * 14 | * @return An AllOut object which represents the output route for 'All' type messages 15 | */ 16 | AllOut out(); 17 | 18 | /** 19 | * This method provides a contract for getting the output route for 'Even' type messages. 20 | * Any class implementing this interface will provide its own implementation of this method. 21 | * 22 | * @return An EvenIn object which represents the output route for 'Even' type messages 23 | */ 24 | EvenIn evens(); 25 | 26 | /** 27 | * This method provides a contract for getting the output route for 'Triple' type messages. 28 | * Any class implementing this interface will provide its own implementation of this method. 29 | * 30 | * @return A TripleIn object which represents the output route for 'Triple' type messages 31 | */ 32 | TripleIn triples(); 33 | } 34 | -------------------------------------------------------------------------------- /event-routing/src/main/java/run/chronicle/routing/out/api/Triple.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.routing.out.api; 2 | 3 | import net.openhft.chronicle.wire.SelfDescribingMarshallable; 4 | 5 | /** 6 | * This is the Triple class extending SelfDescribingMarshallable. 7 | * It encapsulates a long value, providing methods for setting and retrieving this value. 8 | * The class is designed to follow the builder pattern with the 'val' method returning the current instance. 9 | */ 10 | public class Triple extends SelfDescribingMarshallable { 11 | 12 | // The encapsulated long value 13 | private long val; 14 | 15 | /** 16 | * This method is a getter for the val instance variable. 17 | * It returns the current long value of this Triple object. 18 | * 19 | * @return The current long value of this Triple object 20 | */ 21 | public long val() { 22 | return val; 23 | } 24 | 25 | /** 26 | * This method is a setter for the val instance variable. 27 | * It sets the provided long value to the val instance variable and returns the current instance. 28 | * This method is part of the builder pattern allowing chained method calls. 29 | * 30 | * @param value The new long value to be set 31 | * @return The current instance of the Triple class 32 | */ 33 | public Triple val(long value) { 34 | this.val = value; 35 | return this; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /event-routing/src/main/java/run/chronicle/routing/out/api/TripleIn.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.routing.out.api; 2 | 3 | /** 4 | * This is a TripleIn interface. 5 | * It provides a contract for any class that needs to process a Triple object. 6 | * The purpose of this interface is to encapsulate the operation on a Triple object. 7 | */ 8 | public interface TripleIn { 9 | 10 | /** 11 | * This method provides a contract for processing a Triple object. 12 | * Any class implementing this interface will need to provide its own implementation of this method. 13 | * 14 | * @param triple A Triple object to be processed 15 | */ 16 | void triple(Triple triple); 17 | } 18 | -------------------------------------------------------------------------------- /event-routing/src/main/java/run/chronicle/routing/out/api/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package, run.chronicle.routing.out.api, contains interfaces and classes that facilitate 3 | * the routing and processing of messages in the output part of the system. 4 | * 5 | * This includes: 6 | * 7 | * - AllOut: An interface providing a contract for any class that wants to send a value message using the 'value' method. 8 | * - Even: A class that encapsulates a long value and provides methods for setting and retrieving this value. 9 | * - EvenIn: An interface providing a contract for classes that need to process an Even object. 10 | * - SifterIn: An interface providing a contract for any class that needs to process a Value object. 11 | * - SifterOut: An interface providing a contract for classes that manage the output to various destinations. 12 | * - Triple: A class that encapsulates a long value, providing methods for setting and retrieving this value. 13 | * - TripleIn: An interface providing a contract for any class that needs to process a Triple object. 14 | * 15 | * The goal of this package is to provide a flexible and extensible means of routing and processing messages 16 | * in the output part of the system. 17 | */ 18 | package run.chronicle.routing.out.api; 19 | -------------------------------------------------------------------------------- /event-routing/src/main/java/run/chronicle/routing/out/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package, run.chronicle.routing.out, contains classes related to the output routing functionality. 3 | *

4 | * It includes: 5 | * 6 | * - SifterImpl: A class implementing the SifterIn interface. This class processes a Value object based on 7 | * whether its 'val' property is an even number or divisible by 3. The processing logic decides how the Value 8 | * object will be routed out. 9 | *

10 | * The aim of this package is to provide classes and logic for output operations. This includes taking 11 | * the processed input data, and routing it to the appropriate channels for further use. 12 | */ 13 | package run.chronicle.routing.out; 14 | -------------------------------------------------------------------------------- /event-routing/src/test/java/run/chronicle/routing/inout/ViaThreeFiveTest.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.routing.inout; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | // ViaThreeFiveTest is a test class for testing the ViaThreeFive class. 8 | @SuppressWarnings("deprecation") 9 | public class ViaThreeFiveTest { 10 | 11 | // The `via` method is a unit test for the `via` method in the ViaThreeFive class. 12 | @Test 13 | public void via() { 14 | doTest("three-five"); 15 | } 16 | 17 | @Test 18 | public void values() { 19 | doTest("three-five-values"); 20 | } 21 | 22 | private static void doTest(String path) { 23 | // yt is an instance of YamlTester. The `runTest` method runs a test on the ViaThreeFive class with the input. 24 | final net.openhft.chronicle.wire.utils.YamlTester yt = net.openhft.chronicle.wire.utils.YamlTester.runTest(ViaThreeFive.class, path); 25 | 26 | // Asserts that the expected result is equal to the actual result. 27 | // The `replace` method replaces any occurrences of "---\n---" in the actual result with "---". 28 | assertEquals(yt.expected(), yt.actual().replace("---\n---", "---")); 29 | } 30 | } -------------------------------------------------------------------------------- /event-routing/src/test/java/run/chronicle/routing/out/SifterImplTest.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.routing.out; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | // SifterImplTest is a test class for testing the SifterImpl class. 8 | @SuppressWarnings("deprecation") 9 | public class SifterImplTest { 10 | 11 | // The `value` method is a unit test for the `value` method in the SifterImpl class. 12 | @Test 13 | public void value() { 14 | // yt is an instance of YamlTester. The `runTest` method runs a test on the SifterImpl class with the input "sifter". 15 | final net.openhft.chronicle.wire.utils.YamlTester yt = net.openhft.chronicle.wire.utils.YamlTester.runTest(SifterImpl.class, "sifter"); 16 | 17 | // Asserts that the expected result is equal to the actual result. 18 | // The `replace` method replaces any occurrences of "---\n---" in the actual result with "---". 19 | assertEquals(yt.expected(), yt.actual().replace("---\n---", "---")); 20 | } 21 | } -------------------------------------------------------------------------------- /event-routing/src/test/resources/sifter/in.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | value: { 3 | val: 1 4 | } 5 | ... 6 | --- 7 | value: { 8 | val: 2 9 | } 10 | ... 11 | --- 12 | value: { 13 | val: 3 14 | } 15 | ... 16 | --- 17 | value: { 18 | val: 4 19 | } 20 | ... 21 | --- 22 | value: { 23 | val: 5 24 | } 25 | ... 26 | --- 27 | value: { 28 | val: 6 29 | } 30 | ... 31 | --- 32 | value: { 33 | val: 15 34 | } 35 | ... 36 | -------------------------------------------------------------------------------- /event-routing/src/test/resources/sifter/out.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | out: "" 3 | value: { 4 | val: 1 5 | } 6 | ... 7 | --- 8 | evens: "" 9 | even: { 10 | val: 2 11 | } 12 | ... 13 | out: "" 14 | value: { 15 | val: 2 16 | } 17 | ... 18 | --- 19 | triples: "" 20 | triple: { 21 | val: 3 22 | } 23 | ... 24 | out: "" 25 | value: { 26 | val: 3 27 | } 28 | ... 29 | --- 30 | evens: "" 31 | even: { 32 | val: 4 33 | } 34 | ... 35 | out: "" 36 | value: { 37 | val: 4 38 | } 39 | ... 40 | --- 41 | out: "" 42 | value: { 43 | val: 5 44 | } 45 | ... 46 | --- 47 | evens: "" 48 | even: { 49 | val: 6 50 | } 51 | ... 52 | triples: "" 53 | triple: { 54 | val: 6 55 | } 56 | ... 57 | out: "" 58 | value: { 59 | val: 6 60 | } 61 | ... 62 | --- 63 | triples: "" 64 | triple: { 65 | val: 15 66 | } 67 | ... 68 | out: "" 69 | value: { 70 | val: 15 71 | } 72 | ... -------------------------------------------------------------------------------- /event-routing/src/test/resources/three-five-values/in.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: 6 -> expect route to "three" 2 | --- 3 | in: eff 4 | value: { val: 6 } 5 | ... 6 | # Scenario: 15 -> expect route to "three" and "five" 7 | --- 8 | in: eff 9 | value: { val: 15 } 10 | ... 11 | # Scenario: Negative -1 -> error 12 | --- 13 | in: eff 14 | value: { val: -1 } 15 | ... 16 | # Scenario: No match (like val=2) 17 | --- 18 | in: eff 19 | value: { val: 2 } 20 | ... 21 | -------------------------------------------------------------------------------- /event-routing/src/test/resources/three-five-values/out.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: 6 -> expect route to "three" 2 | --- 3 | out: "" 4 | value: { 5 | val: 6 6 | } 7 | ... 8 | # Scenario: 15 -> expect route to "three" and "five" 9 | --- 10 | out: "" 11 | value: { 12 | val: 15 13 | } 14 | ... 15 | # Scenario: Negative -1 -> error 16 | --- 17 | via: error 18 | value: { 19 | val: -1 20 | } 21 | ... 22 | out: "" 23 | value: { 24 | val: -1 25 | } 26 | ... 27 | # Scenario: No match (like val=2) 28 | --- 29 | out: "" 30 | value: { 31 | val: 2 32 | } 33 | ... 34 | -------------------------------------------------------------------------------- /event-routing/src/test/resources/three-five/in.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | in: "" 3 | value: { 4 | val: 0 5 | } 6 | ... 7 | --- 8 | via: aye 9 | value: { 10 | val: 1 11 | } 12 | ... 13 | --- 14 | via: bee 15 | value: { 16 | val: 2 17 | } 18 | ... 19 | --- 20 | via: cee 21 | value: { 22 | val: 3 23 | } 24 | ... 25 | --- 26 | via: dee 27 | value: { 28 | val: 4 29 | } 30 | ... 31 | --- 32 | via: ee 33 | value: { 34 | val: 5 35 | } 36 | ... 37 | --- 38 | via: eff 39 | value: { 40 | val: 6 41 | } 42 | ... 43 | --- 44 | via: oh 45 | value: { 46 | val: 15 47 | } 48 | ... 49 | -------------------------------------------------------------------------------- /event-routing/src/test/resources/three-five/out.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | out: "" 3 | value: { 4 | val: 0 5 | } 6 | ... 7 | --- 8 | out: "" 9 | value: { 10 | val: 1 11 | } 12 | ... 13 | --- 14 | out: "" 15 | value: { 16 | val: 2 17 | } 18 | ... 19 | --- 20 | via: three 21 | value: { 22 | val: 3 23 | } 24 | ... 25 | out: "" 26 | value: { 27 | val: 3 28 | } 29 | ... 30 | --- 31 | out: "" 32 | value: { 33 | val: 4 34 | } 35 | ... 36 | --- 37 | via: five 38 | value: { 39 | val: 5 40 | } 41 | ... 42 | out: "" 43 | value: { 44 | val: 5 45 | } 46 | ... 47 | --- 48 | via: three 49 | value: { 50 | val: 6 51 | } 52 | ... 53 | out: "" 54 | value: { 55 | val: 6 56 | } 57 | ... 58 | --- 59 | out: "" 60 | value: { 61 | val: 15 62 | } 63 | ... -------------------------------------------------------------------------------- /hello-world/src/main/hello-world-requirements.adoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/hello-world/src/main/hello-world-requirements.adoc -------------------------------------------------------------------------------- /hello-world/src/main/java/event/driven/program/AddsExclamation.java: -------------------------------------------------------------------------------- 1 | package event.driven.program; 2 | 3 | import event.driven.program.api.Says; 4 | 5 | /** 6 | * This is an AddsExclamation class implementing the {@link Says} interface. 7 | * It decorates a given {@link Says} object, adding an exclamation mark to the end of each input message before delegating the call. 8 | */ 9 | public class AddsExclamation implements Says { 10 | // The Says object to which the decorated calls will be delegated. 11 | private final Says out; 12 | 13 | /** 14 | * Constructs a new AddsExclamation object that decorates the given Says object. 15 | * 16 | * @param out the original Says object to be decorated 17 | */ 18 | public AddsExclamation(Says out) { 19 | this.out = out; 20 | } 21 | 22 | /** 23 | * Says the given words with an added exclamation mark at the end. 24 | * It adds the exclamation mark to the words and delegates the call to the original Says object. 25 | * 26 | * @param words The text to be spoken, with an added exclamation mark. 27 | */ 28 | public void say(String words) { 29 | // Adds an exclamation mark before delegating the call 30 | this.out.say(words + "!"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /hello-world/src/main/java/event/driven/program/DirectWithExclamationMain.java: -------------------------------------------------------------------------------- 1 | package event.driven.program; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * This is a DirectWithExclamationMain class. 7 | * It reads lines of text from the standard input, adds an exclamation mark to the end of each line, and then prints the result to the console. 8 | * This class leverages the {@link AddsExclamation} and {@link SaysOutput} implementations to achieve this functionality. 9 | */ 10 | public class DirectWithExclamationMain { 11 | /** 12 | * This method creates a new {@link AddsExclamation} object that wraps a {@link SaysOutput} object. 13 | * It will add an exclamation mark to the end of each input message and then print the result to the console. 14 | * This behavior is orchestrated by the {@link SaysInput} class, which reads the input and forwards it to the given {@link SaysInput} implementation. 15 | * 16 | * @param args Command-line arguments, not used in this implementation. 17 | * @throws IOException If an I/O error occurs while reading from the standard input. 18 | */ 19 | public static void main(String[] args) throws IOException { 20 | // Create a new AddsExclamation object that wraps a SaysOutput object. 21 | // This will add an exclamation mark to the end of each input message, 22 | // and then print the result to the console. 23 | SaysInput.input(new AddsExclamation(new SaysOutput())); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /hello-world/src/main/java/event/driven/program/RecordInputAsYamlMain.java: -------------------------------------------------------------------------------- 1 | package event.driven.program; 2 | 3 | import event.driven.program.api.Says; 4 | import net.openhft.chronicle.wire.Wires; 5 | 6 | import java.io.IOException; 7 | 8 | /** 9 | * This is a RecordInputAsYamlMain class. 10 | * It reads lines of text from the standard input and forwards them to a YAML-formatted logger, which writes the interactions to the console. 11 | * This class leverages the {@link Wires} utility class to create a proxy that records method calls in YAML format. 12 | */ 13 | public class RecordInputAsYamlMain { 14 | /** 15 | * This method obtains a proxy of the {@link Says} interface that writes method calls and their arguments in YAML format 16 | * to the given PrintStream (in this case, standard output). It takes each line of input from the user and calls the {@code say} method 17 | * each time, allowing the says proxy to log the call in YAML format. 18 | * 19 | * @param args Command-line arguments, not used in this implementation. 20 | * @throws IOException If an I/O error occurs while reading from the standard input. 21 | */ 22 | public static void main(String[] args) throws IOException { 23 | // Obtains a proxy of the Says interface that writes method calls and their arguments 24 | // in YAML format to the given PrintStream (in this case, standard output). 25 | final Says says = Wires.recordAsYaml(Says.class, System.out); 26 | 27 | // Takes each line of input from the user and calls the say(theLine) method each time, 28 | // allowing the says proxy to log the call in YAML format. 29 | SaysInput.input(says); 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /hello-world/src/main/java/event/driven/program/RecordInputToConsoleMain.java: -------------------------------------------------------------------------------- 1 | package event.driven.program; 2 | 3 | import event.driven.program.api.Says; 4 | 5 | import java.io.IOException; 6 | 7 | /** 8 | * This is a RecordInputToConsoleMain class. 9 | * It reads lines of text from the standard input and forwards them to the {@link SaysOutput} class, which prints them to the console. 10 | */ 11 | public class RecordInputToConsoleMain { 12 | /** 13 | * This method creates a new {@link SaysOutput} object that writes text to the console in each call to the {@code say} method. 14 | * It utilizes the {@link SaysInput} class to take each line of input from the user and calls the {@code say} method on the {@link Says} object each time. 15 | * In this instance, the {@link Says} object is configured to write directly to the console. 16 | * 17 | * @param args Command-line arguments, not used in this implementation. 18 | * @throws IOException If an I/O error occurs while reading from the standard input. 19 | */ 20 | public static void main(String[] args) throws IOException { 21 | // Creates a new SaysOutput object that writes text to the console 22 | // in each call to the say(line) method. 23 | final Says says = new SaysOutput(); 24 | 25 | // Utilizes the SaysInput class to take each line of input from the user 26 | // and calls the say(line) method on the Says object each time. 27 | // In this instance, the Says object is configured to write directly to the console. 28 | SaysInput.input(says); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /hello-world/src/main/java/event/driven/program/ReplayOutputMain.java: -------------------------------------------------------------------------------- 1 | package event.driven.program; 2 | 3 | import net.openhft.chronicle.wire.Wires; 4 | 5 | import java.io.IOException; 6 | 7 | /** 8 | * This is a ReplayOutputMain class. 9 | * It reads the content of a specified YAML file and replays it using the {@link SaysOutput} class, printing the interactions to the console. 10 | */ 11 | public class ReplayOutputMain { 12 | /** 13 | * This method reads the content of a YAML file specified by the first command-line argument (args[0]) 14 | * and feeds it to a {@link SaysOutput} object, which handles printing the text to the console. 15 | * By doing so, it effectively replays the interactions stored in the YAML file. 16 | * 17 | * @param args Command-line arguments, where the first argument specifies the path to the YAML file. 18 | * @throws IOException If an I/O error occurs while reading the YAML file. 19 | */ 20 | public static void main(String[] args) throws IOException { 21 | // Reads the content of a YAML file specified by the first command-line argument (args[0]) 22 | // and feeds it to the SaysOutput object, effectively replaying the interactions stored in the YAML file. 23 | Wires.replay(args[0], new SaysOutput()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /hello-world/src/main/java/event/driven/program/SaysInput.java: -------------------------------------------------------------------------------- 1 | package event.driven.program; 2 | 3 | import event.driven.program.api.Says; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.IOException; 7 | import java.io.InputStreamReader; 8 | 9 | /** 10 | * This is a SaysInput class. 11 | * It provides a static method to read text lines from the standard input and forward them to a provided {@link Says} implementation. 12 | */ 13 | public class SaysInput { 14 | 15 | /** 16 | * This method reads text lines from the standard input and calls the {@code say} method of the provided {@link Says} object for each line. 17 | * It continues reading and processing lines until the end of the input is reached (i.e., the input returns {@code null}). 18 | * 19 | * @param says An implementation of the {@link Says} interface that will handle the lines of text read from the input. 20 | * @throws IOException If an I/O error occurs while reading from the input. 21 | */ 22 | public static void input(Says says) throws IOException { 23 | // Creates a BufferedReader to read lines from the standard input 24 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 25 | // Continuously reads lines from the standard input until reaching the end 26 | for (String line; ((line = br.readLine()) != null); ) 27 | // Calls the say method of the provided Says object with the read line 28 | says.say(line); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /hello-world/src/main/java/event/driven/program/SaysOutput.java: -------------------------------------------------------------------------------- 1 | package event.driven.program; 2 | 3 | import event.driven.program.api.Says; 4 | 5 | /** 6 | * This is a SaysOutput class. 7 | * It provides an implementation of the {@link Says} interface that outputs the given words directly to the standard output. 8 | */ 9 | public class SaysOutput implements Says { 10 | 11 | /** 12 | * This method implements the {@code say} method of the {@link Says} interface. 13 | * It takes a string of words and prints them directly to the standard output. 14 | * 15 | * @param words The words to be printed to the standard output. 16 | */ 17 | public void say(String words) { 18 | // Prints the given words directly to the standard output 19 | System.out.println(words); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /hello-world/src/main/java/event/driven/program/api/Says.java: -------------------------------------------------------------------------------- 1 | package event.driven.program.api; 2 | 3 | /** 4 | * This is a Says interface. 5 | * It defines a contract for classes that need to handle speaking or outputting words. 6 | * Implementations of this interface are responsible for determining how the words are said or output. 7 | */ 8 | public interface Says { 9 | 10 | /** 11 | * This method is expected to be implemented to say or output the given words. 12 | * The specific behavior of how the words are said or output depends on the implementing class. 13 | * 14 | * @param words The text to be said or output. 15 | */ 16 | void say(String words); 17 | } -------------------------------------------------------------------------------- /hello-world/src/main/java/event/driven/program/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package contains classes and interfaces related to an event-driven programming model. 3 | * Event-driven programming is a paradigm in which the flow of the program is determined by events, 4 | * such as user actions, sensor outputs, or messages from other programs or threads. 5 | * 6 | *

Classes in this package may define specific events, listeners, and mechanisms to handle events 7 | * within an application. Implementations can vary widely depending on the requirements of the system. 8 | */ 9 | package event.driven.program; 10 | -------------------------------------------------------------------------------- /hello-world/src/main/resources/says.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | say: One 3 | ... 4 | --- 5 | say: Two 6 | ... 7 | --- 8 | say: Three 9 | ... 10 | 11 | -------------------------------------------------------------------------------- /hello-world/src/test/java/event/driven/program/AddsExclamationTest.java: -------------------------------------------------------------------------------- 1 | package event.driven.program; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | @SuppressWarnings("deprecation") 8 | public class AddsExclamationTest { 9 | // Test method for the 'say' functionality in the AddsExclamation class 10 | @Test 11 | public void say() { 12 | // Create a YamlTester object by running a test on AddsExclamation class with the provided data file 'says' 13 | net.openhft.chronicle.wire.utils.YamlTester yt = net.openhft.chronicle.wire.utils.YamlTester.runTest(AddsExclamation.class, "says"); 14 | 15 | // Assert that the expected value matches the actual value returned by the 'say' method 16 | assertEquals(yt.expected(), yt.actual()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /hello-world/src/test/resources/says/in.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | say: One 3 | ... 4 | --- 5 | say: Two 6 | ... 7 | --- 8 | say: Three 9 | ... -------------------------------------------------------------------------------- /hello-world/src/test/resources/says/out.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | say: One! 3 | ... 4 | --- 5 | say: Two! 6 | ... 7 | --- 8 | say: Three! 9 | ... -------------------------------------------------------------------------------- /images/AddJDK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/images/AddJDK.png -------------------------------------------------------------------------------- /images/Clone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/images/Clone.png -------------------------------------------------------------------------------- /images/JDKhome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/images/JDKhome.png -------------------------------------------------------------------------------- /images/OutputMain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/images/OutputMain.png -------------------------------------------------------------------------------- /images/Two-hop-latency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/images/Two-hop-latency.png -------------------------------------------------------------------------------- /images/directory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/images/directory.png -------------------------------------------------------------------------------- /images/gitpack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/images/gitpack.png -------------------------------------------------------------------------------- /images/homegit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/images/homegit.png -------------------------------------------------------------------------------- /images/lotsafiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/images/lotsafiles.png -------------------------------------------------------------------------------- /images/queue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/images/queue.png -------------------------------------------------------------------------------- /images/runin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/images/runin.png -------------------------------------------------------------------------------- /images/runout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/images/runout.png -------------------------------------------------------------------------------- /images/sayhello.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/images/sayhello.png -------------------------------------------------------------------------------- /images/setJDK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Queue-Demo/9c63d74b63ac47a74a33df11ff8763d266441de0/images/setJDK.png -------------------------------------------------------------------------------- /md-pipeline/README.adoc: -------------------------------------------------------------------------------- 1 | = Chronicle-Queue-Sample 2 | :imagesdir: ../images 3 | 4 | == Market Data Pipeline 5 | 6 | This example is code for the article link:https://chronicle.software/unix-philosophy-for-low-latency[The Unix Philosophy for Low Latency] 7 | 8 | === To run 9 | 10 | Start up three terminal screens and run the the following in the `md-pipeline` directory to start the services 11 | 12 | ``` 13 | mvn exec:java@generate 14 | ``` 15 | 16 | ``` 17 | mvn exec:java@aggregator 18 | ``` 19 | 20 | ``` 21 | mvn exec:java@strategy 22 | ``` 23 | 24 | And to watch the output from each service start up three more screens 25 | 26 | ``` 27 | mvn exec:java@tailf -Dqueue=agg-in 28 | ``` 29 | 30 | ``` 31 | mvn exec:java@tailf -Dqueue=agg-out 32 | ``` 33 | 34 | ``` 35 | mvn exec:java@tailf -Dqueue=strat-out 36 | ``` 37 | 38 | -------------------------------------------------------------------------------- /md-pipeline/src/main/java/org/trading/AggregatorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Chronicle Software Ltd 3 | */ 4 | 5 | package org.trading; 6 | 7 | import org.trading.api.AggregatorIn; 8 | import org.trading.api.AggregatorOut; 9 | import org.trading.dto.BuySell; 10 | import org.trading.dto.MarketDataIncrement; 11 | import org.trading.dto.MarketDataSnapshot; 12 | 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | /** 17 | * This is an implementation of the AggregatorIn interface, known as AggregatorImpl. 18 | * It maintains a map of market data snapshots and interfaces with an AggregatorOut object 19 | * to process and handle aggregated market data. 20 | */ 21 | public class AggregatorImpl implements AggregatorIn { 22 | 23 | // A map holding market data snapshots, keyed by a long identifier 24 | private final Map md = new HashMap<>(); 25 | 26 | // The output interface for handling aggregated data 27 | private final AggregatorOut out; 28 | 29 | /** 30 | * Constructor for the AggregatorImpl class. 31 | * Initialises the AggregatorOut instance for output handling. 32 | * 33 | * @param out An implementation of the AggregatorOut interface for handling aggregated data 34 | */ 35 | public AggregatorImpl(AggregatorOut out) { 36 | this.out = out; 37 | } 38 | 39 | /** 40 | * The main method to start the AggregatorImpl. 41 | * Invokes the Runner class to run the aggregator with specific input and output channels. 42 | * 43 | * @param args Command-line arguments (not used in this implementation) 44 | */ 45 | public static void main(String[] args) { 46 | Runner.run("agg-in", "agg-out", AggregatorOut.class, AggregatorImpl::new); 47 | } 48 | 49 | @Override 50 | public void mdi(MarketDataIncrement mdi) { 51 | MarketDataSnapshot aggregated = md.computeIfAbsent(mdi.symbol(), MarketDataSnapshot::new); 52 | // trivially simple aggregation and book build 53 | if (mdi.side() == BuySell.buy) 54 | aggregated.bid(mdi.price()); 55 | else 56 | aggregated.ask(mdi.price()); 57 | aggregated.transactTime(mdi.transactTime()); 58 | if (aggregated.valid()) 59 | out.marketDataSnapshot(aggregated); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /md-pipeline/src/main/java/org/trading/OMSImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Chronicle Software Ltd 3 | */ 4 | 5 | package org.trading; 6 | 7 | import org.trading.api.OMSIn; 8 | import org.trading.api.OMSOut; 9 | import org.trading.dto.NewOrderSingle; 10 | 11 | /** 12 | * This is the OMSImpl class, which implements the OMSIn interface. 13 | * It represents the core functionality of an Order Management System (OMS) and provides the methods for interacting with the OMS. 14 | */ 15 | public class OMSImpl implements OMSIn { 16 | 17 | // This is the output interface for the OMS 18 | private final OMSOut out; 19 | 20 | /** 21 | * This is the constructor for the OMSImpl class. 22 | * It initialises the out instance variable with the provided OMSOut object. 23 | * 24 | * @param out An instance of the OMSOut interface that will handle the output of the OMS. 25 | */ 26 | public OMSImpl(OMSOut out) { 27 | this.out = out; 28 | } 29 | 30 | /** 31 | * This is the main method for the OMSImpl class. 32 | * It sets up the system and initialises the necessary components for running the OMS. 33 | * 34 | * @param args Command-line arguments (not used in this implementation) 35 | */ 36 | public static void main(String[] args) { 37 | // Running the system with the specified input and output channels and the provided OMSOut class 38 | Runner.run("strat-out", "oms-out", OMSOut.class, OMSImpl::new); 39 | } 40 | 41 | @Override 42 | public void newOrderSingle(NewOrderSingle nos) { 43 | System.out.println("I got an order! " + nos); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /md-pipeline/src/main/java/org/trading/Runner.java: -------------------------------------------------------------------------------- 1 | package org.trading; 2 | 3 | import net.openhft.chronicle.bytes.MethodReader; 4 | import net.openhft.chronicle.core.Jvm; 5 | import net.openhft.chronicle.queue.ChronicleQueue; 6 | import net.openhft.chronicle.queue.impl.single.SingleChronicleQueueBuilder; 7 | 8 | import java.util.function.Function; 9 | 10 | /** 11 | * This is the Runner class, responsible for setting up and running a microservice that listens and outputs to specific queues. 12 | */ 13 | public class Runner { 14 | 15 | /** 16 | * Start up and run a microservice listening to a specified input queue {@code inq} and outputting to a specified output queue {@code outq} 17 | */ 18 | static void run(String inq, String outq, Class mwClass, Function serviceVendor) { 19 | try (ChronicleQueue in = SingleChronicleQueueBuilder.binary(inq).build(); 20 | ChronicleQueue out = SingleChronicleQueueBuilder.binary(outq).build()) { 21 | 22 | // Create a Chronicle Wire method writer such that when the service calls a method on 23 | // the "out" method writer, the method call is serialised and written to the out queue 24 | T mw = out.createAppender().methodWriter(mwClass); 25 | Object service = serviceVendor.apply(mw); 26 | 27 | // Create a method reader to read in the in queue for any and all methods implemented by the service 28 | MethodReader mr = in.createTailer().toEnd().methodReader(service); 29 | while (!Thread.currentThread().isInterrupted()) { 30 | // and dispatch these events to the service 31 | if (!mr.readOne()) 32 | Jvm.pause(10); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /md-pipeline/src/main/java/org/trading/StrategyImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Chronicle Software Ltd 3 | */ 4 | 5 | package org.trading; 6 | 7 | import org.trading.api.AggregatorOut; 8 | import org.trading.api.OMSIn; 9 | import org.trading.dto.BuySell; 10 | import org.trading.dto.MarketDataSnapshot; 11 | import org.trading.dto.NewOrderSingle; 12 | 13 | /** 14 | * This is the StrategyImpl class, implementing the {@link AggregatorOut} interface. 15 | * It encapsulates the strategy logic and communicates with the Order Management System (OMS) input interface. 16 | */ 17 | public class StrategyImpl implements AggregatorOut { 18 | private final OMSIn out; // The output interface for OMS 19 | private final NewOrderSingle nos; // Object representing a new order 20 | private int clordId; // The client order ID 21 | 22 | /** 23 | * Constructor for the StrategyImpl class. 24 | * It initialises the output interface for OMS and a new order object. 25 | * 26 | * @param out An instance of {@link OMSIn} to be used for communication with the OMS 27 | */ 28 | public StrategyImpl(OMSIn out) { 29 | this.out = out; 30 | this.nos = new NewOrderSingle(); 31 | } 32 | 33 | /** 34 | * Main method to start the Strategy implementation. 35 | * It calls the {@link Runner} class to run the microservice, listening and outputting to specific queues. 36 | * 37 | * @param args Command-line arguments (unused) 38 | */ 39 | public static void main(String[] args) { 40 | Runner.run("agg-out", "strat-out", OMSIn.class, StrategyImpl::new); 41 | } 42 | 43 | @Override 44 | public void marketDataSnapshot(MarketDataSnapshot mds) { 45 | if (mds.spread() < 1) 46 | out.newOrderSingle(sellAtAsk(mds)); 47 | } 48 | 49 | private NewOrderSingle sellAtAsk(MarketDataSnapshot mds) { 50 | nos.clOrdID(Integer.toString(clordId++)) 51 | .transactTime(mds.transactTime()) 52 | .symbol(mds.symbol()) 53 | .orderQty(10_000) 54 | .price(mds.ask()) 55 | .side(BuySell.sell); 56 | return nos; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /md-pipeline/src/main/java/org/trading/api/AggregatorIn.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Chronicle Software Ltd 3 | */ 4 | 5 | package org.trading.api; 6 | 7 | import org.trading.dto.MarketDataIncrement; 8 | 9 | /** 10 | * This is the {@code AggregatorIn} interface, which defines a contract for handling incoming market data increments (MDI). 11 | * 12 | * Implementing classes should provide a concrete implementation for processing the market data increments. 13 | */ 14 | public interface AggregatorIn { 15 | 16 | /** 17 | * This method handles the provided {@link MarketDataIncrement} object, typically processing or forwarding the increment. 18 | * 19 | * @param mdi A {@link MarketDataIncrement} object representing a market data increment to be handled. 20 | */ 21 | void mdi(MarketDataIncrement mdi); 22 | } 23 | -------------------------------------------------------------------------------- /md-pipeline/src/main/java/org/trading/api/AggregatorOut.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Chronicle Software Ltd 3 | */ 4 | 5 | package org.trading.api; 6 | 7 | import org.trading.dto.MarketDataSnapshot; 8 | 9 | /** 10 | * This is the {@code AggregatorOut} interface, which defines a contract for handling outgoing market data snapshots (MDS). 11 | * 12 | * Implementing classes should provide a concrete implementation for processing or forwarding the market data snapshots. 13 | */ 14 | public interface AggregatorOut { 15 | 16 | /** 17 | * This method handles the provided {@link MarketDataSnapshot} object, typically processing or forwarding the snapshot. 18 | * 19 | * @param mds A {@link MarketDataSnapshot} object representing a market data snapshot to be handled. 20 | */ 21 | void marketDataSnapshot(MarketDataSnapshot mds); 22 | } 23 | -------------------------------------------------------------------------------- /md-pipeline/src/main/java/org/trading/api/All.java: -------------------------------------------------------------------------------- 1 | package org.trading.api; 2 | 3 | /** 4 | * Convenience interface for {@code ChronicleReaderMain} to include all interfaces. 5 | */ 6 | public interface All extends AggregatorIn, AggregatorOut, OMSIn { 7 | } 8 | -------------------------------------------------------------------------------- /md-pipeline/src/main/java/org/trading/api/OMSIn.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Chronicle Software Ltd 3 | */ 4 | 5 | package org.trading.api; 6 | 7 | import org.trading.dto.NewOrderSingle; 8 | 9 | /** 10 | * This is the {@code OMSIn} interface, defining a contract for receiving and handling new single orders within the Order Management System (OMS). 11 | * 12 | * Implementing classes should provide a concrete implementation for processing or forwarding the new single order messages. 13 | */ 14 | public interface OMSIn { 15 | 16 | /** 17 | * This method handles the provided {@link NewOrderSingle} object, typically processing or forwarding the new single order. 18 | * 19 | * @param nos A {@link NewOrderSingle} object representing a new single order to be handled. 20 | */ 21 | void newOrderSingle(NewOrderSingle nos); 22 | } 23 | -------------------------------------------------------------------------------- /md-pipeline/src/main/java/org/trading/api/OMSOut.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Chronicle Software Ltd 3 | */ 4 | 5 | package org.trading.api; 6 | 7 | public interface OMSOut { 8 | // TODO: xxxxx 9 | } 10 | -------------------------------------------------------------------------------- /md-pipeline/src/main/java/org/trading/api/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The {@code org.trading.api} package contains interfaces that define the contracts 3 | * for various components of the trading system. These interfaces facilitate communication 4 | * between different parts of the system such as the Order Management System (OMS), aggregators, 5 | * strategies, and exchange simulators. 6 | */ 7 | package org.trading.api; 8 | -------------------------------------------------------------------------------- /md-pipeline/src/main/java/org/trading/dto/BuySell.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Chronicle Software Ltd 3 | */ 4 | 5 | package org.trading.dto; 6 | 7 | /** 8 | * This is a BuySell enumeration representing the two possible sides of a trading order: Buy or Sell. 9 | * Each side is associated with a direction, with Buy being -1 and Sell being +1. 10 | */ 11 | public enum BuySell { 12 | // Buy side of the trade, represented with a direction of -1 13 | buy(-1), 14 | 15 | // Sell side of the trade, represented with a direction of +1 16 | sell(+1); 17 | 18 | // The direction associated with the side of the trade 19 | public final int direction; 20 | 21 | /** 22 | * Constructor for the BuySell enumeration, initializing the direction. 23 | * 24 | * @param direction An int representing the direction of the trade, where -1 is Buy and +1 is Sell 25 | */ 26 | BuySell(int direction) { 27 | this.direction = direction; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /md-pipeline/src/main/java/org/trading/dto/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package contains classes and enumerations related to trading data transfer objects (DTOs). 3 | * It encapsulates various aspects of the trading domain, such as orders, market data, and related structures. 4 | */ 5 | package org.trading.dto; 6 | -------------------------------------------------------------------------------- /md-pipeline/src/main/java/org/trading/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The {@code org.trading} package contains classes and interfaces related to trading functionalities, 3 | * including order management, aggregation, market data handling, and various trading strategies. 4 | */ 5 | package org.trading; 6 | -------------------------------------------------------------------------------- /md-pipeline/src/test/java/org/trading/AggregatorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Chronicle Software Ltd 3 | */ 4 | 5 | package org.trading; 6 | 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | 11 | @SuppressWarnings("deprecation") 12 | public class AggregatorTest { 13 | public static void runTest(String path) { 14 | // Runs the test using the YamlTester against the AggregatorImpl class, passing the path to the YAML file 15 | net.openhft.chronicle.wire.utils.YamlTester yt = net.openhft.chronicle.wire.utils.YamlTester.runTest(AggregatorImpl.class, path); 16 | // Asserts that the expected state defined in the YAML file matches the actual state obtained from running the test 17 | assertEquals(yt.expected(), yt.actual()); 18 | } 19 | 20 | @Test 21 | public void strategy() { 22 | // Running the test case defined in the "aggregator" YAML file 23 | runTest("aggregator"); 24 | } 25 | } -------------------------------------------------------------------------------- /md-pipeline/src/test/java/org/trading/StrategyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Chronicle Software Ltd 3 | */ 4 | 5 | package org.trading; 6 | 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | 11 | @SuppressWarnings("deprecation") 12 | public class StrategyTest { 13 | public static void runTest(String path) { 14 | // Runs the test using the YamlTester against the StrategyImpl class, passing the path to the YAML file 15 | net.openhft.chronicle.wire.utils.YamlTester yt = net.openhft.chronicle.wire.utils.YamlTester.runTest(StrategyImpl.class, path); 16 | // Asserts that the expected state defined in the YAML file matches the actual state obtained from running the test 17 | assertEquals(yt.expected(), yt.actual()); 18 | } 19 | 20 | @Test 21 | public void strategy() { 22 | // Running the test case defined in the "strategy" YAML file 23 | runTest("strategy"); 24 | } 25 | } -------------------------------------------------------------------------------- /md-pipeline/src/test/resources/aggregator/in.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | mdi: { 3 | symbol: BTCUSD, 4 | transactTime: 2019-12-03T09:54:37.345678, 5 | rate: 23418.5, 6 | side: buy 7 | } 8 | --- 9 | mdi: { 10 | symbol: BTCUSD, 11 | transactTime: 2019-12-03T09:54:38, 12 | rate: 23419.5, 13 | side: sell 14 | } 15 | -------------------------------------------------------------------------------- /md-pipeline/src/test/resources/aggregator/out.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | marketDataSnapshot: { 4 | symbol: BTCUSD, 5 | transactTime: 2019-12-03T09:54:38, 6 | bid: 23418.5, 7 | ask: 23419.5 8 | } 9 | ... -------------------------------------------------------------------------------- /md-pipeline/src/test/resources/strategy/in.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | marketDataSnapshot: { 3 | symbol: BTCUSD, 4 | transactTime: 2019-12-03T09:54:37.345678, 5 | bid: 23418.5, 6 | ask: 23420.1 7 | } 8 | --- 9 | marketDataSnapshot: { 10 | symbol: BTCUSD, 11 | transactTime: 2019-12-03T09:54:38, 12 | bid: 23419.01, 13 | ask: 23420.0 14 | } 15 | -------------------------------------------------------------------------------- /md-pipeline/src/test/resources/strategy/out.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | newOrderSingle: { 4 | symbol: BTCUSD, 5 | transactTime: 2019-12-03T09:54:38, 6 | orderQty: 10E3, 7 | price: 23420.0, 8 | side: sell, 9 | clOrdID: "0" 10 | } 11 | ... -------------------------------------------------------------------------------- /message-history-demo/src/main/java/town/lost/processor/events/AbstractEvent.java: -------------------------------------------------------------------------------- 1 | package town.lost.processor.events; 2 | 3 | import net.openhft.chronicle.wire.SelfDescribingMarshallable; 4 | import net.openhft.chronicle.wire.converter.NanoTime; 5 | 6 | @SuppressWarnings("unchecked") 7 | public class AbstractEvent> extends SelfDescribingMarshallable { 8 | private String eventSource; 9 | 10 | @NanoTime 11 | private long eventTimeStamp; 12 | 13 | public String eventSource() { 14 | return eventSource; 15 | } 16 | 17 | public E eventSource(String eventSource) { 18 | this.eventSource = eventSource; 19 | return (E) this; 20 | } 21 | 22 | public long eventTimeStamp() { 23 | return eventTimeStamp; 24 | } 25 | 26 | public E eventTimeStamp(long eventTimeStamp) { 27 | this.eventTimeStamp = eventTimeStamp; 28 | return (E) this; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /message-history-demo/src/main/java/town/lost/processor/events/BridgeMain.java: -------------------------------------------------------------------------------- 1 | package town.lost.processor.events; 2 | 3 | import net.openhft.chronicle.bytes.MethodReader; 4 | import net.openhft.chronicle.core.io.IOTools; 5 | import net.openhft.chronicle.queue.ChronicleQueue; 6 | 7 | public class BridgeMain { 8 | static boolean running = true; 9 | 10 | public static void main(String[] args) { 11 | IOTools.deleteDirWithFiles("in", 2); 12 | IOTools.deleteDirWithFiles("out", 2); 13 | 14 | long events = 0, lastPrint = 0; 15 | try (ChronicleQueue queue = ChronicleQueue.singleBuilder("in").sourceId(1).build()) { 16 | try (ChronicleQueue queue2 = ChronicleQueue.singleBuilder("out").sourceId(2).build()) { 17 | 18 | Events out = queue2.methodWriterBuilder(Events.class).build(); 19 | Events bridge = new BridgeEvents(out); 20 | MethodReader methodReader = queue.createTailer("bridge") 21 | .methodReader(bridge); 22 | System.out.println("Started"); 23 | long last = 0; 24 | while (running) { 25 | if (methodReader.readOne()) { 26 | events++; 27 | } else { 28 | long now = System.currentTimeMillis(); 29 | if (lastPrint != events && now > last + 250) { 30 | System.out.println("events: " + events); 31 | lastPrint = events; 32 | last = now; 33 | } else { 34 | Thread.yield(); 35 | } 36 | } 37 | } 38 | } 39 | } 40 | System.out.println("... finished"); 41 | } 42 | } 43 | 44 | class BridgeEvents implements Events { 45 | final Events out; 46 | 47 | public BridgeEvents(Events out) { 48 | this.out = out; 49 | } 50 | 51 | @Override 52 | public void eventOne(EventOne one) { 53 | out.eventOne(one); 54 | if (one.text().equalsIgnoreCase("Bye")) 55 | BridgeMain.running = false; 56 | } 57 | 58 | @Override 59 | public void eventTwo(EventTwo two) { 60 | out.eventTwo(two); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /message-history-demo/src/main/java/town/lost/processor/events/DumpDecodedMain.java: -------------------------------------------------------------------------------- 1 | package town.lost.processor.events; 2 | 3 | import net.openhft.chronicle.bytes.MethodReader; 4 | import net.openhft.chronicle.queue.ChronicleQueue; 5 | import net.openhft.chronicle.wire.MessageHistory; 6 | import net.openhft.chronicle.wire.MicroTimestampLongConverter; 7 | 8 | public class DumpDecodedMain { 9 | public static void main(String[] args) { 10 | try (ChronicleQueue queue2 = ChronicleQueue.singleBuilder("out").sourceId(2).build()) { 11 | long last = Long.MAX_VALUE / 2; 12 | MethodReader methodReader = queue2.createTailer("dump") 13 | .methodReader(new EventHandler()); 14 | System.out.println("Started"); 15 | while (true) { 16 | long now = System.currentTimeMillis(); 17 | if (methodReader.readOne()) { 18 | last = now; 19 | } else { 20 | // stop if nothing for 2.5 seconds. 21 | if (now > last + 2500) 22 | break; 23 | Thread.yield(); 24 | } 25 | } 26 | } 27 | System.out.println(".. Finished"); 28 | System.exit(0); 29 | } 30 | 31 | private static class EventHandler implements Events { 32 | @Override 33 | public void eventOne(EventOne one) { 34 | printMessageHistory("eventOne", one); 35 | // use EventOne here 36 | } 37 | 38 | @Override 39 | public void eventTwo(EventTwo two) { 40 | printMessageHistory("eventTwo", two); 41 | // use EventTwo here 42 | } 43 | 44 | private void printMessageHistory(String eventName, AbstractEvent event) { 45 | MessageHistory mh = MessageHistory.get(); 46 | System.out.println(mh + " - " + eventName + ", source: " + event.eventSource() + ", ts: " + MicroTimestampLongConverter.INSTANCE.asString(event.eventTimeStamp())); 47 | System.out.println(event); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /message-history-demo/src/main/java/town/lost/processor/events/EventOne.java: -------------------------------------------------------------------------------- 1 | package town.lost.processor.events; 2 | 3 | public class EventOne extends AbstractEvent { 4 | String text; 5 | 6 | public String text() { 7 | return text; 8 | } 9 | 10 | public EventOne text(String text) { 11 | this.text = text; 12 | return this; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /message-history-demo/src/main/java/town/lost/processor/events/EventTwo.java: -------------------------------------------------------------------------------- 1 | package town.lost.processor.events; 2 | 3 | public class EventTwo extends AbstractEvent { 4 | String symbol; 5 | double price; 6 | double quantiity; 7 | 8 | public String symbol() { 9 | return symbol; 10 | } 11 | 12 | public EventTwo symbol(String symbol) { 13 | this.symbol = symbol; 14 | return this; 15 | } 16 | 17 | public double price() { 18 | return price; 19 | } 20 | 21 | public EventTwo price(double price) { 22 | this.price = price; 23 | return this; 24 | } 25 | 26 | public double quantiity() { 27 | return quantiity; 28 | } 29 | 30 | public EventTwo quantiity(double quantiity) { 31 | this.quantiity = quantiity; 32 | return this; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /message-history-demo/src/main/java/town/lost/processor/events/EventWithHistory.java: -------------------------------------------------------------------------------- 1 | package town.lost.processor.events; 2 | 3 | import net.openhft.chronicle.wire.VanillaMessageHistory; 4 | 5 | interface EventWithHistory extends Events { 6 | EventWithHistory history(VanillaMessageHistory mh); 7 | } 8 | -------------------------------------------------------------------------------- /message-history-demo/src/main/java/town/lost/processor/events/Events.java: -------------------------------------------------------------------------------- 1 | package town.lost.processor.events; 2 | 3 | public interface Events { 4 | // @MethodId(1) 5 | void eventOne(EventOne one); 6 | 7 | // @MethodId(2) 8 | void eventTwo(EventTwo two); 9 | } 10 | -------------------------------------------------------------------------------- /message-history-demo/src/main/java/town/lost/processor/events/PublisherMain.java: -------------------------------------------------------------------------------- 1 | package town.lost.processor.events; 2 | 3 | import net.openhft.chronicle.core.time.UniqueMicroTimeProvider; 4 | import net.openhft.chronicle.queue.ChronicleQueue; 5 | 6 | public class PublisherMain { 7 | 8 | private static final int EVENTS = Integer.getInteger("events", 100_000); 9 | private static final int RATE = Integer.getInteger("rate", 10_000); 10 | 11 | public static void main(String[] args) { 12 | System.out.println("Started"); 13 | try (ChronicleQueue queue = ChronicleQueue.singleBuilder("in").sourceId(1).build()) { 14 | Events build = queue.methodWriterBuilder(Events.class).build(); 15 | long start = System.nanoTime(); 16 | long interval = (long) (1e9 / RATE); 17 | EventTwo two = new EventTwo(); 18 | 19 | for (int i = 0; i < EVENTS; i++) { 20 | while (System.nanoTime() < start) 21 | ; 22 | publish(build, two, "Hello World"); 23 | start += interval; 24 | } 25 | publish(build, two, "Bye"); 26 | } 27 | System.out.println("... Finished"); 28 | System.exit(0); 29 | } 30 | 31 | private static void publish(Events build, EventTwo two, String text) { 32 | two.eventSource("publisher"); 33 | two.eventTimeStamp(UniqueMicroTimeProvider.INSTANCE.currentTimeMicros()); 34 | two.symbol(text); 35 | two.price(two.price + 1); 36 | two.quantiity(two.quantiity + 1); 37 | build.eventTwo(two); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /messages-with-text/README.adoc: -------------------------------------------------------------------------------- 1 | = Messages With Text Demo 2 | Peter Lawrey 3 | 4 | This demo shows a writing and reading messages containing text without creating garbage 5 | 6 | == What you need to get started. 7 | 8 | - Maven 3.6.x 9 | - Java 8 update 180+ 10 | - Intellij CE or another IDE 11 | - Access to the internet for maven to download the JARs needed 12 | 13 | -------------------------------------------------------------------------------- /messages-with-text/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | run.chronicle 9 | chronicle-queue-demo 10 | 1.0-SNAPSHOT 11 | ../pom.xml 12 | 13 | 14 | messages-with-text 15 | OpenHFT/${project.parent.artifactId}/${project.artifactId} 16 | 17 | 18 | 19 | net.openhft 20 | chronicle-wire 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /messages-with-text/src/main/java/run/chronicle/queue/Message.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.queue; 2 | 3 | import net.openhft.chronicle.bytes.Bytes; 4 | import net.openhft.chronicle.wire.BytesInBinaryMarshallable; 5 | import net.openhft.chronicle.wire.LongConversion; 6 | import net.openhft.chronicle.wire.MilliTimestampLongConverter; 7 | 8 | public class Message extends BytesInBinaryMarshallable { 9 | private final Bytes text = Bytes.allocateElasticOnHeap(); 10 | 11 | @LongConversion(MilliTimestampLongConverter.class) 12 | private long timeStamp; 13 | 14 | //Getters and Setters 15 | public Bytes getText() { 16 | return text; 17 | } 18 | 19 | public void setText(CharSequence text) { 20 | this.text.clear().append(text); 21 | } 22 | 23 | public long getTimeStamp() { 24 | return timeStamp; 25 | } 26 | 27 | public void setTimeStamp(long timeStamp) { 28 | this.timeStamp = timeStamp; 29 | } 30 | } -------------------------------------------------------------------------------- /messages-with-text/src/main/java/run/chronicle/queue/MessageMain.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.queue; 2 | 3 | import net.openhft.chronicle.bytes.MethodReader; 4 | import net.openhft.chronicle.core.io.IOTools; 5 | import net.openhft.chronicle.queue.ChronicleQueue; 6 | 7 | // run with -Xmx128m -XX:NewSize=96m -verbose:gc 8 | public class MessageMain { 9 | private static final int COUNT = Integer.getInteger("count", 10_000_000); 10 | 11 | public static void main(String[] args) { 12 | for (int t = 0; t < 5; t++) { 13 | long start = System.nanoTime(); 14 | String test = "test-" + start; 15 | try (ChronicleQueue queue = ChronicleQueue.single(test)) { 16 | Messages messages = queue.methodWriter(Messages.class); 17 | Message message = new Message(); 18 | for (int i = 0; i < COUNT; i++) { 19 | message.getText().clear().append("Hello ").append(i); 20 | message.setTimeStamp(System.currentTimeMillis()); 21 | messages.mesg(message); 22 | } 23 | 24 | int[] count = {0}; 25 | Messages messagesCounter = message1 -> count[0]++; 26 | MethodReader reader = queue.createTailer().methodReader(messagesCounter); 27 | while (reader.readOne()) { 28 | } 29 | long time = System.nanoTime() - start; 30 | System.out.printf("Read %,d of %,d messages in %.3f seconds%n", count[0], COUNT, time / 1e9); 31 | } 32 | IOTools.deleteDirWithFiles(test); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /messages-with-text/src/main/java/run/chronicle/queue/Messages.java: -------------------------------------------------------------------------------- 1 | package run.chronicle.queue; 2 | 3 | public interface Messages { 4 | void mesg(Message message); 5 | } 6 | -------------------------------------------------------------------------------- /order-processor/src/main/java/town/lost/oms/OrderViewerMain.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2024 Chronicle Software Ltd 3 | */ 4 | 5 | package town.lost.oms; 6 | 7 | import net.openhft.chronicle.bytes.MethodReader; 8 | import net.openhft.chronicle.core.Jvm; 9 | import net.openhft.chronicle.core.util.Mocker; 10 | import net.openhft.chronicle.queue.ChronicleQueue; 11 | import net.openhft.chronicle.queue.impl.single.SingleChronicleQueueBuilder; 12 | import net.openhft.chronicle.queue.rollcycles.TestRollCycles; 13 | import town.lost.oms.api.OMSIn; 14 | 15 | /** 16 | * The {@code OrderViewerMain} class is a utility application that continuously reads and displays 17 | * orders from a Chronicle Queue. It acts as a simple viewer for incoming orders, logging them to 18 | * the console. 19 | */ 20 | public class OrderViewerMain { 21 | 22 | /** 23 | * The entry point of the application. 24 | * 25 | * @param args the input arguments (none expected) 26 | */ 27 | public static void main(String[] args) { 28 | // Inform the user that the program is waiting for messages 29 | System.out.println("\nWaiting for messages..."); 30 | 31 | // Establish connection with the queue 32 | try (ChronicleQueue q = SingleChronicleQueueBuilder.binary("in") 33 | .rollCycle(TestRollCycles.TEST8_DAILY) 34 | .build()) { 35 | 36 | // Create a logging mock for OMSIn 37 | OMSIn logging = Mocker.logging(OMSIn.class, "read - ", System.out); 38 | 39 | // Create a MethodReader from the tail of the queue 40 | MethodReader reader = q.createTailer().methodReader(logging); 41 | 42 | // Continuously read messages from the queue 43 | while (true) { 44 | // Read one message from the queue; pause if no message was read 45 | if (!reader.readOne()) { 46 | Jvm.pause(50); 47 | } 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /order-processor/src/main/java/town/lost/oms/api/ErrorListener.java: -------------------------------------------------------------------------------- 1 | package town.lost.oms.api; 2 | 3 | /** 4 | * The {@code ErrorListener} interface defines how critical errors or exceptions 5 | * are communicated back to the system. This is conceptually similar to capturing 6 | * unexpected events in a FIX flow (e.g., invalid data or system faults) and passing 7 | * them upstream to a monitoring or logging component. 8 | *

9 | * In a FIX-based system, errors might also be reflected in Reject messages or 10 | * {@code jvmError(msg)} calls if the framework intercepts an unhandled exception. 11 | */ 12 | public interface ErrorListener { 13 | 14 | /** 15 | * Called when any critical system error occurs. 16 | * 17 | * @param msg A descriptive message about the JVM error or exception. 18 | */ 19 | void jvmError(String msg); 20 | } 21 | -------------------------------------------------------------------------------- /order-processor/src/main/java/town/lost/oms/api/OMSIn.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2024 Chronicle Software Ltd 3 | */ 4 | 5 | package town.lost.oms.api; 6 | 7 | import net.openhft.chronicle.bytes.MethodId; 8 | import town.lost.oms.dto.CancelAll; 9 | import town.lost.oms.dto.CancelOrderRequest; 10 | import town.lost.oms.dto.NewOrderSingle; 11 | 12 | /** 13 | * The {@code OMSIn} interface defines inbound operations for an Order Management System (OMS). 14 | *

15 | * In FIX 4.2 terms, these methods handle the logical equivalents of: 16 | *

    17 | *
  • NewOrderSingle (35=D) - see {@link NewOrderSingle}
  • 18 | *
  • OrderCancelRequest (35=F) - see {@link CancelOrderRequest}
  • 19 | *
  • A custom "CancelAll" message (not a standard FIX 4.2 message) - see {@link CancelAll}
  • 20 | *
21 | * The framework typically validates each DTO before calling these methods. On success or failure, 22 | * an appropriate outbound message (e.g., ExecutionReport, OrderCancelReject) is generated by 23 | * the OMS implementation. 24 | */ 25 | public interface OMSIn { 26 | 27 | /** 28 | * Processes a new single-order submission (FIX 4.2 MsgType=35=D). 29 | * 30 | * @param nos The {@link NewOrderSingle} representing the details of the new order. 31 | */ 32 | @MethodId('D') 33 | void newOrderSingle(NewOrderSingle nos); 34 | 35 | /** 36 | * Processes a request to cancel a specific order (FIX 4.2 MsgType=35=F). 37 | * 38 | * @param cor The {@link CancelOrderRequest} representing the details of the cancel request. 39 | */ 40 | @MethodId('F') 41 | void cancelOrderRequest(CancelOrderRequest cor); 42 | 43 | /** 44 | * Processes a request to cancel all orders for a particular symbol or filter 45 | * (custom extension beyond FIX 4.2). 46 | * 47 | * @param cancelAll The {@link CancelAll} object representing the mass-cancel request. 48 | */ 49 | void cancelAll(CancelAll cancelAll); 50 | } 51 | -------------------------------------------------------------------------------- /order-processor/src/main/java/town/lost/oms/api/OMSOut.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2024 Chronicle Software Ltd 3 | */ 4 | 5 | package town.lost.oms.api; 6 | 7 | import net.openhft.chronicle.bytes.MethodId; 8 | import town.lost.oms.dto.ExecutionReport; 9 | import town.lost.oms.dto.OrderCancelReject; 10 | 11 | /** 12 | * The {@code OMSOut} interface defines outbound operations from the Order Management System (OMS). 13 | *

14 | * In FIX 4.2 terms, these correspond to: 15 | *

    16 | *
  • ExecutionReport (35=8) - see {@link ExecutionReport}
  • 17 | *
  • OrderCancelReject (35=9) - see {@link OrderCancelReject}
  • 18 | *
19 | * This interface also extends {@link ErrorListener} to handle critical errors. 20 | * Typically, these methods are called by {@code OMSImpl} once inbound requests 21 | * have been processed and an outcome is determined. 22 | */ 23 | public interface OMSOut extends ErrorListener { 24 | 25 | /** 26 | * Handles an execution report (FIX 4.2 MsgType=35=8), which might indicate a new, 27 | * partially filled, filled, or canceled order status. 28 | * 29 | * @param er The {@link ExecutionReport} object representing the order’s current state. 30 | */ 31 | @MethodId(11) 32 | void executionReport(ExecutionReport er); 33 | 34 | /** 35 | * Handles an order-cancel-reject (FIX 4.2 MsgType=35=9), indicating that a cancellation 36 | * request could not be honored (e.g., no such order). 37 | * 38 | * @param ocr The {@link OrderCancelReject} object representing the reason for rejection. 39 | */ 40 | @MethodId(12) 41 | void orderCancelReject(OrderCancelReject ocr); 42 | } 43 | -------------------------------------------------------------------------------- /order-processor/src/main/java/town/lost/oms/api/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Provides the API interfaces for interactions with the Order Management System (OMS) in the 'town.lost.oms' project. 3 | * 4 | *

This package includes the following interfaces: 5 | * 6 | *

    7 | *
  • {@link town.lost.oms.api.OMSIn}, which defines the methods for inbound operations that an OMS can perform, such as handling new single orders, cancel order requests, and cancel all orders.
  • 8 | *
  • {@link town.lost.oms.api.OMSOut}, which defines the methods for outbound operations from the OMS, including handling execution reports and order cancel rejections.
  • 9 | *
10 | * 11 | *

Each interface includes methods that correspond to specific actions within the OMS, facilitating communication between clients and the OMS. 12 | * 13 | *

For more details, refer to the documentation for each individual interface. 14 | */ 15 | package town.lost.oms.api; 16 | 17 | -------------------------------------------------------------------------------- /order-processor/src/main/java/town/lost/oms/dto/OrderType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2024 Chronicle Software Ltd 3 | */ 4 | 5 | package town.lost.oms.dto; 6 | /** 7 | * Enumeration for the types of orders in a trading system. 8 | * 9 | *

It contains two values: MARKET and LIMIT, which represent the two main types of orders that can be placed 10 | * in a trading system. A MARKET order is an order to buy or sell a security at the current market price, 11 | * whereas a LIMIT order is an order to buy or sell a security at a specific price or better. 12 | * 13 | *

This enumeration can be used when creating trading orders, like so: 14 | * 15 | *

16 |  * NewOrderSingle nos = new NewOrderSingle()
17 |  *    .sender(ShortText.parse("client"))
18 |  *    .target(ShortText.parse("OMS"))
19 |  *    .clOrdID("clOrdID")
20 |  *    .orderQty(1e6)
21 |  *    .price(1.6)
22 |  *    .symbol(ShortText.parse("AUDUSD"))
23 |  *    .ordType(OrderType.LIMIT)
24 |  *    .side(BuySell.BUY);
25 |  * 
26 | * 27 | *

Note that the order type is indicated by the {@link OrderType} used in the 'ordType' field of the order. 28 | */ 29 | public enum OrderType { 30 | /** 31 | * Market order type, which means the order should be executed at the current market price. 32 | */ 33 | MARKET, 34 | 35 | /** 36 | * Limit order type, which means the order should be executed at a specific price or better. 37 | */ 38 | LIMIT, 39 | 40 | /** 41 | * Pegged order type, where the price is pegged to a benchmark price, such as the best bid or ask. 42 | */ 43 | PEGGED, 44 | 45 | /** 46 | * Fill or Kill order type, which must be executed immediately in its entirety or cancelled. 47 | */ 48 | FILL_OR_KILL, 49 | 50 | /** 51 | * Immediate or Cancel order type, which executes all or part immediately and cancels any unfilled portion. 52 | */ 53 | IMMEDIATE_OR_CANCEL, 54 | } 55 | 56 | -------------------------------------------------------------------------------- /order-processor/src/main/java/town/lost/oms/dto/Side.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2024 Chronicle Software Ltd 3 | */ 4 | 5 | package town.lost.oms.dto; 6 | 7 | /** 8 | * Enumeration for the direction of a trade order. 9 | * 10 | *

It contains two values: BUY and SELL, which represents the direction of the order. BUY (+1) means the order is to 11 | * purchase, while SELL (-1) implies the order is to sell. 12 | * 13 | *

This enumeration can be used to create trading orders, like so: 14 | * 15 | *

{@code
16 |  * NewOrderSingle nos = new NewOrderSingle()
17 |  *    .sender(toLong("sender"))
18 |  *    .target(toLong("target"))
19 |  *    .transactTime(now())
20 |  *    .sendingTime(now())
21 |  *    .orderQty(1)
22 |  *    .ordType(OrderType.MARKET)
23 |  *    .side(Side.BUY)
24 |  *    .symbol(toLong("EURUSD"));
25 |  * }
26 | * 27 | *

Note that the direction is indicated by the {@link Side} used in the 'side' field of the order. 28 | */ 29 | public enum Side { 30 | /** 31 | * Buy order direction, represented by an integer value of +1. 32 | * Indicates an order to purchase. 33 | */ 34 | BUY(+1), 35 | 36 | /** 37 | * Sell order direction, represented by an integer value of -1. 38 | * Indicates an order to sell. 39 | */ 40 | SELL(-1); 41 | 42 | /** 43 | * The direction of the order. 44 | */ 45 | public final int direction; 46 | 47 | /** 48 | * Constructs a BuySell enum with the specified direction. 49 | * 50 | * @param direction the direction of the order (+1 for buy, -1 for sell) 51 | */ 52 | Side(int direction) { 53 | this.direction = direction; 54 | } 55 | 56 | /** 57 | * Gets the direction indicator of the order. 58 | * 59 | * @return the direction indicator as an integer 60 | */ 61 | public int direction() { 62 | return direction; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /order-processor/src/main/java/town/lost/oms/dto/ValidateUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2024 Chronicle Software Ltd 3 | */ 4 | package town.lost.oms.dto; 5 | 6 | /** 7 | * The {@code ValidateUtil} class provides utility methods for validating numerical values such as price and quantity. 8 | * 9 | *

This class is final and cannot be instantiated. It contains static methods that check whether a given price or quantity 10 | * is valid according to predefined business rules. 11 | * 12 | *

Example usage: 13 | * 14 | *

{@code
15 |  * double price = 100.0;
16 |  * if (ValidateUtil.invalidPrice(price)) {
17 |  *     throw new IllegalArgumentException("Invalid price");
18 |  * }
19 |  * }
20 | */ 21 | public final class ValidateUtil { 22 | 23 | /** 24 | * Private constructor to prevent instantiation. 25 | */ 26 | private ValidateUtil() { 27 | } 28 | 29 | /** 30 | * Checks if the provided price is invalid. 31 | * 32 | *

A price is considered invalid if it is not a finite number or if it is less than or equal to zero. 33 | * 34 | * @param price the price to validate 35 | * @return {@code true} if the price is invalid; {@code false} otherwise 36 | */ 37 | public static boolean invalidPrice(double price) { 38 | return !Double.isFinite(price) || (price <= 0); 39 | } 40 | 41 | /** 42 | * Checks if the provided quantity is invalid. 43 | * 44 | *

A quantity is considered invalid if it is not a finite number or if it is less than zero. 45 | * 46 | * @param quantity the quantity to validate 47 | * @return {@code true} if the quantity is invalid; {@code false} otherwise 48 | */ 49 | public static boolean invalidQuantity(double quantity) { 50 | return !Double.isFinite(quantity) || (quantity < 0); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /order-processor/src/main/java/town/lost/oms/dto/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Provides the classes and interfaces necessary to create and manage Order Management System (OMS) data transfer objects (DTOs) aligned with 3 | * the FIX 4.2 specification (https://www.fixtrading.org/standards/fix-4-2/). 4 | * 5 | *

This package includes the following key components: 6 | * 7 | *

    8 | *
  • AbstractEvent and its subclasses, which represent different types of events that can occur in an OMS, such as: 9 | *
      10 | *
    • {@link town.lost.oms.dto.NewOrderSingle}: Represents a new order submission.
    • 11 | *
    • {@link town.lost.oms.dto.CancelOrderRequest}: Represents a request to cancel an existing order.
    • 12 | *
    • {@link town.lost.oms.dto.ExecutionReport}: Represents the execution status of an order.
    • 13 | *
    • {@link town.lost.oms.dto.OrderCancelReject}: Indicates that an order cancellation request was rejected.
    • 14 | *
    • {@link town.lost.oms.dto.CancelAll}: Represents a request to cancel all orders for a specific symbol.
    • 15 | *
    16 | *
  • 17 | *
  • Enums that define constants for various order attributes: 18 | *
      19 | *
    • {@link town.lost.oms.dto.Side}: Represents the side of an order (e.g., buy or sell).
    • 20 | *
    • {@link town.lost.oms.dto.OrderType}: Represents the type of an order (e.g., market, limit).
    • 21 | *
    • {@link town.lost.oms.dto.TimeInForce}: Represents the time-in-force instructions for an order.
    • 22 | *
    • {@link town.lost.oms.dto.Ccy}: Represents currency codes as per ISO 4217.
    • 23 | *
    24 | *
  • 25 | *
  • Utility Classes: 26 | *
      27 | *
    • {@link town.lost.oms.dto.ValidateUtil}: Provides utility methods for validating order parameters such as price and quantity.
    • 28 | *
    29 | *
  • 30 | *
31 | * 32 | *

Each class is designed to be marshalled and unmarshalled efficiently for high-performance data transfer, leveraging serialization optimizations provided by Chronicle Wire. 33 | * 34 | *

For more details, refer to the documentation of each individual class. 35 | */ 36 | package town.lost.oms.dto; 37 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/cancelAll/in.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Scenario: Cancel a single existing order 3 | # This is a test for the CancelOrderRequest operation. 4 | # The CLIENT1 (sender) is sending a request to the Order Management System (OMS1, the target) 5 | # to cancel an order that was previously placed. The order is identified by its unique ID (clOrdID). 6 | 7 | cancelOrderRequest: { 8 | sender: CLIENT1, 9 | target: OMS1, 10 | sendingTime: 2019-12-03T09:54:37.134475, 11 | symbol: EURUSD, 12 | account: ACC-12345, 13 | clOrdID: dkj4378fwh, 14 | origClOrdID: ABC1234567, 15 | side: BUY 16 | } 17 | ... 18 | --- 19 | # Scenario: Cancel all orders for EURUSD 20 | # The CLIENT1 (sender) sends a request to the OMS1 (target) to cancel all orders. 21 | cancelAll: { 22 | sender: CLIENT1, 23 | target: OMS1, 24 | sendingTime: 2019-12-03T09:54:37.134475, 25 | symbol: EURUSD, 26 | clOrdID: CANCEL_ALL, 27 | } 28 | ... 29 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/cancelAll/out-missing-field-clOrdID.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Cancel a single existing order 2 | # This is a test for the CancelOrderRequest operation. 3 | # The CLIENT1 (sender) is sending a request to the Order Management System (OMS1, the target) 4 | # to cancel an order that was previously placed. The order is identified by its unique ID (clOrdID). 5 | # missing clOrdID: dkj4378fwh, 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: clOrdID is required" 7 | ... 8 | # Scenario: Cancel all orders for EURUSD 9 | # The CLIENT1 (sender) sends a request to the OMS1 (target) to cancel all orders. 10 | # missing clOrdID: CANCEL_ALL, 11 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: clOrdID is required" 12 | ... 13 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/cancelAll/out-set-field-clOrdID=__.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Cancel a single existing order 2 | # This is a test for the CancelOrderRequest operation. 3 | # The CLIENT1 (sender) is sending a request to the Order Management System (OMS1, the target) 4 | # to cancel an order that was previously placed. The order is identified by its unique ID (clOrdID). 5 | # override clOrdID: dkj4378fwh to clOrdID: '' 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: clOrdID is required" 7 | ... 8 | # Scenario: Cancel all orders for EURUSD 9 | # The CLIENT1 (sender) sends a request to the OMS1 (target) to cancel all orders. 10 | # override clOrdID: CANCEL_ALL to clOrdID: '' 11 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: clOrdID is required" 12 | ... 13 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/cancelAll/out-set-field-sendingTime=__.yaml: -------------------------------------------------------------------------------- 1 | jvmError: "Unhandled Exception net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime is required" 2 | ... 3 | # Scenario: Cancel all orders for EURUSD 4 | # The CLIENT1 (sender) sends a request to the OMS1 (target) to cancel all orders. 5 | # override sendingTime: 2019-12-03T09:54:37.134475 to sendingTime: '' 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/cancelAll/out.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Cancel a single existing order 2 | # This is a test for the CancelOrderRequest operation. 3 | # The CLIENT1 (sender) is sending a request to the Order Management System (OMS1, the target) 4 | # to cancel an order that was previously placed. The order is identified by its unique ID (clOrdID). 5 | --- 6 | orderCancelReject: { 7 | sender: OMS1, 8 | target: CLIENT1, 9 | sendingTime: 2019-12-03T09:54:37.134475, 10 | symbol: EURUSD, 11 | clOrdID: dkj4378fwh, 12 | reason: No such order 13 | } 14 | ... 15 | # Scenario: Cancel all orders for EURUSD 16 | # The CLIENT1 (sender) sends a request to the OMS1 (target) to cancel all orders. 17 | --- 18 | orderCancelReject: { 19 | sender: OMS1, 20 | target: CLIENT1, 21 | sendingTime: 2019-12-03T09:54:37.134475, 22 | symbol: EURUSD, 23 | clOrdID: CANCEL_ALL, 24 | reason: No orders to cancel 25 | } 26 | ... 27 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/cancelOrderRequest/in.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Scenario: Cancel a single existing order 3 | # This is a test for the CancelOrderRequest operation. 4 | # The CLIENT1 (sender) is sending a request to the Order Management System (OMS1, the target) 5 | # to cancel an order that was previously placed. The order is identified by its unique ID (clOrdID). 6 | 7 | cancelOrderRequest: { 8 | sender: CLIENT1, 9 | target: OMS1, 10 | sendingTime: 2019-12-03T09:54:37.134475, 11 | symbol: EURUSD, 12 | account: ACC-12345, 13 | clOrdID: dkj4378fwh, 14 | origClOrdID: ABC1234567, 15 | side: BUY 16 | } 17 | ... 18 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/cancelOrderRequest/out-missing-field-sender.yaml: -------------------------------------------------------------------------------- 1 | jvmError: "Unhandled Exception net.openhft.chronicle.core.io.InvalidMarshallableException: target is required" 2 | ... 3 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/cancelOrderRequest/out-missing-field-side.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Cancel a single existing order 2 | # This is a test for the CancelOrderRequest operation. 3 | # The CLIENT1 (sender) is sending a request to the Order Management System (OMS1, the target) 4 | # to cancel an order that was previously placed. The order is identified by its unique ID (clOrdID). 5 | # missing side: BUY 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: side is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/cancelOrderRequest/out-missing-field-target.yaml: -------------------------------------------------------------------------------- 1 | jvmError: "Unhandled Exception net.openhft.chronicle.core.io.InvalidMarshallableException: sender is required" 2 | ... 3 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/cancelOrderRequest/out-set-field-sendingTime=__.yaml: -------------------------------------------------------------------------------- 1 | jvmError: "Unhandled Exception net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime is required" 2 | ... 3 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/cancelOrderRequest/out.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Cancel a single existing order 2 | # This is a test for the CancelOrderRequest operation. 3 | # The CLIENT1 (sender) is sending a request to the Order Management System (OMS1, the target) 4 | # to cancel an order that was previously placed. The order is identified by its unique ID (clOrdID). 5 | --- 6 | orderCancelReject: { 7 | sender: OMS1, 8 | target: CLIENT1, 9 | sendingTime: 2019-12-03T09:54:37.134475, 10 | symbol: EURUSD, 11 | clOrdID: dkj4378fwh, 12 | reason: No such order 13 | } 14 | ... 15 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/in.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Scenario: Basic NewOrderSingle for EURUSD 3 | # This is a test for the NewOrderSingle operation. 4 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 5 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 6 | 7 | newOrderSingle: { 8 | sender: CLIENT, 9 | target: OMS, 10 | sendingTime: 2019-12-03T09:54:37.134475, 11 | symbol: EURUSD, 12 | transactTime: 2019-12-03T09:54:37.344751, 13 | account: ACC-12345, 14 | orderQty: 10E6, 15 | price: 1.2123, 16 | side: BUY, 17 | clOrdID: dkj4378fwh, 18 | ordType: LIMIT, 19 | timeInForce: GTC, 20 | currency: USD 21 | } 22 | ... 23 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-missing-field-account.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # missing account: ACC-12345, 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: account is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-missing-field-clOrdID.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # missing clOrdID: dkj4378fwh, 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: clOrdID is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-missing-field-currency.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # missing currency: USD 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: currency is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-missing-field-ordType.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # missing ordType: LIMIT, 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: ordType is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-missing-field-orderQty.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # missing orderQty: 10E6, 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: orderQty is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-missing-field-price.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # missing price: 1.2123, 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: price is invalid" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-missing-field-sender.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # missing sender: CLIENT, 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sender is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-missing-field-sendingTime.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # missing sendingTime: 2019-12-03T09:54:37.134475, 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-missing-field-side.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # missing side: BUY, 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: side is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-missing-field-symbol.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # missing symbol: EURUSD, 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: symbol is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-missing-field-target.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # missing target: OMS, 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: target is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-missing-field-timeInForce.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # missing timeInForce: GTC, 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: timeInForce is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-missing-field-transactTime.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # missing transactTime: 2019-12-03T09:54:37.344751, 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: transactTime is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-set-field-clOrdID=__.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # override clOrdID: dkj4378fwh to clOrdID: '' 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: clOrdID is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-set-field-ordType=__.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # override ordType: LIMIT to ordType: '' 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: ordType is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-set-field-orderQty=-1.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # override orderQty: 10E6 to orderQty: -1 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: orderQty is invalid" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-set-field-orderQty=NaN.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # override orderQty: 10E6 to orderQty: NaN 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: orderQty is invalid" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-set-field-price=-1.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # override price: 1.2123 to price: -1 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: price is invalid" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-set-field-price=NaN.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # override price: 1.2123 to price: NaN 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: price is invalid" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-set-field-sendingTime=__.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # override sendingTime: 2019-12-03T09:54:37.134475 to sendingTime: '' 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-set-field-side=__.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # override side: BUY to side: '' 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: side is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out-set-field-symbol=__.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | # override symbol: EURUSD to symbol: '' 6 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: symbol is required" 7 | ... 8 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingle/out.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Basic NewOrderSingle for EURUSD 2 | # This is a test for the NewOrderSingle operation. 3 | # The client (sender) is sending a new order to the Order Management System (OMS, the target). 4 | # The order details such as the trading symbol, order quantity, price, and the order type are specified. 5 | --- 6 | executionReport: { 7 | sender: OMS, 8 | target: CLIENT, 9 | sendingTime: 2019-12-03T09:54:37.134475, 10 | symbol: EURUSD, 11 | transactTime: 2019-12-03T09:54:37.344751, 12 | orderQty: 10E6, 13 | price: 1.2123, 14 | orderID: 2019-12-03T09:54:37.345679, 15 | lastPx: 0.0, 16 | leavesQty: 0.0, 17 | cumQty: 0.0, 18 | avgPx: 0.0, 19 | side: BUY, 20 | ordType: LIMIT, 21 | clOrdID: dkj4378fwh, 22 | text: Not ready 23 | } 24 | ... 25 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/in.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Scenario: Submit a new AAPL equity order 3 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 4 | newOrderSingle: { 5 | sender: CLIENT1, 6 | target: OMS1, 7 | sendingTime: 2023-10-20T14:25:37.134475, 8 | symbol: AAPL, 9 | transactTime: 2023-10-20T14:25:37.134475, 10 | account: ACC-12345, 11 | orderQty: 1000, 12 | price: 150.25, 13 | side: BUY, 14 | clOrdID: ABC1234567, 15 | ordType: LIMIT, 16 | timeInForce: DAY, 17 | currency: USD 18 | } 19 | ... 20 | --- 21 | # Scenario: Submit a new GOOGL equity order 22 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 23 | newOrderSingle: { 24 | sender: CLIENT2, 25 | target: OMS1, 26 | sendingTime: 2023-10-20T14:27:15.987654, 27 | symbol: GOOGL, 28 | transactTime: 2023-10-20T14:27:15.987654, 29 | account: ACC-67890, 30 | orderQty: 500, 31 | price: 2750.50, 32 | side: SELL, 33 | clOrdID: XYZ7654321, 34 | ordType: MARKET, 35 | timeInForce: DAY, 36 | currency: USD 37 | } 38 | ... 39 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-missing-field-account.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # missing account: ACC-12345, 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: account is required" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # missing account: ACC-67890, 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: account is required" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-missing-field-clOrdID.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # missing clOrdID: ABC1234567, 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: clOrdID is required" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # missing clOrdID: XYZ7654321, 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: clOrdID is required" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-missing-field-ordType.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # missing ordType: LIMIT, 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: ordType is required" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # missing ordType: MARKET, 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: ordType is required" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-missing-field-orderQty.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # missing orderQty: 1000, 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: orderQty is required" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # missing orderQty: 500, 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: orderQty is required" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-missing-field-price.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # missing price: 150.25, 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: price is invalid" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # missing price: 2750.50, 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: price is invalid" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-missing-field-sender.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # missing sender: CLIENT1, 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sender is required" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # missing sender: CLIENT2, 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sender is required" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-missing-field-sendingTime.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # missing sendingTime: 2023-10-20T14:25:37.134475, 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime is required" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # missing sendingTime: 2023-10-20T14:27:15.987654, 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime is required" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-missing-field-side.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # missing side: BUY, 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: side is required" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # missing side: SELL, 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: side is required" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-missing-field-symbol.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # missing symbol: AAPL, 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: symbol is required" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # missing symbol: GOOGL, 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: symbol is required" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-missing-field-target.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # missing target: OMS1, 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: target is required" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # missing target: OMS1, 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: target is required" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-missing-field-timeInForce.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # missing timeInForce: DAY, 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: timeInForce is required" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # missing timeInForce: DAY, 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: timeInForce is required" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-missing-field-transactTime.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # missing transactTime: 2023-10-20T14:25:37.134475, 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: transactTime is required" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # missing transactTime: 2023-10-20T14:27:15.987654, 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: transactTime is required" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-missing-msg-0.yaml: -------------------------------------------------------------------------------- 1 | # Missing message 0 2 | # Scenario: Submit a new GOOGL equity order 3 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 4 | --- 5 | executionReport: { 6 | sender: OMS1, 7 | target: CLIENT2, 8 | sendingTime: 2023-10-20T14:27:15.987654, 9 | symbol: GOOGL, 10 | transactTime: 2023-10-20T14:27:15.987654, 11 | orderQty: 500.0, 12 | price: 2750.5, 13 | orderID: 2019-12-03T09:54:37.345679, 14 | lastPx: 0.0, 15 | leavesQty: 0.0, 16 | cumQty: 0.0, 17 | avgPx: 0.0, 18 | side: SELL, 19 | ordType: MARKET, 20 | clOrdID: XYZ7654321, 21 | text: Not ready 22 | } 23 | ... 24 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-msg-0-duplicated.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | --- 4 | executionReport: { 5 | sender: OMS1, 6 | target: CLIENT1, 7 | sendingTime: 2023-10-20T14:25:37.134475, 8 | symbol: AAPL, 9 | transactTime: 2023-10-20T14:25:37.134475, 10 | orderQty: 1E3, 11 | price: 150.25, 12 | orderID: 2019-12-03T09:54:37.345679, 13 | lastPx: 0.0, 14 | leavesQty: 0.0, 15 | cumQty: 0.0, 16 | avgPx: 0.0, 17 | side: BUY, 18 | ordType: LIMIT, 19 | clOrdID: ABC1234567, 20 | text: Not ready 21 | } 22 | ... 23 | # Scenario: Submit a new GOOGL equity order 24 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 25 | --- 26 | executionReport: { 27 | sender: OMS1, 28 | target: CLIENT2, 29 | sendingTime: 2023-10-20T14:27:15.987654, 30 | symbol: GOOGL, 31 | transactTime: 2023-10-20T14:27:15.987654, 32 | orderQty: 500.0, 33 | price: 2750.5, 34 | orderID: 2019-12-03T09:54:38.345679, 35 | lastPx: 0.0, 36 | leavesQty: 0.0, 37 | cumQty: 0.0, 38 | avgPx: 0.0, 39 | side: SELL, 40 | ordType: MARKET, 41 | clOrdID: XYZ7654321, 42 | text: Not ready 43 | } 44 | ... 45 | # Scenario: Submit a new AAPL equity order 46 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 47 | --- 48 | executionReport: { 49 | sender: OMS1, 50 | target: CLIENT1, 51 | sendingTime: 2023-10-20T14:25:37.134475, 52 | symbol: AAPL, 53 | transactTime: 2023-10-20T14:25:37.134475, 54 | orderQty: 1E3, 55 | price: 150.25, 56 | orderID: 2019-12-03T09:54:39.345679, 57 | lastPx: 0.0, 58 | leavesQty: 0.0, 59 | cumQty: 0.0, 60 | avgPx: 0.0, 61 | side: BUY, 62 | ordType: LIMIT, 63 | clOrdID: ABC1234567, 64 | text: Not ready 65 | } 66 | ... 67 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-set-field-clOrdID=__.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # override clOrdID: ABC1234567 to clOrdID: '' 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: clOrdID is required" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # override clOrdID: XYZ7654321 to clOrdID: '' 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: clOrdID is required" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-set-field-ordType=__.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # override ordType: LIMIT to ordType: '' 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: ordType is required" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # override ordType: MARKET to ordType: '' 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: ordType is required" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-set-field-orderQty=-1.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # override orderQty: 1000 to orderQty: -1 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: orderQty is invalid" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # override orderQty: 500 to orderQty: -1 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: orderQty is invalid" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-set-field-orderQty=NaN.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # override orderQty: 1000 to orderQty: NaN 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: orderQty is invalid" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # override orderQty: 500 to orderQty: NaN 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: orderQty is invalid" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-set-field-price=-1.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # override price: 150.25 to price: -1 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: price is invalid" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # override price: 2750.50 to price: -1 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: price is invalid" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-set-field-price=NaN.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # override price: 150.25 to price: NaN 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: price is invalid" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # override price: 2750.50 to price: NaN 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: price is invalid" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-set-field-sendingTime=__.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # override sendingTime: 2023-10-20T14:25:37.134475 to sendingTime: '' 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime is required" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # override sendingTime: 2023-10-20T14:27:15.987654 to sendingTime: '' 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: sendingTime is required" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-set-field-side=__.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # override side: BUY to side: '' 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: side is required" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # override side: SELL to side: '' 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: side is required" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out-set-field-symbol=__.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | # override symbol: AAPL to symbol: '' 4 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: symbol is required" 5 | ... 6 | # Scenario: Submit a new GOOGL equity order 7 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 8 | # override symbol: GOOGL to symbol: '' 9 | jvmError: "net.openhft.chronicle.core.io.InvalidMarshallableException: symbol is required" 10 | ... 11 | -------------------------------------------------------------------------------- /order-processor/src/test/resources/newOrderSingleEquity/out.yaml: -------------------------------------------------------------------------------- 1 | # Scenario: Submit a new AAPL equity order 2 | # Sample `NewOrderSingle` message representing a client's new order sent to the Order Management System (OMS). 3 | --- 4 | executionReport: { 5 | sender: OMS1, 6 | target: CLIENT1, 7 | sendingTime: 2023-10-20T14:25:37.134475, 8 | symbol: AAPL, 9 | transactTime: 2023-10-20T14:25:37.134475, 10 | orderQty: 1E3, 11 | price: 150.25, 12 | orderID: 2019-12-03T09:54:37.345679, 13 | lastPx: 0.0, 14 | leavesQty: 0.0, 15 | cumQty: 0.0, 16 | avgPx: 0.0, 17 | side: BUY, 18 | ordType: LIMIT, 19 | clOrdID: ABC1234567, 20 | text: Not ready 21 | } 22 | ... 23 | # Scenario: Submit a new GOOGL equity order 24 | # Sample `NewOrderSingle` message representing another client's new order sent to the Order Management System (OMS). 25 | --- 26 | executionReport: { 27 | sender: OMS1, 28 | target: CLIENT2, 29 | sendingTime: 2023-10-20T14:27:15.987654, 30 | symbol: GOOGL, 31 | transactTime: 2023-10-20T14:27:15.987654, 32 | orderQty: 500.0, 33 | price: 2750.5, 34 | orderID: 2019-12-03T09:54:38.345679, 35 | lastPx: 0.0, 36 | leavesQty: 0.0, 37 | cumQty: 0.0, 38 | avgPx: 0.0, 39 | side: SELL, 40 | ordType: MARKET, 41 | clOrdID: XYZ7654321, 42 | text: Not ready 43 | } 44 | ... 45 | -------------------------------------------------------------------------------- /simple-avro-example/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | run.chronicle 9 | chronicle-queue-demo 10 | 1.0-SNAPSHOT 11 | ../pom.xml 12 | 13 | 14 | simple-avro-example 15 | OpenHFT/${project.parent.artifactId}/${project.artifactId} 16 | 17 | 18 | 19 | org.apache.avro 20 | avro 21 | 1.11.4 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /simple-avro-example/src/main/java/net/openhft/chronicle/queue/simple/avro/InputMain.java: -------------------------------------------------------------------------------- 1 | package net.openhft.chronicle.queue.simple.avro; 2 | 3 | import net.openhft.chronicle.queue.ExcerptAppender; 4 | import net.openhft.chronicle.queue.impl.single.SingleChronicleQueue; 5 | import net.openhft.chronicle.queue.impl.single.SingleChronicleQueueBuilder; 6 | import net.openhft.chronicle.wire.DocumentContext; 7 | import org.apache.avro.generic.GenericRecord; 8 | 9 | import java.io.IOException; 10 | 11 | public class InputMain { 12 | public static void main(String[] args) throws IOException { 13 | AvroHelper avro = new AvroHelper(); 14 | 15 | String path = "queue"; 16 | SingleChronicleQueue queue = SingleChronicleQueueBuilder.binary(path).build(); 17 | ExcerptAppender appender = queue.createAppender(); 18 | 19 | try (DocumentContext dc = appender.writingDocument()) { 20 | GenericRecord user = avro.getGenericRecord(); 21 | user.put("name", "Alyssa"); 22 | user.put("favorite_number", 256); 23 | avro.writeToOS(user, dc.wire().bytes().outputStream()); 24 | } 25 | 26 | try (DocumentContext dc = appender.writingDocument()) { 27 | GenericRecord user = avro.getGenericRecord(); 28 | user.put("name", "Ben"); 29 | user.put("favorite_number", 7); 30 | user.put("favorite_colour", "red"); 31 | avro.writeToOS(user, dc.wire().bytes().outputStream()); 32 | } 33 | 34 | System.out.println("2 records written."); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /simple-avro-example/src/main/java/net/openhft/chronicle/queue/simple/avro/OutputMain.java: -------------------------------------------------------------------------------- 1 | package net.openhft.chronicle.queue.simple.avro; 2 | 3 | import net.openhft.chronicle.queue.ExcerptTailer; 4 | import net.openhft.chronicle.queue.impl.single.SingleChronicleQueue; 5 | import net.openhft.chronicle.queue.impl.single.SingleChronicleQueueBuilder; 6 | import net.openhft.chronicle.wire.DocumentContext; 7 | import org.apache.avro.generic.GenericRecord; 8 | 9 | import java.io.IOException; 10 | 11 | public class OutputMain { 12 | public static void main(String[] args) throws IOException { 13 | AvroHelper avro = new AvroHelper(); 14 | 15 | String path = "queue"; 16 | SingleChronicleQueue queue = SingleChronicleQueueBuilder.binary(path).build(); 17 | ExcerptTailer tailer = queue.createTailer(); 18 | 19 | while (true) { 20 | try (DocumentContext dc = tailer.readingDocument()) { 21 | if (dc.wire() == null) 22 | break; 23 | 24 | GenericRecord user = avro.readFromIS(dc.wire().bytes().inputStream()); 25 | System.out.println("Read: " + user); 26 | } 27 | } 28 | 29 | System.out.println("All done"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /simple-avro-example/src/main/resources/user.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "namespace": "net.openhft.chronicle.queue.sample.avro", 3 | "type": "record", 4 | "name": "User", 5 | "fields": [ 6 | {"name": "name", "type": "string"}, 7 | {"name": "favorite_number", "type": ["int", "null"]}, 8 | {"name": "favorite_color", "type": ["string", "null"]} 9 | ] 10 | } -------------------------------------------------------------------------------- /simple-input/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | run.chronicle 9 | chronicle-queue-demo 10 | 1.0-SNAPSHOT 11 | ../pom.xml 12 | 13 | 14 | simple-input 15 | OpenHFT/${project.parent.artifactId}/${project.artifactId} 16 | 17 | -------------------------------------------------------------------------------- /simple-input/src/main/java/net/openhft/chronicle/queue/simple/input/InputMain.java: -------------------------------------------------------------------------------- 1 | package net.openhft.chronicle.queue.simple.input; 2 | 3 | import net.openhft.chronicle.queue.ChronicleQueue; 4 | import net.openhft.chronicle.queue.ExcerptAppender; 5 | import java.util.Scanner; 6 | 7 | /** 8 | * Created by catherine on 17/07/2016. 9 | */ 10 | public class InputMain { 11 | public static void main(String[] args) { 12 | // Allow the queue path to be specified via command-line arguments 13 | String path = (args.length > 0) ? args[0] : "queue"; 14 | 15 | // Use try-with-resources for proper resource management 16 | try (ChronicleQueue queue = ChronicleQueue.single(path); 17 | Scanner scanner = new Scanner(System.in)) { 18 | 19 | ExcerptAppender appender = queue.createAppender(); 20 | System.out.println("Starting InputMain. Type your input (empty line to exit)."); 21 | 22 | while (true) { 23 | System.out.print("Input> "); 24 | String line = scanner.nextLine(); 25 | if (line.isEmpty()) { 26 | break; 27 | } 28 | appender.writeText(line); 29 | System.out.println("Written to queue: " + line); 30 | } 31 | System.out.println("... bye."); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /simple-input/src/main/java/net/openhft/chronicle/queue/simple/input/OutputMain.java: -------------------------------------------------------------------------------- 1 | package net.openhft.chronicle.queue.simple.input; 2 | 3 | import net.openhft.chronicle.core.Jvm; 4 | import net.openhft.chronicle.queue.ExcerptTailer; 5 | import net.openhft.chronicle.queue.ChronicleQueue; 6 | 7 | 8 | /** 9 | * Created by catherine on 17/07/2016. 10 | */ 11 | public class OutputMain { 12 | public static void main(String[] args) { 13 | // Allow the queue path to be specified via command-line arguments 14 | String path = (args.length > 0) ? args[0] : "queue"; 15 | 16 | // Use try-with-resources for proper resource management 17 | try (ChronicleQueue queue = ChronicleQueue.single(path)) { 18 | ExcerptTailer tailer = queue.createTailer(); 19 | 20 | System.out.println("Starting OutputMain. Waiting for messages..."); 21 | 22 | while (true) { 23 | String text = tailer.readText(); 24 | if (text == null) { 25 | // Pause briefly to avoid busy-waiting 26 | Jvm.pause(10); 27 | } else { 28 | System.out.println("Read from queue: " + text); 29 | } 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /simple-input/src/main/java/net/openhft/chronicle/queue/simple/input/PrintQueueMain.java: -------------------------------------------------------------------------------- 1 | package net.openhft.chronicle.queue.simple.input; 2 | 3 | import net.openhft.chronicle.queue.main.DumpMain; 4 | 5 | import java.io.FileNotFoundException; 6 | 7 | /** 8 | * Created by catherine on 18/07/2016. 9 | */ 10 | public class PrintQueueMain { 11 | public static void main(String[] args) throws FileNotFoundException { 12 | // Allow the queue path to be specified via command-line arguments 13 | String path = (args.length > 0) ? args[0] : "queue"; 14 | 15 | DumpMain.dump(path); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /simple-input/src/main/java/net/openhft/chronicle/queue/simple/input/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package contains simple examples demonstrating how to use Chronicle Queue for inter-process communication. 3 | * 4 | *

Classes included:

5 | *
    6 | *
  • {@link net.openhft.chronicle.queue.simple.input.InputMain}: Reads input from the console and writes it to the queue.
  • 7 | *
  • {@link net.openhft.chronicle.queue.simple.input.OutputMain}: Reads messages from the queue and outputs them to the console.
  • 8 | *
  • {@link net.openhft.chronicle.queue.simple.input.PrintQueueMain}: Dumps the contents of the queue to the console.
  • 9 | *
10 | * 11 | *

These examples showcase basic usage patterns of Chronicle Queue, illustrating how to write to and read from a queue, 12 | * and how to dump the queue contents.

13 | * 14 | *

The examples demonstrate inter-process communication, 15 | * one of the main features of Chronicle Queue.

16 | */ 17 | package net.openhft.chronicle.queue.simple.input; 18 | -------------------------------------------------------------------------------- /simple-translator/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | run.chronicle 9 | chronicle-queue-demo 10 | 1.0-SNAPSHOT 11 | ../pom.xml 12 | 13 | 14 | simple-translator 15 | OpenHFT/${project.parent.artifactId}/${project.artifactId} 16 | 17 | 18 | 19 | org.junit.jupiter 20 | junit-jupiter 21 | test 22 | 23 | 24 | org.mockito 25 | mockito-core 26 | test 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /simple-translator/src/main/java/net/openhft/chronicle/queue/simple/translator/InputMain.java: -------------------------------------------------------------------------------- 1 | package net.openhft.chronicle.queue.simple.translator; 2 | 3 | import net.openhft.chronicle.queue.impl.single.SingleChronicleQueue; 4 | import net.openhft.chronicle.queue.impl.single.SingleChronicleQueueBuilder; 5 | 6 | import java.util.Scanner; 7 | 8 | /** 9 | * A Main class that takes user input from the console and writes it to a queue ("queue-en"). 10 | * Continues to accept input until an empty line is entered by the user. 11 | * 12 | * Created by catherine on 26/07/2016. 13 | */ 14 | public class InputMain { 15 | public static void main(String[] args) { 16 | // Path to the queue where input will be stored 17 | String path_en = "queue-en"; 18 | 19 | // Create a SingleChronicleQueue for storing the input 20 | SingleChronicleQueue queue_en = SingleChronicleQueueBuilder.binary(path_en).build(); 21 | 22 | // Create a MessageConsumer that will append messages to the queue 23 | MessageConsumer messageConsumer = queue_en.createAppender().methodWriter(MessageConsumer.class); 24 | 25 | // Create a Scanner to read input from the console 26 | Scanner read = new Scanner(System.in); 27 | 28 | // Continuously read input from the console and write it to the queue 29 | while (true) { 30 | System.out.println("type something"); 31 | String line = read.nextLine(); 32 | 33 | // Exit the loop if the input line is empty 34 | if (line.isEmpty()) 35 | break; 36 | 37 | // Write the input to the queue 38 | messageConsumer.onMessage(line); 39 | } 40 | 41 | // Inform the user that the program has finished 42 | System.out.println("... bye."); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /simple-translator/src/main/java/net/openhft/chronicle/queue/simple/translator/MessageConsumer.java: -------------------------------------------------------------------------------- 1 | package net.openhft.chronicle.queue.simple.translator; 2 | 3 | /** 4 | * Represents a consumer that processes translated messages. 5 | *

6 | * Implementations of this interface define the strategy for handling or processing 7 | * messages that have been translated from one language to another. 8 | *

9 | * 10 | * Created by catherine on 26/07/2016. 11 | */ 12 | @FunctionalInterface 13 | public interface MessageConsumer { 14 | 15 | /** 16 | * Processes the specified message. 17 | * 18 | * @param message the translated message to be processed; must not be {@code null} 19 | * @throws IllegalArgumentException if {@code message} is {@code null} 20 | */ 21 | void onMessage(String message); 22 | } 23 | -------------------------------------------------------------------------------- /simple-translator/src/main/java/net/openhft/chronicle/queue/simple/translator/OutputMain.java: -------------------------------------------------------------------------------- 1 | package net.openhft.chronicle.queue.simple.translator; 2 | 3 | import net.openhft.chronicle.bytes.MethodReader; 4 | import net.openhft.chronicle.queue.impl.single.SingleChronicleQueue; 5 | import net.openhft.chronicle.queue.impl.single.SingleChronicleQueueBuilder; 6 | 7 | /** 8 | * A Main class that reads messages from a queue ("queue-fr") and outputs them to the console. 9 | * It creates a MessageConsumer using a lambda expression to print the received messages. 10 | * 11 | * Created by catherine on 17/07/2016. 12 | */ 13 | public class OutputMain { 14 | public static void main(String[] args) throws InterruptedException { 15 | // Path to the queue from which messages will be read 16 | String path = "queue-fr"; 17 | 18 | // Create a SingleChronicleQueue for reading the messages 19 | SingleChronicleQueue queue = SingleChronicleQueueBuilder.binary(path).build(); 20 | 21 | // Create a MessageConsumer that will print the received messages to the console 22 | MessageConsumer messagePrinter = System.out::println; 23 | 24 | // Create a MethodReader that will read messages from the queue 25 | MethodReader methodReader = queue.createTailer().methodReader(messagePrinter); 26 | 27 | // Continuously read and print messages from the queue 28 | while (true) { 29 | // Read and print one message, if available 30 | // If no message was available, pause for a short time to avoid busy-waiting 31 | if (!methodReader.readOne()) 32 | Thread.sleep(10); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /simple-translator/src/main/java/net/openhft/chronicle/queue/simple/translator/PrintQueueMain.java: -------------------------------------------------------------------------------- 1 | package net.openhft.chronicle.queue.simple.translator; 2 | 3 | import net.openhft.chronicle.queue.main.DumpMain; 4 | 5 | import java.io.FileNotFoundException; 6 | 7 | /** 8 | * A Main class that prints out the contents of two queues ("queue-en" and "queue-fr"). 9 | * It uses the DumpMain utility from the Chronicle Queue library to perform the printing. 10 | * 11 | * Created by catherine on 18/07/2016. 12 | */ 13 | public class PrintQueueMain { 14 | public static void main(String[] args) throws FileNotFoundException { 15 | // Print the contents of the English queue 16 | DumpMain.dump("queue-en"); 17 | 18 | // Print the contents of the French queue 19 | DumpMain.dump("queue-fr"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /simple-translator/src/main/java/net/openhft/chronicle/queue/simple/translator/TranslatorMain.java: -------------------------------------------------------------------------------- 1 | package net.openhft.chronicle.queue.simple.translator; 2 | 3 | import net.openhft.chronicle.bytes.MethodReader; 4 | import net.openhft.chronicle.queue.impl.single.SingleChronicleQueue; 5 | import net.openhft.chronicle.queue.impl.single.SingleChronicleQueueBuilder; 6 | 7 | /** 8 | * A Main class that sets up a translator for messages between two queues. 9 | * This class reads messages from an English queue, translates them into French, 10 | * and then writes the translated messages into a French queue. 11 | * 12 | * Created by catherine on 26/07/2016. 13 | */ 14 | public class TranslatorMain { 15 | public static void main(String[] args) throws InterruptedException { 16 | // Path to the queue for French messages 17 | String pathfr = "queue-fr"; 18 | 19 | // Create a SingleChronicleQueue for French messages 20 | SingleChronicleQueue queuefr = SingleChronicleQueueBuilder.binary(pathfr).build(); 21 | 22 | // Create a MessageConsumer that will append messages to the French queue 23 | MessageConsumer messageConsumer = queuefr.createAppender().methodWriter(MessageConsumer.class); 24 | 25 | // Create a SimpleTranslator that will translate messages to French 26 | MessageConsumer simpleTranslator = new SimpleTranslator(messageConsumer); 27 | 28 | // Path to the queue for English messages 29 | String path_en = "queue-en"; 30 | 31 | // Create a SingleChronicleQueue for English messages 32 | SingleChronicleQueue queue_en = SingleChronicleQueueBuilder.binary(path_en).build(); 33 | 34 | // Create a MethodReader that will read messages from the English queue 35 | MethodReader methodReader = queue_en.createTailer().methodReader(simpleTranslator); 36 | 37 | // Continuously read and translate messages from the English queue to the French queue 38 | while (true) { 39 | // Read and translate one message, if available 40 | // If no message was available, pause for a short time to avoid busy-waiting 41 | if (!methodReader.readOne()) 42 | Thread.sleep(10); 43 | } 44 | } 45 | } 46 | --------------------------------------------------------------------------------