├── .gitignore ├── LICENSE ├── README.md ├── _config.yml ├── pom.xml └── src ├── main ├── java │ └── io │ │ └── github │ │ └── nsforth │ │ └── vxrifa │ │ ├── GeneratorsHelper.java │ │ ├── MethodsHelper.java │ │ ├── PublisherGenerator.java │ │ ├── RIFAMessage.java │ │ ├── RIFAMessageCodec.java │ │ ├── RIFAReply.java │ │ ├── RIFAReplyCodec.java │ │ ├── ReceiverGenerator.java │ │ ├── SenderGenerator.java │ │ ├── VxRifa.java │ │ ├── VxRifaAnnotationProcessor.java │ │ ├── VxRifaDeliveryOptions.java │ │ ├── VxRifaIgnore.java │ │ ├── VxRifaPublish.java │ │ ├── VxRifaReceiver.java │ │ ├── VxRifaReceivingReadStream.java │ │ ├── VxRifaReceivingWriteStream.java │ │ ├── VxRifaSendingReadStream.java │ │ ├── VxRifaSendingWriteStream.java │ │ └── VxRifaUtil.java └── resources │ └── META-INF │ └── services │ └── javax.annotation.processing.Processor └── test └── java └── io └── github └── nsforth └── vxrifa └── test ├── NoMethodsInterface.java ├── PublisherInterface.java ├── SenderReceiverInterface.java ├── StreamOfStrings.java ├── StreamOfStringsService.java ├── StreamService.java ├── StringsConsumer.java ├── TestSimpleSender.java └── TestStreams.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | # MacOS 24 | .DS_Store 25 | 26 | # IDEA 27 | **/.idea/ 28 | **/*.iml 29 | 30 | # NetBeans 31 | **/nbproject/ 32 | **/nb*.xml 33 | 34 | # Gradle 35 | **/.gradle/ 36 | **/gradle/ 37 | 38 | **/build/ 39 | **/.build/ 40 | **/out/ 41 | **/.out/ 42 | **/target/ 43 | **/.target/ 44 | 45 | **/.vertx/ 46 | 47 | .gradle/ 48 | .nb-gradle/ 49 | 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 489 | USA 490 | 491 | Also add information on how to contact you by electronic and paper mail. 492 | 493 | You should also get your employer (if you work as a programmer) or your 494 | school, if any, to sign a "copyright disclaimer" for the library, if 495 | necessary. Here is a sample; alter the names: 496 | 497 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 498 | library `Frob' (a library for tweaking knobs) written by James Random 499 | Hacker. 500 | 501 | , 1 April 1990 502 | Ty Coon, President of Vice 503 | 504 | That's all there is to it! 505 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Vert.X RIFA - Rich Interfaces For Actors 2 | This library introduces concept of asynchronous object-oriented programming 'by contract' in Vert.X.
3 | Usually if you want to send message in Vert.X from one Actor(Verticle) to other you need to use eventBus.send or eventBus.publish with some object as payload. 4 | Objects should be some sort of simple types like String,Integer or special objects like JsonObject. 5 | Of course you can register own codec and send anything you want but type checking on receiving side is a developer responsibility. 6 | You should also write boilerplate for message handlers and handler registering.
7 | VxRifa library implements Java-idiomatic style for actors messaging based on Interfaces. 8 | ## Getting started 9 | If you are using Maven or Gradle, add the following dependency to the dependencies section of your project descriptor to access the VxRifa:
10 | Maven (in your pom.xml): 11 | ``` 12 | 13 | io.github.nsforth 14 | vxrifa 15 | 1.4.3 16 | 17 | ``` 18 | Gradle (in your gradle build.xml): 19 | ``` 20 | dependencies { 21 | compile 'io.github.nsforth:vxrifa:1.4.3' 22 | } 23 | ``` 24 | Any interface can be annotated with @VxRifa. Methods should return one of void, io.vertx.core.Future, io.vertx.core.streams.ReadStream, io.vertx.core.streams.WriteStream. 25 | Whenever java compiler processes annotations (when building project or on the fly in modern IDEs) VxRifa generates special classes that do all work. You can see generated code under target/generated-sources with maven or under build directory with gradle. 26 | For example: 27 | ```java 28 | @VxRifa 29 | public interface Calculator { 30 | 31 | Future sumTwoDoubles(Double one, Double two); 32 | 33 | void reset(); 34 | 35 | } 36 | ``` 37 | Implementation in Verticle that exporting such API would look like that: 38 | ```java 39 | public class CalculatorImpl implements Calculator { 40 | 41 | @Override 42 | public Future sumTwoDoubles(Double one, Double two) { 43 | Future future = Future.future(); 44 | future.complete(one + two); 45 | return future; 46 | } 47 | 48 | @Override 49 | public void reset() { 50 | 51 | // Some reset actions 52 | 53 | } 54 | 55 | } 56 | ``` 57 | Now you can get instance of VxRifaReceiver with VxRifaUtil.getReceiverRegistrator 58 | which creates any needed eventBus.consumer's and calls methods of Calculator whenever it receives messages from other actors.
59 | Other Verticles should use VxRifaUtil.getSenderByInterface that returns VxRifa-driven implementation of Calculator which send messages under the hood. 60 | For example: 61 | ```java 62 | .... CalculatorVerticle .... 63 | 64 | Calculator calc_impl = new CalculatorImpl(); 65 | VxRifaReceiver registrator = VxRifaUtil.getReceiverRegistrator(vertx, Calculator.class); 66 | Future when_registered = registrator.registerReceiver(calc_impl); 67 | 68 | .... Some other verticles that wants to use Calculator API .... 69 | 70 | Calculator calc = VxRifaUtil.getSenderByInterface(vertx, Calculator.class); 71 | calc.sumTwoDoubles(1.0, 2.0).setHandler(result -> { 72 | if (result.succeeded()) { 73 | Double sum = result.result(); 74 | } 75 | }); 76 | ``` 77 | ## Publish/Subscribe scheme 78 | It is possible to send broadcast messages for multiple instances of some interface annotated with @VxRifaPublish. 79 | It's one way communication of course so methods can't return anything but void. 80 | You should use VxRifaUtil.getPublisherByInterface to get instance of publisher for @VxRifaPublish subscribers. 81 | ## Streams support 82 | Interfaces annotated with @VxRifa can have methods returning two types of streams: ReadStream and WriteStream. 83 | VxRifa wraps your streams and push your data through Vert.X eventbus automatically. 84 | Stream is not immediately ready after invoking on sender side method with Stream return types and you should properly connect it to your handlers. 85 | For example, you should set drainHandler for WriteStream. For ReadStream it should be handler and endHandler. 86 | ## Notes and limitations 87 | There is one small thing that should be done before using VxRifa. You must call VxRifaUtil.registerRIFACodec once for any instance of Vert.x. 88 | VxRifa uses wrapper as container for methods parameters so that wrapper should be registered before any sending by eventBus.
89 | You should also remember that any parameters and returned objects should be immutable(effectively immutable) or at least thread-safe. 90 | Currently messaging by VxRifa only possible for local non-clustered Vert.X instances because RIFAMessageCodec not supported network encoding/decoding of objects. 91 | I hope to solve that in near future. 92 | ## Supported Vert.x and Java versions 93 | Starting from VxRifa 1.4.0 Java 8 is not supported anymore. Vert.X minimum supported version is 3.9 94 | You can use 1.3.1 and previous versions with Java 8 and Vert.x 3.6 95 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-tactile -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | io.github.nsforth 5 | vxrifa 6 | 1.4.3 7 | jar 8 | VxRifa 9 | Object-oriented reactive programming for Vert.X 10 | https://github.com/nsforth/vxrifa 11 | 12 | 13 | GNU Lesser General Public License, version 2.1 14 | https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt 15 | repo 16 | 17 | 18 | 19 | https://github.com/nsforth/vxrifa 20 | scm:git:https://github.com/nsforth/vxrifa.git 21 | 22 | 23 | 24 | nsforth 25 | Nikita Staroverov 26 | nsforth@gmail.com 27 | UTC+3 28 | 29 | 30 | 31 | UTF-8 32 | 33 | 34 | 35 | 36 | org.apache.maven.plugins 37 | maven-compiler-plugin 38 | 3.8.0 39 | 40 | 41 | 42 | -Xlint:deprecation 43 | -Xlint:unchecked 44 | 45 | 11 46 | 47 | 48 | 49 | default-compile 50 | 51 | compile 52 | 53 | 54 | none 55 | 56 | 57 | 58 | compile-with-annotations-processor 59 | 60 | compile 61 | 62 | 63 | only 64 | 65 | ${project.build.directory}/generated-test-sources/test-annotations 66 | 67 | 68 | 69 | 70 | 71 | 72 | org.apache.maven.plugins 73 | maven-source-plugin 74 | 75 | 76 | attach-sources 77 | 78 | jar 79 | 80 | 81 | 82 | 83 | 84 | org.apache.maven.plugins 85 | maven-javadoc-plugin 86 | 87 | 88 | attach-javadocs 89 | 90 | jar 91 | 92 | 93 | 94 | 95 | 96 | io.github.nsforth.vxrifa.test 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | io.vertx 105 | vertx-core 106 | [3.9.0,3.9.2] 107 | 108 | 109 | com.squareup 110 | javapoet 111 | 1.13.0 112 | compile 113 | 114 | 115 | io.vertx 116 | vertx-unit 117 | [3.9.0,3.9.2] 118 | test 119 | 120 | 121 | junit 122 | junit 123 | 4.13.1 124 | test 125 | jar 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/GeneratorsHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | import com.squareup.javapoet.AnnotationSpec; 22 | import com.squareup.javapoet.TypeSpec; 23 | import java.time.LocalDate; 24 | import java.time.format.DateTimeFormatter; 25 | import javax.lang.model.element.Element; 26 | import javax.lang.model.element.ElementKind; 27 | import javax.lang.model.element.ExecutableElement; 28 | import javax.lang.model.element.Modifier; 29 | import javax.lang.model.element.TypeElement; 30 | 31 | /** 32 | * 33 | * @author Nikita Staroverov 34 | */ 35 | class GeneratorsHelper { 36 | 37 | static boolean isElementSuitableMethod(Element enclosedElement) { 38 | 39 | if (enclosedElement.getKind() == ElementKind.METHOD) { 40 | 41 | ExecutableElement method = (ExecutableElement) enclosedElement; 42 | 43 | if (!method.getModifiers().contains(Modifier.ABSTRACT)) { 44 | return false; 45 | } 46 | 47 | } 48 | 49 | return true; 50 | 51 | } 52 | 53 | static TypeSpec.Builder generateClass(TypeElement interfaceElement, String suffix) { 54 | 55 | return TypeSpec.classBuilder(String.format("%s%s", interfaceElement.getSimpleName(), suffix)) 56 | .addModifiers(Modifier.PUBLIC) 57 | .addAnnotation( 58 | AnnotationSpec.builder(javax.annotation.processing.Generated.class) 59 | .addMember("value", "$S", GeneratorsHelper.class.getPackage().getName()) 60 | .addMember("date", "$S", DateTimeFormatter.ISO_DATE.format(LocalDate.now())) 61 | .build() 62 | ); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/MethodsHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | import com.squareup.javapoet.ParameterSpec; 22 | import com.squareup.javapoet.TypeName; 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | import javax.lang.model.element.ExecutableElement; 26 | import javax.lang.model.element.VariableElement; 27 | 28 | /** 29 | * 30 | * @author Nikita Staroverov 31 | */ 32 | class MethodsHelper { 33 | 34 | private final ExecutableElement method; 35 | private final List parameters; 36 | private final String paramsNamesCommaSeparated; 37 | private final String paramsTypesCommaSeparated; 38 | private final String paramsTypesClassesCommaSeparated; 39 | 40 | MethodsHelper(ExecutableElement method) { 41 | 42 | this.method = method; 43 | 44 | parameters = new ArrayList<>(); 45 | 46 | StringBuilder params_names_comma_separated = new StringBuilder(); 47 | StringBuilder params_types_comma_separated = new StringBuilder(); 48 | StringBuilder params_types_classes_comma_separated = new StringBuilder(); 49 | 50 | for (VariableElement parameter : method.getParameters()) { 51 | 52 | ParameterSpec ps = ParameterSpec.get(parameter); 53 | 54 | parameters.add(ps); 55 | 56 | params_names_comma_separated.append(ps.name); 57 | params_types_comma_separated.append(ps.type); 58 | params_types_classes_comma_separated.append(ps.type.toString().replaceAll("<.*>", "")); 59 | params_names_comma_separated.append(","); 60 | params_types_comma_separated.append(","); 61 | params_types_classes_comma_separated.append(".class,"); 62 | 63 | } 64 | 65 | // Remove trailing comma 66 | if (params_names_comma_separated.length() > 0) { 67 | params_names_comma_separated.deleteCharAt(params_names_comma_separated.length() - 1); 68 | } 69 | if (params_types_comma_separated.length() > 0) { 70 | params_types_comma_separated.deleteCharAt(params_types_comma_separated.length() - 1); 71 | } 72 | if (params_types_classes_comma_separated.length() > 0) { 73 | params_types_classes_comma_separated.deleteCharAt(params_types_classes_comma_separated.length() - 1); 74 | } 75 | 76 | paramsNamesCommaSeparated = params_names_comma_separated.toString(); 77 | paramsTypesCommaSeparated = params_types_comma_separated.toString(); 78 | paramsTypesClassesCommaSeparated = params_types_classes_comma_separated.toString(); 79 | 80 | } 81 | 82 | String generateEventBusSuffix() { 83 | return String.format("%s(%s)", method.getSimpleName(), paramsTypesCommaSeparated); 84 | } 85 | 86 | List getParameters() { 87 | return parameters; 88 | } 89 | 90 | String getParamsNamesCommaSeparated() { 91 | return paramsNamesCommaSeparated; 92 | } 93 | 94 | String getParamsNamesCommaSeparatedOrCastedNull() { 95 | if (paramsNamesCommaSeparated.equals("")) { 96 | return "(Object[]) null"; 97 | } else { 98 | return paramsNamesCommaSeparated; 99 | } 100 | } 101 | 102 | String getParamsTypesCommaSeparated() { 103 | return paramsTypesCommaSeparated; 104 | } 105 | 106 | String getParamsTypesClassesCommaSeparated() { 107 | return paramsTypesClassesCommaSeparated; 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/PublisherGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | import com.squareup.javapoet.ClassName; 22 | import com.squareup.javapoet.FieldSpec; 23 | import com.squareup.javapoet.MethodSpec; 24 | import com.squareup.javapoet.TypeName; 25 | import com.squareup.javapoet.TypeSpec; 26 | import java.text.MessageFormat; 27 | import javax.annotation.processing.Messager; 28 | import javax.lang.model.element.Element; 29 | import javax.lang.model.element.ExecutableElement; 30 | import javax.lang.model.element.Modifier; 31 | import javax.lang.model.element.TypeElement; 32 | import javax.lang.model.type.TypeKind; 33 | import javax.lang.model.type.TypeMirror; 34 | import javax.lang.model.util.Elements; 35 | import javax.tools.Diagnostic; 36 | 37 | /** 38 | * 39 | * @author Nikita Staroverov 40 | */ 41 | class PublisherGenerator { 42 | 43 | static final String VXRIFA_PUBLISHER_SUFFIX = "VxRifaPublisher"; 44 | 45 | private final Messager messager; 46 | private final TypeElement interfaceElement; 47 | private final Elements elements; 48 | 49 | private FieldSpec vertxField; 50 | private FieldSpec eventBusAddressField; 51 | 52 | private TypeSpec.Builder tsb; 53 | 54 | PublisherGenerator(Messager messager, TypeElement interfaceElement, Elements elements) { 55 | this.messager = messager; 56 | this.interfaceElement = interfaceElement; 57 | this.elements = elements; 58 | } 59 | 60 | PublisherGenerator generateInitializing() { 61 | 62 | tsb = GeneratorsHelper.generateClass(interfaceElement, VXRIFA_PUBLISHER_SUFFIX); 63 | 64 | tsb.addSuperinterface(TypeName.get(interfaceElement.asType())); 65 | 66 | vertxField = FieldSpec.builder(io.vertx.core.Vertx.class, "vertx", Modifier.PRIVATE, Modifier.FINAL).build(); 67 | tsb.addField(vertxField); 68 | 69 | eventBusAddressField = FieldSpec.builder(java.lang.String.class, "eventBusAddress", Modifier.PRIVATE, Modifier.FINAL).build(); 70 | tsb.addField(eventBusAddressField); 71 | 72 | tsb.addMethod( 73 | MethodSpec.constructorBuilder() 74 | .addModifiers(Modifier.PUBLIC) 75 | .addParameter(io.vertx.core.Vertx.class, vertxField.name) 76 | .addStatement("assert $N != null: \"vertx should not be null! May be you try to create publisher not in verticle start?\"", vertxField) 77 | .addStatement("this.$N = $N", vertxField, vertxField) 78 | .addStatement("this.$N = $S", eventBusAddressField, interfaceElement.getQualifiedName().toString()) 79 | .build() 80 | ); 81 | 82 | tsb.addMethod( 83 | MethodSpec.constructorBuilder() 84 | .addModifiers(Modifier.PUBLIC) 85 | .addParameter(io.vertx.core.Vertx.class, vertxField.name) 86 | .addParameter(java.lang.String.class, eventBusAddressField.name) 87 | .addStatement("assert $N != null: \"vertx should not be null! May be you try to create publisher not in verticle start?\"", vertxField) 88 | .addStatement("this.$N = $N", vertxField, vertxField) 89 | .addStatement("this.$N = $N", eventBusAddressField, eventBusAddressField) 90 | .build() 91 | ); 92 | 93 | return this; 94 | 95 | } 96 | 97 | PublisherGenerator generateMethods() { 98 | 99 | for (Element enclosedElement : elements.getAllMembers(interfaceElement)) { 100 | 101 | if (GeneratorsHelper.isElementSuitableMethod(enclosedElement)) { 102 | 103 | ExecutableElement method = (ExecutableElement) enclosedElement; 104 | 105 | TypeMirror returnType = method.getReturnType(); 106 | 107 | if (returnType.getKind() != TypeKind.VOID) { 108 | 109 | messager.printMessage(Diagnostic.Kind.ERROR, String.format("%s.%s should return void", interfaceElement, enclosedElement), enclosedElement); 110 | continue; 111 | 112 | } 113 | 114 | MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(method.getSimpleName().toString()) 115 | .addModifiers(Modifier.PUBLIC) 116 | .returns(TypeName.get(returnType)); 117 | 118 | MethodsHelper methodsHelper = new MethodsHelper(method); 119 | 120 | methodsHelper.getParameters().forEach(param -> methodBuilder.addParameter(param)); 121 | 122 | if (methodsHelper.getParameters().isEmpty()) { 123 | methodBuilder.addStatement("this.$N.eventBus().publish($N, $T.of($S, null))", vertxField, eventBusAddressField, RIFAMessage.class, methodsHelper.generateEventBusSuffix()); 124 | } else { 125 | methodBuilder.addStatement("this.$N.eventBus().publish($N, $T.of($S, $N))", vertxField, eventBusAddressField, RIFAMessage.class, methodsHelper.generateEventBusSuffix(), methodsHelper.getParamsNamesCommaSeparated()); 126 | } 127 | 128 | methodBuilder.addAnnotation(Override.class); 129 | 130 | tsb.addMethod(methodBuilder.build()); 131 | 132 | } 133 | 134 | } 135 | 136 | return this; 137 | 138 | } 139 | 140 | TypeSpec buildClass() { 141 | 142 | return tsb.build(); 143 | 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/RIFAMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | /** 22 | * 23 | * @author Nikita Staroverov 24 | */ 25 | public final class RIFAMessage { 26 | 27 | private final String suffix; 28 | private final Object[] payload; 29 | 30 | private RIFAMessage(final String suffix, final Object... payload) { 31 | this.suffix = suffix; 32 | this.payload = payload; 33 | } 34 | 35 | public String getSuffix() { 36 | return suffix; 37 | } 38 | 39 | public Object getParameter(int index) { 40 | return payload[index]; 41 | } 42 | 43 | public int parametersCount() { 44 | return payload.length; 45 | } 46 | 47 | public static RIFAMessage of(final String suffix, final Object... payload) { 48 | return new RIFAMessage(suffix, payload); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/RIFAMessageCodec.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | import io.vertx.core.buffer.Buffer; 22 | import io.vertx.core.eventbus.MessageCodec; 23 | 24 | /** 25 | * 26 | * @author Nikita Staroverov 27 | */ 28 | class RIFAMessageCodec implements MessageCodec{ 29 | 30 | @Override 31 | public void encodeToWire(Buffer buffer, RIFAMessage s) { 32 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. 33 | } 34 | 35 | @Override 36 | public RIFAMessage decodeFromWire(int pos, Buffer buffer) { 37 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. 38 | } 39 | 40 | @Override 41 | public RIFAMessage transform(RIFAMessage s) { 42 | return s; 43 | } 44 | 45 | @Override 46 | public String name() { 47 | return RIFAMessageCodec.class.getCanonicalName(); 48 | } 49 | 50 | @Override 51 | public byte systemCodecID() { 52 | return -1; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/RIFAReply.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | /** 22 | * 23 | * @author Nikita Staroverov 24 | */ 25 | public final class RIFAReply { 26 | 27 | private final Object result; 28 | private final Throwable exception; 29 | 30 | private RIFAReply(Object result) { 31 | this.result = result; 32 | this.exception = null; 33 | } 34 | 35 | public RIFAReply(Throwable exception) { 36 | this.result = null; 37 | this.exception = exception; 38 | } 39 | 40 | public Object getResult() { 41 | return result; 42 | } 43 | 44 | public Throwable getException() { 45 | return exception; 46 | } 47 | 48 | public boolean isExceptional() { 49 | return !(exception == null); 50 | } 51 | 52 | public static RIFAReply of(final Object result) { 53 | return new RIFAReply(result); 54 | } 55 | 56 | public static RIFAReply of(final Throwable exception) { 57 | return new RIFAReply(exception); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/RIFAReplyCodec.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | import io.vertx.core.buffer.Buffer; 22 | import io.vertx.core.eventbus.MessageCodec; 23 | 24 | /** 25 | * 26 | * @author Nikita Staroverov 27 | */ 28 | class RIFAReplyCodec implements MessageCodec{ 29 | 30 | @Override 31 | public void encodeToWire(Buffer buffer, RIFAReply s) { 32 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. 33 | } 34 | 35 | @Override 36 | public RIFAReply decodeFromWire(int pos, Buffer buffer) { 37 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. 38 | } 39 | 40 | @Override 41 | public RIFAReply transform(RIFAReply s) { 42 | return s; 43 | } 44 | 45 | @Override 46 | public String name() { 47 | return RIFAReplyCodec.class.getCanonicalName(); 48 | } 49 | 50 | @Override 51 | public byte systemCodecID() { 52 | return -1; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/ReceiverGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | import com.squareup.javapoet.ClassName; 22 | import com.squareup.javapoet.CodeBlock; 23 | import com.squareup.javapoet.FieldSpec; 24 | import com.squareup.javapoet.MethodSpec; 25 | import com.squareup.javapoet.ParameterSpec; 26 | import com.squareup.javapoet.ParameterizedTypeName; 27 | import com.squareup.javapoet.TypeName; 28 | import com.squareup.javapoet.TypeSpec; 29 | import com.squareup.javapoet.WildcardTypeName; 30 | import io.vertx.core.Future; 31 | import io.vertx.core.Handler; 32 | import io.vertx.core.Promise; 33 | import io.vertx.core.eventbus.Message; 34 | import io.vertx.core.eventbus.MessageConsumer; 35 | import java.text.MessageFormat; 36 | import java.util.HashMap; 37 | import java.util.Map; 38 | import javax.annotation.processing.Messager; 39 | import javax.lang.model.element.Element; 40 | import javax.lang.model.element.ExecutableElement; 41 | import javax.lang.model.element.Modifier; 42 | import javax.lang.model.element.TypeElement; 43 | import javax.lang.model.element.VariableElement; 44 | import javax.lang.model.type.TypeKind; 45 | import javax.lang.model.util.Elements; 46 | 47 | /** 48 | * Generates delegate class that do mapping between vertx.consumer handler and 49 | * some class that implements interface annotated with {@link VxRifa} or 50 | * {@link VxRifaPublish} 51 | * 52 | * @author Nikita Staroverov 53 | */ 54 | class ReceiverGenerator { 55 | 56 | static final String VXRIFA_RECEIVER_SUFFIX = "VxRifaReceiver"; 57 | 58 | private final Messager messager; 59 | private final TypeElement interfaceElement; 60 | private final Elements elements; 61 | 62 | private FieldSpec vertxField; 63 | private FieldSpec eventBusAddressField; 64 | private FieldSpec handlersField; 65 | private FieldSpec consumerField; 66 | private TypeSpec.Builder tsb; 67 | 68 | ReceiverGenerator(Messager messager, TypeElement interfaceElement, Elements elements) { 69 | this.messager = messager; 70 | this.interfaceElement = interfaceElement; 71 | this.elements = elements; 72 | } 73 | 74 | ReceiverGenerator generateInitializing() { 75 | 76 | tsb = GeneratorsHelper.generateClass(interfaceElement, VXRIFA_RECEIVER_SUFFIX); 77 | 78 | tsb.addSuperinterface(ParameterizedTypeName.get(ClassName.get(VxRifaReceiver.class), TypeName.get(interfaceElement.asType()))); 79 | 80 | vertxField = FieldSpec.builder(io.vertx.core.Vertx.class, "vertx", Modifier.PRIVATE, Modifier.FINAL).build(); 81 | tsb.addField(vertxField); 82 | 83 | eventBusAddressField = FieldSpec.builder(java.lang.String.class, "eventBusAddress", Modifier.PRIVATE, Modifier.FINAL).build(); 84 | tsb.addField(eventBusAddressField); 85 | 86 | handlersField = FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(Map.class), TypeName.get(String.class), ParameterizedTypeName.get(ClassName.get(Handler.class), ParameterizedTypeName.get(ClassName.get(Message.class), ParameterizedTypeName.get(RIFAMessage.class)))), "handlers", Modifier.PRIVATE) 87 | .build(); 88 | tsb.addField(handlersField); 89 | 90 | consumerField = FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(MessageConsumer.class), TypeName.get(RIFAMessage.class)), "consumer", Modifier.PRIVATE).build(); 91 | tsb.addField(consumerField); 92 | 93 | tsb.addMethod( 94 | MethodSpec.constructorBuilder() 95 | .addModifiers(Modifier.PUBLIC) 96 | .addParameter(io.vertx.core.Vertx.class, vertxField.name) 97 | .addStatement("assert $N != null: \"vertx should not be null! May be you try to create receiver not in verticle start?\"", vertxField) 98 | .addStatement("this.$N = $N", vertxField, vertxField) 99 | .addStatement("this.$N = $S", eventBusAddressField, interfaceElement.getQualifiedName().toString()) 100 | .build() 101 | ); 102 | 103 | tsb.addMethod( 104 | MethodSpec.constructorBuilder() 105 | .addModifiers(Modifier.PUBLIC) 106 | .addParameter(io.vertx.core.Vertx.class, vertxField.name) 107 | .addParameter(java.lang.String.class, eventBusAddressField.name) 108 | .addStatement("assert $N != null: \"vertx should not be null! May be you try to create receiver not in verticle start?\"", vertxField) 109 | .addStatement("this.$N = $N", vertxField, vertxField) 110 | .addStatement("this.$N = $N", eventBusAddressField, eventBusAddressField) 111 | .build() 112 | ); 113 | 114 | return this; 115 | 116 | } 117 | 118 | ReceiverGenerator generateRegisterMethod() { 119 | 120 | MethodSpec.Builder registerMB = MethodSpec.methodBuilder("registerReceiver"); 121 | 122 | registerMB.addAnnotation(Override.class) 123 | .addModifiers(Modifier.PUBLIC) 124 | .addParameter(TypeName.get(interfaceElement.asType()), "receiver", Modifier.FINAL) 125 | .returns(ParameterizedTypeName.get(ClassName.get(Future.class), WildcardTypeName.subtypeOf(Object.class))); 126 | 127 | registerMB.addStatement("$N = new $T<>()", handlersField, HashMap.class); 128 | 129 | registerMB.beginControlFlow("try"); 130 | 131 | for (Element enclosedElement : elements.getAllMembers(interfaceElement)) { 132 | 133 | if (GeneratorsHelper.isElementSuitableMethod(enclosedElement)) { 134 | 135 | ExecutableElement method = (ExecutableElement) enclosedElement; 136 | 137 | MethodsHelper methodsHelper = new MethodsHelper(method); 138 | 139 | String paramsTypesClassesCommaSeparated = methodsHelper.getParamsTypesClassesCommaSeparated(); 140 | if ("".equals(paramsTypesClassesCommaSeparated)) { 141 | registerMB.beginControlFlow("if (receiver.getClass().getMethod($S, (Class[]) null).getAnnotation($T.class) == null)", 142 | method.getSimpleName(), TypeName.get(VxRifaIgnore.class) 143 | ); 144 | } else { 145 | registerMB.beginControlFlow("if (receiver.getClass().getMethod($S, $L).getAnnotation($T.class) == null)", 146 | method.getSimpleName(), paramsTypesClassesCommaSeparated, TypeName.get(VxRifaIgnore.class) 147 | ); 148 | } 149 | registerMB.addStatement("$N.put($S, handler -> {$W$L$W})", 150 | handlersField, 151 | methodsHelper.generateEventBusSuffix(), 152 | makeMethodHandler(method).toString() 153 | ); 154 | registerMB.endControlFlow(); 155 | 156 | } 157 | } 158 | 159 | registerMB.addStatement("$N = this.$N.eventBus().consumer($N, message -> $N.getOrDefault(message.body().getSuffix(), msg -> msg.reply($T.of(new UnsupportedOperationException(\"Method implementation is not provided\")))).handle(message))", 160 | consumerField, vertxField, eventBusAddressField, handlersField, RIFAReply.class 161 | ); 162 | 163 | registerMB.nextControlFlow("catch ($T ex)", TypeName.get(NoSuchMethodException.class)); 164 | registerMB.addStatement("throw new $T(ex)", TypeName.get(IllegalArgumentException.class)); 165 | registerMB.endControlFlow(); 166 | registerMB.addStatement("$T promise = $T.promise()", ParameterizedTypeName.get(ClassName.get(Promise.class), TypeName.get(Void.class)), Promise.class); 167 | registerMB.addStatement("$N.completionHandler(promise)", consumerField); 168 | registerMB.addStatement("return promise.future()"); 169 | 170 | tsb.addMethod(registerMB.build()); 171 | 172 | return this; 173 | 174 | } 175 | 176 | ReceiverGenerator generateUnregisterMethod() { 177 | 178 | MethodSpec.Builder unregisterMB = MethodSpec.methodBuilder("unregisterReceiver"); 179 | 180 | // Generates cosumers waiting Future for success handler unregistration 181 | unregisterMB.addAnnotation(Override.class) 182 | .addModifiers(Modifier.PUBLIC) 183 | .addStatement("$T promise = $T.promise()", ParameterizedTypeName.get(ClassName.get(Promise.class), TypeName.get(Void.class)), Promise.class) 184 | .addStatement("$N.unregister(promise)", consumerField) 185 | .addStatement("return promise.future()") 186 | .returns(ParameterizedTypeName.get(ClassName.get(Future.class), WildcardTypeName.subtypeOf(Object.class))); 187 | 188 | tsb.addMethod(unregisterMB.build()); 189 | 190 | return this; 191 | 192 | } 193 | 194 | private CodeBlock makeMethodHandler(ExecutableElement method) { 195 | 196 | CodeBlock.Builder result = CodeBlock.builder(); 197 | 198 | // Generates list of params with class casting for example "(String)message.get(0),(Integer)message.get(1)" 199 | StringBuilder parametersWithCasting = new StringBuilder(); 200 | int parameterNumber = 0; 201 | for (VariableElement parameter : method.getParameters()) { 202 | parametersWithCasting.append("(") 203 | .append(ParameterSpec.get(parameter).type) 204 | .append(")") 205 | .append("message.getParameter(") 206 | .append(parameterNumber++) 207 | .append("),"); 208 | } 209 | if (parameterNumber > 0) { 210 | result.addStatement("$T message = handler.body()", RIFAMessage.class); 211 | } 212 | // Remove trailing comma 213 | if (parametersWithCasting.length() > 0) { 214 | parametersWithCasting.deleteCharAt(parametersWithCasting.length() - 1); 215 | } 216 | 217 | if (method.getReturnType().getKind() == TypeKind.VOID) { 218 | result.addStatement("receiver.$L($L)", method.getSimpleName(), parametersWithCasting.toString()); 219 | } else if (method.getReturnType().toString().startsWith(io.vertx.core.streams.ReadStream.class.getCanonicalName())) { 220 | result 221 | .beginControlFlow("try") 222 | .addStatement("$T readStream = receiver.$L($L)", TypeName.get(method.getReturnType()), method.getSimpleName(), parametersWithCasting.toString()) 223 | .addStatement("assert readStream != null: \"Returned ReadStream should not be null! May be you forget to create appropriate result in $L.$L?\"", method.getEnclosingElement(), method.toString()) 224 | .addStatement("String controlAddress = $N + Long.toHexString(java.util.concurrent.ThreadLocalRandom.current().nextLong())", eventBusAddressField) 225 | .addStatement("handler.reply($T.of(controlAddress))", RIFAReply.class) 226 | .addStatement("$T vxRifaSendingReadStream = new $T<>($N, handler.headers().get(\"DataAddress\"), controlAddress, readStream)", 227 | ParameterizedTypeName.get(ClassName.get(VxRifaSendingReadStream.class), WildcardTypeName.subtypeOf(Object.class)), VxRifaSendingReadStream.class, vertxField) 228 | .nextControlFlow("catch (Throwable ex)") 229 | .addStatement("handler.reply($T.of(ex))", RIFAReply.class) 230 | .endControlFlow(); 231 | } else if (method.getReturnType().toString().startsWith(io.vertx.core.streams.WriteStream.class.getCanonicalName())) { 232 | result 233 | .beginControlFlow("try") 234 | .addStatement("$T writeStream = receiver.$L($L)", TypeName.get(method.getReturnType()), method.getSimpleName(), parametersWithCasting.toString()) 235 | .addStatement("assert writeStream != null: \"Returned WriteStream should not be null! May be you forget to create appropriate result in $L.$L?\"", method.getEnclosingElement(), method.toString()) 236 | .addStatement("String dataAddress = $N + Long.toHexString(java.util.concurrent.ThreadLocalRandom.current().nextLong())", eventBusAddressField) 237 | .addStatement("$T vxRifaReceivingWriteStream = new $T<>($N, dataAddress, handler.headers().get(\"ControlAddress\"), handler, writeStream)", 238 | ParameterizedTypeName.get(ClassName.get(VxRifaReceivingWriteStream.class), WildcardTypeName.subtypeOf(Object.class)), VxRifaReceivingWriteStream.class, vertxField) 239 | .nextControlFlow("catch (Throwable ex)") 240 | .addStatement("handler.reply($T.of(ex))", RIFAReply.class) 241 | .endControlFlow(); 242 | } else { 243 | CodeBlock.Builder lambdaBody = CodeBlock.builder() 244 | .indent() 245 | .beginControlFlow("if (result.succeeded())") 246 | .addStatement("handler.reply($T.of(result.result()))", RIFAReply.class) 247 | .nextControlFlow("else") 248 | .addStatement("handler.reply($T.of(result.cause()))", RIFAReply.class) 249 | .endControlFlow(); 250 | result 251 | .beginControlFlow("try") 252 | .addStatement("$T returnedFuture = receiver.$L($L)", TypeName.get(method.getReturnType()), method.getSimpleName(), parametersWithCasting.toString()) 253 | .addStatement("assert returnedFuture != null: \"Returned future should not be null! May be you forget to create appropriate result in $L.$L?\"", method.getEnclosingElement(), method.toString()) 254 | .addStatement("returnedFuture.onComplete(result -> {\n$W$L\n})", lambdaBody.build().toString()) 255 | .nextControlFlow("catch (Throwable ex)") 256 | .addStatement("handler.reply($T.of(ex))", RIFAReply.class) 257 | .endControlFlow(); 258 | } 259 | 260 | return result.build(); 261 | 262 | } 263 | 264 | TypeSpec buildClass() { 265 | 266 | return tsb.build(); 267 | 268 | } 269 | 270 | } 271 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/SenderGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | import com.squareup.javapoet.*; 22 | import io.vertx.core.Promise; 23 | import io.vertx.core.eventbus.DeliveryOptions; 24 | 25 | import javax.annotation.processing.Messager; 26 | import javax.lang.model.element.Element; 27 | import javax.lang.model.element.ExecutableElement; 28 | import javax.lang.model.element.Modifier; 29 | import javax.lang.model.element.TypeElement; 30 | import javax.lang.model.type.TypeKind; 31 | import javax.lang.model.type.TypeMirror; 32 | import javax.lang.model.util.Elements; 33 | import javax.tools.Diagnostic; 34 | 35 | /** 36 | * Generates implementation for interface annotated with {@link VxRifa}. 37 | * Generated implementation wraps method's params to {@link RIFAMessage} and 38 | * sends message by eventBus. 39 | * 40 | * @author Nikita Staroverov 41 | */ 42 | class SenderGenerator { 43 | 44 | static final String VXRIFA_SENDER_SUFFIX = "VxRifaSender"; 45 | 46 | private final Messager messager; 47 | private final TypeElement interfaceElement; 48 | private final Elements elements; 49 | 50 | private FieldSpec vertxField; 51 | private FieldSpec eventBusAddressField; 52 | 53 | private TypeSpec.Builder classBuilder; 54 | 55 | SenderGenerator(Messager messager, TypeElement interfaceElement, Elements elements) { 56 | this.messager = messager; 57 | this.interfaceElement = interfaceElement; 58 | this.elements = elements; 59 | } 60 | 61 | SenderGenerator generateInitializing() { 62 | 63 | classBuilder = GeneratorsHelper.generateClass(interfaceElement, VXRIFA_SENDER_SUFFIX); 64 | 65 | classBuilder.addSuperinterface(TypeName.get(interfaceElement.asType())); 66 | 67 | vertxField = FieldSpec.builder(io.vertx.core.Vertx.class, "vertx", Modifier.PRIVATE, Modifier.FINAL).build(); 68 | classBuilder.addField(vertxField); 69 | 70 | eventBusAddressField = FieldSpec.builder(java.lang.String.class, "eventBusAddress", Modifier.PRIVATE, Modifier.FINAL).build(); 71 | classBuilder.addField(eventBusAddressField); 72 | 73 | classBuilder.addMethod( 74 | MethodSpec.constructorBuilder() 75 | .addModifiers(Modifier.PUBLIC) 76 | .addParameter(io.vertx.core.Vertx.class, vertxField.name) 77 | .addStatement("assert $N != null: \"vertx should not be null! May be you try to create sender not in verticle start?\"", vertxField) 78 | .addStatement("this.$N = $N", vertxField, vertxField) 79 | .addStatement("this.$N = $S", eventBusAddressField, interfaceElement.getQualifiedName().toString()) 80 | .build() 81 | ); 82 | 83 | classBuilder.addMethod( 84 | MethodSpec.constructorBuilder() 85 | .addModifiers(Modifier.PUBLIC) 86 | .addParameter(io.vertx.core.Vertx.class, vertxField.name) 87 | .addParameter(java.lang.String.class, eventBusAddressField.name) 88 | .addStatement("assert $N != null: \"vertx should not be null! May be you try to create sender not in verticle start?\"", vertxField) 89 | .addStatement("this.$N = $N", vertxField, vertxField) 90 | .addStatement("this.$N = $N", eventBusAddressField, eventBusAddressField) 91 | .build() 92 | ); 93 | 94 | return this; 95 | 96 | } 97 | 98 | SenderGenerator generateMethods() { 99 | 100 | for (Element enclosedElement : elements.getAllMembers(interfaceElement)) { 101 | 102 | if (GeneratorsHelper.isElementSuitableMethod(enclosedElement)) { 103 | 104 | ExecutableElement method = (ExecutableElement) enclosedElement; 105 | 106 | TypeMirror returnType = method.getReturnType(); 107 | 108 | if (!(returnType.toString().startsWith(io.vertx.core.Future.class.getCanonicalName()) 109 | || returnType.toString().startsWith(io.vertx.core.streams.ReadStream.class.getCanonicalName()) 110 | || returnType.toString().startsWith(io.vertx.core.streams.WriteStream.class.getCanonicalName()) 111 | || returnType.getKind() == TypeKind.VOID)) { 112 | 113 | messager.printMessage(Diagnostic.Kind.ERROR, String.format("%s.%s should return one of io.vertx.core.Future,io.vertx.core.streams.ReadStream,io.vertx.core.streams.WriteStream,void", interfaceElement, enclosedElement), enclosedElement); 114 | continue; 115 | 116 | } 117 | 118 | MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(method.getSimpleName().toString()) 119 | .addModifiers(Modifier.PUBLIC) 120 | .returns(TypeName.get(returnType)); 121 | 122 | MethodsHelper methodsHelper = new MethodsHelper(method); 123 | 124 | methodsHelper.getParameters().forEach(param -> methodBuilder.addParameter(param)); 125 | 126 | VxRifaDeliveryOptions deliveryOptionsAnnotation = method.getAnnotation(VxRifaDeliveryOptions.class); 127 | 128 | if (returnType.getKind() == TypeKind.VOID) { 129 | if (deliveryOptionsAnnotation != null) { 130 | methodBuilder.addStatement("$T deliveryOptions = new $T().setSendTimeout($L)", DeliveryOptions.class, DeliveryOptions.class, deliveryOptionsAnnotation.timeout()); 131 | } else { 132 | methodBuilder.addStatement("$T deliveryOptions = new $T()", DeliveryOptions.class, DeliveryOptions.class); 133 | } 134 | methodBuilder.addStatement("this.$N.eventBus().send($N, $T.of($S, $N), deliveryOptions)", vertxField, eventBusAddressField, RIFAMessage.class, methodsHelper.generateEventBusSuffix(), methodsHelper.getParamsNamesCommaSeparatedOrCastedNull()); 135 | } else if (returnType.toString().startsWith(io.vertx.core.streams.ReadStream.class.getCanonicalName())) { 136 | methodBuilder.addStatement("String dataAddress = $N + Long.toHexString(java.util.concurrent.ThreadLocalRandom.current().nextLong())", eventBusAddressField); 137 | methodBuilder.addStatement("String remoteAddress = $N", eventBusAddressField); 138 | methodBuilder.addStatement("return new $T<>($N, dataAddress, remoteAddress, $T.of($S, $N))", VxRifaReceivingReadStream.class, vertxField, RIFAMessage.class, methodsHelper.generateEventBusSuffix(), methodsHelper.getParamsNamesCommaSeparatedOrCastedNull()); 139 | } else if (returnType.toString().startsWith(io.vertx.core.streams.WriteStream.class.getCanonicalName())) { 140 | methodBuilder.addStatement("String controlAddress = $N + Long.toHexString(java.util.concurrent.ThreadLocalRandom.current().nextLong())", eventBusAddressField); 141 | methodBuilder.addStatement("String remoteAddress = $N", eventBusAddressField); 142 | methodBuilder.addStatement("return new $T<>($N, controlAddress, remoteAddress, $T.of($S, $N))", VxRifaSendingWriteStream.class, vertxField, RIFAMessage.class, methodsHelper.generateEventBusSuffix(), methodsHelper.getParamsNamesCommaSeparatedOrCastedNull()); 143 | } else { 144 | ParameterizedTypeName parameterizedTypeName = (ParameterizedTypeName) ParameterizedTypeName.get(returnType); 145 | TypeName[] typeNames = parameterizedTypeName.typeArguments.toArray(new TypeName[0]); 146 | methodBuilder.addStatement("$T promise = $T.promise()", ParameterizedTypeName.get(ClassName.get(io.vertx.core.Promise.class), typeNames), Promise.class); 147 | if (deliveryOptionsAnnotation != null) { 148 | methodBuilder.addStatement("$T deliveryOptions = new $T().setSendTimeout($L)", DeliveryOptions.class, DeliveryOptions.class, deliveryOptionsAnnotation.timeout()); 149 | } else { 150 | methodBuilder.addStatement("$T deliveryOptions = new $T()", DeliveryOptions.class, DeliveryOptions.class); 151 | } 152 | methodBuilder.addStatement("this.$N.eventBus().request($N, $T.of($S, $N), deliveryOptions, result -> handle(promise,result))", 153 | vertxField, eventBusAddressField, RIFAMessage.class, methodsHelper.generateEventBusSuffix(), methodsHelper.getParamsNamesCommaSeparatedOrCastedNull() 154 | ); 155 | methodBuilder.addStatement("return promise.future()"); 156 | } 157 | 158 | methodBuilder.addAnnotation(Override.class); 159 | 160 | classBuilder.addMethod(methodBuilder.build()); 161 | 162 | } 163 | 164 | } 165 | 166 | return this; 167 | 168 | } 169 | 170 | SenderGenerator generateHandler() { 171 | 172 | MethodSpec.Builder handlerBuilder = MethodSpec.methodBuilder("handle"); 173 | 174 | TypeVariableName Tvariable = TypeVariableName.get("T"); 175 | 176 | handlerBuilder.addModifiers(Modifier.PRIVATE) 177 | .addTypeVariable(Tvariable) 178 | .addAnnotation(AnnotationSpec.builder(SuppressWarnings.class).addMember("value", "$S", "unchecked").build()); 179 | 180 | ParameterSpec promiseParameter = ParameterSpec.builder(ParameterizedTypeName.get(ClassName.get(io.vertx.core.Promise.class), Tvariable), "promise").build(); 181 | ParameterSpec asyncResultParameter = ParameterSpec.builder( 182 | ParameterizedTypeName.get(ClassName.get(io.vertx.core.AsyncResult.class), 183 | ParameterizedTypeName.get(ClassName.get(io.vertx.core.eventbus.Message.class), TypeName.get(Object.class))), 184 | "asyncResult").build(); 185 | 186 | handlerBuilder.addParameter(promiseParameter) 187 | .addParameter(asyncResultParameter) 188 | .beginControlFlow("if ($N.succeeded())", asyncResultParameter) 189 | .addStatement("$T reply = ($T) $N.result().body()", RIFAReply.class, RIFAReply.class, asyncResultParameter) 190 | .beginControlFlow("if (reply.isExceptional())") 191 | .addStatement("$N.fail(reply.getException())", promiseParameter) 192 | .nextControlFlow("else") 193 | .addStatement("$N.complete(($T) reply.getResult())", promiseParameter, Tvariable) 194 | .endControlFlow() 195 | .nextControlFlow("else") 196 | .addStatement("$N.fail($N.cause().getMessage())", promiseParameter, asyncResultParameter) 197 | .endControlFlow() 198 | .returns(TypeName.VOID); 199 | 200 | classBuilder.addMethod(handlerBuilder.build()); 201 | 202 | return this; 203 | 204 | } 205 | 206 | TypeSpec buildClass() { 207 | 208 | return classBuilder.build(); 209 | 210 | } 211 | 212 | } 213 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/VxRifa.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | import java.lang.annotation.ElementType; 22 | import java.lang.annotation.Retention; 23 | import java.lang.annotation.RetentionPolicy; 24 | import java.lang.annotation.Target; 25 | 26 | /** 27 | *

VxRIFA - Vert.X Rich Interfaces For Actors

28 | * This library introduces concept of asynchronous object-oriented programming 'by contract'.

29 | * Usually if you want to send message in Vert.X from one Actor(Verticle) to other you need to use eventBus.send or eventBus.publish with some object as payload. 30 | * Objects should be some sort of simple types like String,Integer or special objects like JsonObject.
31 | * Of course you can register own 'codec' and send anything you want but type checking on receiving side is a developer responsibility.
32 | * You should also write boiler plate for message handlers and handler registering.

33 | * VxRifa library implements Java-idiomatic style for actors messaging based on Interfaces. 34 | *

How to use library

35 | * Any interface can be annotated with {@link VxRifa}. Methods should return void or {@link io.vertx.core.Future}. 36 | * Whenever java compiler processes annotations (when building project or on the fly in modern IDEs) VxRifa generates special classes that do all work. 37 | * For example: 38 | *

 39 |  * {@literal @}VxRifa
 40 |  * public interface Calculator {
 41 |  * 
 42 |  *      Future<Double> sumTwoDoubles(Double one, Double two);
 43 |  *  
 44 |  *      void reset();
 45 |  * 
 46 |  * }
 47 |  * 
48 | * Implementation in Verticle hat exporting such API would look like that: 49 | *

 50 |  * public class CalculatorImpl implements Calculator {
 51 |  * 
 52 |  *      {@literal @}Override
 53 |  *      public Future<Double> sumTwoDoubles(Double one, Double two) {
 54 |  *          Future<Double> future = Future.future();
 55 |  *          future.complete(one + two);
 56 |  *          return future;
 57 |  *      }
 58 |  *  
 59 |  *      {@literal @}Override
 60 |  *      public void reset() {
 61 |  *          
 62 |  *          // Some reset actions 
 63 |  *  
 64 |  *      }
 65 |  * 
 66 |  * }
 67 |  * 
68 | * Now you can get {@link VxRifaReceiver} with {@link VxRifaUtil#getReceiverRegistrator} 69 | * which creates any needed eventBus.consumer and calls methods of Calculator whenever it receives messages from other actors.
70 | * Other Verticles should use {@link VxRifaUtil#getSenderByInterface} that returns VxRifa-driven implementation of Calculator which send messages under the hood. 71 | * For example: 72 | *

 73 |  * .... CalculatorVerticle ....
 74 |  * 
 75 |  * Calculator calc_impl = new CalculatorImpl();
 76 |  * VxRifaReceiver<Calculator> registrator = VxRifaUtil.getReceiverRegistrator(vertx, Calculator.class);
 77 |  * Future<?> when_registered = registrator.registerReceiver(calc_impl);
 78 |  * 
 79 |  * .... Some other verticles that wants to use Calculator API ....
 80 |  * 
 81 |  * Calculator calc = VxRifaUtil.getSenderByInterface(vertx, Calculator.class);
 82 |  * calc.sumTwoDoubles(1.0, 2.0).setHandler(result -> {
 83 |  *      if (result.succeeded()) {
 84 |  *          Double sum = result.result();
 85 |  *      }
 86 |  * });
 87 |  * 
88 | *

Notes and limitations

89 | * There is one small thing that should be done before using VxRifa. You must call {@link VxRifaUtil#registerRIFACodec(io.vertx.core.Vertx) } once for any instance of Vert.x.
90 | * VxRifa uses wrapper as container for methods parameters so that wrapper should be registered before any sending by eventBus.
91 | * You should also remember that any parameters and returned objects should be immutable(effectively immutable) or at least thread-safe.
92 | * Currently messaging by VxRifa only possible for local non-clustered Vert.X instances because RIFAMessageCodec not supported network encoding/decoding of objects. 93 | * I hope to solve that in near future. 94 | * @author Nikita Staroverov 95 | */ 96 | @Retention(RetentionPolicy.CLASS) 97 | @Target(ElementType.TYPE) 98 | public @interface VxRifa { 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/VxRifaAnnotationProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | import com.squareup.javapoet.JavaFile; 22 | import java.io.IOException; 23 | import java.util.Collections; 24 | import java.util.HashSet; 25 | import java.util.Set; 26 | import java.util.logging.Level; 27 | import java.util.logging.Logger; 28 | import javax.annotation.processing.AbstractProcessor; 29 | import javax.annotation.processing.Filer; 30 | import javax.annotation.processing.Messager; 31 | import javax.annotation.processing.ProcessingEnvironment; 32 | import javax.annotation.processing.RoundEnvironment; 33 | import javax.lang.model.SourceVersion; 34 | import javax.lang.model.element.Element; 35 | import javax.lang.model.element.ElementKind; 36 | import javax.lang.model.element.PackageElement; 37 | import javax.lang.model.element.TypeElement; 38 | import javax.lang.model.util.Elements; 39 | import javax.tools.Diagnostic; 40 | 41 | /** 42 | * 43 | * @author Nikita Staroverov 44 | */ 45 | public class VxRifaAnnotationProcessor extends AbstractProcessor { 46 | 47 | private Messager messager; 48 | private Filer filer; 49 | private Elements elements; 50 | 51 | @Override 52 | public synchronized void init(ProcessingEnvironment processingEnv) { 53 | 54 | super.init(processingEnv); 55 | 56 | messager = processingEnv.getMessager(); 57 | filer = processingEnv.getFiler(); 58 | elements = processingEnv.getElementUtils(); 59 | 60 | } 61 | 62 | @Override 63 | public boolean process(Set annotations, RoundEnvironment roundEnv) { 64 | 65 | Set senders_elements = roundEnv.getElementsAnnotatedWith(VxRifa.class); 66 | Set publishers_elements = roundEnv.getElementsAnnotatedWith(VxRifaPublish.class); 67 | 68 | if (senders_elements.isEmpty() && publishers_elements.isEmpty()) { 69 | 70 | return false; 71 | 72 | } 73 | 74 | for (Element element : senders_elements) { 75 | 76 | if (isNotInterfaceElement(element)) continue; 77 | 78 | TypeElement interfaceElement = (TypeElement) element; 79 | PackageElement packageElement = (PackageElement) interfaceElement.getEnclosingElement(); 80 | 81 | if (hasNoMethodsAtAll(interfaceElement)) continue; 82 | 83 | try { 84 | 85 | generateSender(interfaceElement, packageElement); 86 | generateReceiver(interfaceElement, packageElement); 87 | 88 | } catch (IOException ex) { 89 | Logger.getLogger(VxRifaAnnotationProcessor.class.getName()).log(Level.SEVERE, null, ex); //TODO Заменить на консольный вывод ошибки компиляции 90 | } 91 | 92 | } 93 | 94 | for (Element element : publishers_elements) { 95 | 96 | if (isNotInterfaceElement(element)) continue; 97 | 98 | TypeElement interfaceElement = (TypeElement) element; 99 | PackageElement packageElement = (PackageElement) interfaceElement.getEnclosingElement(); 100 | 101 | if (hasNoMethodsAtAll(interfaceElement)) continue; 102 | 103 | try { 104 | 105 | generatePublisher(interfaceElement, packageElement); 106 | generateReceiver(interfaceElement, packageElement); 107 | 108 | } catch (IOException ex) { 109 | Logger.getLogger(VxRifaAnnotationProcessor.class.getName()).log(Level.SEVERE, null, ex); //TODO Заменить на консольный вывод ошибки компиляции 110 | } 111 | 112 | } 113 | 114 | return true; 115 | 116 | } 117 | 118 | private boolean isNotInterfaceElement(Element element) { 119 | 120 | if (element.getKind() != ElementKind.INTERFACE) { 121 | messager.printMessage(Diagnostic.Kind.ERROR, "This annotation can be applied only to interfaces!", element, element.getAnnotationMirrors().get(0)); 122 | return true; 123 | } 124 | 125 | return false; 126 | 127 | } 128 | 129 | private boolean hasNoMethodsAtAll(TypeElement interfaceElement) { 130 | for (Element enclosedElement : elements.getAllMembers(interfaceElement)) { 131 | if (GeneratorsHelper.isElementSuitableMethod(enclosedElement)) { 132 | return false; 133 | } 134 | } 135 | return true; 136 | } 137 | 138 | private void generateSender(TypeElement interfaceElement, PackageElement packageElement) throws IOException { 139 | 140 | SenderGenerator senderGenerator = new SenderGenerator(messager, interfaceElement, elements) 141 | .generateInitializing() 142 | .generateMethods() 143 | .generateHandler(); 144 | 145 | JavaFile senderFile = JavaFile.builder(packageElement.getQualifiedName().toString(), senderGenerator.buildClass()).build(); 146 | 147 | senderFile.writeTo(filer); 148 | 149 | } 150 | 151 | private void generatePublisher(TypeElement interfaceElement, PackageElement packageElement) throws IOException { 152 | 153 | PublisherGenerator publisherGenerator = new PublisherGenerator(messager, interfaceElement, elements) 154 | .generateInitializing() 155 | .generateMethods(); 156 | 157 | JavaFile publisherFile = JavaFile.builder(packageElement.getQualifiedName().toString(), publisherGenerator.buildClass()).build(); 158 | 159 | publisherFile.writeTo(filer); 160 | 161 | } 162 | 163 | private void generateReceiver(TypeElement interfaceElement, PackageElement packageElement) throws IOException { 164 | 165 | ReceiverGenerator receiverGenerator = new ReceiverGenerator(messager, interfaceElement, elements) 166 | .generateInitializing() 167 | .generateRegisterMethod() 168 | .generateUnregisterMethod(); 169 | 170 | JavaFile receiverFile = JavaFile.builder(packageElement.getQualifiedName().toString(), receiverGenerator.buildClass()).build(); 171 | 172 | receiverFile.writeTo(filer); 173 | 174 | } 175 | 176 | @Override 177 | public Set getSupportedAnnotationTypes() { 178 | 179 | HashSet annotations = new HashSet<>(); 180 | 181 | annotations.add(VxRifa.class.getCanonicalName()); 182 | annotations.add(VxRifaPublish.class.getCanonicalName()); 183 | 184 | return Collections.unmodifiableSet(annotations); 185 | 186 | } 187 | 188 | @Override 189 | public SourceVersion getSupportedSourceVersion() { 190 | 191 | return SourceVersion.latestSupported(); 192 | 193 | } 194 | 195 | } 196 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/VxRifaDeliveryOptions.java: -------------------------------------------------------------------------------- 1 | package io.github.nsforth.vxrifa; 2 | 3 | import io.vertx.core.eventbus.DeliveryOptions; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | @Retention(RetentionPolicy.RUNTIME) 11 | @Target(ElementType.METHOD) 12 | public @interface VxRifaDeliveryOptions { 13 | long timeout() default DeliveryOptions.DEFAULT_TIMEOUT; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/VxRifaIgnore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 Nikita Staroverov . 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | import java.lang.annotation.ElementType; 22 | import java.lang.annotation.Retention; 23 | import java.lang.annotation.RetentionPolicy; 24 | import java.lang.annotation.Target; 25 | 26 | /** 27 | * Sometimes you do not want to implement all methods, for example you want to get events with {@link VxRifaPublish} Listener but only some of them. 28 | * You should annotate unwanted methods in your implementation with {@link VxRifaIgnore} and VxRifa skipped generation of eventBus consumers for such methods.
29 | * {@link VxRifaIgnore} especially useful for Adapter-like classes. 30 | * Use it with care on {@link VxRifa} interfaces. Invoker receives eventBus timeout when tries to call {@link VxRifaIgnore} methods. 31 | * @author Nikita Staroverov 32 | */ 33 | @Retention(RetentionPolicy.RUNTIME) 34 | @Target(ElementType.METHOD) 35 | public @interface VxRifaIgnore { 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/VxRifaPublish.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | import java.lang.annotation.ElementType; 22 | import java.lang.annotation.Retention; 23 | import java.lang.annotation.RetentionPolicy; 24 | import java.lang.annotation.Target; 25 | 26 | /** 27 | * Same as {@link VxRifa} but define publish/subscribe scheme so methods that returns something other than void is not allowed. 28 | * @author Nikita Staroverov 29 | */ 30 | @Retention(RetentionPolicy.CLASS) 31 | @Target(ElementType.TYPE) 32 | public @interface VxRifaPublish { 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/VxRifaReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | import io.vertx.core.Future; 22 | 23 | /** 24 | * Implementor of that class can register some interface annotated with {@link VxRifa} or {@link VxRifaPublish}. 25 | * After registration vertx consumers accepts messages from eventBus and calls methods of receiver. 26 | * You can ask {@link #unregisterReceiver} whenever you want. Of course when verticle that calls {@link #registerReceiver} stopped consumers unregistered automatically. 27 | * @author Nikita Staroverov 28 | * @param Interface type for receiver generation 29 | */ 30 | public interface VxRifaReceiver { 31 | 32 | Future registerReceiver(R receiver); 33 | 34 | Future unregisterReceiver(); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/VxRifaReceivingReadStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | import io.vertx.core.Handler; 22 | import io.vertx.core.Vertx; 23 | import io.vertx.core.eventbus.DeliveryOptions; 24 | import io.vertx.core.eventbus.MessageConsumer; 25 | import io.vertx.core.streams.ReadStream; 26 | 27 | /** 28 | * 29 | * @author Nikita Staroverov 30 | */ 31 | public class VxRifaReceivingReadStream implements ReadStream { 32 | 33 | private static final int ACK_WINDOW = 100; 34 | 35 | private final Vertx vertx; 36 | private final MessageConsumer dataConsumer; 37 | private final ReadStream dataStream; 38 | private String controlAddress; 39 | private long receivedCounter; 40 | private long ackCounter; 41 | private Handler handler; 42 | private Handler exceptionHandler; 43 | private Handler endHandler; 44 | 45 | public VxRifaReceivingReadStream(Vertx vertx, String dataAddress, String remoteAddress, RIFAMessage params) { 46 | this.vertx = vertx; 47 | dataConsumer = vertx.eventBus().consumer(dataAddress); 48 | dataStream = dataConsumer.bodyStream(); 49 | dataStream.handler(msg -> processDataMessage(msg)); 50 | dataConsumer.completionHandler(result -> { 51 | if (result.failed()) { 52 | closeExceptionally(result.cause()); 53 | } else { 54 | vertx.eventBus().request(remoteAddress, params, new DeliveryOptions().addHeader("DataAddress", dataAddress), reply -> { 55 | if (reply.succeeded()) { 56 | RIFAReply rifaReply = (RIFAReply) reply.result().body(); 57 | if (rifaReply.isExceptional()) { 58 | closeExceptionally(result.cause()); 59 | } else { 60 | controlAddress = (String) rifaReply.getResult(); 61 | } 62 | } else { 63 | closeExceptionally(result.cause()); 64 | } 65 | }); 66 | } 67 | }); 68 | } 69 | 70 | @Override 71 | public ReadStream pause() { 72 | dataStream.pause(); 73 | return this; 74 | } 75 | 76 | @Override 77 | public ReadStream resume() { 78 | dataStream.resume(); 79 | return this; 80 | } 81 | 82 | @Override 83 | public ReadStream handler(Handler handler) { 84 | this.handler = handler; 85 | return this; 86 | } 87 | 88 | @Override 89 | public ReadStream exceptionHandler(Handler handler) { 90 | this.exceptionHandler = handler; 91 | return this; 92 | } 93 | 94 | @Override 95 | public ReadStream endHandler(Handler endHandler) { 96 | this.endHandler = endHandler; 97 | return this; 98 | } 99 | 100 | @SuppressWarnings("unchecked") 101 | private void processDataMessage(RIFAMessage rifaMessage) { 102 | receivedCounter++; 103 | String messageType = rifaMessage.getSuffix(); 104 | switch (messageType) { 105 | case "Data": 106 | long acks = receivedCounter - ackCounter; 107 | if (acks > ACK_WINDOW / 2) { 108 | ackCounter = ackCounter + ACK_WINDOW / 2; 109 | vertx.eventBus().send(controlAddress, RIFAMessage.of("Ack", ackCounter)); 110 | } 111 | if (this.handler != null) { 112 | this.handler.handle((T) rifaMessage.getParameter(0)); 113 | } 114 | break; 115 | case "Exception": 116 | vertx.eventBus().send(controlAddress, RIFAMessage.of("Ack", receivedCounter)); 117 | closeExceptionally((Throwable) rifaMessage.getParameter(0)); 118 | break; 119 | case "End": 120 | vertx.eventBus().send(controlAddress, RIFAMessage.of("Ack", receivedCounter)); 121 | dataConsumer.unregister(); 122 | if (this.endHandler != null) { 123 | this.endHandler.handle(null); 124 | } 125 | break; 126 | } 127 | } 128 | 129 | private void closeExceptionally(Throwable ex) { 130 | dataConsumer.unregister(); 131 | if (this.exceptionHandler != null) { 132 | this.exceptionHandler.handle(ex); 133 | } 134 | } 135 | 136 | @Override 137 | public ReadStream fetch(long l) { 138 | dataStream.fetch(l); 139 | return this; 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/VxRifaReceivingWriteStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | import io.vertx.core.Vertx; 22 | import io.vertx.core.eventbus.Message; 23 | import io.vertx.core.eventbus.MessageConsumer; 24 | import io.vertx.core.streams.ReadStream; 25 | import io.vertx.core.streams.WriteStream; 26 | 27 | /** 28 | * 29 | * @author Nikita Staroverov 30 | */ 31 | public class VxRifaReceivingWriteStream { 32 | 33 | private final Vertx vertx; 34 | private final MessageConsumer dataConsumer; 35 | private final ReadStream dataStream; 36 | private final WriteStream writeStream; 37 | private final String controlAddress; 38 | private long receivedCounter; 39 | 40 | public VxRifaReceivingWriteStream(Vertx vertx, String dataAddress, String controlAddress, Message controlReply, WriteStream writeStream) { 41 | this.vertx = vertx; 42 | this.controlAddress = controlAddress; 43 | this.writeStream = writeStream; 44 | dataConsumer = vertx.eventBus().consumer(dataAddress, msg -> processDataMessage(msg.body())); 45 | dataStream = dataConsumer.bodyStream(); 46 | dataStream.pause(); 47 | dataConsumer.completionHandler(result -> { 48 | if (result.succeeded()) { 49 | if (!writeStream.writeQueueFull()) { 50 | dataStream.resume(); 51 | } 52 | writeStream.drainHandler(v -> drainHandler()); 53 | writeStream.exceptionHandler(ex -> excHandler(ex)); 54 | controlReply.reply(RIFAReply.of(dataAddress)); 55 | } else { 56 | controlReply.reply(RIFAReply.of(result.cause())); 57 | } 58 | }); 59 | } 60 | 61 | @SuppressWarnings("unchecked") 62 | private void processDataMessage(RIFAMessage rifaMessage) { 63 | String messageType = rifaMessage.getSuffix(); 64 | switch (messageType) { 65 | case "Data": 66 | receivedCounter++; 67 | writeStream.write((T) rifaMessage.getParameter(0)); 68 | if (writeStream.writeQueueFull()) { 69 | dataStream.pause(); 70 | } 71 | break; 72 | case "SetQueueSize": 73 | writeStream.setWriteQueueMaxSize((int) rifaMessage.getParameter(0)); 74 | if (writeStream.writeQueueFull()) { 75 | dataStream.pause(); 76 | } else { 77 | dataStream.resume(); 78 | vertx.eventBus().send(controlAddress, RIFAMessage.of("Ack", receivedCounter)); 79 | } 80 | break; 81 | case "End": 82 | writeStream.end(); 83 | this.dataConsumer.unregister(); 84 | break; 85 | } 86 | } 87 | 88 | private void drainHandler() { 89 | this.dataStream.resume(); 90 | vertx.eventBus().send(controlAddress, RIFAMessage.of("Ack", receivedCounter)); 91 | } 92 | 93 | private void excHandler(Throwable ex) { 94 | vertx.eventBus().send(controlAddress, RIFAMessage.of("Exception", ex)); 95 | this.dataConsumer.unregister(); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/VxRifaSendingReadStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | import io.vertx.core.Vertx; 22 | import io.vertx.core.eventbus.MessageConsumer; 23 | import io.vertx.core.streams.ReadStream; 24 | 25 | /** 26 | * 27 | * @author Nikita Staroverov 28 | */ 29 | public class VxRifaSendingReadStream { 30 | 31 | private static final int ACK_WINDOW = 100; 32 | 33 | private final Vertx vertx; 34 | private final String dataAddress; 35 | private final MessageConsumer controlConsumer; 36 | private final ReadStream input; 37 | private long sentCounter; 38 | private long ackCounter; 39 | 40 | public VxRifaSendingReadStream(Vertx vertx, String dataAddress, String controlAddress, ReadStream input) { 41 | this.vertx = vertx; 42 | this.dataAddress = dataAddress; 43 | this.input = input; 44 | input.pause(); 45 | input.handler(obj -> sendDataMessage(obj)); 46 | input.endHandler(v -> endHandler()); 47 | input.exceptionHandler(ex -> excHandler(ex)); 48 | controlConsumer = vertx.eventBus().consumer(controlAddress, msg -> receiveControlMessage(msg.body())); 49 | controlConsumer.completionHandler(result -> { 50 | if (result.failed()) { 51 | controlConsumer.unregister(); 52 | input.handler(null); 53 | input.endHandler(null); 54 | input.exceptionHandler(null); 55 | input.resume(); 56 | } else { 57 | input.resume(); 58 | } 59 | }); 60 | } 61 | 62 | 63 | private void sendDataMessage(T obj) { 64 | sentCounter++; 65 | vertx.eventBus().send(dataAddress, RIFAMessage.of("Data", obj)); 66 | if (sentCounter - ackCounter >= ACK_WINDOW) { 67 | input.pause(); 68 | } 69 | } 70 | 71 | private void endHandler() { 72 | sentCounter++; 73 | vertx.eventBus().send(dataAddress, RIFAMessage.of("End")); 74 | controlConsumer.unregister(); 75 | } 76 | 77 | private void excHandler(Throwable ex) { 78 | sentCounter++; 79 | vertx.eventBus().send(dataAddress, RIFAMessage.of("Exception", ex)); 80 | controlConsumer.unregister(); 81 | } 82 | 83 | private void receiveControlMessage(RIFAMessage rifaMessage) { 84 | String messageType = rifaMessage.getSuffix(); 85 | switch (messageType) { 86 | case "Ack": 87 | this.ackCounter = (long) rifaMessage.getParameter(0); 88 | if (sentCounter - ackCounter < ACK_WINDOW) { 89 | input.resume(); 90 | } 91 | break; 92 | } 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/VxRifaSendingWriteStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | import io.vertx.core.AsyncResult; 22 | import io.vertx.core.Handler; 23 | import io.vertx.core.Vertx; 24 | import io.vertx.core.eventbus.DeliveryOptions; 25 | import io.vertx.core.eventbus.MessageConsumer; 26 | import io.vertx.core.streams.WriteStream; 27 | 28 | /** 29 | * 30 | * @author Nikita Staroverov 31 | */ 32 | public class VxRifaSendingWriteStream implements WriteStream { 33 | 34 | private static final int ACK_WINDOW = 100; 35 | 36 | private final Vertx vertx; 37 | private final MessageConsumer controlConsumer; 38 | private String dataAddress; 39 | private int maxQueueSize = ACK_WINDOW; 40 | private long sentCounter; 41 | private long ackCounter; 42 | private Handler drainHandler; 43 | private Handler excHandler; 44 | 45 | public VxRifaSendingWriteStream(Vertx vertx, final String controlAddress, String remoteAddress, RIFAMessage params) { 46 | this.vertx = vertx; 47 | controlConsumer = vertx.eventBus().consumer(controlAddress, msg -> receiveControlMessage(msg.body())); 48 | controlConsumer.completionHandler(result -> { 49 | if (result.failed()) { 50 | closeExceptionally(result.cause()); 51 | } else { 52 | vertx.eventBus().request(remoteAddress, params, new DeliveryOptions().addHeader("ControlAddress", controlAddress), reply -> { 53 | if (reply.succeeded()) { 54 | RIFAReply rifaReply = (RIFAReply) reply.result().body(); 55 | if (rifaReply.isExceptional()) { 56 | closeExceptionally(result.cause()); 57 | } else { 58 | dataAddress = (String) rifaReply.getResult(); 59 | vertx.eventBus().send(dataAddress, RIFAMessage.of("SetQueueSize", maxQueueSize)); 60 | if (this.drainHandler != null) { 61 | this.drainHandler.handle(null); 62 | } 63 | } 64 | } else { 65 | closeExceptionally(result.cause()); 66 | } 67 | }); 68 | } 69 | }); 70 | } 71 | 72 | @Override 73 | public WriteStream write(T data) { 74 | checkDataAddress(); 75 | sentCounter++; 76 | vertx.eventBus().send(dataAddress, RIFAMessage.of("Data", data)); 77 | return this; 78 | } 79 | 80 | @Override 81 | public WriteStream write(T data, Handler> handler) { 82 | checkDataAddress(); 83 | sentCounter++; 84 | vertx.eventBus().request(dataAddress, RIFAMessage.of("Data", data), (e) -> { 85 | handler.handle(null); 86 | }); 87 | return this; 88 | } 89 | 90 | @Override 91 | public void end() { 92 | checkDataAddress(); 93 | controlConsumer.unregister(); 94 | vertx.eventBus().send(dataAddress, RIFAMessage.of("End")); 95 | } 96 | 97 | @Override 98 | public void end(Handler> handler) { 99 | checkDataAddress(); 100 | controlConsumer.unregister(); 101 | vertx.eventBus().request(dataAddress, RIFAMessage.of("End"), (e) -> { 102 | handler.handle(null); 103 | }); 104 | } 105 | 106 | @Override 107 | public WriteStream exceptionHandler(Handler handler) { 108 | this.excHandler = handler; 109 | return this; 110 | } 111 | 112 | @Override 113 | public WriteStream drainHandler(Handler handler) { 114 | this.drainHandler = handler; 115 | return this; 116 | } 117 | 118 | @Override 119 | public WriteStream setWriteQueueMaxSize(int maxSize) { 120 | this.maxQueueSize = maxSize; 121 | if (this.dataAddress != null) { 122 | vertx.eventBus().send(dataAddress, RIFAMessage.of("SetQueueSize", maxSize)); 123 | } 124 | return this; 125 | } 126 | 127 | @Override 128 | public boolean writeQueueFull() { 129 | if (dataAddress == null) { 130 | return true; 131 | } 132 | return sentCounter - ackCounter >= maxQueueSize; 133 | } 134 | 135 | private void receiveControlMessage(RIFAMessage rifaMessage) { 136 | String messageType = rifaMessage.getSuffix(); 137 | switch (messageType) { 138 | case "Ack": 139 | boolean wasFull = writeQueueFull(); 140 | this.ackCounter = (long) rifaMessage.getParameter(0); 141 | boolean nowFull = writeQueueFull(); 142 | if (wasFull && !nowFull) { 143 | if (this.drainHandler != null) { 144 | this.drainHandler.handle(null); 145 | } 146 | } 147 | break; 148 | case "Exception": 149 | closeExceptionally((Throwable) rifaMessage.getParameter(0)); 150 | break; 151 | } 152 | } 153 | 154 | private void closeExceptionally(Throwable ex) { 155 | controlConsumer.unregister(); 156 | if (this.excHandler != null) { 157 | this.excHandler.handle(ex); 158 | } 159 | } 160 | 161 | private void checkDataAddress() throws IllegalStateException { 162 | if (dataAddress == null) { 163 | IllegalStateException ex = new IllegalStateException("WriteStream is not ready!"); 164 | if (this.excHandler != null) { 165 | this.excHandler.handle(ex); 166 | } else { 167 | throw ex; 168 | } 169 | } 170 | } 171 | 172 | } 173 | -------------------------------------------------------------------------------- /src/main/java/io/github/nsforth/vxrifa/VxRifaUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Nikita Staroverov. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 17 | * MA 02110-1301 USA 18 | */ 19 | package io.github.nsforth.vxrifa; 20 | 21 | import io.vertx.core.Future; 22 | import io.vertx.core.Promise; 23 | import io.vertx.core.Vertx; 24 | import java.lang.reflect.InvocationTargetException; 25 | 26 | /** 27 | * 28 | * @author Nikita Staroverov 29 | */ 30 | public class VxRifaUtil { 31 | 32 | /** 33 | * Should be called once per Vertx instance before use other methods from {@link VxRifaUtil} 34 | * @param vertx Vertx instance 35 | */ 36 | public static void registerRIFACodec(Vertx vertx) { 37 | vertx.eventBus().registerDefaultCodec(RIFAMessage.class, new RIFAMessageCodec()); 38 | vertx.eventBus().registerDefaultCodec(RIFAReply.class, new RIFAReplyCodec()); 39 | } 40 | 41 | /** 42 | * Returns implementation that can send eventBus messages under the hood like VertX.EventBus.send. 43 | * Interface should be annotated with {@link VxRifa}. 44 | * @param Some interface which methods should be wrapped to eventBus messages. 45 | * @param vertx VertX instance 46 | * @param interfaceType Class for which implementation should be generated 47 | * @return Generated sender implementation 48 | * @throws IllegalArgumentException when sender instance could not be instantiated 49 | */ 50 | public static I getSenderByInterface(Vertx vertx, Class interfaceType) throws IllegalArgumentException { 51 | return instantiateSenderImplementation(vertx, interfaceType, null); 52 | } 53 | 54 | /** 55 | * Same as {@link #getSenderByInterface(io.vertx.core.Vertx, java.lang.Class)} but with possibility to choose other eventBus address. 56 | * It may be useful when you want to use more than one receivers independent of each other. 57 | * @param Interface 58 | * @param vertx Vertx instance 59 | * @param interfaceType Class for which implementation should be generated 60 | * @param eventBusAddress Alternate eventBus address, by default address came from interface FQN 61 | * @return Generated sender implementation 62 | * @throws IllegalArgumentException when sender instance could not be instantiated 63 | */ 64 | public static I getSenderByInterface(Vertx vertx, Class interfaceType, String eventBusAddress) throws IllegalArgumentException { 65 | return instantiateSenderImplementation(vertx, interfaceType, eventBusAddress); 66 | } 67 | 68 | @SuppressWarnings("unchecked") 69 | private static I instantiateSenderImplementation(Vertx vertx, Class interfaceType, String eventBusAddress) { 70 | assert interfaceType.isInterface(); 71 | try { 72 | Class senderClass = ClassLoader.getSystemClassLoader().loadClass(interfaceType.getCanonicalName() + SenderGenerator.VXRIFA_SENDER_SUFFIX); 73 | try { 74 | I newInstance; 75 | if (eventBusAddress == null) { 76 | newInstance = (I) senderClass.getDeclaredConstructor(Vertx.class).newInstance(vertx); 77 | } else { 78 | newInstance = (I) senderClass.getDeclaredConstructor(Vertx.class, String.class).newInstance(vertx, eventBusAddress); 79 | } 80 | return newInstance; 81 | } catch (InvocationTargetException ex) { 82 | throw new IllegalArgumentException(ex.getCause()); 83 | } catch (InstantiationException | IllegalAccessException ex) { 84 | throw new IllegalArgumentException(ex); 85 | } 86 | } catch (NoSuchMethodException | SecurityException | ClassNotFoundException ex) { 87 | throw new IllegalArgumentException(ex); 88 | } 89 | } 90 | 91 | /** 92 | * Same as {@link #getSenderByInterface(io.vertx.core.Vertx, java.lang.Class)} but returns implementation with broadcast eventBus messages like Vertx.eventBus.publish works. 93 | * @param Interface 94 | * @param vertx Vertx instance 95 | * @param interfaceType Class for which implementation should be generated 96 | * @return Generated publisher implementation 97 | * @throws IllegalArgumentException when publisher instance could not be instantiated 98 | */ 99 | public static I getPublisherByInterface(Vertx vertx, Class interfaceType) throws IllegalArgumentException { 100 | return instantiatePublisherImplementation(vertx, interfaceType, null); 101 | } 102 | 103 | /** 104 | * Same as {@link #getSenderByInterface(io.vertx.core.Vertx, java.lang.Class, java.lang.String)} but returns implementation with broadcast eventBus messages like Vertx.eventBus.publish works. 105 | * It may be useful when you want to use more than one receivers independent of each other. 106 | * @param Interface 107 | * @param vertx Vertx instance 108 | * @param interfaceType Class for which implementation should be generated 109 | * @param eventBusAddress Alternate eventBus address, by default address came from interface FQN 110 | * @return Generated publisher implementation 111 | * @throws IllegalArgumentException when publisher instance could not be instantiated 112 | */ 113 | public static I getPublisherByInterface(Vertx vertx, Class interfaceType, String eventBusAddress) throws IllegalArgumentException { 114 | return instantiatePublisherImplementation(vertx, interfaceType, eventBusAddress); 115 | } 116 | 117 | @SuppressWarnings("unchecked") 118 | private static I instantiatePublisherImplementation(Vertx vertx, Class interfaceType, String eventBusAddress) { 119 | assert interfaceType.isInterface(); 120 | try { 121 | Class publisherClass = ClassLoader.getSystemClassLoader().loadClass(interfaceType.getCanonicalName() + PublisherGenerator.VXRIFA_PUBLISHER_SUFFIX); 122 | try { 123 | I newInstance; 124 | if (eventBusAddress == null) { 125 | newInstance = (I) publisherClass.getDeclaredConstructor(Vertx.class).newInstance(vertx); 126 | } else { 127 | newInstance = (I) publisherClass.getDeclaredConstructor(Vertx.class, String.class).newInstance(vertx, eventBusAddress); 128 | } 129 | return newInstance; 130 | } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { 131 | throw new IllegalArgumentException(ex); 132 | } 133 | } catch (NoSuchMethodException | SecurityException | ClassNotFoundException ex) { 134 | throw new IllegalArgumentException(ex); 135 | } 136 | } 137 | 138 | /** 139 | * Returns object that can register consumer side. Implementation that you get from {@link #getSenderByInterface} or {@link #getPublisherByInterface } 140 | * sends messages to object registered by {@link VxRifaReceiver}. 141 | * @param Interface 142 | * @param vertx Vertx instance 143 | * @param interfaceType Class for which receiver should be generated 144 | * @return Generated receiver for registering of your consumer interface implementation 145 | */ 146 | public static VxRifaReceiver getReceiverRegistrator(Vertx vertx, Class interfaceType) { 147 | return instantiateReceiverRegistrator(vertx, interfaceType, null); 148 | } 149 | 150 | /** 151 | * Same as {@link #getReceiverRegistrator} but tries to register receiver and returns future with it 152 | * @param Interface 153 | * @param vertx Vertx instance 154 | * @param interfaceType Class for which receiver should be generated 155 | * @param receiver Interface implementation that should be registered 156 | * @return Future that on completion returns successfully registered {@link VxRifaReceiver} and fails otherwise 157 | */ 158 | public static Future> registerReceiver(Vertx vertx, Class interfaceType, I receiver) { 159 | Promise> promise = Promise.promise(); 160 | 161 | VxRifaReceiver receiverRegistrator = getReceiverRegistrator(vertx, interfaceType); 162 | receiverRegistrator.registerReceiver(receiver).onComplete(complete -> { 163 | if (complete.succeeded()) { 164 | promise.complete(receiverRegistrator); 165 | } else { 166 | promise.fail(complete.cause()); 167 | } 168 | }); 169 | 170 | return promise.future(); 171 | } 172 | 173 | /** 174 | * Same as {@link #getReceiverRegistrator(io.vertx.core.Vertx, java.lang.Class) } but you can redefine eventBus address. 175 | * @param Interface 176 | * @param vertx Vertx instance 177 | * @param interfaceType Class for which receiver should be generated 178 | * @param eventBusAddress Alternate eventBus address, by default address came from interface FQN 179 | * @return Generated receiver for registering of your consumer interface implementation 180 | */ 181 | public static VxRifaReceiver getReceiverRegistrator(Vertx vertx, Class interfaceType, String eventBusAddress) { 182 | return instantiateReceiverRegistrator(vertx, interfaceType, eventBusAddress); 183 | } 184 | 185 | /** 186 | * Same as {@link #registerReceiver} but with possibility to choose alternate eventBus address 187 | * @param Interface 188 | * @param vertx Vertx instance 189 | * @param interfaceType Class for which receiver should be generated 190 | * @param receiver Interface implementation that should be registered 191 | * @param eventBusAddress Alternate eventBus address, by default address came from interface FQN 192 | * @return Future that on completion returns successfully registered {@link VxRifaReceiver} and fails otherwise 193 | */ 194 | public static Future> registerReceiver(Vertx vertx, Class interfaceType, I receiver, String eventBusAddress) { 195 | Promise> promise = Promise.promise(); 196 | 197 | VxRifaReceiver receiverRegistrator = getReceiverRegistrator(vertx, interfaceType, eventBusAddress); 198 | receiverRegistrator.registerReceiver(receiver).onComplete(complete -> { 199 | if (complete.succeeded()) { 200 | promise.complete(receiverRegistrator); 201 | } else { 202 | promise.fail(complete.cause()); 203 | } 204 | }); 205 | 206 | return promise.future(); 207 | } 208 | 209 | @SuppressWarnings("unchecked") 210 | private static VxRifaReceiver instantiateReceiverRegistrator(Vertx vertx, Class interfaceType, String eventBusAddress) { 211 | assert interfaceType.isInterface(); 212 | try { 213 | Class> receiverRegistratorClass = (Class>) ClassLoader.getSystemClassLoader().loadClass(interfaceType.getCanonicalName() + ReceiverGenerator.VXRIFA_RECEIVER_SUFFIX); 214 | try { 215 | VxRifaReceiver newInstance; 216 | if (eventBusAddress == null) { 217 | newInstance = (VxRifaReceiver) receiverRegistratorClass.getDeclaredConstructor(Vertx.class).newInstance(vertx); 218 | } else { 219 | newInstance = (VxRifaReceiver) receiverRegistratorClass.getDeclaredConstructor(Vertx.class, String.class).newInstance(vertx, eventBusAddress); 220 | } 221 | return newInstance; 222 | } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { 223 | throw new IllegalArgumentException(ex); 224 | } 225 | } catch (NoSuchMethodException | SecurityException | ClassNotFoundException ex) { 226 | throw new IllegalArgumentException(ex); 227 | } 228 | } 229 | 230 | } 231 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/javax.annotation.processing.Processor: -------------------------------------------------------------------------------- 1 | io.github.nsforth.vxrifa.VxRifaAnnotationProcessor 2 | 3 | -------------------------------------------------------------------------------- /src/test/java/io/github/nsforth/vxrifa/test/NoMethodsInterface.java: -------------------------------------------------------------------------------- 1 | package io.github.nsforth.vxrifa.test; 2 | /* 3 | * Copyright (C) 2017 Nikita Staroverov. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301 USA 19 | */ 20 | 21 | 22 | import io.github.nsforth.vxrifa.VxRifa; 23 | 24 | /** 25 | * 26 | * @author Nikita Staroverov 27 | */ 28 | @VxRifa 29 | public interface NoMethodsInterface { 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/io/github/nsforth/vxrifa/test/PublisherInterface.java: -------------------------------------------------------------------------------- 1 | package io.github.nsforth.vxrifa.test; 2 | /* 3 | * Copyright (C) 2017 Nikita Staroverov. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301 USA 19 | */ 20 | 21 | 22 | import io.github.nsforth.vxrifa.VxRifaPublish; 23 | 24 | /** 25 | * 26 | * @author Nikita Staroverov 27 | */ 28 | @VxRifaPublish 29 | public interface PublisherInterface { 30 | 31 | void publishMethod(); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/io/github/nsforth/vxrifa/test/SenderReceiverInterface.java: -------------------------------------------------------------------------------- 1 | package io.github.nsforth.vxrifa.test; 2 | /* 3 | * Copyright (C) 2017 Nikita Staroverov. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301 USA 19 | */ 20 | 21 | 22 | import io.github.nsforth.vxrifa.VxRifa; 23 | import io.github.nsforth.vxrifa.VxRifaDeliveryOptions; 24 | import io.vertx.core.Future; 25 | 26 | /** 27 | * 28 | * @author Nikita Staroverov 29 | */ 30 | @VxRifa 31 | public interface SenderReceiverInterface { 32 | 33 | void withoutParamsAndReturn(); 34 | 35 | Future withoutParams(); 36 | 37 | void withParamsAndWithoutReturn(int param1, String param2); 38 | 39 | Future withParams(int request); 40 | 41 | Future throwsUnexpectedException(String text); 42 | 43 | Future returnsNullInsteadOfFuture(); 44 | 45 | Future ignoredMethod(); 46 | 47 | @VxRifaDeliveryOptions(timeout = 500) 48 | Future customDeliveryOptionsMethod(String param, int param2); 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/io/github/nsforth/vxrifa/test/StreamOfStrings.java: -------------------------------------------------------------------------------- 1 | package io.github.nsforth.vxrifa.test; 2 | /* 3 | * Copyright (C) 2017 Nikita Staroverov. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301 USA 19 | */ 20 | import io.vertx.core.Handler; 21 | import io.vertx.core.streams.ReadStream; 22 | 23 | /** 24 | * 25 | * @author Nikita Staroverov 26 | */ 27 | public class StreamOfStrings implements ReadStream { 28 | 29 | private long counter = 10; 30 | private Handler handler; 31 | private Handler endHandler; 32 | private Handler exceptionHandler; 33 | private boolean flowing; 34 | 35 | @Override 36 | public ReadStream exceptionHandler(Handler handler) { 37 | this.exceptionHandler = handler; 38 | return this; 39 | } 40 | 41 | @Override 42 | public ReadStream handler(Handler handler) { 43 | this.handler = handler; 44 | return this; 45 | } 46 | 47 | @Override 48 | public ReadStream pause() { 49 | this.flowing = false; 50 | return this; 51 | } 52 | 53 | @Override 54 | public ReadStream resume() { 55 | this.flowing = true; 56 | while(handle()) { 57 | 58 | } 59 | return this; 60 | } 61 | 62 | @Override 63 | public ReadStream endHandler(Handler endHandler) { 64 | this.endHandler = endHandler; 65 | return this; 66 | } 67 | 68 | private boolean handle() { 69 | if (handler != null) { 70 | if (flowing) { 71 | if (counter > 0) { 72 | String event = Long.toString(counter--); 73 | this.handler.handle(event); 74 | return true; 75 | } else { 76 | if (counter == 0) { 77 | counter = -1; 78 | this.endHandler.handle(null); 79 | return true; 80 | } 81 | } 82 | } 83 | } 84 | return false; 85 | } 86 | 87 | @Override 88 | public ReadStream fetch(long l) { 89 | return this; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/test/java/io/github/nsforth/vxrifa/test/StreamOfStringsService.java: -------------------------------------------------------------------------------- 1 | package io.github.nsforth.vxrifa.test; 2 | /* 3 | * Copyright (C) 2017 Nikita Staroverov. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301 USA 19 | */ 20 | import io.github.nsforth.vxrifa.VxRifaReceiver; 21 | import io.github.nsforth.vxrifa.VxRifaUtil; 22 | import io.vertx.core.AbstractVerticle; 23 | import io.vertx.core.Future; 24 | import io.vertx.core.Promise; 25 | import io.vertx.core.streams.ReadStream; 26 | import io.vertx.core.streams.WriteStream; 27 | import io.vertx.ext.unit.Async; 28 | 29 | /** 30 | * 31 | * @author Nikita Staroverov 32 | */ 33 | class StreamOfStringsService extends AbstractVerticle implements StreamService { 34 | 35 | private final Async async; 36 | 37 | StreamOfStringsService(Async async) { 38 | this.async = async; 39 | } 40 | 41 | @Override 42 | public void start(Promise startPromise) throws Exception { 43 | Future> registerReceiver = VxRifaUtil.registerReceiver(vertx, StreamService.class, this); 44 | registerReceiver 45 | .onSuccess(result -> startPromise.complete()) 46 | .onFailure(e -> startPromise.fail(e)); 47 | } 48 | 49 | @Override 50 | public ReadStream getStreamOfStrings() { 51 | return new StreamOfStrings(); 52 | } 53 | 54 | @Override 55 | public WriteStream getStringsConsumer() { 56 | return new StringsConsumer(async); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/io/github/nsforth/vxrifa/test/StreamService.java: -------------------------------------------------------------------------------- 1 | package io.github.nsforth.vxrifa.test; 2 | /* 3 | * Copyright (C) 2017 Nikita Staroverov. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301 USA 19 | */ 20 | import io.github.nsforth.vxrifa.VxRifa; 21 | import io.vertx.core.streams.ReadStream; 22 | import io.vertx.core.streams.WriteStream; 23 | 24 | /** 25 | * 26 | * @author Nikita Staroverov 27 | */ 28 | @VxRifa 29 | public interface StreamService { 30 | 31 | ReadStream getStreamOfStrings(); 32 | 33 | WriteStream getStringsConsumer(); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/io/github/nsforth/vxrifa/test/StringsConsumer.java: -------------------------------------------------------------------------------- 1 | package io.github.nsforth.vxrifa.test; 2 | /* 3 | * Copyright (C) 2017 Nikita Staroverov. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301 USA 19 | */ 20 | import io.vertx.core.AsyncResult; 21 | import io.vertx.core.Handler; 22 | import io.vertx.core.streams.WriteStream; 23 | import io.vertx.ext.unit.Async; 24 | 25 | /** 26 | * 27 | * @author Nikita Staroverov 28 | */ 29 | public class StringsConsumer implements WriteStream { 30 | 31 | private final Async async; 32 | private final StringBuilder sb; 33 | 34 | StringsConsumer(Async async) { 35 | this.async = async; 36 | this.sb = new StringBuilder(); 37 | 38 | } 39 | 40 | @Override 41 | public WriteStream exceptionHandler(Handler handler) { 42 | return this; 43 | } 44 | 45 | @Override 46 | public WriteStream write(String data) { 47 | sb.append(data); 48 | async.countDown(); 49 | return this; 50 | } 51 | 52 | @Override 53 | public WriteStream write(String data, Handler> handler) { 54 | sb.append(data); 55 | async.countDown(); 56 | handler.handle(null); 57 | return this; 58 | } 59 | 60 | @Override 61 | public void end() { 62 | if (sb.toString().equals("123")) { 63 | async.countDown(); 64 | } 65 | } 66 | 67 | @Override 68 | public void end(Handler> handler) { 69 | if (sb.toString().equals("123")) { 70 | async.countDown(); 71 | } 72 | handler.handle(null); 73 | } 74 | 75 | @Override 76 | public void end(String s) { 77 | this.write(s); 78 | if (sb.toString().equals("123")) { 79 | async.countDown(); 80 | } 81 | } 82 | 83 | @Override 84 | public WriteStream setWriteQueueMaxSize(int maxSize) { 85 | return this; 86 | } 87 | 88 | @Override 89 | public boolean writeQueueFull() { 90 | return false; 91 | } 92 | 93 | @Override 94 | public WriteStream drainHandler(Handler handler) { 95 | return this; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/test/java/io/github/nsforth/vxrifa/test/TestSimpleSender.java: -------------------------------------------------------------------------------- 1 | package io.github.nsforth.vxrifa.test; 2 | /* 3 | * Copyright (C) 2017 Nikita Staroverov. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301 USA 19 | */ 20 | 21 | import io.github.nsforth.vxrifa.VxRifaIgnore; 22 | import io.github.nsforth.vxrifa.VxRifaReceiver; 23 | import io.github.nsforth.vxrifa.VxRifaUtil; 24 | import io.vertx.core.AbstractVerticle; 25 | import io.vertx.core.Future; 26 | import io.vertx.core.Promise; 27 | import io.vertx.ext.unit.Async; 28 | import io.vertx.ext.unit.TestContext; 29 | import io.vertx.ext.unit.junit.RunTestOnContext; 30 | import io.vertx.ext.unit.junit.VertxUnitRunner; 31 | import org.junit.Before; 32 | import org.junit.Rule; 33 | import org.junit.Test; 34 | import org.junit.runner.RunWith; 35 | 36 | /** 37 | * 38 | * @author Nikita Staroverov 39 | */ 40 | @RunWith(VertxUnitRunner.class) 41 | public class TestSimpleSender { 42 | 43 | @Rule 44 | public final RunTestOnContext rule = new RunTestOnContext(); 45 | 46 | class ReceiverVerticle extends AbstractVerticle implements SenderReceiverInterface { 47 | 48 | volatile String withoutParamsAndReturn; 49 | volatile int param1; 50 | volatile String param2; 51 | 52 | @Override 53 | public void start(Promise startPromise) throws Exception { 54 | Future> registerReceiver = VxRifaUtil.registerReceiver(rule.vertx(), SenderReceiverInterface.class, this); 55 | registerReceiver 56 | .onSuccess(r -> startPromise.complete()) 57 | .onFailure(e -> startPromise.fail(e)); 58 | } 59 | 60 | @Override 61 | public void withoutParamsAndReturn() { 62 | withoutParamsAndReturn = "Passed"; 63 | } 64 | 65 | @Override 66 | public Future withoutParams() { 67 | Promise promise = Promise.promise(); 68 | promise.complete("Passed"); 69 | return promise.future(); 70 | } 71 | 72 | @Override 73 | public void withParamsAndWithoutReturn(int param1, String param2) { 74 | this.param1 = param1; 75 | this.param2 = param2; 76 | } 77 | 78 | @Override 79 | public Future withParams(int request) { 80 | Promise promise = Promise.promise(); 81 | promise.complete(request); 82 | return promise.future(); 83 | } 84 | 85 | @Override 86 | public Future throwsUnexpectedException(String text) { 87 | throw new IllegalStateException(text); 88 | } 89 | 90 | @Override 91 | public Future returnsNullInsteadOfFuture() { 92 | return null; 93 | } 94 | 95 | @Override 96 | @VxRifaIgnore 97 | public Future ignoredMethod() { 98 | return null; 99 | } 100 | 101 | @Override 102 | public Future customDeliveryOptionsMethod(String param, int param2) { 103 | Promise promise = Promise.promise(); 104 | vertx.setTimer(1000, handler -> { 105 | promise.complete(param2); 106 | }); 107 | return promise.future(); 108 | } 109 | 110 | } 111 | 112 | @Before 113 | public void setUp(TestContext context) { 114 | VxRifaUtil.registerRIFACodec(rule.vertx()); 115 | } 116 | 117 | @Test(timeout = 3000L) 118 | public void testConstructorAssertions(TestContext context) { 119 | try { 120 | SenderReceiverInterface sender = VxRifaUtil.getSenderByInterface(null, SenderReceiverInterface.class); 121 | context.fail("Sender constructor assertions broken or assertions disabled!"); 122 | } catch (Throwable ex) { 123 | context.assertEquals(ex.getClass(), IllegalArgumentException.class); 124 | context.assertEquals(ex.getCause().getClass(), AssertionError.class); 125 | context.assertEquals(ex.getCause().getMessage(), "vertx should not be null! May be you try to create sender not in verticle start?"); 126 | } 127 | } 128 | 129 | @Test(timeout = 3000L) 130 | public void testReceiverMethods(TestContext context) { 131 | 132 | Async async = context.async(6); 133 | 134 | ReceiverVerticle receiverVerticle = new ReceiverVerticle(); 135 | SenderReceiverInterface sender = VxRifaUtil.getSenderByInterface(rule.vertx(), SenderReceiverInterface.class); 136 | rule.vertx().deployVerticle(receiverVerticle, deployResult -> { 137 | if (deployResult.succeeded()) { 138 | 139 | sender.withoutParams().onComplete(result -> { 140 | if (result.succeeded()) { 141 | context.assertEquals("Passed", result.result()); 142 | async.countDown(); 143 | } else { 144 | context.fail(result.cause()); 145 | } 146 | }); 147 | 148 | sender.withParams(123).onComplete(result -> { 149 | if (result.succeeded()) { 150 | context.assertEquals(123, result.result()); 151 | async.countDown(); 152 | } else { 153 | context.fail(result.cause()); 154 | } 155 | }); 156 | 157 | sender.withParamsAndWithoutReturn(321, "passed"); 158 | 159 | sender.withoutParamsAndReturn(); 160 | 161 | sender.throwsUnexpectedException("UnexpectedErrorTest").onComplete(handler -> { 162 | if (handler.failed()) { 163 | if (handler.cause() instanceof IllegalStateException) { 164 | Throwable cause = handler.cause(); 165 | context.assertEquals(cause.getMessage(), "UnexpectedErrorTest"); 166 | async.countDown(); 167 | } else { 168 | context.fail("Wrong exception type"); 169 | } 170 | } 171 | }); 172 | 173 | sender.returnsNullInsteadOfFuture().onComplete(handler -> { 174 | if (handler.failed()) { 175 | if (handler.cause() instanceof AssertionError) { 176 | Throwable cause = handler.cause(); 177 | context.assertTrue(cause.getMessage().startsWith("Returned future should not be null! May be you forget to create appropriate result in")); 178 | async.countDown(); 179 | } else { 180 | context.fail("Wrong exception type"); 181 | } 182 | } else { 183 | context.fail("Wrong exception type"); 184 | } 185 | }); 186 | 187 | sender.ignoredMethod().onComplete(handler -> { 188 | if (handler.succeeded()) { 189 | context.fail("Should catch exception"); 190 | } else { 191 | Throwable cause = handler.cause(); 192 | if (cause instanceof UnsupportedOperationException) { 193 | context.assertEquals(cause.getMessage(), "Method implementation is not provided"); 194 | } else { 195 | context.fail("Wrong exception type"); 196 | } 197 | } 198 | async.countDown(); 199 | }); 200 | 201 | sender.customDeliveryOptionsMethod("hello", 123).onComplete(handler -> { 202 | if(handler.succeeded()) { 203 | context.fail("Should catch exception by timeout"); 204 | } else { 205 | Throwable cause = handler.cause(); 206 | context.assertTrue(cause instanceof io.vertx.core.impl.NoStackTraceThrowable); 207 | } 208 | async.countDown(); 209 | }); 210 | 211 | } else { 212 | context.fail(deployResult.cause()); 213 | } 214 | }); 215 | 216 | rule.vertx().setTimer(1000, tid -> { 217 | context.assertEquals(receiverVerticle.param1, 321); 218 | context.assertEquals(receiverVerticle.param2, "passed"); 219 | context.assertEquals(receiverVerticle.withoutParamsAndReturn, "Passed"); 220 | if (async.count() == 0) { 221 | async.complete(); 222 | } else { 223 | context.fail("Not all tests completed!"); 224 | } 225 | }); 226 | 227 | } 228 | 229 | } 230 | -------------------------------------------------------------------------------- /src/test/java/io/github/nsforth/vxrifa/test/TestStreams.java: -------------------------------------------------------------------------------- 1 | package io.github.nsforth.vxrifa.test; 2 | /* 3 | * Copyright (C) 2017 Nikita Staroverov. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | * MA 02110-1301 USA 19 | */ 20 | 21 | import io.github.nsforth.vxrifa.VxRifaUtil; 22 | import io.vertx.core.streams.WriteStream; 23 | import io.vertx.ext.unit.Async; 24 | import io.vertx.ext.unit.TestContext; 25 | import io.vertx.ext.unit.junit.RunTestOnContext; 26 | import io.vertx.ext.unit.junit.VertxUnitRunner; 27 | import java.util.concurrent.atomic.AtomicInteger; 28 | import org.junit.Before; 29 | import org.junit.Rule; 30 | import org.junit.Test; 31 | import org.junit.runner.RunWith; 32 | 33 | /** 34 | * 35 | * @author Nikita Staroverov 36 | */ 37 | @RunWith(VertxUnitRunner.class) 38 | public class TestStreams { 39 | 40 | @Rule 41 | public final RunTestOnContext rule = new RunTestOnContext(); 42 | 43 | @Before 44 | public void setUp(TestContext context) { 45 | VxRifaUtil.registerRIFACodec(rule.vertx()); 46 | } 47 | 48 | @Test(timeout = 3000L) 49 | public void testStreams(TestContext context) { 50 | Async async = context.async(15); 51 | rule.vertx().deployVerticle(new StreamOfStringsService(async), deployResult -> { 52 | if (deployResult.failed()) { 53 | context.fail(deployResult.cause()); 54 | return; 55 | } 56 | StreamService streamService = VxRifaUtil.getSenderByInterface(rule.vertx(), StreamService.class); 57 | streamService.getStreamOfStrings() 58 | .handler(hndlr -> async.countDown()) 59 | .endHandler(end -> async.countDown()); 60 | WriteStream stringsConsumer = streamService.getStringsConsumer(); 61 | AtomicInteger counter = new AtomicInteger(0); 62 | stringsConsumer.drainHandler(hndlr -> { 63 | while (!stringsConsumer.writeQueueFull()) { 64 | int ctr = counter.incrementAndGet(); 65 | if (ctr < 4) { 66 | stringsConsumer.write(String.valueOf(ctr)); 67 | } else { 68 | stringsConsumer.end(); 69 | break; 70 | } 71 | } 72 | }); 73 | }); 74 | rule.vertx().setTimer(1000, tid -> { 75 | if (async.count() == 0) { 76 | async.complete(); 77 | } else { 78 | context.fail("Some tests failed. Async counter is " + async.count()); 79 | } 80 | }); 81 | } 82 | 83 | } 84 | --------------------------------------------------------------------------------