├── .github
└── workflows
│ ├── ci.yml
│ ├── gradle-wrapper-validation.yml
│ └── release.yml
├── .gitignore
├── .travis.yml
├── LICENCE.txt
├── README.md
├── build.gradle
├── config
└── checkstyle
│ └── checkstyle.xml
├── doc
└── DisruptorProxy.jpg
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── manifest
└── MANIFEST.MF
├── settings.gradle
└── src
├── main
└── java
│ └── com
│ └── lmax
│ └── tool
│ └── disruptor
│ ├── BatchListener.java
│ ├── BatchSizeListener.java
│ ├── ConfigurableValidator.java
│ ├── DisruptorProxy.java
│ ├── DropListener.java
│ ├── GeneratorType.java
│ ├── Invoker.java
│ ├── MessagePublicationListener.java
│ ├── NoMessagePublicationListener.java
│ ├── NoOpDropListener.java
│ ├── OverflowStrategy.java
│ ├── ProxyMethodInvocation.java
│ ├── Resetable.java
│ ├── RingBufferProxyEventFactory.java
│ ├── RingBufferProxyGenerator.java
│ ├── RingBufferProxyGeneratorFactory.java
│ ├── RingBufferProxyValidation.java
│ ├── ValidationConfig.java
│ ├── ValidationConfigBuilder.java
│ ├── bytecode
│ ├── ArgumentHolderGenerator.java
│ ├── ArgumentHolderHelper.java
│ ├── ByteCodeHelper.java
│ └── GeneratedRingBufferProxyGenerator.java
│ ├── handlers
│ ├── BatchSizeReportingEventHandler.java
│ ├── EndOfBatchEventHandler.java
│ ├── Handlers.java
│ ├── InvokerEventHandler.java
│ └── ResetHandler.java
│ └── reflect
│ ├── ObjectArrayHolder.java
│ ├── ReflectiveMethodInvoker.java
│ ├── ReflectiveRingBufferInvocationHandler.java
│ └── ReflectiveRingBufferProxyGenerator.java
└── test
└── java
└── com
└── lmax
└── tool
└── disruptor
├── AbstractRingBufferProxyGeneratorTest.java
├── BatchAwareListenerImpl.java
├── CountingDropListener.java
├── CountingMessagePublicationListener.java
├── Listener.java
├── ListenerImpl.java
├── RingBufferProxyGeneratorFactoryTest.java
├── RingBufferProxyValidationTest.java
├── bytecode
├── ArgumentHolderHelperTest.java
└── BytecodeGenerationRingBufferProxyGeneratorTest.java
├── handlers
└── HandlersTest.java
└── reflect
├── ReflectiveRingBufferInvocationHandlerTest.java
└── ReflectiveRingBufferProxyGeneratorTest.java
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Java CI with Gradle
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 | strategy:
13 | matrix:
14 | java: [ 11 ]
15 | name: Java ${{ matrix.java }}
16 | steps:
17 | - uses: actions/checkout@v2
18 |
19 | - name: Set up java
20 | uses: actions/setup-java@v1
21 | with:
22 | java-version: ${{ matrix.java }}
23 |
24 | - name: Setup Gradle
25 | uses: gradle/actions/setup-gradle@v3
26 |
27 | - name: Grant execute permission for gradlew
28 | run: chmod +x gradlew
29 |
30 | - name: Build with Gradle
31 | run: ./gradlew build
32 |
33 | dependency-submission:
34 | runs-on: ubuntu-latest
35 | permissions:
36 | contents: write
37 |
38 | steps:
39 | - uses: actions/checkout@v4
40 |
41 | - name: Set up JDK 17
42 | uses: actions/setup-java@v4
43 | with:
44 | java-version: '11'
45 | distribution: 'temurin'
46 |
47 | - name: Generate and submit dependency graph
48 | uses: gradle/actions/dependency-submission@417ae3ccd767c252f5661f1ace9f835f9654f2b5
49 |
50 | javadoc:
51 | runs-on: ubuntu-latest
52 | permissions:
53 | contents: write
54 | pages: write
55 | id-token: write
56 |
57 | steps:
58 | - uses: actions/checkout@v4
59 |
60 | - name: Set up JDK 17
61 | uses: actions/setup-java@v4
62 | with:
63 | java-version: '17'
64 | distribution: 'temurin'
65 |
66 | - name: Setup Gradle
67 | uses: gradle/actions/setup-gradle@v3
68 |
69 | - name: Build Javadoc
70 | run: ./gradlew javadoc
71 |
72 | - name: Deploy Pages Content
73 | uses: JamesIves/github-pages-deploy-action@v4.6.4
74 | # https://stackoverflow.com/questions/64781462/github-actions-default-branch-variable
75 | if: ${{ always() && format('refs/heads/{0}', github.event.repository.default_branch) == github.ref }}
76 | with:
77 | folder: build/docs/javadoc
--------------------------------------------------------------------------------
/.github/workflows/gradle-wrapper-validation.yml:
--------------------------------------------------------------------------------
1 | name: "Validate Gradle Wrapper"
2 | on: [push, pull_request]
3 |
4 | jobs:
5 | validation:
6 | name: "Validation"
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v2
10 | - uses: gradle/wrapper-validation-action@v1
11 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Publish Release Artifacts
2 | on:
3 | release:
4 | types: [ created ]
5 |
6 | permissions:
7 | contents: write
8 | packages: write
9 | id-token: write
10 |
11 | jobs:
12 | publish:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v4
16 | with:
17 | fetch-depth: '0'
18 | - name: Set up Java
19 | uses: actions/setup-java@v3
20 | with:
21 | java-version: '11'
22 | distribution: 'temurin'
23 | - name: Validate Gradle wrapper
24 | uses: gradle/wrapper-validation-action@v1
25 | - name: Set Gradle App Version to ${{ github.event.release.tag_name }}
26 | run: sed -i "s/version = '.*'/version = '${{ github.event.release.tag_name }}'/g" build.gradle
27 | - name: Publish package
28 | uses: gradle/gradle-build-action@v2.11.1
29 | with:
30 | arguments: publish
31 | env:
32 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33 | - name: Publish package to Maven Central
34 | uses: gradle/gradle-build-action@v2.11.1
35 | with:
36 | arguments: jreleaserFullRelease
37 | env:
38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39 | JRELEASER_MAVENCENTRAL_USERNAME: ${{ secrets.JRELEASER_MAVENCENTRAL_USERNAME }}
40 | JRELEASER_MAVENCENTRAL_TOKEN: ${{ secrets.JRELEASER_MAVENCENTRAL_TOKEN }}
41 | JRELEASER_GPG_SECRET_KEY: "${{ secrets.JRELEASER_GPG_SECRET_KEY }}"
42 | JRELEASER_GPG_PUBLIC_KEY: "${{ secrets.JRELEASER_GPG_PUBLIC_KEY }}"
43 | JRELEASER_GPG_PASSPHRASE: "${{ secrets.JRELEASER_GPG_PASSPHRASE }}"
44 | JRELEASER_GITHUB_TOKEN: ${{ github.token }}
45 | JRELEASER_MAVENCENTRAL_STAGE: "FULL"
46 | - name: Add Artifact to GitHub Release
47 | uses: softprops/action-gh-release@v1
48 | with:
49 | files: build/libs/disruptor-proxy-*.jar
50 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.toptal.com/developers/gitignore/api/java,linux,gradle,intellij
2 | # Edit at https://www.toptal.com/developers/gitignore?templates=java,linux,gradle,intellij
3 |
4 | ### Intellij ###
5 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
6 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
7 |
8 | # User-specific stuff
9 | .idea/**/workspace.xml
10 | .idea/**/tasks.xml
11 | .idea/**/usage.statistics.xml
12 | .idea/**/dictionaries
13 | .idea/**/shelf
14 |
15 | # AWS User-specific
16 | .idea/**/aws.xml
17 |
18 | # Generated files
19 | .idea/**/contentModel.xml
20 |
21 | # Sensitive or high-churn files
22 | .idea/**/dataSources/
23 | .idea/**/dataSources.ids
24 | .idea/**/dataSources.local.xml
25 | .idea/**/sqlDataSources.xml
26 | .idea/**/dynamic.xml
27 | .idea/**/uiDesigner.xml
28 | .idea/**/dbnavigator.xml
29 |
30 | # Gradle
31 | .idea/**/gradle.xml
32 | .idea/**/libraries
33 |
34 | # Gradle and Maven with auto-import
35 | # When using Gradle or Maven with auto-import, you should exclude module files,
36 | # since they will be recreated, and may cause churn. Uncomment if using
37 | # auto-import.
38 | # .idea/artifacts
39 | # .idea/compiler.xml
40 | # .idea/jarRepositories.xml
41 | # .idea/modules.xml
42 | # .idea/*.iml
43 | # .idea/modules
44 | # *.iml
45 | # *.ipr
46 |
47 | # CMake
48 | cmake-build-*/
49 |
50 | # Mongo Explorer plugin
51 | .idea/**/mongoSettings.xml
52 |
53 | # File-based project format
54 | *.iws
55 |
56 | # IntelliJ
57 | out/
58 |
59 | # mpeltonen/sbt-idea plugin
60 | .idea_modules/
61 |
62 | # JIRA plugin
63 | atlassian-ide-plugin.xml
64 |
65 | # Cursive Clojure plugin
66 | .idea/replstate.xml
67 |
68 | # SonarLint plugin
69 | .idea/sonarlint/
70 |
71 | # Crashlytics plugin (for Android Studio and IntelliJ)
72 | com_crashlytics_export_strings.xml
73 | crashlytics.properties
74 | crashlytics-build.properties
75 | fabric.properties
76 |
77 | # Editor-based Rest Client
78 | .idea/httpRequests
79 |
80 | # Android studio 3.1+ serialized cache file
81 | .idea/caches/build_file_checksums.ser
82 |
83 | ### Intellij Patch ###
84 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
85 |
86 | # *.iml
87 | # modules.xml
88 | # .idea/misc.xml
89 | # *.ipr
90 |
91 | # Sonarlint plugin
92 | # https://plugins.jetbrains.com/plugin/7973-sonarlint
93 | .idea/**/sonarlint/
94 |
95 | # SonarQube Plugin
96 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
97 | .idea/**/sonarIssues.xml
98 |
99 | # Markdown Navigator plugin
100 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
101 | .idea/**/markdown-navigator.xml
102 | .idea/**/markdown-navigator-enh.xml
103 | .idea/**/markdown-navigator/
104 |
105 | # Cache file creation bug
106 | # See https://youtrack.jetbrains.com/issue/JBR-2257
107 | .idea/$CACHE_FILE$
108 |
109 | # CodeStream plugin
110 | # https://plugins.jetbrains.com/plugin/12206-codestream
111 | .idea/codestream.xml
112 |
113 | # Azure Toolkit for IntelliJ plugin
114 | # https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
115 | .idea/**/azureSettings.xml
116 |
117 | ### Java ###
118 | # Compiled class file
119 | *.class
120 |
121 | # Log file
122 | *.log
123 |
124 | # BlueJ files
125 | *.ctxt
126 |
127 | # Mobile Tools for Java (J2ME)
128 | .mtj.tmp/
129 |
130 | # Package Files #
131 | *.jar
132 | *.war
133 | *.nar
134 | *.ear
135 | *.zip
136 | *.tar.gz
137 | *.rar
138 |
139 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
140 | hs_err_pid*
141 | replay_pid*
142 |
143 | ### Linux ###
144 | *~
145 |
146 | # temporary files which can be created if a process still has a handle open of a deleted file
147 | .fuse_hidden*
148 |
149 | # KDE directory preferences
150 | .directory
151 |
152 | # Linux trash folder which might appear on any partition or disk
153 | .Trash-*
154 |
155 | # .nfs files are created when an open file is removed but is still being accessed
156 | .nfs*
157 |
158 | ### Gradle ###
159 | .gradle
160 | **/build/
161 | !src/**/build/
162 |
163 | # Ignore Gradle GUI config
164 | gradle-app.setting
165 |
166 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
167 | !gradle-wrapper.jar
168 |
169 | # Avoid ignore Gradle wrappper properties
170 | !gradle-wrapper.properties
171 |
172 | # Cache of project
173 | .gradletasknamecache
174 |
175 | # Eclipse Gradle plugin generated files
176 | # Eclipse Core
177 | .project
178 | # JDT-specific (Eclipse Java Development Tools)
179 | .classpath
180 |
181 | ### Gradle Patch ###
182 | # Java heap dump
183 | *.hprof
184 |
185 | # End of https://www.toptal.com/developers/gitignore/api/java,linux,gradle,intellij
186 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 |
--------------------------------------------------------------------------------
/LICENCE.txt:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # disruptor-proxy
2 |
3 | 
4 | [](https://github.com/LMAX-Exchange/disruptor-proxy/blob/master/LICENCE.txt)
5 |
6 | The disruptor-proxy is a tool for creating thread-safe proxies to your existing business code.
7 |
8 | Utilising the power of the [Disruptor](https://github.com/LMAX-Exchange/disruptor),
9 | disruptor-proxy will provide a high-performance, low-latency multi-threaded interface
10 | to your single-threaded components.
11 |
12 | This in turn allows users to exploit the
13 | [single-writer principle](http://mechanical-sympathy.blogspot.co.uk/2011/09/single-writer-principle.html)
14 | for maximum straight-line performance.
15 |
16 | 
17 |
18 | ## Maintainer
19 |
20 |
21 | LMAX Development Team
22 |
23 | ## Examples
24 |
25 | ```java
26 |
27 | // Basic usage
28 |
29 | final RingBufferProxyGeneratorFactory generatorFactory = new RingBufferProxyGeneratorFactory();
30 |
31 | final T tImpl = new ConcreteT();
32 |
33 | final RingBufferProxyGenerator generator = generatorFactory.newProxy(GeneratorType.BYTECODE_GENERATION);
34 |
35 | final T proxy = generator.createRingBufferProxy(T.class, disruptor, OverflowStrategy.DROP, tImpl);
36 |
37 | disruptor.start();
38 | ```
39 |
40 |
41 |
42 | ```java
43 |
44 | // Get notified of end-of-batch events
45 |
46 | final RingBufferProxyGeneratorFactory generatorFactory = new RingBufferProxyGeneratorFactory();
47 |
48 | final T tImpl = new ConcreteT();
49 | final BatchListener batchListener = (BatchListener) tImpl; // implement BatchListener in your component
50 |
51 | final RingBufferProxyGenerator generator = generatorFactory.newProxy(GeneratorType.BYTECODE_GENERATION);
52 |
53 | final T proxy = generator.createRingBufferProxy(T.class, disruptor, OverflowStrategy.DROP, tImpl);
54 |
55 | disruptor.start();
56 | ```
57 |
58 |
59 |
60 | ```java
61 |
62 | // Get notified of buffer-overflow events
63 |
64 | final RingBufferProxyGeneratorFactory generatorFactory = new RingBufferProxyGeneratorFactory();
65 |
66 | final T tImpl = new ConcreteT();
67 | final DropListener dropListener = new MyDropListener(); // handle drop events
68 |
69 | final RingBufferProxyGenerator generator =
70 | generatorFactory.newProxy(GeneratorType.BYTECODE_GENERATION,
71 | new ConfigurableValidator(true, true),
72 | dropListener);
73 |
74 | final T proxy = generator.createRingBufferProxy(T.class, disruptor, OverflowStrategy.DROP, tImpl);
75 |
76 | disruptor.start();
77 | ```
78 |
79 |
80 | ## GeneratorType
81 |
82 | * `GeneratorType.JDK_REFLECTION` - uses `java.lang.reflect.Proxy` to generate a dynamic proxy that will add events to the RingBuffer. Use this for minimal dependencies.
83 | * `GeneratorType.BYTECODE_GENERATION` - uses Javassist to generate classes that will add events to the RingBuffer. Use this for maximum performance.
84 |
85 |
86 | ## Dependencies
87 |
88 | Minimal dependency is the Disruptor JAR.
89 |
90 | If you are using byte-code generation for the proxy class (specified by `GeneratorType`), you'll also need the Javassist JAR.
91 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | plugins {
18 | id 'java'
19 | id 'java-library'
20 | id 'maven-publish'
21 | id 'signing'
22 | id 'checkstyle'
23 | id 'idea'
24 | id "biz.aQute.bnd.builder" version "6.3.1"
25 | id 'org.jreleaser' version '1.14.0'
26 | }
27 |
28 |
29 | defaultTasks 'checkstyleTest', 'checkstyleMain', 'build'
30 |
31 | group = 'com.lmax'
32 | // The below is updated by CI during the release
33 | version = '1.0.0'
34 |
35 | ext {
36 | fullName = 'Disruptor-Proxy'
37 | fullDescription = 'A utility for generating Disruptor-backed proxies for easy execution serialisation'
38 | teamName = 'LMAX Development Team'
39 | siteUrl = 'https://github.com/LMAX-Exchange/disruptor-proxy'
40 | sourceUrl = 'git@github.com:LMAX-Exchange/disruptor-proxy.git'
41 | }
42 |
43 | repositories {
44 | mavenCentral()
45 | }
46 |
47 | dependencies {
48 | testImplementation 'junit:junit:4.5'
49 | testImplementation 'org.hamcrest:hamcrest-core:1.3'
50 | implementation 'org.javassist:javassist:3.30.2-GA'
51 | implementation 'com.lmax:disruptor:3.3.0'
52 | }
53 |
54 |
55 | java {
56 | toolchain {
57 | languageVersion = JavaLanguageVersion.of(11)
58 | }
59 | withJavadocJar()
60 | withSourcesJar()
61 | }
62 |
63 | checkstyle {
64 | toolVersion = 6.3
65 | }
66 |
67 | publishing {
68 | publications {
69 | disruptor(MavenPublication) {
70 | from components.java
71 |
72 | groupId = 'com.lmax'
73 | artifactId = 'disruptor-proxy'
74 |
75 | pom {
76 | name = project.ext.fullName
77 | description = project.ext.fullDescription
78 | url = project.ext.siteUrl
79 |
80 | scm {
81 | url = "scm:${project.ext.sourceUrl}"
82 | connection = "scm:${project.ext.sourceUrl}"
83 | developerConnection = "scm:${project.ext.sourceUrl}"
84 | }
85 |
86 | licenses {
87 | license {
88 | name = 'Apache-2.0'
89 | url = 'https://spdx.org/licenses/Apache-2.0.html'
90 | }
91 | }
92 |
93 | developers {
94 | developer {
95 | id = 'LMAX Group Open Source'
96 | name = teamName
97 | email = 'opensource@lmax.com'
98 | }
99 | }
100 | }
101 | }
102 | }
103 |
104 |
105 | repositories {
106 | maven {
107 | url = layout.buildDirectory.dir('staging-deploy')
108 | }
109 | }
110 | }
111 |
112 | jreleaser {
113 | files {
114 | active = 'ALWAYS'
115 | glob {
116 | pattern = 'build/staging-deploy/**/*.jar'
117 | pattern = 'build/staging-deploy/**/*.pom'
118 | pattern = 'build/staging-deploy/**/*.module'
119 | }
120 | }
121 | signing {
122 | active = 'ALWAYS'
123 | armored = true
124 | mode = 'MEMORY'
125 | }
126 | deploy {
127 | maven {
128 | mavenCentral {
129 | sonatype {
130 | active = 'ALWAYS'
131 | url = 'https://central.sonatype.com/api/v1/publisher'
132 | stagingRepository('build/staging-deploy')
133 | applyMavenCentralRules = true
134 | }
135 | }
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/config/checkstyle/checkstyle.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
192 |
194 |
195 |
196 |
197 |
198 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
--------------------------------------------------------------------------------
/doc/DisruptorProxy.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LMAX-Exchange/disruptor-proxy/f6b99be6c7835c1d8a60643e796548d179b556db/doc/DisruptorProxy.jpg
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LMAX-Exchange/disruptor-proxy/f6b99be6c7835c1d8a60643e796548d179b556db/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
4 | networkTimeout=10000
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
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 | # https://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 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | # This is normally unused
84 | # shellcheck disable=SC2034
85 | APP_BASE_NAME=${0##*/}
86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
87 |
88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
147 | # shellcheck disable=SC3045
148 | MAX_FD=$( ulimit -H -n ) ||
149 | warn "Could not query maximum file descriptor limit"
150 | esac
151 | case $MAX_FD in #(
152 | '' | soft) :;; #(
153 | *)
154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
155 | # shellcheck disable=SC3045
156 | ulimit -n "$MAX_FD" ||
157 | warn "Could not set maximum file descriptor limit to $MAX_FD"
158 | esac
159 | fi
160 |
161 | # Collect all arguments for the java command, stacking in reverse order:
162 | # * args from the command line
163 | # * the main class name
164 | # * -classpath
165 | # * -D...appname settings
166 | # * --module-path (only if needed)
167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
168 |
169 | # For Cygwin or MSYS, switch paths to Windows format before running java
170 | if "$cygwin" || "$msys" ; then
171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
173 |
174 | JAVACMD=$( cygpath --unix "$JAVACMD" )
175 |
176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
177 | for arg do
178 | if
179 | case $arg in #(
180 | -*) false ;; # don't mess with options #(
181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
182 | [ -e "$t" ] ;; #(
183 | *) false ;;
184 | esac
185 | then
186 | arg=$( cygpath --path --ignore --mixed "$arg" )
187 | fi
188 | # Roll the args list around exactly as many times as the number of
189 | # args, so each arg winds up back in the position where it started, but
190 | # possibly modified.
191 | #
192 | # NB: a `for` loop captures its iteration list before it begins, so
193 | # changing the positional parameters here affects neither the number of
194 | # iterations, nor the values presented in `arg`.
195 | shift # remove old arg
196 | set -- "$@" "$arg" # push replacement arg
197 | done
198 | fi
199 |
200 | # Collect all arguments for the java command;
201 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
202 | # shell script including quotes and variable substitutions, so put them in
203 | # double quotes to make sure that they get re-expanded; and
204 | # * put everything else in single quotes, so that it's not re-expanded.
205 |
206 | set -- \
207 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
208 | -classpath "$CLASSPATH" \
209 | org.gradle.wrapper.GradleWrapperMain \
210 | "$@"
211 |
212 | # Stop when "xargs" is not available.
213 | if ! command -v xargs >/dev/null 2>&1
214 | then
215 | die "xargs is not available"
216 | fi
217 |
218 | # Use "xargs" to parse quoted args.
219 | #
220 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
221 | #
222 | # In Bash we could simply go:
223 | #
224 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
225 | # set -- "${ARGS[@]}" "$@"
226 | #
227 | # but POSIX shell has neither arrays nor command substitution, so instead we
228 | # post-process each arg (as a line of input to sed) to backslash-escape any
229 | # character that might be a shell metacharacter, then use eval to reverse
230 | # that process (while maintaining the separation between arguments), and wrap
231 | # the whole thing up as a single "set" statement.
232 | #
233 | # This will of course break if any of these variables contains a newline or
234 | # an unmatched quote.
235 | #
236 |
237 | eval "set -- $(
238 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
239 | xargs -n1 |
240 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
241 | tr '\n' ' '
242 | )" '"$@"'
243 |
244 | exec "$JAVACMD" "$@"
245 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo.
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
48 | echo.
49 | echo Please set the JAVA_HOME variable in your environment to match the
50 | echo location of your Java installation.
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo.
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
62 | echo.
63 | echo Please set the JAVA_HOME variable in your environment to match the
64 | echo location of your Java installation.
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/manifest/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Project: @project.name@
2 | Author: Mark Price
3 | Version: @version.major@.@version.minor@
4 | Build-Date: @version.timestamp@
5 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | rootProject.name = 'disruptor-proxy'
18 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/BatchListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor;
18 |
19 | /**
20 | * An interface to describe objects that will be called on the end of a Disruptor batch.
21 | *
22 | * Implement this interface in your implementation object if you wish to be notified of the end of a Disruptor batch.
23 | */
24 | public interface BatchListener
25 | {
26 | /**
27 | * Will be called at the end of a Disruptor batch
28 | */
29 | void onEndOfBatch();
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/BatchSizeListener.java:
--------------------------------------------------------------------------------
1 | package com.lmax.tool.disruptor;
2 |
3 | /**
4 | * An interface to describe objects that will be notified of the current batch size at the end of each Disruptor batch.
5 | *
6 | * Implement this interface in your implementation object if you wish to be notified of the size of each Disruptor batch.
7 | */
8 | public interface BatchSizeListener
9 | {
10 |
11 | /**
12 | * Will be called at the end of a Disruptor batch
13 | * @param batchSize The size of the batch
14 | */
15 | void onEndOfBatch(int batchSize);
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/ConfigurableValidator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lmax.tool.disruptor;
17 |
18 | import com.lmax.disruptor.dsl.Disruptor;
19 |
20 | import java.lang.annotation.Annotation;
21 | import java.lang.reflect.Field;
22 |
23 | public final class ConfigurableValidator implements RingBufferProxyValidation, ValidationConfig
24 | {
25 |
26 | private final boolean validateProxyInterfaces;
27 | private final boolean validateExceptionHandler;
28 |
29 | public ConfigurableValidator(final ProxyInterface proxyInterfaceConfiguration,
30 | final ExceptionHandler exceptionHandlerConfiguration)
31 | {
32 | this(proxyInterfaceConfiguration.shouldValidateProxyInterfaces(),
33 | exceptionHandlerConfiguration.shouldValidateExceptionHandler());
34 | }
35 |
36 |
37 | public ConfigurableValidator(final boolean validateProxyInterfaces, final boolean validateExceptionHandler)
38 | {
39 | this.validateProxyInterfaces = validateProxyInterfaces;
40 | this.validateExceptionHandler = validateExceptionHandler;
41 | }
42 |
43 | public ConfigurableValidator(final ValidationConfig validationConfig)
44 | {
45 | this(validationConfig.validateProxyInterfaces(), validationConfig.validateExceptionHandler());
46 | }
47 |
48 | @Override
49 | public void validateAll(final Disruptor> disruptor, final Class> disruptorProxyInterface)
50 | {
51 | ensureThatProxyInterfaceIsAnInterface(disruptorProxyInterface);
52 | ensureDisruptorInstanceHasAnExceptionHandler(disruptor);
53 | ensureDisruptorProxyIsAnnotatedWithDisruptorProxyAnnotation(disruptorProxyInterface);
54 | }
55 |
56 | private void ensureThatProxyInterfaceIsAnInterface(final Class> disruptorProxyInterface)
57 | {
58 | if(!disruptorProxyInterface.isInterface())
59 | {
60 | throw new IllegalArgumentException("Not an interface: " + disruptorProxyInterface);
61 | }
62 | }
63 |
64 | private void ensureDisruptorInstanceHasAnExceptionHandler(final Disruptor> disruptor)
65 | {
66 | if (!validateExceptionHandler)
67 | {
68 | return;
69 | }
70 | try
71 | {
72 | final Field field = Disruptor.class.getDeclaredField("exceptionHandler");
73 | field.setAccessible(true);
74 | final Object exceptionHandler = field.get(disruptor);
75 | if (exceptionHandler == null)
76 | {
77 | throw new IllegalStateException("Please supply an ExceptionHandler to the Disruptor instance. " +
78 | "The default Disruptor behaviour is to stop processing when an exception occurs.");
79 | }
80 | if (exceptionHandler.getClass().getSimpleName().equals("com.lmax.disruptor.dsl.ExceptionHandlerWrapper"))
81 | {
82 | final Field delegateField = exceptionHandler.getClass().getDeclaredField("delegate");
83 | delegateField.setAccessible(true);
84 | final Object nestedExceptionHandler = delegateField.get(exceptionHandler);
85 | if (nestedExceptionHandler == null)
86 | {
87 | throw new IllegalStateException("Please supply an ExceptionHandler to the Disruptor instance. " +
88 | "The default Disruptor behaviour is to stop processing when an exception occurs.");
89 | }
90 | }
91 | }
92 | catch (NoSuchFieldException | IllegalAccessException e)
93 | {
94 | throw new RuntimeException("Unable to inspect Disruptor instance", e);
95 | }
96 | }
97 |
98 | // visible for testing
99 | void ensureDisruptorProxyIsAnnotatedWithDisruptorProxyAnnotation(final Class> disruptorProxyInterface)
100 | {
101 | if (!validateProxyInterfaces)
102 | {
103 | return;
104 | }
105 | for (Annotation annotation : disruptorProxyInterface.getAnnotations())
106 | {
107 | if (annotation instanceof DisruptorProxy)
108 | {
109 | return;
110 | }
111 | }
112 | throw new IllegalArgumentException("Please supply a disruptor proxy interface that is annotated with " + DisruptorProxy.class);
113 | }
114 |
115 | @Override
116 | public boolean validateProxyInterfaces()
117 | {
118 | return validateProxyInterfaces;
119 | }
120 |
121 | @Override
122 | public boolean validateExceptionHandler()
123 | {
124 | return validateExceptionHandler;
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/DisruptorProxy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lmax.tool.disruptor;
17 |
18 | import java.lang.annotation.ElementType;
19 | import java.lang.annotation.Retention;
20 | import java.lang.annotation.RetentionPolicy;
21 | import java.lang.annotation.Target;
22 |
23 | @Retention(RetentionPolicy.RUNTIME)
24 | @Target(ElementType.TYPE)
25 | public @interface DisruptorProxy
26 | {
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/DropListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor;
18 |
19 | /**
20 | * Interface for receiving notifications that the ring-buffer is full when using the DROP OverflowStrategy
21 | */
22 | public interface DropListener
23 | {
24 | void onDrop();
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/GeneratorType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor;
18 |
19 | /**
20 | * Specifies the proxy generator
21 | */
22 | public enum GeneratorType
23 | {
24 | /**
25 | * Use JDK reflection to create a proxy (creates garbage, has reflection overhead)
26 | */
27 | JDK_REFLECTION("com.lmax.tool.disruptor.reflect.ReflectiveRingBufferProxyGenerator"),
28 | /**
29 | * Use a bytecode-generation library to create a proxy (garbage-free, no reflection overhead)
30 | */
31 | BYTECODE_GENERATION("com.lmax.tool.disruptor.bytecode.GeneratedRingBufferProxyGenerator");
32 |
33 | private final String generatorClassname;
34 |
35 | GeneratorType(final String generatorClassName)
36 | {
37 | this.generatorClassname = generatorClassName;
38 | }
39 |
40 | public String getGeneratorClassName()
41 | {
42 | return generatorClassname;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/Invoker.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor;
18 |
19 | /**
20 | * Interface for a component that can invoke arguments on a target object
21 | */
22 | public interface Invoker
23 | {
24 | void invokeWithArgumentHolder(final Object implementation, final Object argumentHolder);
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/MessagePublicationListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor;
18 |
19 | /**
20 | * Interface for receiving notifications pre and post message publication
21 | */
22 | public interface MessagePublicationListener
23 | {
24 | /**
25 | * Called before message is published to the ringbuffer
26 | */
27 | void onPrePublish();
28 |
29 | /**
30 | * Called after message is published to the ringbuffer. Will not be called if using DROP overflow strategy
31 | * and message is dropped.
32 | */
33 | void onPostPublish();
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/NoMessagePublicationListener.java:
--------------------------------------------------------------------------------
1 | package com.lmax.tool.disruptor;
2 |
3 | /**
4 | * Default implementation of MessagePublicationListener
5 | */
6 | public enum NoMessagePublicationListener implements MessagePublicationListener
7 | {
8 | INSTANCE;
9 |
10 | @Override
11 | public void onPrePublish()
12 | {
13 |
14 | }
15 |
16 | @Override
17 | public void onPostPublish()
18 | {
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/NoOpDropListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor;
18 |
19 | /**
20 | * Default implementation of DropListener
21 | */
22 | public enum NoOpDropListener implements DropListener
23 | {
24 | INSTANCE;
25 |
26 | @Override
27 | public void onDrop()
28 | {
29 | // no-op
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/OverflowStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor;
18 |
19 | /**
20 | * Specifies the action to take when the ring-buffer is full
21 | */
22 | public enum OverflowStrategy
23 | {
24 | /**
25 | * Block the publishing Thread
26 | */
27 | BLOCK,
28 | /**
29 | * Discard the message and continue
30 | */
31 | DROP
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/ProxyMethodInvocation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor;
18 |
19 | /**
20 | * A container for storing the arguments of a method invocation
21 | */
22 | public final class ProxyMethodInvocation
23 | {
24 | private Invoker invoker;
25 | private Resetable argumentHolder;
26 |
27 | public Invoker getInvoker()
28 | {
29 | return invoker;
30 | }
31 |
32 | public void setInvoker(final Invoker invoker)
33 | {
34 | this.invoker = invoker;
35 | }
36 |
37 | public void setArgumentHolder(final Resetable argumentHolder)
38 | {
39 | this.argumentHolder = argumentHolder;
40 | }
41 |
42 | public Object getArgumentHolder()
43 | {
44 | return argumentHolder;
45 | }
46 |
47 | public void reset()
48 | {
49 | argumentHolder.reset();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/Resetable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor;
18 |
19 | /**
20 | * A generic interface for components that can be reset
21 | */
22 | public interface Resetable
23 | {
24 | /**
25 | * Reset this component
26 | */
27 | void reset();
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/RingBufferProxyEventFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor;
18 |
19 | import com.lmax.disruptor.EventFactory;
20 |
21 | /**
22 | * A Disruptor EventFactory used to create ring-buffer entries
23 | */
24 | public final class RingBufferProxyEventFactory implements EventFactory
25 | {
26 | public static final EventFactory FACTORY = new RingBufferProxyEventFactory();
27 |
28 | @Override
29 | public ProxyMethodInvocation newInstance()
30 | {
31 | return new ProxyMethodInvocation();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/RingBufferProxyGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor;
18 |
19 | import com.lmax.disruptor.dsl.Disruptor;
20 |
21 | /**
22 | * Creates an implementation of the specified interface, backed by a Disruptor instance
23 | */
24 | public interface RingBufferProxyGenerator
25 | {
26 | /**
27 | * Create a disruptor proxy with a single implementation instance
28 | *
29 | * @param the type of the implementation
30 | * @param definition the type of the implementation
31 | * @param disruptor a disruptor instance
32 | * @param overflowStrategy an indicator of what action should be taken when the ring-buffer is full
33 | * @param implementation the implementation object to be invoked by the Disruptor event handler
34 | * @return an implementation of type T
35 | */
36 | T createRingBufferProxy(final Class definition, final Disruptor disruptor,
37 | final OverflowStrategy overflowStrategy, final T implementation);
38 |
39 | /**
40 | * Create a disruptor proxy with multiple implementation instances
41 | *
42 | * @param definition the type of the implementation
43 | * @param disruptor a disruptor instance
44 | * @param overflowStrategy an indicator of what action should be taken when the ring-buffer is full
45 | * @param implementations the implementation objects to be invoked by the Disruptor event handler (each on its own Thread)
46 | * @param the type of the implementation
47 | * @return an implementation of type T
48 | */
49 | @SuppressWarnings("varargs")
50 | T createRingBufferProxy(final Class definition, final Disruptor disruptor,
51 | final OverflowStrategy overflowStrategy, final T... implementations);
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/RingBufferProxyGeneratorFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor;
18 |
19 | import java.lang.reflect.Constructor;
20 |
21 | /**
22 | * A utility class to load a RingBufferProxyGenerator for the supplied type
23 | */
24 | public final class RingBufferProxyGeneratorFactory
25 | {
26 | /**
27 | * Creates a RingBufferProxyGenerator
28 | * @param generatorType the type of generator
29 | * @return the RingBufferProxyGenerator
30 | */
31 | public RingBufferProxyGenerator newProxy(final GeneratorType generatorType)
32 | {
33 | final ConfigurableValidator validateAsMuchAsPossibleValidator = new ConfigurableValidator(true, true);
34 | return newProxy(generatorType, validateAsMuchAsPossibleValidator);
35 | }
36 |
37 | /**
38 | * Creates a RingBufferProxyGenerator
39 | * @param generatorType the type of generator
40 | * @param config configure how much validation the ringBufferProxyGenerator should have
41 | * @return the RingBufferProxyGenerator
42 | */
43 | public RingBufferProxyGenerator newProxy(final GeneratorType generatorType, final ValidationConfig config)
44 | {
45 | return newProxy(generatorType, config, NoOpDropListener.INSTANCE);
46 | }
47 |
48 | /**
49 | * Creates a RingBufferProxyGenerator
50 | * @param generatorType the type of generator
51 | * @param config configure how much validation the ringBufferProxyGenerator should have
52 | * @param dropListener the supplied DropListener will be notified if the ring-buffer is full when OverflowStrategy is DROP
53 | * @return the RingBufferProxyGenerator
54 | */
55 | public RingBufferProxyGenerator newProxy(final GeneratorType generatorType, final ValidationConfig config, final DropListener dropListener)
56 | {
57 | return newProxy(generatorType, config, dropListener, NoMessagePublicationListener.INSTANCE);
58 | }
59 |
60 | /**
61 | * Creates a RingBufferProxyGenerator
62 | * @param generatorType the type of generator
63 | * @param config configure how much validation the ringBufferProxyGenerator should have
64 | * @param dropListener the supplied DropListener will be notified if the ring-buffer is full when OverflowStrategy is DROP
65 | * @param messagePublicationListener the supplied MessagePublicationListener will be notified before and after publishing
66 | * @return the RingBufferProxyGenerator
67 | */
68 | public RingBufferProxyGenerator newProxy(final GeneratorType generatorType, final ValidationConfig config,
69 | final DropListener dropListener, final MessagePublicationListener messagePublicationListener)
70 | {
71 | try
72 | {
73 | final Class> clazz = Class.forName(generatorType.getGeneratorClassName());
74 | ConfigurableValidator validator = new ConfigurableValidator(config.validateProxyInterfaces(), config.validateExceptionHandler());
75 | final Constructor> constructorForRingBufferProxyGenerator = clazz.getConstructor(RingBufferProxyValidation.class, DropListener.class, MessagePublicationListener.class);
76 | return (RingBufferProxyGenerator) constructorForRingBufferProxyGenerator.newInstance(validator, dropListener, messagePublicationListener);
77 | }
78 | catch (Exception e)
79 | {
80 | throw new IllegalStateException(String.format("Unable to instantiate generator %s",
81 | generatorType.getGeneratorClassName()), e);
82 | }
83 | }
84 |
85 | /**
86 | * @deprecated prefer newProxy().
87 | *
88 | * This method is left to preserve the existing behaviour now configurable in ValidationConfig.
89 | *
90 | * @param generatorType the type of generator
91 | * @return the RingBufferProxyGenerator
92 | */
93 | @Deprecated
94 | public RingBufferProxyGenerator create(final GeneratorType generatorType)
95 | {
96 | final ConfigurableValidator backwardsCompatibleValidator = new ConfigurableValidator(false, true);
97 | return newProxy(generatorType, backwardsCompatibleValidator);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/RingBufferProxyValidation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor;
18 |
19 | import com.lmax.disruptor.dsl.Disruptor;
20 |
21 | public interface RingBufferProxyValidation
22 | {
23 | void validateAll(Disruptor> disruptor, Class> disruptorProxyInterface);
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/ValidationConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lmax.tool.disruptor;
17 |
18 | public interface ValidationConfig
19 | {
20 | enum ProxyInterface
21 | {
22 | REQUIRES_ANNOTATION(true), NO_ANNOTATION(false);
23 |
24 | private final boolean validateProxyInterfaces;
25 |
26 | ProxyInterface(final boolean validateProxyInterfaces)
27 | {
28 | this.validateProxyInterfaces = validateProxyInterfaces;
29 | }
30 |
31 | public boolean shouldValidateProxyInterfaces()
32 | {
33 | return validateProxyInterfaces;
34 | }
35 | }
36 |
37 | enum ExceptionHandler
38 | {
39 | REQUIRED(true), NOT_REQUIRED(false);
40 |
41 | private final boolean validateExceptionHandler;
42 |
43 | ExceptionHandler(final boolean validateExceptionHandler)
44 | {
45 | this.validateExceptionHandler = validateExceptionHandler;
46 | }
47 |
48 | public boolean shouldValidateExceptionHandler()
49 | {
50 | return validateExceptionHandler;
51 | }
52 | }
53 |
54 | boolean validateProxyInterfaces();
55 |
56 | boolean validateExceptionHandler();
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/ValidationConfigBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lmax.tool.disruptor;
17 |
18 | public final class ValidationConfigBuilder implements ValidationConfig
19 | {
20 | private boolean validateExceptionHandler = true;
21 | private boolean validateProxyInterfaces = false;
22 |
23 | @Override
24 | public boolean validateProxyInterfaces()
25 | {
26 | return validateProxyInterfaces;
27 | }
28 |
29 | public void validateProxyInterfaces(boolean validateProxyInterfaces)
30 | {
31 | this.validateProxyInterfaces = validateProxyInterfaces;
32 | }
33 |
34 | @Override
35 | public boolean validateExceptionHandler()
36 | {
37 | return validateExceptionHandler;
38 | }
39 |
40 | public void validateExceptionHandler(boolean validateExceptionHandler)
41 | {
42 | this.validateExceptionHandler = validateExceptionHandler;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/bytecode/ArgumentHolderGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor.bytecode;
18 |
19 |
20 | import com.lmax.tool.disruptor.Resetable;
21 | import javassist.CannotCompileException;
22 | import javassist.ClassPool;
23 | import javassist.CtClass;
24 | import javassist.CtNewConstructor;
25 |
26 | import java.util.HashMap;
27 | import java.util.Map;
28 |
29 | import static com.lmax.tool.disruptor.bytecode.ByteCodeHelper.addInterface;
30 | import static com.lmax.tool.disruptor.bytecode.ByteCodeHelper.createField;
31 | import static com.lmax.tool.disruptor.bytecode.ByteCodeHelper.createMethod;
32 | import static com.lmax.tool.disruptor.bytecode.ByteCodeHelper.getUniqueIdentifier;
33 | import static com.lmax.tool.disruptor.bytecode.ByteCodeHelper.makeClass;
34 | import static com.lmax.tool.disruptor.bytecode.ByteCodeHelper.makePublicFinal;
35 |
36 | final class ArgumentHolderGenerator
37 | {
38 | private final ArgumentHolderHelper helper = new ArgumentHolderHelper();
39 | private final ClassPool classPool;
40 |
41 | private String generatedClassName;
42 | private Class> generatedClass;
43 | private Map, Integer> parameterTypeCounts;
44 | private Map, Character> parameterFieldSuffix = new HashMap, Character>();
45 |
46 | public ArgumentHolderGenerator(final ClassPool classPool)
47 | {
48 | this.classPool = classPool;
49 | }
50 |
51 | public void createArgumentHolderClass(final Class> proxyInterface)
52 | {
53 | final CtClass ctClass = makeClass(classPool, "com.lmax.tool.disruptor.bytecode._argumentHolder_" + proxyInterface.getSimpleName() + "_" + getUniqueIdentifier());
54 |
55 | parameterTypeCounts = helper.getParameterTypeCounts(proxyInterface);
56 | createFields(ctClass);
57 | createMethod(ctClass, generateResetMethod());
58 | addInterface(ctClass, Resetable.class, classPool);
59 |
60 | try
61 | {
62 | ctClass.addConstructor(CtNewConstructor.defaultConstructor(ctClass));
63 | makePublicFinal(ctClass);
64 | generatedClass = ctClass.toClass(ArgumentHolderGenerator.class);
65 | }
66 | catch (CannotCompileException e)
67 | {
68 | throw new RuntimeException("Cannot generate argument holder object", e);
69 | }
70 |
71 | generatedClassName = ctClass.getName();
72 |
73 | }
74 |
75 | public void resetFieldNames()
76 | {
77 | parameterFieldSuffix.clear();
78 | for (Class> parameterType : parameterTypeCounts.keySet())
79 | {
80 | parameterFieldSuffix.put(parameterType, 'a');
81 | }
82 | }
83 |
84 | public String getNextFieldNameForType(final Class> parameterType)
85 | {
86 | final Character suffix = parameterFieldSuffix.get(parameterType);
87 | parameterFieldSuffix.put(parameterType, (char) (suffix + 1));
88 | return getSanitisedFieldName(parameterType) + "_" + suffix;
89 | }
90 |
91 | public String getGeneratedClassName()
92 | {
93 | return generatedClassName;
94 | }
95 |
96 | public Class> getGeneratedClass()
97 | {
98 | return generatedClass;
99 | }
100 |
101 | private void createFields(final CtClass ctClass)
102 | {
103 | for (Map.Entry, Integer> entry : parameterTypeCounts.entrySet())
104 | {
105 | final StringBuilder buffer = new StringBuilder();
106 | final char suffix = 'a';
107 | final int parameterCount = entry.getValue();
108 |
109 | final Class> parameterType = entry.getKey();
110 | final String parameterTypeName = sanitiseParameterType(parameterType);
111 | for(int i = 0; i < parameterCount; i++)
112 | {
113 | buffer.setLength(0);
114 | buffer.append("public ").append(parameterTypeName).append(' ');
115 | buffer.append(sanitiseParameterName(parameterTypeName));
116 | buffer.append('_').append((char) (suffix + i));
117 | buffer.append(";\n");
118 | createField(ctClass, buffer.toString());
119 | }
120 | }
121 | }
122 |
123 | private String generateResetMethod()
124 | {
125 | final StringBuilder buffer = new StringBuilder();
126 |
127 | buffer.append("public void reset() {\n");
128 | for (Map.Entry, Integer> entry : parameterTypeCounts.entrySet())
129 | {
130 | final char suffix = 'a';
131 | final int parameterCount = entry.getValue();
132 |
133 | final Class> parameterType = entry.getKey();
134 | if(!parameterType.isPrimitive())
135 | {
136 | for(int i = 0; i < parameterCount; i++)
137 | {
138 | buffer.append(getSanitisedFieldName(parameterType)).append("_").
139 | append((char) (suffix + i)).append(" = null;\n");
140 | }
141 | }
142 | }
143 | buffer.append("}\n");
144 |
145 | return buffer.toString();
146 | }
147 |
148 | private static String getSanitisedFieldName(final Class> parameterType)
149 | {
150 | return sanitiseParameterName(sanitiseParameterType(parameterType));
151 | }
152 |
153 | private static String sanitiseParameterName(final String parameterTypeName)
154 | {
155 | return parameterTypeName.replace('[', '_').replace(']', '_').replace('.', '_');
156 | }
157 |
158 | private static String sanitiseParameterType(final Class> parameterType)
159 | {
160 | if(parameterType.isArray())
161 | {
162 | return parameterType.getComponentType().getName() + "[]";
163 | }
164 |
165 | return parameterType.getName();
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/bytecode/ArgumentHolderHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor.bytecode;
18 |
19 |
20 | import java.lang.reflect.Method;
21 | import java.util.HashMap;
22 | import java.util.Map;
23 |
24 | import static java.lang.Math.max;
25 |
26 | final class ArgumentHolderHelper
27 | {
28 | public Map, Integer> getParameterTypeCounts(final Class> type)
29 | {
30 | final Method[] methods = type.getMethods();
31 | final Map, Integer> parameterTypeCounts = new HashMap, Integer>();
32 | for (Method method : methods)
33 | {
34 | final Map, Integer> methodTypeCounts = new HashMap, Integer>();
35 | final Class>[] parameterTypes = method.getParameterTypes();
36 | for (final Class> parameterType : parameterTypes)
37 | {
38 | ensureTypeCountExists(methodTypeCounts, parameterType);
39 |
40 | methodTypeCounts.put(parameterType, methodTypeCounts.get(parameterType) + 1);
41 | }
42 |
43 | for (final Class> parameterType : methodTypeCounts.keySet())
44 | {
45 | if(parameterTypeCounts.containsKey(parameterType))
46 | {
47 | parameterTypeCounts.put(parameterType,
48 | max(parameterTypeCounts.get(parameterType),
49 | methodTypeCounts.get(parameterType)));
50 | }
51 | else
52 | {
53 | parameterTypeCounts.put(parameterType, methodTypeCounts.get(parameterType));
54 | }
55 | }
56 | }
57 | return parameterTypeCounts;
58 | }
59 |
60 | private void ensureTypeCountExists(final Map, Integer> parameterTypeCounts, final Class> parameterType)
61 | {
62 | if(!parameterTypeCounts.containsKey(parameterType))
63 | {
64 | parameterTypeCounts.put(parameterType, 0);
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/bytecode/ByteCodeHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor.bytecode;
18 |
19 | import javassist.CannotCompileException;
20 | import javassist.ClassPool;
21 | import javassist.CtClass;
22 | import javassist.CtField;
23 | import javassist.CtMethod;
24 | import javassist.Modifier;
25 | import javassist.NotFoundException;
26 |
27 | import java.util.concurrent.atomic.AtomicInteger;
28 |
29 | enum ByteCodeHelper
30 | {
31 | INSTANCE;
32 |
33 | private static final AtomicInteger UNIQUE_GENERATED_CLASS_NAME_COUNTER = new AtomicInteger();
34 | static final boolean DEBUG = false;
35 |
36 | static int getUniqueIdentifier()
37 | {
38 | return UNIQUE_GENERATED_CLASS_NAME_COUNTER.incrementAndGet();
39 | }
40 |
41 | static CtClass makeClass(final ClassPool classPool, final String className)
42 | {
43 | if(DEBUG)
44 | {
45 | System.out.println("Making class " + className);
46 | }
47 |
48 | return classPool.makeClass(className);
49 | }
50 |
51 | static void createMethod(final CtClass ctClass, final String methodSrc)
52 | {
53 | if(DEBUG)
54 | {
55 | System.out.println("Creating method for class " + ctClass.getName());
56 | System.out.println(methodSrc);
57 | }
58 | try
59 | {
60 | ctClass.addMethod(CtMethod.make(methodSrc, ctClass));
61 | }
62 | catch (CannotCompileException e)
63 | {
64 | throw new RuntimeException("Unable to compile class", e);
65 | }
66 | }
67 |
68 | static void createField(final CtClass ctClass, final String fieldSrc)
69 | {
70 | if(DEBUG)
71 | {
72 | System.out.println("Creating field for class " + ctClass.getName());
73 | System.out.println(fieldSrc);
74 | }
75 | try
76 | {
77 | ctClass.addField(CtField.make(fieldSrc, ctClass));
78 | }
79 | catch (CannotCompileException e)
80 | {
81 | throw new RuntimeException("Unable to generate field: " + fieldSrc, e);
82 | }
83 | }
84 |
85 | static void makePublicFinal(final CtClass ctClass)
86 | {
87 | ctClass.setModifiers(Modifier.PUBLIC | Modifier.FINAL);
88 | }
89 |
90 | static void addInterface(final CtClass ctClass, final Class> interfaceClass,
91 | final ClassPool classPool)
92 | {
93 | try
94 | {
95 | ctClass.addInterface(classPool.get(interfaceClass.getName()));
96 | }
97 | catch (NotFoundException e)
98 | {
99 | throw new RuntimeException("Cannot load class: " + interfaceClass.getName(), e);
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/bytecode/GeneratedRingBufferProxyGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor.bytecode;
18 |
19 | import com.lmax.disruptor.EventHandler;
20 | import com.lmax.disruptor.RingBuffer;
21 | import com.lmax.disruptor.dsl.Disruptor;
22 | import com.lmax.tool.disruptor.DropListener;
23 | import com.lmax.tool.disruptor.Invoker;
24 | import com.lmax.tool.disruptor.MessagePublicationListener;
25 | import com.lmax.tool.disruptor.NoMessagePublicationListener;
26 | import com.lmax.tool.disruptor.NoOpDropListener;
27 | import com.lmax.tool.disruptor.OverflowStrategy;
28 | import com.lmax.tool.disruptor.ProxyMethodInvocation;
29 | import com.lmax.tool.disruptor.Resetable;
30 | import com.lmax.tool.disruptor.RingBufferProxyGenerator;
31 | import com.lmax.tool.disruptor.RingBufferProxyValidation;
32 | import com.lmax.tool.disruptor.handlers.ResetHandler;
33 | import javassist.CannotCompileException;
34 | import javassist.ClassPool;
35 | import javassist.CtClass;
36 | import javassist.CtConstructor;
37 | import javassist.CtMethod;
38 | import javassist.CtNewConstructor;
39 | import javassist.LoaderClassPath;
40 | import javassist.NotFoundException;
41 |
42 | import java.lang.reflect.Constructor;
43 | import java.lang.reflect.InvocationTargetException;
44 | import java.lang.reflect.Method;
45 | import java.util.HashMap;
46 | import java.util.Map;
47 |
48 | import static com.lmax.tool.disruptor.handlers.Handlers.createMultipleImplementationHandlerChain;
49 | import static com.lmax.tool.disruptor.handlers.Handlers.createSingleImplementationHandlerChain;
50 | import static com.lmax.tool.disruptor.bytecode.ByteCodeHelper.addInterface;
51 | import static com.lmax.tool.disruptor.bytecode.ByteCodeHelper.createField;
52 | import static com.lmax.tool.disruptor.bytecode.ByteCodeHelper.createMethod;
53 | import static com.lmax.tool.disruptor.bytecode.ByteCodeHelper.getUniqueIdentifier;
54 | import static com.lmax.tool.disruptor.bytecode.ByteCodeHelper.makeClass;
55 | import static com.lmax.tool.disruptor.bytecode.ByteCodeHelper.makePublicFinal;
56 |
57 | /**
58 | * {@inheritDoc}
59 | */
60 | public final class GeneratedRingBufferProxyGenerator implements RingBufferProxyGenerator
61 | {
62 | private final ClassPool classPool;
63 | private final RingBufferProxyValidation validator;
64 | private final DropListener dropListener;
65 | private final MessagePublicationListener messagePublicationListener;
66 |
67 | public GeneratedRingBufferProxyGenerator(final RingBufferProxyValidation validator)
68 | {
69 | this(validator, NoOpDropListener.INSTANCE);
70 |
71 | }
72 |
73 | public GeneratedRingBufferProxyGenerator(final RingBufferProxyValidation validator,
74 | final DropListener dropListener)
75 | {
76 | this(validator, dropListener, NoMessagePublicationListener.INSTANCE);
77 | }
78 |
79 | public GeneratedRingBufferProxyGenerator(final RingBufferProxyValidation validator,
80 | final DropListener dropListener,
81 | final MessagePublicationListener messagePublicationListener)
82 | {
83 | this.validator = validator;
84 | this.dropListener = dropListener;
85 | this.messagePublicationListener = messagePublicationListener;
86 | classPool = GeneratedRingBufferProxyGenerator.configureClassPool();
87 | }
88 |
89 | /**
90 | * {@inheritDoc}
91 | */
92 | @SuppressWarnings("unchecked")
93 | @Override
94 | public T createRingBufferProxy(final Class proxyInterface, final Disruptor disruptor, final OverflowStrategy overflowStrategy, final T implementation)
95 | {
96 | validator.validateAll(disruptor, proxyInterface);
97 |
98 | disruptor.handleEventsWith(createSingleImplementationHandlerChain(implementation));
99 |
100 | final ArgumentHolderGenerator argumentHolderGenerator = new ArgumentHolderGenerator(classPool);
101 | argumentHolderGenerator.createArgumentHolderClass(proxyInterface);
102 |
103 | prefillArgumentHolderObjects(disruptor.getRingBuffer(), argumentHolderGenerator);
104 |
105 | final Map methodToInvokerMap = createMethodToInvokerMap(proxyInterface, argumentHolderGenerator);
106 |
107 | return generateProxy(proxyInterface, disruptor.getRingBuffer(), methodToInvokerMap, overflowStrategy, argumentHolderGenerator);
108 | }
109 |
110 | /**
111 | * {@inheritDoc}
112 | */
113 | @Override
114 | @SuppressWarnings("unchecked")
115 | public T createRingBufferProxy(final Class proxyInterface, final Disruptor disruptor,
116 | final OverflowStrategy overflowStrategy, final T... implementations)
117 | {
118 | validator.validateAll(disruptor, proxyInterface);
119 |
120 | if (implementations.length < 1)
121 | {
122 | throw new IllegalArgumentException("Must have at least one implementation");
123 | }
124 | else if (implementations.length == 1)
125 | {
126 | return createRingBufferProxy(proxyInterface, disruptor, overflowStrategy, implementations[0]);
127 | }
128 |
129 | final EventHandler[] handlers = new EventHandler[implementations.length];
130 | for (int i = 0; i < implementations.length; i++)
131 | {
132 | handlers[i] = createMultipleImplementationHandlerChain(implementations[i]);
133 | disruptor.handleEventsWith(handlers[i]);
134 | }
135 | disruptor.after(handlers).then(new ResetHandler());
136 |
137 | final ArgumentHolderGenerator argumentHolderGenerator = new ArgumentHolderGenerator(classPool);
138 | argumentHolderGenerator.createArgumentHolderClass(proxyInterface);
139 |
140 | prefillArgumentHolderObjects(disruptor.getRingBuffer(), argumentHolderGenerator);
141 |
142 | final Map methodToInvokerMap = createMethodToInvokerMap(proxyInterface, argumentHolderGenerator);
143 |
144 | return generateProxy(proxyInterface, disruptor.getRingBuffer(), methodToInvokerMap, overflowStrategy, argumentHolderGenerator);
145 | }
146 |
147 | private void prefillArgumentHolderObjects(final RingBuffer ringBuffer,
148 | final ArgumentHolderGenerator argumentHolderGenerator)
149 | {
150 | final int bufferSize = ringBuffer.getBufferSize();
151 | for(int i = 0; i < bufferSize; i++)
152 | {
153 | ringBuffer.get(i).setArgumentHolder((Resetable) instantiate(argumentHolderGenerator.getGeneratedClass(), new Class[] {}));
154 | }
155 | }
156 |
157 | private T generateProxy(final Class proxyInterface, final RingBuffer ringBuffer,
158 | final Map methodToInvokerMap, final OverflowStrategy overflowStrategy,
159 | final ArgumentHolderGenerator argumentHolderGenerator)
160 | {
161 | final CtClass ctClass = makeClass(classPool, "com.lmax.tool.disruptor.bytecode._proxy" + proxyInterface.getSimpleName() + '_' +
162 | getUniqueIdentifier());
163 |
164 | addInterface(ctClass, proxyInterface, classPool);
165 | makePublicFinal(ctClass);
166 |
167 | createFields(methodToInvokerMap, ctClass);
168 | createConstructor(ctClass);
169 |
170 | for (final Method method : proxyInterface.getMethods())
171 | {
172 | createRingBufferPublisherMethod(ctClass, method, methodToInvokerMap.get(method), overflowStrategy, argumentHolderGenerator);
173 | }
174 |
175 | return instantiateProxy(ctClass, ringBuffer);
176 | }
177 |
178 | private T instantiateProxy(final CtClass ctClass, final RingBuffer ringBuffer)
179 | {
180 | try
181 | {
182 | return instantiate(ctClass.toClass(GeneratedRingBufferProxyGenerator.class), new Class[]{RingBuffer.class, DropListener.class,
183 | MessagePublicationListener.class}, ringBuffer, dropListener, messagePublicationListener);
184 | }
185 | catch (CannotCompileException e)
186 | {
187 | throw new RuntimeException("Unable to compile class", e);
188 | }
189 | }
190 |
191 | @SuppressWarnings("unchecked")
192 | private T instantiate(final Class generatedClass, final Class[] constructorArgumentTypes,
193 | final Object... args)
194 | {
195 | try
196 | {
197 |
198 | final Constructor jdkConstructor = generatedClass.getConstructor(constructorArgumentTypes);
199 | return (T) jdkConstructor.newInstance(args);
200 | }
201 | catch (NoSuchMethodException e)
202 | {
203 | throw new RuntimeException("Unable to instantiate class", e);
204 | }
205 | catch (InstantiationException e)
206 | {
207 | throw new RuntimeException("Unable to instantiate class", e);
208 | }
209 | catch (IllegalAccessException e)
210 | {
211 | throw new RuntimeException("Unable to instantiate class", e);
212 | }
213 | catch (InvocationTargetException e)
214 | {
215 | throw new RuntimeException("Unable to instantiate class", e);
216 | }
217 | }
218 |
219 | private void createConstructor(final CtClass ctClass)
220 | {
221 | try
222 | {
223 | final CtConstructor ctConstructor = new CtConstructor(
224 | new CtClass[]{
225 | classPool.getCtClass(RingBuffer.class.getName()),
226 | classPool.getCtClass(DropListener.class.getName()),
227 | classPool.getCtClass(MessagePublicationListener.class.getName())
228 | }, ctClass);
229 | ctConstructor.setBody("{ringBuffer = $1;dropListener = $2;messagePublicationListener = $3;}");
230 | ctClass.addConstructor(ctConstructor);
231 | }
232 | catch (NotFoundException e)
233 | {
234 | throw new RuntimeException("Unable to create constructor", e);
235 | }
236 | catch (CannotCompileException e)
237 | {
238 | throw new RuntimeException("Unable to create constructor", e);
239 | }
240 | }
241 |
242 | private void createFields(final Map methodToInvokerMap, final CtClass ctClass)
243 | {
244 | createField(ctClass, "private final " + RingBuffer.class.getName() + " ringBuffer;");
245 | createField(ctClass, "private final " + DropListener.class.getName() + " dropListener;");
246 | createField(ctClass, "private final " + MessagePublicationListener.class.getName() + " messagePublicationListener;");
247 |
248 | for (final Method method : methodToInvokerMap.keySet())
249 | {
250 | final Invoker invoker = methodToInvokerMap.get(method);
251 |
252 | createField(ctClass, "private final " + invoker.getClass().getName() + " _" +
253 | invoker.getClass().getName().replace(".", "_") + " = new " + invoker.getClass().getName() + "();");
254 | }
255 | }
256 |
257 | private void createRingBufferPublisherMethod(final CtClass ctClass, final Method method, final Invoker invoker,
258 | final OverflowStrategy overflowStrategy,
259 | final ArgumentHolderGenerator argumentHolderGenerator)
260 | {
261 | final StringBuilder methodSrc = new StringBuilder("public void ").append(method.getName()).append("(");
262 | final Class>[] parameterTypes = method.getParameterTypes();
263 | char paramId = 'a';
264 | for (int i = 0, parameterTypesLength = parameterTypes.length; i < parameterTypesLength; i++)
265 | {
266 | final Class> parameterType = parameterTypes[i];
267 |
268 | if (parameterType.isArray())
269 | {
270 | methodSrc.append(parameterType.getComponentType().getName()).append("[] ").append(paramId++);
271 | }
272 | else
273 | {
274 | methodSrc.append(parameterType.getName()).append(' ').append(paramId++);
275 | }
276 |
277 | if (i < parameterTypesLength - 1)
278 | {
279 | methodSrc.append(", ");
280 | }
281 | }
282 | methodSrc.append(")\n{\n");
283 |
284 | methodSrc.append("messagePublicationListener.onPrePublish();\n");
285 |
286 | handleOverflowStrategy(overflowStrategy, methodSrc);
287 |
288 | methodSrc.append("final long sequence = ringBuffer.next();\n").append("try\n").
289 | append("{\n").
290 | append("final ProxyMethodInvocation proxyMethodInvocation = (ProxyMethodInvocation) ringBuffer.get(sequence);\n");
291 |
292 | final String argumentHolderClass = argumentHolderGenerator.getGeneratedClassName();
293 |
294 | methodSrc.append("final ").append(argumentHolderClass).append(" holder = (").
295 | append(argumentHolderClass).append(") proxyMethodInvocation.getArgumentHolder();\n");
296 |
297 | argumentHolderGenerator.resetFieldNames();
298 |
299 | for (int i = 0; i < parameterTypes.length; i++)
300 | {
301 | final Class> parameterType = parameterTypes[i];
302 | final String holderField = argumentHolderGenerator.getNextFieldNameForType(parameterType);
303 | methodSrc.append("holder.").append(holderField).append(" = ").append((char) ('a' + i)).append(";");
304 | }
305 |
306 | methodSrc.append("proxyMethodInvocation.setInvoker(_").append(invoker.getClass().getName().replace(".", "_")).
307 | append(");\n").
308 | append("}\n").
309 | append("catch(Throwable t){t.printStackTrace();}\n").
310 | append("finally\n").
311 | append("{\n").
312 | append("ringBuffer.publish(sequence);\n").
313 | append("messagePublicationListener.onPostPublish();\n").
314 | append("}\n");
315 | methodSrc.append("}\n");
316 |
317 | createMethod(ctClass, methodSrc.toString());
318 | }
319 |
320 | private void handleOverflowStrategy(final OverflowStrategy overflowStrategy, final StringBuilder methodSrc)
321 | {
322 | if (overflowStrategy == OverflowStrategy.DROP)
323 | {
324 | methodSrc.append("if(!ringBuffer.hasAvailableCapacity(1))\n");
325 | methodSrc.append("{");
326 | methodSrc.append("dropListener.onDrop();");
327 | methodSrc.append("return;\n");
328 | methodSrc.append("}\n");
329 | }
330 | }
331 |
332 | @SuppressWarnings("unchecked")
333 | private Invoker generateInvoker(final Class proxyInterface, final Method method, final ArgumentHolderGenerator argumentHolderGenerator)
334 | {
335 | final StringBuilder invokerClassName = new StringBuilder("com.lmax.tool.disruptor.bytecode._invoker").append(proxyInterface.getSimpleName()).
336 | append(method.getName()).append('_').append(getUniqueIdentifier());
337 |
338 | final Class>[] parameterTypes = method.getParameterTypes();
339 | for (final Class> paramType : parameterTypes)
340 | {
341 | if (paramType.isArray())
342 | {
343 | invokerClassName.append(paramType.getComponentType().getSimpleName()).append("Array");
344 | }
345 | else
346 | {
347 | invokerClassName.append(paramType.getSimpleName());
348 | }
349 | }
350 |
351 | final CtClass ctClass = makeClass(classPool, invokerClassName.toString());
352 | addInterface(ctClass, Invoker.class, classPool);
353 | makePublicFinal(ctClass);
354 |
355 | final StringBuilder methodSrc = new StringBuilder("public void invokeWithArgumentHolder(").append("Object").
356 | append(" implementation, Object argumentHolder) {\n");
357 |
358 | if (parameterTypes.length != 0)
359 | {
360 | methodSrc.append("final ").append(argumentHolderGenerator.getGeneratedClassName()).append(" holder = ").
361 | append("(").append(argumentHolderGenerator.getGeneratedClassName()).append(") argumentHolder;\n");
362 | }
363 |
364 | methodSrc.append("((").append(proxyInterface.getName().replace('$', '.')).
365 | append(")implementation).").append(method.getName()).append('(');
366 |
367 |
368 | appendParametersFromArgumentHolder(parameterTypes, methodSrc, argumentHolderGenerator);
369 |
370 | methodSrc.append(");\n}\n");
371 |
372 | return generateInvoker(ctClass, methodSrc);
373 | }
374 |
375 | private Invoker generateInvoker(final CtClass ctClass, final StringBuilder methodSrc)
376 | {
377 | try
378 | {
379 | ctClass.addMethod(CtMethod.make(methodSrc.toString(), ctClass));
380 | ctClass.addConstructor(CtNewConstructor.defaultConstructor(ctClass));
381 | final Class generatedClass = ctClass.toClass(GeneratedRingBufferProxyGenerator.class);
382 | return (Invoker) generatedClass.newInstance();
383 | }
384 | catch (CannotCompileException e)
385 | {
386 | throw new RuntimeException("Unable to compile generated source: " + methodSrc, e);
387 | }
388 | catch (InstantiationException e)
389 | {
390 | throw new RuntimeException("Unable to compile generated source: " + methodSrc, e);
391 | }
392 | catch (IllegalAccessException e)
393 | {
394 | throw new RuntimeException("Unable to compile generated source: " + methodSrc, e);
395 | }
396 | }
397 |
398 | private Map createMethodToInvokerMap(final Class proxyInterface,
399 | final ArgumentHolderGenerator argumentHolderGenerator)
400 | {
401 | final Map methodToInvokerMap = new HashMap();
402 |
403 | final Method[] declaredMethods = proxyInterface.getMethods();
404 |
405 | for (Method declaredMethod : declaredMethods)
406 | {
407 | methodToInvokerMap.put(declaredMethod, generateInvoker(proxyInterface, declaredMethod, argumentHolderGenerator));
408 | }
409 |
410 | return methodToInvokerMap;
411 | }
412 |
413 | private void appendParametersFromArgumentHolder(final Class>[] parameterTypes, final StringBuilder methodSrc,
414 | final ArgumentHolderGenerator argumentHolderGenerator)
415 | {
416 | argumentHolderGenerator.resetFieldNames();
417 | for (int i = 0; i < parameterTypes.length; i++)
418 | {
419 | final Class> parameterType = parameterTypes[i];
420 | methodSrc.append("holder.").append(argumentHolderGenerator.getNextFieldNameForType(parameterType));
421 |
422 | if (i < parameterTypes.length - 1)
423 | {
424 | methodSrc.append(", ");
425 | }
426 | }
427 | }
428 |
429 | private static ClassPool configureClassPool()
430 | {
431 | final ClassPool classPool = new ClassPool(ClassPool.getDefault());
432 | classPool.appendClassPath(new LoaderClassPath(Thread.currentThread().getContextClassLoader()));
433 | classPool.appendClassPath(new LoaderClassPath(ClassLoader.getSystemClassLoader()));
434 | classPool.importPackage("com.lmax.tool.disruptor");
435 | return classPool;
436 | }
437 | }
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/handlers/BatchSizeReportingEventHandler.java:
--------------------------------------------------------------------------------
1 | package com.lmax.tool.disruptor.handlers;
2 |
3 | import com.lmax.disruptor.EventHandler;
4 | import com.lmax.tool.disruptor.BatchSizeListener;
5 | import com.lmax.tool.disruptor.ProxyMethodInvocation;
6 |
7 | class BatchSizeReportingEventHandler implements EventHandler
8 | {
9 | private final EventHandler delegate;
10 | private final BatchSizeListener batchSizeListener;
11 |
12 | private int batchCounter;
13 |
14 | BatchSizeReportingEventHandler(final BatchSizeListener batchSizeListener, final EventHandler delegate)
15 | {
16 | this.batchSizeListener = batchSizeListener;
17 | this.delegate = delegate;
18 | }
19 |
20 | @Override
21 | public void onEvent(final ProxyMethodInvocation event, final long sequence, final boolean endOfBatch) throws Exception
22 | {
23 | try
24 | {
25 | ++batchCounter;
26 | delegate.onEvent(event, sequence, endOfBatch);
27 | }
28 | finally
29 | {
30 | if (endOfBatch)
31 | {
32 | batchSizeListener.onEndOfBatch(batchCounter);
33 | batchCounter = 0;
34 | }
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/handlers/EndOfBatchEventHandler.java:
--------------------------------------------------------------------------------
1 | package com.lmax.tool.disruptor.handlers;
2 |
3 | import com.lmax.disruptor.EventHandler;
4 | import com.lmax.tool.disruptor.BatchListener;
5 | import com.lmax.tool.disruptor.ProxyMethodInvocation;
6 |
7 | /**
8 | * A Disruptor event handler that will notify the supplied batchListener at the end of a batch
9 | */
10 | final class EndOfBatchEventHandler implements EventHandler
11 | {
12 | private final BatchListener batchListener;
13 | private final EventHandler delegate;
14 |
15 | public EndOfBatchEventHandler(final BatchListener batchListener, final EventHandler delegate)
16 | {
17 | this.batchListener = batchListener;
18 | this.delegate = delegate;
19 | }
20 |
21 | @Override
22 | public void onEvent(final ProxyMethodInvocation event, final long sequence, final boolean endOfBatch) throws Exception
23 | {
24 | delegate.onEvent(event, sequence, endOfBatch);
25 |
26 | if (endOfBatch)
27 | {
28 | batchListener.onEndOfBatch();
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/handlers/Handlers.java:
--------------------------------------------------------------------------------
1 | package com.lmax.tool.disruptor.handlers;
2 |
3 | import com.lmax.disruptor.EventHandler;
4 | import com.lmax.tool.disruptor.BatchListener;
5 | import com.lmax.tool.disruptor.BatchSizeListener;
6 | import com.lmax.tool.disruptor.ProxyMethodInvocation;
7 |
8 | public class Handlers
9 | {
10 | public static EventHandler createSingleImplementationHandlerChain(final T implementation)
11 | {
12 | return createHandlers(implementation, true);
13 | }
14 |
15 | public static EventHandler createMultipleImplementationHandlerChain(final T implementation)
16 | {
17 | return createHandlers(implementation, false);
18 | }
19 |
20 | private static EventHandler createHandlers(final T implementation, final boolean reset)
21 | {
22 | EventHandler handler = new InvokerEventHandler(implementation, reset);
23 | if (implementation instanceof BatchListener)
24 | {
25 | handler = new EndOfBatchEventHandler((BatchListener) implementation, handler);
26 | }
27 | if (implementation instanceof BatchSizeListener)
28 | {
29 | handler = new BatchSizeReportingEventHandler((BatchSizeListener) implementation, handler);
30 | }
31 | return handler;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/handlers/InvokerEventHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor.handlers;
18 |
19 | import com.lmax.disruptor.EventHandler;
20 | import com.lmax.tool.disruptor.ProxyMethodInvocation;
21 |
22 | /**
23 | * A Disruptor event handler that will invoke an operation on the supplied implementation
24 | * @param the type of the implementation object to be invoked
25 | */
26 | final class InvokerEventHandler implements EventHandler
27 | {
28 | private final T implementation;
29 | private final boolean reset;
30 |
31 | public InvokerEventHandler(final T implementation, boolean reset)
32 | {
33 | this.implementation = implementation;
34 | this.reset = reset;
35 | }
36 |
37 | public InvokerEventHandler(final T implementation)
38 | {
39 | this(implementation, true);
40 | }
41 |
42 | @Override
43 | public void onEvent(final ProxyMethodInvocation event, final long sequence, final boolean endOfBatch) throws Exception
44 | {
45 | event.getInvoker().invokeWithArgumentHolder(implementation, event.getArgumentHolder());
46 | if (reset)
47 | {
48 | event.reset();
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/handlers/ResetHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor.handlers;
18 |
19 | import com.lmax.disruptor.EventHandler;
20 | import com.lmax.tool.disruptor.ProxyMethodInvocation;
21 |
22 | /**
23 | * A Disruptor EventHandler that will reset the ring-buffer entry
24 | */
25 | public final class ResetHandler implements EventHandler
26 | {
27 | @Override
28 | public void onEvent(final ProxyMethodInvocation event, final long sequence, final boolean endOfBatch) throws Exception
29 | {
30 | event.reset();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/reflect/ObjectArrayHolder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor.reflect;
18 |
19 | import com.lmax.tool.disruptor.Resetable;
20 |
21 | final class ObjectArrayHolder implements Resetable
22 | {
23 | private Object[] args;
24 |
25 | public void set(final Object[] args)
26 | {
27 | this.args = args;
28 | }
29 |
30 | public Object[] get()
31 | {
32 | return args;
33 | }
34 |
35 | @Override
36 | public void reset()
37 | {
38 | args = null;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/reflect/ReflectiveMethodInvoker.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor.reflect;
18 |
19 | import com.lmax.tool.disruptor.Invoker;
20 |
21 | import java.lang.reflect.InvocationTargetException;
22 | import java.lang.reflect.Method;
23 |
24 | final class ReflectiveMethodInvoker implements Invoker
25 | {
26 | private final Method method;
27 |
28 | public ReflectiveMethodInvoker(final Method method)
29 | {
30 | this.method = method;
31 | }
32 |
33 | @Override
34 | public void invokeWithArgumentHolder(final Object implementation, final Object argumentHolder)
35 | {
36 | try
37 | {
38 | final int numberOfParameters = method.getParameterTypes().length;
39 | if(numberOfParameters == 0)
40 | {
41 | method.invoke(implementation, (Object[]) null);
42 | }
43 | else
44 | {
45 | method.invoke(implementation, ((ObjectArrayHolder) argumentHolder).get());
46 | }
47 | }
48 | catch (IllegalAccessException e)
49 | {
50 | throw new RuntimeException("Failed to invoke", e);
51 | }
52 | catch (InvocationTargetException e)
53 | {
54 | throw new RuntimeException("Failed to invoke", e);
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/reflect/ReflectiveRingBufferInvocationHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor.reflect;
18 |
19 | import com.lmax.disruptor.RingBuffer;
20 | import com.lmax.tool.disruptor.DropListener;
21 | import com.lmax.tool.disruptor.Invoker;
22 | import com.lmax.tool.disruptor.MessagePublicationListener;
23 | import com.lmax.tool.disruptor.OverflowStrategy;
24 | import com.lmax.tool.disruptor.ProxyMethodInvocation;
25 |
26 | import java.lang.reflect.InvocationHandler;
27 | import java.lang.reflect.Method;
28 | import java.util.Map;
29 |
30 | final class ReflectiveRingBufferInvocationHandler implements InvocationHandler
31 | {
32 | private static final String TO_STRING_METHOD_NAME = "toString";
33 |
34 | private final RingBuffer ringBuffer;
35 | private final Map methodToInvokerMap;
36 | private final OverflowStrategy overflowStrategy;
37 | private final DropListener dropListener;
38 | private final MessagePublicationListener messagePublicationListener;
39 |
40 | ReflectiveRingBufferInvocationHandler(final RingBuffer ringBuffer,
41 | final Map methodToInvokerMap,
42 | final OverflowStrategy overflowStrategy,
43 | final DropListener dropListener,
44 | final MessagePublicationListener messagePublicationListener)
45 | {
46 | this.ringBuffer = ringBuffer;
47 | this.methodToInvokerMap = methodToInvokerMap;
48 | this.overflowStrategy = overflowStrategy;
49 | this.dropListener = dropListener;
50 | this.messagePublicationListener = messagePublicationListener;
51 | }
52 |
53 | @Override
54 | public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable
55 | {
56 | if (TO_STRING_METHOD_NAME.equals(method.getName()) && args == null)
57 | {
58 | return this.toString();
59 | }
60 |
61 | messagePublicationListener.onPrePublish();
62 | if(overflowStrategy == OverflowStrategy.DROP && !ringBuffer.hasAvailableCapacity(1))
63 | {
64 | dropListener.onDrop();
65 | return null;
66 | }
67 | final long sequence = ringBuffer.next();
68 | try
69 | {
70 | final ProxyMethodInvocation proxyMethodInvocation = ringBuffer.get(sequence);
71 | final ObjectArrayHolder argumentHolder = (ObjectArrayHolder) proxyMethodInvocation.getArgumentHolder();
72 | if(args != null)
73 | {
74 | final Object[] copyOfArgs = new Object[args.length];
75 | System.arraycopy(args, 0, copyOfArgs, 0, args.length);
76 | argumentHolder.set(copyOfArgs);
77 | }
78 | else
79 | {
80 | argumentHolder.set(null);
81 | }
82 | proxyMethodInvocation.setInvoker(methodToInvokerMap.get(method));
83 | }
84 | finally
85 | {
86 | ringBuffer.publish(sequence);
87 | messagePublicationListener.onPostPublish();
88 | }
89 | return null;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/java/com/lmax/tool/disruptor/reflect/ReflectiveRingBufferProxyGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor.reflect;
18 |
19 | import com.lmax.disruptor.EventHandler;
20 | import com.lmax.disruptor.RingBuffer;
21 | import com.lmax.disruptor.dsl.Disruptor;
22 | import com.lmax.tool.disruptor.DropListener;
23 | import com.lmax.tool.disruptor.Invoker;
24 | import com.lmax.tool.disruptor.MessagePublicationListener;
25 | import com.lmax.tool.disruptor.NoMessagePublicationListener;
26 | import com.lmax.tool.disruptor.NoOpDropListener;
27 | import com.lmax.tool.disruptor.OverflowStrategy;
28 | import com.lmax.tool.disruptor.ProxyMethodInvocation;
29 | import com.lmax.tool.disruptor.handlers.ResetHandler;
30 | import com.lmax.tool.disruptor.RingBufferProxyGenerator;
31 | import com.lmax.tool.disruptor.RingBufferProxyValidation;
32 |
33 | import java.lang.reflect.Method;
34 | import java.util.Map;
35 | import java.util.concurrent.ConcurrentHashMap;
36 |
37 | import static com.lmax.tool.disruptor.handlers.Handlers.createMultipleImplementationHandlerChain;
38 | import static com.lmax.tool.disruptor.handlers.Handlers.createSingleImplementationHandlerChain;
39 | import static java.lang.Thread.currentThread;
40 | import static java.lang.reflect.Proxy.newProxyInstance;
41 |
42 | /**
43 | * {@inheritDoc}
44 | */
45 | public final class ReflectiveRingBufferProxyGenerator implements RingBufferProxyGenerator
46 | {
47 | private final RingBufferProxyValidation validator;
48 | private final DropListener dropListener;
49 | private final MessagePublicationListener messagePublicationListener;
50 |
51 | public ReflectiveRingBufferProxyGenerator(final RingBufferProxyValidation validator)
52 | {
53 | this(validator, NoOpDropListener.INSTANCE, NoMessagePublicationListener.INSTANCE);
54 | }
55 |
56 | public ReflectiveRingBufferProxyGenerator(final RingBufferProxyValidation validator,
57 | final DropListener dropListener)
58 | {
59 | this(validator, dropListener, NoMessagePublicationListener.INSTANCE);
60 | }
61 |
62 | public ReflectiveRingBufferProxyGenerator(RingBufferProxyValidation validator, DropListener dropListener, MessagePublicationListener messagePublicationListener)
63 | {
64 | this.validator = validator;
65 | this.dropListener = dropListener;
66 | this.messagePublicationListener = messagePublicationListener;
67 | }
68 |
69 |
70 | /**
71 | * {@inheritDoc}
72 | */
73 | @SuppressWarnings("unchecked")
74 | @Override
75 | public T createRingBufferProxy(final Class proxyInterface, final Disruptor disruptor,
76 | final OverflowStrategy overflowStrategy, final T implementation)
77 | {
78 | validator.validateAll(disruptor, proxyInterface);
79 |
80 | final ReflectiveRingBufferInvocationHandler invocationHandler =
81 | createInvocationHandler(proxyInterface, disruptor, overflowStrategy, dropListener,
82 | messagePublicationListener);
83 | preallocateArgumentHolders(disruptor.getRingBuffer());
84 |
85 | disruptor.handleEventsWith(createSingleImplementationHandlerChain(implementation));
86 |
87 | return generateProxy(proxyInterface, invocationHandler);
88 | }
89 |
90 | /**
91 | * {@inheritDoc}
92 | */
93 | @SuppressWarnings("unchecked")
94 | @Override
95 | public T createRingBufferProxy(final Class proxyInterface, final Disruptor disruptor,
96 | final OverflowStrategy overflowStrategy, final T... implementations)
97 | {
98 | validator.validateAll(disruptor, proxyInterface);
99 |
100 | if (implementations.length < 1)
101 | {
102 | throw new IllegalArgumentException("Must have at least one implementation");
103 | }
104 | else if (implementations.length == 1)
105 | {
106 | return createRingBufferProxy(proxyInterface, disruptor, overflowStrategy, implementations[0]);
107 | }
108 |
109 | final ReflectiveRingBufferInvocationHandler invocationHandler =
110 | createInvocationHandler(proxyInterface, disruptor, overflowStrategy, dropListener, messagePublicationListener);
111 | preallocateArgumentHolders(disruptor.getRingBuffer());
112 |
113 | final EventHandler[] handlers = new EventHandler[implementations.length];
114 | for (int i = 0; i < implementations.length; i++)
115 | {
116 | handlers[i] = createMultipleImplementationHandlerChain(implementations[i]);
117 | disruptor.handleEventsWith(handlers[i]);
118 | }
119 | disruptor.after(handlers).then(new ResetHandler());
120 |
121 | return generateProxy(proxyInterface, invocationHandler);
122 | }
123 |
124 | private static ReflectiveRingBufferInvocationHandler createInvocationHandler(
125 | final Class proxyInterface,
126 | final Disruptor disruptor,
127 | final OverflowStrategy overflowStrategy,
128 | final DropListener dropListener, MessagePublicationListener messagePublicationListener)
129 | {
130 | final Map methodToInvokerMap = createMethodToInvokerMap(proxyInterface);
131 | return new ReflectiveRingBufferInvocationHandler(disruptor.getRingBuffer(), methodToInvokerMap, overflowStrategy, dropListener,
132 | messagePublicationListener);
133 | }
134 |
135 | @SuppressWarnings("unchecked")
136 | private static T generateProxy(final Class proxyInterface, final ReflectiveRingBufferInvocationHandler invocationHandler)
137 | {
138 | return (T) newProxyInstance(currentThread().getContextClassLoader(), new Class>[]{proxyInterface}, invocationHandler);
139 | }
140 |
141 | private static void preallocateArgumentHolders(final RingBuffer ringBuffer)
142 | {
143 | final int bufferSize = ringBuffer.getBufferSize();
144 | for(int i = 0; i < bufferSize; i++)
145 | {
146 | ringBuffer.get(i).setArgumentHolder(new ObjectArrayHolder());
147 | }
148 | }
149 |
150 | private static Map createMethodToInvokerMap(final Class proxyInterface)
151 | {
152 | final Map methodToInvokerMap = new ConcurrentHashMap();
153 | final Method[] declaredMethods = proxyInterface.getMethods();
154 |
155 | for (final Method declaredMethod : declaredMethods)
156 | {
157 | methodToInvokerMap.put(declaredMethod, new ReflectiveMethodInvoker(declaredMethod));
158 | }
159 |
160 | return methodToInvokerMap;
161 | }
162 |
163 | }
--------------------------------------------------------------------------------
/src/test/java/com/lmax/tool/disruptor/AbstractRingBufferProxyGeneratorTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor;
18 |
19 | import com.lmax.disruptor.ExceptionHandler;
20 | import com.lmax.disruptor.FatalExceptionHandler;
21 | import com.lmax.disruptor.RingBuffer;
22 | import com.lmax.disruptor.dsl.Disruptor;
23 | import org.junit.Test;
24 |
25 | import java.util.concurrent.CountDownLatch;
26 | import java.util.concurrent.ExecutorService;
27 | import java.util.concurrent.Executors;
28 | import java.util.concurrent.ScheduledThreadPoolExecutor;
29 | import java.util.concurrent.TimeUnit;
30 | import java.util.concurrent.atomic.AtomicInteger;
31 |
32 | import static com.lmax.tool.disruptor.ValidationConfig.ExceptionHandler.NOT_REQUIRED;
33 | import static com.lmax.tool.disruptor.ValidationConfig.ProxyInterface.NO_ANNOTATION;
34 | import static org.hamcrest.CoreMatchers.equalTo;
35 | import static org.hamcrest.CoreMatchers.not;
36 | import static org.hamcrest.CoreMatchers.is;
37 | import static org.junit.Assert.assertThat;
38 | import static org.junit.Assert.assertTrue;
39 |
40 | public abstract class AbstractRingBufferProxyGeneratorTest
41 | {
42 | private static final int ITERATIONS = 3;
43 | private final GeneratorType generatorType;
44 | private final CountingDropListener dropListener = new CountingDropListener();
45 | private final CountingMessagePublicationListener messagePublicationListener = new CountingMessagePublicationListener();
46 |
47 | protected AbstractRingBufferProxyGeneratorTest(final GeneratorType generatorType)
48 | {
49 | this.generatorType = generatorType;
50 | }
51 |
52 | private static final class ConcreteClass
53 | {
54 |
55 | }
56 |
57 | @Test(expected = IllegalArgumentException.class)
58 | public void shouldBlowUpIfSuppliedClassIsNotAnInterface() throws Exception
59 | {
60 | final Disruptor disruptor =
61 | createDisruptor(Executors.newSingleThreadExecutor(), 1024);
62 | final RingBufferProxyGeneratorFactory generatorFactory = new RingBufferProxyGeneratorFactory();
63 | final RingBufferProxyGenerator ringBufferProxyGenerator = generatorFactory.newProxy(generatorType, new ConfigurableValidator(false, true));
64 | ringBufferProxyGenerator.createRingBufferProxy(ConcreteClass.class, disruptor, OverflowStrategy.DROP, new ConcreteClass());
65 | }
66 |
67 | @Test(expected = IllegalStateException.class)
68 | public void shouldThrowExceptionIfDisruptorInstanceDoesNotHaveAnExceptionHandler() throws Exception
69 | {
70 | final Disruptor disruptor =
71 | new Disruptor(new RingBufferProxyEventFactory(), 1024, Executors.newSingleThreadExecutor());
72 | final RingBufferProxyGeneratorFactory generatorFactory = new RingBufferProxyGeneratorFactory();
73 | final RingBufferProxyGenerator ringBufferProxyGenerator = generatorFactory.newProxy(generatorType);
74 | final ListenerImpl implementation = new ListenerImpl();
75 | ringBufferProxyGenerator.createRingBufferProxy(Listener.class, disruptor, OverflowStrategy.DROP, implementation);
76 | }
77 |
78 | @SuppressWarnings("deprecation")
79 | @Test
80 | public void shouldNotValidateRingBufferProxyAnnotationByDefaultToPreserveBackwardsCompatibility() throws Exception
81 | {
82 | final RingBufferProxyGeneratorFactory generatorFactory = new RingBufferProxyGeneratorFactory();
83 | final RingBufferProxyGenerator generator = generatorFactory.create(generatorType);
84 | generator.createRingBufferProxy(MyDisruptorProxyWithoutTheDisruptorAnnotation.class,
85 | createDisruptor(Executors.newSingleThreadExecutor(), 1024), OverflowStrategy.DROP, new StubImplementationForInterface());
86 | }
87 |
88 | @Test(expected = IllegalArgumentException.class)
89 | public void shouldValidateRingBufferProxyAnnotationIfConfiguredThatWay() throws Exception
90 | {
91 | final RingBufferProxyGeneratorFactory generatorFactory = new RingBufferProxyGeneratorFactory();
92 | final RingBufferProxyGenerator generator = generatorFactory.newProxy(generatorType, new ConfigurableValidator(true, false));
93 | generator.createRingBufferProxy(MyDisruptorProxyWithoutTheDisruptorAnnotation.class,
94 | createDisruptor(Executors.newSingleThreadExecutor(), 1024), OverflowStrategy.DROP, new StubImplementationForInterface());
95 | }
96 |
97 | @SuppressWarnings("deprecation")
98 | @Test(expected = IllegalStateException.class)
99 | public void shouldValidateExceptionHandlerByDefaultToPreserveBackwardsCompatibility() throws Exception
100 | {
101 | final RingBufferProxyGeneratorFactory generatorFactory = new RingBufferProxyGeneratorFactory();
102 | final RingBufferProxyGenerator generator = generatorFactory.create(generatorType);
103 | final Disruptor disruptor = new Disruptor(new RingBufferProxyEventFactory(), 1024, Executors.newSingleThreadExecutor());
104 | generator.createRingBufferProxy(MyDisruptorProxyWithoutTheDisruptorAnnotation.class, disruptor,
105 | OverflowStrategy.DROP, new StubImplementationForInterface());
106 | }
107 |
108 | @Test
109 | public void shouldNotValidateExceptionHandlerIfConfiguredThatWay() throws Exception
110 | {
111 | final RingBufferProxyGeneratorFactory generatorFactory = new RingBufferProxyGeneratorFactory();
112 | final RingBufferProxyGenerator generator = generatorFactory.newProxy(generatorType, new ConfigurableValidator(false, false));
113 | final Disruptor disruptor = new Disruptor(new RingBufferProxyEventFactory(), 1024, Executors.newSingleThreadExecutor());
114 | generator.createRingBufferProxy(MyDisruptorProxyWithoutTheDisruptorAnnotation.class, disruptor,
115 | OverflowStrategy.DROP, new StubImplementationForInterface());
116 | }
117 |
118 | @SuppressWarnings("StatementWithEmptyBody")
119 | @Test
120 | public void shouldProxy()
121 | {
122 | final Disruptor disruptor = createDisruptor(Executors.newSingleThreadExecutor(), 1024);
123 | final RingBufferProxyGeneratorFactory generatorFactory = new RingBufferProxyGeneratorFactory();
124 | final RingBufferProxyGenerator ringBufferProxyGenerator = generatorFactory.newProxy(generatorType);
125 |
126 | final ListenerImpl implementation = new ListenerImpl();
127 | final Listener listener = ringBufferProxyGenerator.createRingBufferProxy(Listener.class, disruptor, OverflowStrategy.DROP, implementation);
128 | disruptor.start();
129 |
130 | for(int i = 0; i < 3; i++)
131 | {
132 | listener.onString("single string " + i);
133 | listener.onFloatAndInt((float) i, i);
134 | listener.onVoid();
135 | listener.onObjectArray(new Double[]{(double) i});
136 | listener.onMixedMultipleArgs(0, 1, "a", "b", 2);
137 | }
138 |
139 | RingBuffer ringBuffer = disruptor.getRingBuffer();
140 | while (ringBuffer.getMinimumGatingSequence() != ringBuffer.getCursor())
141 | {
142 | // Spin
143 | }
144 |
145 | disruptor.shutdown();
146 | Executors.newSingleThreadExecutor().shutdown();
147 |
148 | assertThat(implementation.getLastStringValue(), is("single string 2"));
149 | assertThat(implementation.getLastFloatValue(), is((float) 2));
150 | assertThat(implementation.getLastIntValue(), is(2));
151 | assertThat(implementation.getVoidInvocationCount(), is(3));
152 | assertThat(implementation.getMixedArgsInvocationCount(), is(3));
153 | assertThat(implementation.getLastDoubleArray(), is(equalTo(new Double[] {(double) 2})));
154 | }
155 |
156 | @SuppressWarnings("StatementWithEmptyBody")
157 | @Test
158 | public void shouldProxyMultipleImplementations()
159 | {
160 | final Disruptor disruptor = createDisruptor(Executors.newCachedThreadPool(), 1024);
161 | final RingBufferProxyGeneratorFactory generatorFactory = new RingBufferProxyGeneratorFactory();
162 | final RingBufferProxyGenerator ringBufferProxyGenerator = generatorFactory.newProxy(generatorType);
163 |
164 | final ListenerImpl[] implementations = new ListenerImpl[]
165 | {
166 | new ListenerImpl(), new ListenerImpl()
167 | };
168 |
169 | final Listener listener = ringBufferProxyGenerator.createRingBufferProxy(Listener.class, disruptor, OverflowStrategy.DROP, implementations);
170 | disruptor.start();
171 |
172 | for(int i = 0; i < ITERATIONS; i++)
173 | {
174 | listener.onString("single string " + i);
175 | listener.onFloatAndInt((float) i, i);
176 | listener.onVoid();
177 | listener.onObjectArray(new Double[]{(double) i});
178 | listener.onMixedMultipleArgs(0, 1, "a", "b", 2);
179 | }
180 |
181 | RingBuffer ringBuffer = disruptor.getRingBuffer();
182 | while (ringBuffer.getMinimumGatingSequence() != ringBuffer.getCursor())
183 | {
184 | // Spin
185 | }
186 |
187 | disruptor.shutdown();
188 | Executors.newCachedThreadPool().shutdown();
189 |
190 | for (ListenerImpl implementation : implementations)
191 | {
192 | assertThat(implementation.getLastStringValue(), is("single string 2"));
193 | assertThat(implementation.getLastFloatValue(), is((float) 2));
194 | assertThat(implementation.getLastIntValue(), is(2));
195 | assertThat(implementation.getVoidInvocationCount(), is(3));
196 | assertThat(implementation.getMixedArgsInvocationCount(), is(3));
197 | assertThat(implementation.getLastDoubleArray(), is(equalTo(new Double[] {(double) 2})));
198 | }
199 | }
200 |
201 | @Test
202 | public void shouldNotifyOnPreAndPostPublish() throws Exception
203 | {
204 | final Disruptor disruptor = createDisruptor(Executors.newSingleThreadExecutor(), 1024);
205 | final RingBufferProxyGeneratorFactory generatorFactory = new RingBufferProxyGeneratorFactory();
206 | final RingBufferProxyGenerator ringBufferProxyGenerator = generatorFactory.newProxy(generatorType,
207 | new ConfigurableValidator(NO_ANNOTATION, NOT_REQUIRED), dropListener, messagePublicationListener);
208 |
209 | final ListenerImpl implementation = new ListenerImpl();
210 | final Listener listener = ringBufferProxyGenerator.createRingBufferProxy(Listener.class, disruptor, OverflowStrategy.DROP, implementation);
211 | disruptor.start();
212 |
213 | for(int i = 0; i < 3; i++)
214 | {
215 | listener.onVoid();
216 | }
217 |
218 | RingBuffer ringBuffer = disruptor.getRingBuffer();
219 | while (ringBuffer.getMinimumGatingSequence() != ringBuffer.getCursor())
220 | {
221 | // Spin
222 | }
223 |
224 | disruptor.shutdown();
225 | Executors.newSingleThreadExecutor().shutdown();
226 |
227 | assertThat(messagePublicationListener.getPreCount(), is(3));
228 | assertThat(messagePublicationListener.getPostCount(), is(3));
229 | }
230 |
231 | @Test
232 | public void shouldDropMessagesIfRingBufferIsFull() throws Exception
233 | {
234 | final Disruptor disruptor = createDisruptor(Executors.newSingleThreadExecutor(), 4);
235 | final RingBufferProxyGeneratorFactory generatorFactory = new RingBufferProxyGeneratorFactory();
236 | final RingBufferProxyGenerator ringBufferProxyGenerator = generatorFactory.newProxy(generatorType, new ConfigurableValidator(false, true), dropListener);
237 |
238 | final CountDownLatch latch = new CountDownLatch(1);
239 | final BlockingOverflowTest implementation = new BlockingOverflowTest(latch);
240 | final OverflowTest listener = ringBufferProxyGenerator.createRingBufferProxy(OverflowTest.class, disruptor, OverflowStrategy.DROP, implementation);
241 | disruptor.start();
242 |
243 | for(int i = 0; i < 8; i++)
244 | {
245 | listener.invoke();
246 | }
247 |
248 | latch.countDown();
249 |
250 | Thread.sleep(250L);
251 |
252 | disruptor.shutdown();
253 | Executors.newSingleThreadExecutor().shutdown();
254 |
255 | assertThat(implementation.getInvocationCount(), is(4));
256 | assertThat(dropListener.getDropCount(), is(4));
257 | }
258 |
259 | @Test
260 | public void shouldReportBatchSize() throws Exception
261 | {
262 |
263 | final Disruptor disruptor = createDisruptor(Executors.newSingleThreadExecutor(), 8);
264 | final RingBufferProxyGeneratorFactory generatorFactory = new RingBufferProxyGeneratorFactory();
265 | final RingBufferProxyGenerator ringBufferProxyGenerator =
266 | generatorFactory.newProxy(generatorType, new ConfigurableValidator(false, true), dropListener);
267 |
268 | final CountDownLatch latch1 = new CountDownLatch(1);
269 | final CountDownLatch latch2 = new CountDownLatch(1);
270 | final BatchSizeTrackingHandler batchSizeTracker = new BatchSizeTrackingHandler(latch1, latch2);
271 | final OverflowTest listener = ringBufferProxyGenerator.createRingBufferProxy(OverflowTest.class, disruptor, OverflowStrategy.BLOCK, batchSizeTracker);
272 | disruptor.start();
273 |
274 | for(int i = 0; i < 8; i++)
275 | {
276 | listener.invoke();
277 | latch1.await();
278 | }
279 |
280 | latch2.countDown();
281 |
282 | Thread.sleep(250L);
283 |
284 | disruptor.shutdown();
285 | Executors.newSingleThreadExecutor().shutdown();
286 |
287 | assertThat(batchSizeTracker.getInvocationCount(), is(8));
288 | assertThat(batchSizeTracker.getMaxBatchSize(), is(7));
289 | }
290 |
291 | @Test
292 | public void shouldNotNotifyOnPostPublishForDroppedMessages() throws Exception
293 | {
294 | final Disruptor disruptor = createDisruptor(Executors.newSingleThreadExecutor(), 4);
295 | final RingBufferProxyGeneratorFactory generatorFactory = new RingBufferProxyGeneratorFactory();
296 | final RingBufferProxyGenerator ringBufferProxyGenerator = generatorFactory.newProxy(generatorType, new ConfigurableValidator(false, true), dropListener, messagePublicationListener);
297 |
298 | final CountDownLatch latch = new CountDownLatch(1);
299 | final BlockingOverflowTest implementation = new BlockingOverflowTest(latch);
300 | final OverflowTest listener = ringBufferProxyGenerator.createRingBufferProxy(OverflowTest.class, disruptor, OverflowStrategy.DROP, implementation);
301 | disruptor.start();
302 |
303 | for(int i = 0; i < 8; i++)
304 | {
305 | listener.invoke();
306 | }
307 |
308 | latch.countDown();
309 |
310 | Thread.sleep(250L);
311 |
312 | disruptor.shutdown();
313 | Executors.newSingleThreadExecutor().shutdown();
314 |
315 | assertThat(implementation.getInvocationCount(), is(4));
316 | assertThat(dropListener.getDropCount(), is(4));
317 | assertThat(messagePublicationListener.getPreCount(), is(8));
318 | assertThat(messagePublicationListener.getPostCount(), is(4));
319 | }
320 |
321 | @Test
322 | public void shouldNotifyBatchListenerImplementationOfEndOfBatch() throws Exception
323 | {
324 | final Disruptor disruptor = createDisruptor(Executors.newSingleThreadExecutor(), 4);
325 | final RingBufferProxyGeneratorFactory generatorFactory = new RingBufferProxyGeneratorFactory();
326 | final RingBufferProxyGenerator ringBufferProxyGenerator = generatorFactory.newProxy(generatorType);
327 |
328 | final BatchAwareListenerImpl implementation = new BatchAwareListenerImpl();
329 | final Listener listener = ringBufferProxyGenerator.createRingBufferProxy(Listener.class, disruptor, OverflowStrategy.DROP, implementation);
330 | disruptor.start();
331 |
332 | listener.onString("foo1");
333 | listener.onString("foo2");
334 | listener.onString("foo3");
335 | listener.onString("foo4");
336 |
337 |
338 | long timeoutAt = System.currentTimeMillis() + 2000L;
339 |
340 | while(implementation.getBatchCount() == 0 && System.currentTimeMillis() < timeoutAt)
341 | {
342 | Thread.sleep(1);
343 | }
344 |
345 | final int firstBatchCount = implementation.getBatchCount();
346 | assertThat(firstBatchCount, is(not(0)));
347 |
348 | listener.onVoid();
349 | listener.onVoid();
350 | listener.onVoid();
351 |
352 | timeoutAt = System.currentTimeMillis() + 2000L;
353 |
354 | while(implementation.getBatchCount() == firstBatchCount && System.currentTimeMillis() < timeoutAt)
355 | {
356 | Thread.sleep(1);
357 | }
358 |
359 | disruptor.shutdown();
360 | Executors.newSingleThreadExecutor().shutdown();
361 |
362 | assertThat(implementation.getBatchCount() > firstBatchCount, is(true));
363 | }
364 |
365 | @Test
366 | public void shouldAllowProxyToInheritMethodsFromOtherInterfaces() throws Exception
367 | {
368 | final Disruptor disruptor = createDisruptor(new ScheduledThreadPoolExecutor(1), 1024);
369 | disruptor.handleExceptionsWith(new ThrowExceptionHandler());
370 |
371 | final CountDownLatch bothMethodsAreCalled = new CountDownLatch(2);
372 | final ProxyWhichExtendsAnotherInterface catDog = new RingBufferProxyGeneratorFactory()
373 | .newProxy(generatorType)
374 | .createRingBufferProxy(ProxyWhichExtendsAnotherInterface.class,
375 | disruptor,
376 | OverflowStrategy.DROP, new ProxyWhichExtendsAnotherInterface()
377 | {
378 | @Override
379 | public void meow(String meow, int age)
380 | {
381 | bothMethodsAreCalled.countDown();
382 | }
383 |
384 | @Override
385 | public void interitedMethodBark(boolean bark)
386 | {
387 | bothMethodsAreCalled.countDown();
388 | }
389 | });
390 | disruptor.start();
391 |
392 | catDog.meow("meow", 3);
393 | catDog.interitedMethodBark(true);
394 |
395 | assertTrue(bothMethodsAreCalled.await(2, TimeUnit.SECONDS));
396 | }
397 |
398 | public interface AnotherInterface
399 | {
400 | void interitedMethodBark(boolean bark);
401 | }
402 |
403 | @DisruptorProxy
404 | public interface ProxyWhichExtendsAnotherInterface extends AnotherInterface
405 | {
406 | void meow(String meow, int age);
407 | }
408 |
409 | private static final class BlockingOverflowTest implements OverflowTest
410 | {
411 | private final CountDownLatch blocker;
412 | private final AtomicInteger invocationCount = new AtomicInteger(0);
413 |
414 | private BlockingOverflowTest(final CountDownLatch blocker)
415 | {
416 | this.blocker = blocker;
417 | }
418 |
419 | @Override
420 | public void invoke()
421 | {
422 | try
423 | {
424 | blocker.await();
425 | }
426 | catch (InterruptedException e)
427 | {
428 | throw new RuntimeException();
429 | }
430 | invocationCount.incrementAndGet();
431 | }
432 |
433 | int getInvocationCount()
434 | {
435 | return invocationCount.get();
436 | }
437 | }
438 |
439 | @DisruptorProxy
440 | public interface OverflowTest
441 | {
442 | void invoke();
443 | }
444 |
445 | public interface MyDisruptorProxyWithoutTheDisruptorAnnotation
446 | {
447 | }
448 |
449 | private Disruptor createDisruptor(final ExecutorService executor, final int ringBufferSize)
450 | {
451 | final Disruptor disruptor = new Disruptor(new RingBufferProxyEventFactory(), ringBufferSize, executor);
452 | disruptor.handleExceptionsWith(new FatalExceptionHandler());
453 | return disruptor;
454 | }
455 |
456 | private static class StubImplementationForInterface implements MyDisruptorProxyWithoutTheDisruptorAnnotation
457 | {
458 | }
459 |
460 | private static class ThrowExceptionHandler implements ExceptionHandler
461 | {
462 | @Override
463 | public void handleEventException(Throwable ex, long sequence, Object event)
464 | {
465 | throw new RuntimeException("fail " + ex.getMessage());
466 | }
467 |
468 | @Override
469 | public void handleOnStartException(Throwable ex)
470 | {
471 | throw new RuntimeException("fail " + ex.getMessage());
472 | }
473 |
474 | @Override
475 | public void handleOnShutdownException(Throwable ex)
476 | {
477 | throw new RuntimeException("fail " + ex.getMessage());
478 | }
479 | }
480 |
481 | private static class BatchSizeTrackingHandler implements OverflowTest, BatchSizeListener
482 | {
483 | private final CountDownLatch latch1;
484 | private final CountDownLatch latch2;
485 | private int invocationCount;
486 | private int maxBatchSize;
487 |
488 | public BatchSizeTrackingHandler(final CountDownLatch latch1, final CountDownLatch latch2)
489 | {
490 |
491 | this.latch1 = latch1;
492 | this.latch2 = latch2;
493 | }
494 |
495 | @Override
496 | public void invoke()
497 | {
498 | invocationCount++;
499 |
500 | latch1.countDown();
501 | try
502 | {
503 | latch2.await();
504 | }
505 | catch (final InterruptedException e)
506 | {
507 | throw new RuntimeException(e);
508 | }
509 | }
510 |
511 | @Override
512 | public void onEndOfBatch(final int batchSize)
513 | {
514 | maxBatchSize = Math.max(maxBatchSize, batchSize);
515 | }
516 |
517 | public int getMaxBatchSize()
518 | {
519 | return maxBatchSize;
520 | }
521 |
522 | public int getInvocationCount()
523 | {
524 | return invocationCount;
525 | }
526 | }
527 | }
528 |
--------------------------------------------------------------------------------
/src/test/java/com/lmax/tool/disruptor/BatchAwareListenerImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor;
18 |
19 | public final class BatchAwareListenerImpl implements Listener, BatchListener
20 | {
21 | private volatile int batchCount = 0;
22 |
23 | @Override
24 | public void onString(final String value)
25 | {
26 | }
27 |
28 | @Override
29 | public void onFloatAndInt(final Float floatValue, final int intValue)
30 | {
31 | }
32 |
33 | @Override
34 | public void onVoid()
35 | {
36 | }
37 |
38 | @Override
39 | public void onObjectArray(final Double[] value)
40 | {
41 | }
42 |
43 | @Override
44 | public void onMixedMultipleArgs(final int int0, final int int1, final String s0, final String s1, final int i2)
45 | {
46 | }
47 |
48 | public int getBatchCount()
49 | {
50 | return batchCount;
51 | }
52 |
53 | @Override
54 | public void onEndOfBatch()
55 | {
56 | batchCount++;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/test/java/com/lmax/tool/disruptor/CountingDropListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lmax.tool.disruptor;
17 |
18 | public final class CountingDropListener implements DropListener
19 | {
20 | private int dropCount = 0;
21 |
22 | @Override
23 | public void onDrop()
24 | {
25 | dropCount++;
26 | }
27 |
28 | public int getDropCount()
29 | {
30 | return dropCount;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/test/java/com/lmax/tool/disruptor/CountingMessagePublicationListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lmax.tool.disruptor;
17 |
18 | public final class CountingMessagePublicationListener implements MessagePublicationListener
19 | {
20 |
21 | private int preCount = 0;
22 | private int postCount = 0;
23 |
24 | @Override
25 | public void onPrePublish()
26 | {
27 | preCount++;
28 | }
29 |
30 | @Override
31 | public void onPostPublish()
32 | {
33 | postCount++;
34 | }
35 |
36 |
37 | public int getPreCount()
38 | {
39 | return preCount;
40 | }
41 |
42 | public int getPostCount()
43 | {
44 | return postCount;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/test/java/com/lmax/tool/disruptor/Listener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor;
18 |
19 | @DisruptorProxy
20 | public interface Listener
21 | {
22 | void onString(final String value);
23 | void onFloatAndInt(final Float value, final int intValue);
24 | void onVoid();
25 | void onObjectArray(final Double[] value);
26 | void onMixedMultipleArgs(final int int0, final int int1, final String s0, final String s1, final int i2);
27 | }
28 |
--------------------------------------------------------------------------------
/src/test/java/com/lmax/tool/disruptor/ListenerImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor;
18 |
19 | public final class ListenerImpl implements Listener
20 | {
21 | private volatile String lastStringValue;
22 | private volatile int lastIntValue;
23 | private volatile Float lastFloatValue;
24 | private volatile int voidInvocationCount;
25 | private volatile Double[] lastDoubleArray;
26 | private int mixedArgsInvocationCount;
27 |
28 | @Override
29 | public void onString(final String value)
30 | {
31 | lastStringValue = value;
32 | }
33 |
34 | @Override
35 | public void onFloatAndInt(final Float floatValue, final int intValue)
36 | {
37 | lastFloatValue = floatValue;
38 | lastIntValue = intValue;
39 | }
40 |
41 | @Override
42 | public void onVoid()
43 | {
44 | voidInvocationCount++;
45 | }
46 |
47 | @Override
48 | public void onObjectArray(final Double[] value)
49 | {
50 | lastDoubleArray = value;
51 | }
52 |
53 | @Override
54 | public void onMixedMultipleArgs(final int int0, final int int1, final String s0, final String s1, final int i2)
55 | {
56 | mixedArgsInvocationCount++;
57 | }
58 |
59 | public String getLastStringValue()
60 | {
61 | return lastStringValue;
62 | }
63 |
64 | public int getLastIntValue()
65 | {
66 | return lastIntValue;
67 | }
68 |
69 | public Float getLastFloatValue()
70 | {
71 | return lastFloatValue;
72 | }
73 |
74 | public int getVoidInvocationCount()
75 | {
76 | return voidInvocationCount;
77 | }
78 |
79 | public Double[] getLastDoubleArray()
80 | {
81 | return lastDoubleArray;
82 | }
83 |
84 | public int getMixedArgsInvocationCount()
85 | {
86 | return mixedArgsInvocationCount;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/test/java/com/lmax/tool/disruptor/RingBufferProxyGeneratorFactoryTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lmax.tool.disruptor;
17 |
18 | import org.junit.Test;
19 |
20 | public class RingBufferProxyGeneratorFactoryTest
21 | {
22 | @Test
23 | public void shouldBeAbleToCreateRingBufferProxyGenerator() throws Exception
24 | {
25 | for (GeneratorType generatorType : GeneratorType.values())
26 | {
27 | new RingBufferProxyGeneratorFactory().newProxy(generatorType);
28 | }
29 | // no exception is thrown
30 | }
31 | }
--------------------------------------------------------------------------------
/src/test/java/com/lmax/tool/disruptor/RingBufferProxyValidationTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lmax.tool.disruptor;
17 |
18 | import org.junit.Test;
19 |
20 | public class RingBufferProxyValidationTest
21 | {
22 | @Test(expected = IllegalArgumentException.class)
23 | public void shouldThrowExceptionWhenInterfaceIsNotAnnotatedWithDisruptorProxy() throws Exception
24 | {
25 | new ConfigurableValidator(true, false).ensureDisruptorProxyIsAnnotatedWithDisruptorProxyAnnotation(MyProxyWithoutAnnotation.class);
26 | }
27 |
28 | @Test
29 | public void shouldNotThrowExceptionWhenInterfaceIsAnnotatedWithDisruptorProxy() throws Exception
30 | {
31 | new ConfigurableValidator(true, false).ensureDisruptorProxyIsAnnotatedWithDisruptorProxyAnnotation(MyProxyWithAnnotation.class);
32 | }
33 |
34 | private interface MyProxyWithoutAnnotation
35 | {
36 | }
37 |
38 | @DisruptorProxy
39 | private interface MyProxyWithAnnotation
40 | {
41 | }
42 |
43 | }
--------------------------------------------------------------------------------
/src/test/java/com/lmax/tool/disruptor/bytecode/ArgumentHolderHelperTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor.bytecode;
18 |
19 | import org.junit.Test;
20 |
21 | import java.util.Map;
22 |
23 | import static org.hamcrest.CoreMatchers.is;
24 | import static org.junit.Assert.assertThat;
25 |
26 | public final class ArgumentHolderHelperTest
27 | {
28 | private final ArgumentHolderHelper argumentHolderHelper = new ArgumentHolderHelper();
29 |
30 | @Test
31 | public void shouldDetermineParameterTypeCounts() throws Exception
32 | {
33 | final Map, Integer> parameterTypeCounts =
34 | argumentHolderHelper.getParameterTypeCounts(TestInterface.class);
35 |
36 | assertThat(parameterTypeCounts.get(String.class), is(1));
37 | assertThat(parameterTypeCounts.get(int.class), is(3));
38 | assertThat(parameterTypeCounts.get(Double.class), is(1));
39 | assertThat(parameterTypeCounts.get(double.class), is(1));
40 | }
41 |
42 | private interface TestInterface
43 | {
44 | void one(final String s);
45 | void two(final String s, final int i);
46 | void three(final int i0, final int i1, final int i3);
47 | void four(final Double d0, final double d1);
48 | }
49 | }
--------------------------------------------------------------------------------
/src/test/java/com/lmax/tool/disruptor/bytecode/BytecodeGenerationRingBufferProxyGeneratorTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor.bytecode;
18 |
19 | import com.lmax.tool.disruptor.AbstractRingBufferProxyGeneratorTest;
20 | import com.lmax.tool.disruptor.GeneratorType;
21 |
22 | public final class BytecodeGenerationRingBufferProxyGeneratorTest extends AbstractRingBufferProxyGeneratorTest
23 | {
24 | public BytecodeGenerationRingBufferProxyGeneratorTest()
25 | {
26 | super(GeneratorType.BYTECODE_GENERATION);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/test/java/com/lmax/tool/disruptor/handlers/HandlersTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor.handlers;
18 |
19 | import com.lmax.disruptor.EventHandler;
20 | import com.lmax.tool.disruptor.BatchAwareListenerImpl;
21 | import com.lmax.tool.disruptor.Invoker;
22 | import com.lmax.tool.disruptor.ListenerImpl;
23 | import com.lmax.tool.disruptor.ProxyMethodInvocation;
24 | import com.lmax.tool.disruptor.Resetable;
25 | import org.junit.Test;
26 |
27 | import static com.lmax.tool.disruptor.handlers.Handlers.createSingleImplementationHandlerChain;
28 | import static org.hamcrest.CoreMatchers.is;
29 | import static org.junit.Assert.assertThat;
30 |
31 |
32 | public final class HandlersTest
33 | {
34 | @Test
35 | public void shouldNotifyBatchListenerOnEndOfBatch() throws Exception
36 | {
37 | final BatchAwareListenerImpl batchAwareListener = new BatchAwareListenerImpl();
38 | final EventHandler eventHandler = createSingleImplementationHandlerChain(batchAwareListener);
39 | final ProxyMethodInvocation proxyMethodInvocation = new ProxyMethodInvocation();
40 | proxyMethodInvocation.setArgumentHolder(new StubResetable());
41 | proxyMethodInvocation.setInvoker(new NoOpInvoker());
42 |
43 | eventHandler.onEvent(proxyMethodInvocation, 17L, true);
44 |
45 | assertThat(batchAwareListener.getBatchCount(), is(1));
46 | }
47 |
48 | @Test
49 | public void shouldNotNotifyNonBatchListenerOnEndOfBatch() throws Exception
50 | {
51 | final ListenerImpl nonBatchAwareListener = new ListenerImpl();
52 | final EventHandler eventHandler = createSingleImplementationHandlerChain(nonBatchAwareListener);
53 | final ProxyMethodInvocation proxyMethodInvocation = new ProxyMethodInvocation();
54 | proxyMethodInvocation.setArgumentHolder(new StubResetable());
55 | proxyMethodInvocation.setInvoker(new NoOpInvoker());
56 |
57 | eventHandler.onEvent(proxyMethodInvocation, 17L, true);
58 | }
59 |
60 | private static class NoOpInvoker implements Invoker
61 | {
62 | @Override
63 | public void invokeWithArgumentHolder(final Object implementation, final Object argumentHolder)
64 | {
65 | }
66 | }
67 |
68 | private static final class StubResetable implements Resetable
69 | {
70 | @Override
71 | public void reset()
72 | {
73 |
74 | }
75 | }
76 | }
--------------------------------------------------------------------------------
/src/test/java/com/lmax/tool/disruptor/reflect/ReflectiveRingBufferInvocationHandlerTest.java:
--------------------------------------------------------------------------------
1 | package com.lmax.tool.disruptor.reflect;
2 |
3 | import org.junit.Test;
4 |
5 | import java.lang.reflect.Proxy;
6 |
7 | import static org.hamcrest.core.StringStartsWith.startsWith;
8 | import static org.junit.Assert.assertThat;
9 |
10 | public class ReflectiveRingBufferInvocationHandlerTest
11 | {
12 | interface Foo
13 | {
14 | }
15 |
16 | @Test
17 | public void shouldReturnToStringOfInvokerWhenCallingToStringOnProxy() throws Exception
18 | {
19 | final ReflectiveRingBufferInvocationHandler invocationHandler = new ReflectiveRingBufferInvocationHandler(null, null, null, null, null);
20 |
21 | Foo proxy = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[]{Foo.class}, invocationHandler);
22 |
23 | assertThat(proxy.toString(), startsWith("com.lmax.tool.disruptor.reflect.ReflectiveRingBufferInvocationHandler@"));
24 | }
25 | }
--------------------------------------------------------------------------------
/src/test/java/com/lmax/tool/disruptor/reflect/ReflectiveRingBufferProxyGeneratorTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 LMAX Ltd.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lmax.tool.disruptor.reflect;
18 |
19 | import com.lmax.tool.disruptor.AbstractRingBufferProxyGeneratorTest;
20 | import com.lmax.tool.disruptor.GeneratorType;
21 |
22 | public final class ReflectiveRingBufferProxyGeneratorTest extends AbstractRingBufferProxyGeneratorTest
23 | {
24 | public ReflectiveRingBufferProxyGeneratorTest()
25 | {
26 | super(GeneratorType.JDK_REFLECTION);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------