pax_global_header00006660000000000000000000000064125515047720014522gustar00rootroot0000000000000052 comment=3b58aef5c29255f0f481f58f85f445da8421851d jeromq-0.3.5/000077500000000000000000000000001255150477200130245ustar00rootroot00000000000000jeromq-0.3.5/.gitignore000066400000000000000000000001641255150477200150150ustar00rootroot00000000000000*.jar *.iml .project .classpath .settings .idea target maven-build.properties maven-build.xml build.xml .checkstyle jeromq-0.3.5/.travis.yml000066400000000000000000000001541255150477200151350ustar00rootroot00000000000000install: mvn install --quiet -DskipTests=true -Dgpg.skip=true language: java jdk: - openjdk7 - openjdk6 jeromq-0.3.5/AUTHORS000066400000000000000000000030301255150477200140700ustar00rootroot00000000000000Contributors ============ AJ Lewis Alexej Lotz Andrew Thompson Asko Kauppi Barak Amar Ben Gray Bernd Melchers Bernd Prager Bob Beaty Brett Cameron Brian Buchanan Burak Arslan Carl Clemens Chia-liang Kao Chris Rempel Chris Wong Christian Gudrian Chuck Remes Conrad D. Steenberg Constantin Rack Dhammika Pathirana Dhruva Krishnamurthy Dirk O. Kaar Dongmin Yu Douglas Creager Erich Heine Erik Algell Erik Rigtorp Fabien Ninoles Frank Denis George Neill Gerard Toonstra Ghislain Putois Gonzalo Diethelm Guido Goldstein Ian Barber Ilja Golshtein Ivo Danihelka Jacob Rideout Joe Thornber Jon Dyte Kamil Shakirov Lourens Naudé Marc Rossi Martin Hurton Martin Lucina Martin Pales Martin Sustrik Matus Hamorsky Max Wolf McClain Looney Michael Compton Mika Fischer Mikael Helbo Kjaer Mikko Koppanen Min Ragan-Kelley Neale Ferguson Nir Soffer Paul Betts Paul Colomiets Pavel Gushcha Pavol Malosek Perry Kundert Peter Bourgon Philip Kovacs Pieter Hintjens Piotr Trojanek Robert G. Jakabosky Sebastian Otaegui Steven McCoy Stuart Webster Tamara Kustarova Taras Shpot Tero Marttila Terry Wilson Thijs Terlouw Toralf Wittner Tore Halvorsen Trevor Bernard Vitaly Mayatskikh Credits ======= Aamir Mohammad Adrian von Bidder Aleksey Yeschenko Alessio Spadaro Alexander Majorov Anh Vu Bernd Schumacher Brian Granger Carsten Dinkelmann David Bahi Dirk Eddelbuettel Evgueny Khartchenko Frank Vanden Berghen Ian Barber John Apps Markus Fischer Matt Muggeridge Michael Santy Oleg Sevostyanov Paulo Henrique Silva Peter Busser Peter Lemenkov Robert Zhang Toralf Wittner Zed Shaw jeromq-0.3.5/CHANGELOG.md000066400000000000000000000115311255150477200146360ustar00rootroot00000000000000# Changelog ## v0.3.4 * Various code improvements * Add unbind method to org.zeromq.ZMQ.Socket * Added double checked locking for shared variable context. getContext() and createSocket() should now be thread safe. * Extend support for ZMQ monitors to inline with jzmq * Apply checkstyle and sample changes * Fixed recvFrame to return null on no data. Added Test cases. * Corrected ZMsg documentation. * Adds lazy create context to getContext() method * Fix wrong Router xwrite_activated assert * Raise exception when bind fails * Fix issue #80 * throw an exception if the ByteBuffer provided to Msg is not flipped * re-resolve tcp addresses on reconnections * add convenience methods to set TCP keep alive options * Refactor Msg to better handle memory and Java idiomatic * Force StreamEngine to use big endian * Remove org.jeromq.* namespace and associated tests * Revert back to use currentTimeMillis because it's less expensive than nanoTime * Fix issue #122 - handshake now uses ByteBuffer accessor methods directly ## v0.3.2 * Various code improvements * Update junit to version 4.11 * Fix issue #115 - Expose all Context options * Fix issue #58 - XPUB can receive multipart messages * Fix issue #109 - Make ZMQ.Context and ZMQ.Socket implement java.io.Closeable * Use UTF-8 as default charset * Use monotonic source for time * Use try finally idiom on locks * Backport fix for race condition on shutdown * sendByteBuffer should return number of sent bytes ## v0.3.1 * [maven-release-plugin] prepare release v0.3.1 * Update README.md * [maven-release-plugin] prepare for next development iteration ## v0.3.0 * [maven-release-plugin] prepare release v0.3.0 * Prepare for release * Update maven plugins * Change groupId to zeromq * Use the org.zeromq groupId * Add build status icon * Fix issue #95 - Add travis-ci support * remove usage of bytebuffer just for the sake of a byte array * use configurable Charset in every String.getBytes() and new String() * support DirectByteBuffer on socket.sendByteBuffer() * ignore whole target and also ignore Eclipse's .settings folder * fixes zeromq/jeromq#86 * Improved handling of ephemeral ports * Possible fix for a memory leak in Poller.fd_table. * subscriber should ignore HUGZ * support ZMQ_DELAY_ATTACH_ON_CONNECT socket option * Close inproc socket pairs on zmq_disconnect * Rewrite TestConnectDelay * Backport for LIBZMQ-541 fix * Fix issue when building with Ant and system default encoding is not UTF-8 * Update clonesrv6.java * Ignore CtxTerminatedException at ZContext.destroy * Fix issue #76, #77 but at topic remove at trie * Remove global errno * expose special purpose raw zmq.SocketBase * Work around for LIBZMQ-496 The problem is that other threads might still be in mailbox::send() when it is destroyed. So as a workaround, we just acquire the mutex in the destructor. Therefore the running send will finish before the mailbox is destroyed. * patch for issue 456 Do not filter out duplicate subscriptions on the XSUB side of XSUB/XPUB, so that ZMQ_XPUB_VERBOSE doesn't get blocked by forwarding devices (as long as the devices all use ZMQ_XPUB_VERBOSE) * Issue #72 resource leak at Reaper * Issue #70 Remove thread local at errno * Fix IPv6 address parsing. * added osgi manifest headers with maven-bundle-plugin * osgi manifest * Fix issue #66 - Add ByteBuffer API to Sockets for sending and receiving messages * Fix a bug that socket disconnect didn't terminate properly * add setTCPKeepAlive socket option * add a pom helper for the latest sonatype snapshot * fix missing frame at monitoring * Add chapter 5 guide * ZMsg.recv documentation of flag options * new timer during handling timer_event doesn't set correctly * chapter 4 java guide * fix a bug which unsubscribe doesn't work correctly * Set the compiler version to 1.6 * Suppress platform dependent encoding warning * ZContext.close doesn't have to throw an exception * implement Closeable on ZContext * user friendly error at bind failure * change jeromq package namespace and cleanup guide * Add set method for sockopt ZMQ_XPUB_VERBOSE * Add disconnect method * Ignore eclipse workspace files * rewrite poller as it compatile with jzmq * converted asyncsrv guide example to use the org.zeromq packaged code, and updated for the slightly different API. * fix constant collision between jzmq and czmq * simplify the ZMQ mayRaise logic * fix typo * make jzmq compatible and update examples * LIBZMQ-497 send unsent data in encoder buffer at termination * moving namespace from org.jeromq to org.zeromq * Issue#34 inproc connect should raise ZMQException * fix POLLOUT polling causes InvalidArgumentException * jdk epoll bug workaround * ZMsg.send returns boolean value * handle ConcurrentModification Exception * returns -1 with EAGAIN when mandatory is set and pipe is full * enhance device code * update README about 0.2.0 release * remove persistence related code * persistence helper encoder * start 0.3.0-SNAPSHOT jeromq-0.3.5/COPYING000066400000000000000000001045151255150477200140650ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . jeromq-0.3.5/COPYING.LESSER000066400000000000000000000226251255150477200150620ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. -------------------------------------------------------------------------------- SPECIAL EXCEPTION GRANTED BY COPYRIGHT HOLDERS As a special exception, copyright holders give you permission to link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this library, you must extend this exception to your version of the library. -------------------------------------------------------------------------------- Parts of the software are licensed under the MIT (X11) license as follows: Copyright (c) 2007-2010 Contributors as listed in AUTHORS Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. jeromq-0.3.5/README.md000066400000000000000000000046311255150477200143070ustar00rootroot00000000000000#JeroMQ Pure Java implementation of libzmq (http://zeromq.org). [![Build Status](https://travis-ci.org/zeromq/jeromq.png)](https://travis-ci.org/zeromq/jeromq) ## Features * Based on libzmq 3.2.5. * ZMTP/2.0 (http://rfc.zeromq.org/spec:15). * tcp:// protocol and inproc:// is compatible with zeromq. * ipc:// protocol works only between jeromq (uses tcp://127.0.0.1:port internally). * Not too bad performance compared to zeromq. * 4.5M messages (100B) per sec. * [Performance](https://github.com/zeromq/jeromq/wiki/Performance). * Exactly same developer experience with zeromq and jzmq. ## Not supported Features * ipc:// protocol with zeromq. Java doesn't support UNIX domain socket. * pgm:// protocol. Cannot find a pgm Java implementation. ## Extended Features * Build your own StreamEngine's Decoder/Encoder: * [TestProxyTcp](https://github.com/zeromq/jeromq/blob/master/src/test/java/zmq/TestProxyTcp.java) * [Proxy](https://github.com/zeromq/jeromq/blob/master/src/main/java/org/jeromq/codec/Proxy.java) ## Contribution Process This project uses the [C4 process](http://rfc.zeromq.org/spec:16) for all code changes. "Everyone, without distinction or discrimination, SHALL have an equal right to become a Contributor under the terms of this contract." ## Usage Add it to your Maven project's `pom.xml`: ```xml org.zeromq jeromq 0.3.4 org.zeromq jeromq 0.3.5-SNAPSHOT sonatype-nexus-snapshots https://oss.sonatype.org/content/repositories/snapshots false true ``` ## Using ANT To generate an ant build file from `pom.xml`, issue the following command: ```bash mvn ant:ant ``` Also please refer the [Wiki](https://github.com/zeromq/jeromq/wiki). ## Copying Free use of this software is granted under the terms of the GNU Lesser General Public License (LGPL). For details see the files `COPYING` and `COPYING.LESSER` included with the JeroMQ distribution. jeromq-0.3.5/pom.xml000066400000000000000000000154671255150477200143560ustar00rootroot00000000000000 4.0.0 org.zeromq jeromq jar 0.3.5 JeroMQ Pure Java implementation of libzmq https://github.com/zeromq/jeromq GNU General Lesser Public License (LGPL) version 3.0 http://www.gnu.org/licenses/lgpl-3.0.html org.sonatype.oss oss-parent 7 git@github.com:zeromq/jeromq.git scm:git:git@github.com:zeromq/jeromq.git scm:git:git@github.com:zeromq/jeromq.git v0.3.5 UTF-8 junit junit 4.11 test org.apache.maven.plugins maven-source-plugin 2.4 attach-sources jar org.apache.maven.plugins maven-javadoc-plugin 2.10.1 attach-javadocs jar org.apache.maven.plugins maven-compiler-plugin 3.2 1.6 1.6 maven-jar-plugin ${project.build.outputDirectory}/META-INF/MANIFEST.MF org.apache.felix maven-bundle-plugin 2.3.7 true * bundle-manifest process-classes manifest org.apache.maven.plugins maven-checkstyle-plugin 2.11 validate check true true ${project.basedir}/src/checkstyle/checks.xml true **/guide/* org.apache.maven.plugins maven-release-plugin 2.5.1 v@{project.version} org.eclipse.m2e lifecycle-mapping 1.0.0 org.apache.maven.plugins maven-checkstyle-plugin [2.11,) check doclint-java8-disable [1.8,) org.apache.maven.plugins maven-javadoc-plugin 2.9.1 -Xdoclint:none attach-javadocs jar release-sign-artifacts performRelease true org.apache.maven.plugins maven-gpg-plugin 1.4 sign-artifacts verify sign jeromq-0.3.5/src/000077500000000000000000000000001255150477200136135ustar00rootroot00000000000000jeromq-0.3.5/src/checkstyle/000077500000000000000000000000001255150477200157515ustar00rootroot00000000000000jeromq-0.3.5/src/checkstyle/checks.xml000066400000000000000000000120021255150477200177260ustar00rootroot00000000000000 jeromq-0.3.5/src/main/000077500000000000000000000000001255150477200145375ustar00rootroot00000000000000jeromq-0.3.5/src/main/java/000077500000000000000000000000001255150477200154605ustar00rootroot00000000000000jeromq-0.3.5/src/main/java/org/000077500000000000000000000000001255150477200162475ustar00rootroot00000000000000jeromq-0.3.5/src/main/java/org/zeromq/000077500000000000000000000000001255150477200175645ustar00rootroot00000000000000jeromq-0.3.5/src/main/java/org/zeromq/ZActor.java000066400000000000000000000514701255150477200216400ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import java.nio.channels.SelectableChannel; import java.nio.channels.Selector; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.zeromq.ZMQ.Socket; import org.zeromq.ZPoller.EventsHandler; /** * First implementation of a background actor remotely controlled for 0MQ. *

* This implementation is based on the {@link ZStar} one (TODO via inheritance now but this is not totally stamped and the use of the ZAgent would probably limit the collateral damages if changed) * so you should be first familiar with the metaphor there. *
* To extensively sum up: *

* A side or endpoint designates the same thing: the thread where lives one of the two parts of the Actor system. *
* An actor has 2 sides (with a trial to use theater terms for fun (: and hopefully clarity :) *
* - the Corbeille side, or control side *
* This is where one can {@link #send(ZMsg) send} and {@link #recv() receive} control messages to the underneath actor via the ZActor and/or its agent. *
* The ZActor lives on this side and is a way to safely communicate with the distant provided Actor *
* Note: Corbeille is a french word designing the most privileged seats in the theater, * 1st floor, just above the orchestra (Wikipedia...). * It was the place where the King was standing during the shows, with the best seat of course! * * Fast users who would want to communicate with the distant {@link Actor} can use * {@link #send(ZMsg)} or {@link #recv()} from the ZActor as the ZActor is itself an agent! *

* - the Plateau side, or background side where all the performances are made by the provided actor. *
* The provided {@link Actor} is living on the Plateau. *
* The Plateau is made of the Stage where {@link Actor#stage(Socket, Socket, ZPoller, int) the effective processing occurs} and of the Backstage * where the provided actor can {@link Actor#backstage(Socket, ZPoller, int) send and receive} control messages to and from the ZActor. *
* From this side, the work is done via callbacks using the template-method pattern, applied with interfaces (?) *

* * The main purpose (or at least its intent) of this class is to clarify the contracts, roles, responsibilities and action levers related to the Plateau. *

* The provided Actor will not be alone to do the processing of each loop. *
* It will be helped by a double responsible for passing the appropriate structures at the right moment. * As a developer point of view, this double helps also to limit the complexity of the process. * However Double is an uncommon one, capturing all the lights while letting the Actor taking care of all the invisible work in the shadows. * And this is one of the points where we begin to reach the limits of the metaphor... *

* The ZActor takes care of the establishment of the background processing, calling the provided Actor * at appropriate times via its Double. It can also manage the {@link #sign() exited} state on the control side, * if using the provided {@link #send(ZMsg)} or {@link #recv()} methods. *
* It also takes care of the automatic closing of sockets and context if it had to create one. *

* An {@link Actor actor} is basically a contract interface that anyone who uses this ZActor SHALL comply to.
* TODO This interface is still a little bit tough, as instead of the 5+2 Star callbacks, here are 10! * But they allow you to have a hand on the key points of the looping, restart a new actor if needed, ... * Anyway, adapters like a {@link SimpleActor simple one} or a {@link Duo duo} are present to help you on that, reducing the amount of * methods to write. *

* PS: Je sais qu'il y a une différence entre acteur et comédien :) * PPS: I know nothing about theater! *

* Example of code for a minimalistic actor with no socket handling other than the control pipe: * *

*

 * {@code
        Actor acting = new ZActor.SimpleActor()
        {
            public List createSockets(ZContext ctx, Object[] args)
            {
                assert ("TEST".equals(args[0]));
                return Arrays.asList(ctx.createSocket(ZMQ.PUB));
            }

            public boolean backstage(Socket pipe, ZPoller poller, int events)
            {
                String cmd = pipe.recvStr();
                if ("HELLO".equals(cmd)) {
                    pipe.send("WORLD");
                    // end of the actor
                    return false;
                }
                return true;
            }
        };
        ZActor actor = new ZActor(acting, "LOCK", Arrays.asList("TEST").toArray());
        Socket pipe = actor.pipe();
        boolean rc = pipe.send("HELLO");
        assert (rc);
        ZMsg msg = actor.recv();
        String world = msg.popString();
        assert ("WORLD".equals(world));
        msg = actor.recv();
        assert (msg == null);
        rc = actor.sign();
        assert (!rc);
        rc = actor.send("whatever");
        assert (!rc);
        // don't try to use the pipe
}
 */
// remote controlled background message processing API for 0MQ.
public class ZActor extends ZStar
// once on stage, any actor IS a star
{
    /**
     * Defines the contract for the acting instance.
     *
     */
    // contract interface for acting on the distant stage
    // TODO what can be done to reduce the amount of methods ? Split interface?
    public interface Actor
    {
        /**
         * This is the grand premiere!
         * Called before the creation of the first double and the sockets
         * 2nd in the order call of the global acting.
         *
         * @param pipe   the backstage control pipe
         * @return the name of the upcoming performance
         */
        String premiere(Socket pipe);

        /**
         * Creates and initializes sockets for the double.
         * This is done at each creation of a new double.
         * 3rd in the order call of the global acting.
         * 1st in the order call of the new double.
         *
         * @param ctx    the context used to create sockets
         * @param args   the arguments passed as parameters of the ZActor
         * @return a list of created sockets that will be managed by the double. Not null.
         */
        List createSockets(ZContext ctx, Object[] args);

        /**
         * Called when the double is started, before the first loop.
         * 4th in the order call of the global acting.
         * 2nd in the order call of the new double.
         *
         * @param pipe     the backstage control pipe
         * @param sockets  the managed sockets that were created in the previous step
         * @param poller   the poller where to eventually register the sockets for events
         */
        void start(Socket pipe, List sockets, ZPoller poller);

        /**
         * Called every time just before a loop starts.
         * 5th in the order call of the global acting.
         * 3nd in the order call of the new double.
         * 1st in the order call of the new loop.
         *
         * @param pipe   the backstage control pipe
         * @param poller the poller of the double
         * @return the timeout of the coming loop. -1 to block, 0 to not wait, > 0 to wait till max the returned duration in milliseconds
         */
        long looping(Socket pipe, ZPoller poller);

        /**
         * Called when the actor received a control message from its pipe during a loop.
         * 2nd in the order call of the new loop.
         *
         * @param pipe    the backstage control pipe receiving the message
         * @param poller  the poller of the double.
         * @param events  the events source of the call
         * @return true in case of success, false to stop the double.
         */
        boolean backstage(Socket pipe, ZPoller poller, int events);

        /**
         * The actor received a message from the created sockets during a loop.
         * 2nd ex-aequo in the order call of the new loop.
         *
         * @param socket  the socket receiving the message
         * @param pipe    the backstage control pipe
         * @param poller  the poller of the double.
         * @param events  the events source of the call
         * @return true in case of success, false to stop the double.
         */
        boolean stage(Socket socket, Socket pipe, ZPoller poller, int events);

        /**
         * Called at the end of each loop.
         * 3rd in the order call of the new loop.
         *
         * @param pipe   the backstage control pipe
         * @param poller the poller of the double.
         * @return true to continue with the current double, false to stop it.
         */
        boolean looped(Socket pipe, ZPoller poller);

        /**
         * Called when a created socket has been closed.
         * The process of destroying the double has already started.
         *
         * @param socket   the closed socked.
         */
        void closed(Socket socket);

        /**
         * Called when the current double has been destroyed.
         * Last in the order call of the double.
         *
         * @param pipe   the backstage control pipe
         * @param poller the poller of the double.
         * @return true to restart a new double, false to stop the acting process
         */
        boolean destroyed(Socket pipe, ZPoller poller);

        /**
         * Called when the stage is finished.
         * This is the last call to the actor.
         * Last in the order call of the global acting.
         *
         * @param pipe   the backstage control pipe
         * @return true to spread the word of the actor's leaving
         */
        boolean finished(Socket pipe);
    }

    /**
     * Simple adapter for an actor, with no sockets, blocking calls and immediate termination.
     */
    // simple contract implementation for acting on the stage
    public static class SimpleActor implements Actor
    {
        @Override
        public String premiere(final Socket pipe)
        {
            // do nothing
            return "?";
        }

        @Override
        public List createSockets(final ZContext ctx,
                final Object[] args)
        {
            return Collections.emptyList();
        }

        @Override
        public void start(final Socket pipe, final List sockets,
                final ZPoller poller)
        {
            // do nothing
        }

        @Override
        public long looping(Socket pipe, ZPoller poller)
        {
            // blocking loop
            return -1;
        }

        @Override
        public boolean backstage(final Socket pipe, final ZPoller poller,
                final int events)
        {
            // stop looping
            return false;
        }

        @Override
        public boolean stage(final Socket socket, final Socket pipe,
                final ZPoller poller, int events)
        {
            // stop looping
            return false;
        }

        @Override
        public boolean looped(final Socket pipe, final ZPoller poller)
        {
            // continue with the same double
            return true;
        }

        @Override
        public void closed(final Socket socket)
        {
            // do nothing
        }

        @Override
        public boolean destroyed(final Socket pipe, ZPoller poller)
        {
            // no restart
            return false;
        }

        @Override
        public boolean finished(final Socket pipe)
        {
            // mot de la fin if not null
            return true;
        }
    }

    /**
     * Another actor will be called just before the main one,
     * without participating to the decisions.
     */
    // contract implementation for a duo actor on the stage
    public static class Duo implements Actor
    {
        // the actor that will play an active role on the stage
        private final Actor main;
        // the actor that will play a passive role on the stage
        private final Actor shadow;

        public Duo(final Actor main, final Actor shadow)
        {
            super();
            assert (main != null);
            assert (shadow != null);
            this.main = main;
            this.shadow = shadow;
        }

        @Override
        public String premiere(final Socket pipe)
        {
            shadow.premiere(pipe);
            return main.premiere(pipe);
        }

        @Override
        public List createSockets(final ZContext ctx,
                final Object[] args)
        {
            shadow.createSockets(ctx, args);
            return main.createSockets(ctx, args);
        }

        @Override
        public void start(final Socket pipe, final List sockets,
                final ZPoller poller)
        {
            shadow.start(pipe, sockets, poller);
            main.start(pipe, sockets, poller);
        }

        @Override
        public long looping(Socket pipe, ZPoller poller)
        {
            shadow.looping(pipe, poller);
            return main.looping(pipe, poller);
        }

        @Override
        public boolean backstage(final Socket pipe, final ZPoller poller,
                final int events)
        {
            shadow.backstage(pipe, poller, events);
            return main.backstage(pipe, poller, events);
        }

        @Override
        public boolean stage(final Socket socket, final Socket pipe,
                final ZPoller poller, final int events)
        {
            shadow.stage(socket, pipe, poller, events);
            return main.stage(socket, pipe, poller, events);
        }

        @Override
        public boolean looped(final Socket pipe, final ZPoller poller)
        {
            shadow.looped(pipe, poller);
            return main.looped(pipe, poller);
        }

        @Override
        public void closed(final Socket socket)
        {
            shadow.closed(socket);
            main.closed(socket);
        }

        @Override
        public boolean destroyed(final Socket pipe, final ZPoller poller)
        {
            shadow.destroyed(pipe, poller);
            return main.destroyed(pipe, poller);
        }

        @Override
        public boolean finished(final Socket pipe)
        {
            shadow.finished(pipe);
            return main.finished(pipe);
        }
    }

    /**
     * Creates a new ZActor.
     *
     * @param actor
     *            the actor handling messages from either stage and backstage
     * @param args
     *            the optional arguments that will be passed to the distant actor
     */
    public ZActor(Actor actor, final String motdelafin, Object... args)
    {
        this(null, null, actor, motdelafin, args);
    }

    /**
     * Creates a new ZActor.
     *
     * @param selector
     *            the creator of the selector used on the Plateau.
     * @param actor
     *            the actor handling messages from either stage and backstage
     * @param args
     *            the optional arguments that will be passed to the distant actor
     */
    public ZActor(final SelectorCreator selector, final Actor actor, final String motdelafin, final Object... args)
    {
        this(null, selector, actor, motdelafin, args);
    }

    /**
     * Creates a new ZActor.
     *
     * @param context
     *            the main context used. If null, a new context will be created
     *            and closed at the stop of the operation.
     * If not null, it is the responsibility of the caller to close it.
     *
     * @param selector
     *            the creator of the selector used on the Plateau.
     * @param actor
     *            the actor handling messages from either stage and backstage
     * @param args
     *            the optional arguments that will be passed to the distant actor
     */
    public ZActor(final ZContext context, final SelectorCreator selector,
            final Actor actor, final String motdelafin, final Object[] args)
    {
        super(context, selector, new ActorFortune(actor), motdelafin, args);
    }

    // actor creator
    private static final class ActorFortune implements Fortune
    {
        private final Actor actor;

        public ActorFortune(Actor actor)
        {
            assert (actor != null);
            this.actor = actor;
        }

        @Override
        public String premiere(Socket mic, Object[] args)
        {
            return actor.premiere(mic);
        }

        @Override
        public Star create(ZContext ctx, Socket pipe, Selector sel,
                int count, Star previous, Object[] args)
        {
            Star star = new ZActor.Double(ctx, pipe, sel, actor, args);
            return star;
        }

        @Override
        public boolean interview(Socket mic)
        {
            return actor.finished(mic);
        }

        @Override
        public void party(ZContext ctx)
        {
        }
    }

    // double for the loops, easing life for the actor
    private static final class Double implements EventsHandler, Star
    {
        // poller used for the loop
        private final ZPoller poller;

        // control pipe for Backstage side
        private final Socket pipe;

        // managed sockets
        private final List sockets;

        // actor responsible for processing messages
        private final Actor actor;

        // creates a new double
        public Double(final ZContext ctx, final Socket pipe,
                final Selector selector, final Actor actor,
                final Object[] args)
        {
            this.pipe = pipe;
            this.actor = actor;

            final List created = actor.createSockets(ctx, args);
            assert (created != null);

            sockets = new ArrayList(created);

            poller = new ZPoller(selector);
            poller.setGlobalHandler(this);
        }

        // before starting the loops
        @Override
        public void prepare()
        {
            poller.register(pipe, ZPoller.POLLIN);
            actor.start(pipe, Collections.unmodifiableList(sockets), poller);
        }

        // gives the number of events to process
        @Override
        public int breathe()
        {
            long timeout = actor.looping(pipe, poller);
            return poller.poll(timeout);
            // events have been dispatched,
        }

        // acting takes place, return true to continue till the end
        @Override
        public boolean act(int events)
        {
            // act is actually already finished for handlers
            return events >= 0; //  Context is not shut down
        }

        // a loop just finished, return true to continue acting
        @Override
        public boolean entract()
        {
            return actor.looped(pipe, poller);
        }

        // destroys the double
        @Override
        public boolean renews()
        {
            // close every managed sockets
            Iterator iter = sockets.iterator();
            while (iter.hasNext()) {
                final Socket socket = iter.next();
                iter.remove();
                if (socket != null) {
                    poller.unregister(socket);
                    socket.close();
                    // call back the actor to inform that a socket has been closed.
                    actor.closed(socket);
                }
            }
            // let the actor decide if the stage restarts a new double
            return actor.destroyed(pipe, poller);
        }

        @Override
        public boolean events(SelectableChannel channel, int events)
        {
            // TODO dispatch events from channels
            return true;
        }

        // an event has occurred on a registered socket
        @Override
        public boolean events(final Socket socket, final int events)
        {
            if (socket != pipe) {
                // Process a stage message, time to play
                return actor.stage(socket, pipe, poller, events);
            }
            else {
                // Process a control message, time to update your playing
                return actor.backstage(pipe, poller, events);
            }
        }
    }
}
jeromq-0.3.5/src/main/java/org/zeromq/ZAgent.java000066400000000000000000000171501255150477200216230ustar00rootroot00000000000000/*
    Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file

    This file is part of 0MQ.

    0MQ is free software; you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    0MQ is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see .
 */

package org.zeromq;

import java.io.IOException;
import java.nio.channels.Selector;
import java.util.Arrays;

import org.zeromq.ZMQ.Socket;

/**
 * First implementation of an agent for a remotely controlled background service for 0MQ.
 * Used in conjunction with a ZStar, but not mandatory.
 *

* An agent is a mechanism allowing to send messages from one thread to another, and to receive messages from this other thread. *

* Its built-in implementation provides an easy communication-lock * system that will close the access once the remote thread is finished. *

* Are proposed for you a restrained set of simple but powerful messaging commands for a quick learning curve * and an access to the underlying Socket for advanced usage. */ // agent for a remote controlled background message processing API for 0MQ. // contract to be agent of a star public interface ZAgent { /** * Receives a control message sent from the Plateau in the Corbeille. * The call is blocking. * * @return the received message or null if the context was shut down. */ ZMsg recv(); /** * Receives a control message sent from the Plateau in the Corbeille. * The call is blocking depending on the parameter. * * @param wait true to make a blocking call, false to not wait, and possibly return null * @return the received message or null if the context was shut down or if no message if not blocking. */ ZMsg recv(boolean wait); /** * Sends a control message from the Corbeille to the Plateau. * * @param message the message to send * @return true if the message was sent, otherwise false (if the distant Star is dead for example) */ boolean send(ZMsg message); /** * Sends a control message from Corbeille side to the Plateau side. * * @param msg the message to send * @param destroy true to destroy the message after sending it. * @return true if the message was sent, otherwise false (if the distant Star is dead for example) */ boolean send(ZMsg msg, boolean destroy); /** * Sends a control message from the Corbeille to the Plateau side. * * @param word the message to send * @return true if the message was sent, otherwise false (if the distant Star is dead for example) */ boolean send(String word); /** * Sends a control message from the Corbeille to the Plateau side. * * @param word the message to send * @param more true to send more strings in a single message * @return true if the message was sent, otherwise false (if the distant Star is dead for example) */ boolean send(String word, boolean more); /** * Gives a sign if the distant Star is here. * * @return true if here, otherwise false */ boolean sign(); /** * Forcely destroys the Star. * @deprecated not sure it is useful or recommended */ @Deprecated void nova(); /** * Returns the socket used for communication. * For advanced usage. * * @return the socket used to communicate with the distant Star. */ Socket pipe(); public static class Creator { public static ZAgent create(Socket pipe, String lock) { return new SimpleAgent(pipe, lock); } } /** * Creates a very simple agent with an easy lock mechanism. */ public static final class SimpleAgent implements ZAgent { // the pipe used for communicating with the star private final Socket pipe; // the key used to lock the agent. private final byte[] lock; // the locked state. private boolean locked; /** * Creates a new simple agent. * * @param pipe the pipe used to send control messages to the distant IStar. * @param lock the lock to use. If null, the locking mechanism is omitted. */ public SimpleAgent(Socket pipe, String lock) { this.pipe = pipe; this.lock = lock == null ? null : lock.getBytes(ZMQ.CHARSET); } @Override public boolean sign() { return !locked; } @Override public ZMsg recv() { return recv(true); } @Override public ZMsg recv(boolean wait) { if (locked) { return null; } ZMsg msg = ZMsg.recvMsg(pipe, wait ? 0 : ZMQ.DONTWAIT); if (msg == null) { return null; } final ZFrame frame = msg.peek(); byte[] key = frame.getData(); if (lock != null && Arrays.equals(lock, key)) { locked = true; // this is the last message anyway, and not a one for a public display msg = null; pipe.close(); } return msg; } @Override public boolean send(ZMsg message) { if (locked) { return false; } return message.send(pipe); } @Override public boolean send(String word) { if (locked) { return false; } return pipe.send(word); } @Override public boolean send(String word, boolean more) { if (locked) { return false; } return pipe.send(word, more ? ZMQ.SNDMORE : 0); } @Override public boolean send(ZMsg msg, boolean destroy) { if (locked) { return false; } return msg.send(pipe, destroy); } @Override public Socket pipe() { return pipe; } @Override public void nova() { pipe.close(); } } /** * Creates a selector and destroys it. */ // Contract for selector creation. // will be called in backstage side. public static interface SelectorCreator { /** * Creates and opens a selector. * * @return the opened selector. */ Selector create() throws IOException; /** * Destroys the previously opened selector. * @param selector the selector to close */ void destroy(Selector selector) throws IOException; } // very simple selector creator public static class VerySimpleSelectorCreator implements SelectorCreator { @Override public Selector create() throws IOException { return Selector.open(); } @Override public void destroy(Selector selector) throws IOException { if (selector != null) { selector.close(); } } } } jeromq-0.3.5/src/main/java/org/zeromq/ZBeacon.java000066400000000000000000000172501255150477200217550ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import java.io.IOException; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.DatagramChannel; import java.util.Arrays; public class ZBeacon { public static final long DEFAULT_BROADCAST_INTERVAL = 1000L; public static final String DEFAULT_BROADCAST_HOST = "255.255.255.255"; private final int port; private InetAddress broadcastInetAddress; private final BroadcastClient broadcastClient; private final BroadcastServer broadcastServer; private final byte[] beacon; private byte[] prefix = {}; private long broadcastInterval = DEFAULT_BROADCAST_INTERVAL; private Listener listener = null; public ZBeacon(int port, byte[] beacon) { this(DEFAULT_BROADCAST_HOST, port, beacon); } public ZBeacon(String host, int port, byte[] beacon) { this(host, port, beacon, true); } public ZBeacon(String host, int port, byte[] beacon, boolean ignoreLocalAddress) { this.port = port; this.beacon = beacon; try { broadcastInetAddress = InetAddress.getByName(host); } catch (UnknownHostException unknownHostException) { throw new RuntimeException(unknownHostException); } broadcastServer = new BroadcastServer(ignoreLocalAddress); broadcastServer.setDaemon(true); broadcastClient = new BroadcastClient(); broadcastClient.setDaemon(true); } public void start() { if (listener != null) { broadcastServer.start(); } broadcastClient.start(); } public void stop() throws InterruptedException { if (broadcastClient != null) { broadcastClient.interrupt(); broadcastClient.join(); } if (broadcastServer != null) { broadcastServer.interrupt(); broadcastServer.join(); } } public void setPrefix(byte[] prefix) { this.prefix = prefix; } public byte[] getPrefix() { return prefix; } public void setListener(Listener listener) { this.listener = listener; } public Listener getListener() { return listener; } /** * All beacons with matching prefix are passed to a listener. */ public interface Listener { void onBeacon(InetAddress sender, byte[] beacon); } /** * The broadcast client periodically sends beacons via UDP to the network. */ private class BroadcastClient extends Thread { private DatagramChannel broadcastChannel; private final InetSocketAddress broadcastInetSocketAddress; public BroadcastClient() { broadcastInetSocketAddress = new InetSocketAddress(broadcastInetAddress, port); } @Override public void run() { try { broadcastChannel = DatagramChannel.open(); broadcastChannel.socket().setBroadcast(true); while (!interrupted()) { try { broadcastChannel.send(ByteBuffer.wrap(beacon), broadcastInetSocketAddress); Thread.sleep(broadcastInterval); } catch (InterruptedException interruptedException) { break; } catch (Exception exception) { throw new RuntimeException(exception); } } } catch (IOException ioException) { throw new RuntimeException(ioException); } finally { try { broadcastChannel.close(); } catch (IOException ioException) { throw new RuntimeException(ioException); } } } } /** * The broadcast server receives beacons. */ private class BroadcastServer extends Thread { private DatagramChannel handle; // Socket for send/recv private final boolean ignoreLocalAddress; public BroadcastServer(boolean ignoreLocalAddress) { this.ignoreLocalAddress = ignoreLocalAddress; try { // Create UDP socket handle = DatagramChannel.open(); handle.configureBlocking(false); DatagramSocket sock = handle.socket(); sock.setReuseAddress(true); sock.bind(new InetSocketAddress(InetAddress.getByAddress(new byte[] { 0, 0, 0, 0 }), port)); } catch (IOException ioException) { throw new RuntimeException(ioException); } } @Override public void run() { ByteBuffer buffer = ByteBuffer.allocate(65535); SocketAddress sender; int size; while (!interrupted()) { buffer.clear(); try { int read = buffer.remaining(); sender = handle.receive(buffer); if (sender == null) { continue; } InetAddress senderAddress = ((InetSocketAddress) sender).getAddress(); if (ignoreLocalAddress && (InetAddress.getLocalHost().getHostAddress().equals(senderAddress.getHostAddress()) || senderAddress.isAnyLocalAddress() || senderAddress.isLoopbackAddress())) { continue; } size = read - buffer.remaining(); handleMessage(buffer, size, senderAddress); } catch (ClosedChannelException ioException) { break; } catch (IOException ioException) { throw new RuntimeException(ioException); } } handle.socket().close(); } private void handleMessage(ByteBuffer buffer, int size, InetAddress from) { if (size < prefix.length) { return; } byte[] bytes = buffer.array(); // Compare prefix for (int i = 0; i < prefix.length; i++) { if (bytes[i] != prefix[i]) { return; } } listener.onBeacon(from, Arrays.copyOf(bytes, size)); } } public long getBroadcastInterval() { return broadcastInterval; } public void setBroadcastInterval(long broadcastInterval) { this.broadcastInterval = broadcastInterval; } } jeromq-0.3.5/src/main/java/org/zeromq/ZContext.java000066400000000000000000000136161255150477200222140ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import java.io.Closeable; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; import zmq.ZError; /** * ZContext provides a high-level ZeroMQ context management class * * It manages open sockets in the context and automatically closes these before terminating the context. * It provides a simple way to set the linger timeout on sockets, and configure contexts for number of I/O threads. * Sets-up signal (interrupt) handling for the process. * */ public class ZContext implements Closeable { /** * Reference to underlying Context object */ private volatile Context context; /** * List of sockets managed by this ZContext */ private List sockets; /** * Number of io threads allocated to this context, default 1 */ private int ioThreads; /** * Linger timeout, default 0 */ private int linger; /** * HWM timeout, default 1 */ private int hwm; /** * Indicates if context object is owned by main thread * (useful for multi-threaded applications) */ private boolean main; /** * Class Constructor */ public ZContext() { this(1); } public ZContext(int ioThreads) { sockets = new CopyOnWriteArrayList(); this.ioThreads = ioThreads; linger = 0; main = true; } /** * Destructor. Call this to gracefully terminate context and close any managed 0MQ sockets */ public void destroy() { for (Socket socket : sockets) { try { socket.setLinger(linger); } catch (ZError.CtxTerminatedException e) { } socket.close(); } sockets.clear(); // Only terminate context if we are on the main thread if (isMain() && context != null) { context.term(); } context = null; } /** * Creates a new managed socket within this ZContext instance. * Use this to get automatic management of the socket at shutdown * @param type * socket type (see ZMQ static class members) * @return * Newly created Socket object */ public Socket createSocket(int type) { // Create and register socket Socket socket = getContext().socket(type); sockets.add(socket); return socket; } /** * Destroys managed socket within this context * and remove from sockets list * @param s * org.zeromq.Socket object to destroy */ public void destroySocket(Socket s) { if (s == null) { return; } if (sockets.contains(s)) { try { s.setLinger(linger); } catch (ZError.CtxTerminatedException e) { } s.close(); sockets.remove(s); } } /** * Creates new shadow context. * Shares same underlying org.zeromq.Context instance but has own list * of managed sockets, io thread count etc. * @param ctx Original ZContext to create shadow of * @return New ZContext */ public static ZContext shadow(ZContext ctx) { ZContext shadow = new ZContext(); shadow.setContext(ctx.getContext()); shadow.setMain(false); return shadow; } /** * @return the ioThreads */ public int getIoThreads() { return ioThreads; } /** * @param ioThreads the ioThreads to set */ public void setIoThreads(int ioThreads) { this.ioThreads = ioThreads; } /** * @return the linger */ public int getLinger() { return linger; } /** * @param linger the linger to set */ public void setLinger(int linger) { this.linger = linger; } /** * @return the HWM */ public int getHWM() { return hwm; } /** * @param hwm the HWM to set */ public void setHWM(int hwm) { this.hwm = hwm; } /** * @return the main */ public boolean isMain() { return main; } /** * @param main the main to set */ public void setMain(boolean main) { this.main = main; } /** * @return the context */ public Context getContext() { Context result = context; if (result == null) { synchronized (this) { result = context; if (result == null) { result = ZMQ.context(ioThreads); context = result; } } } return result; } /** * @param ctx sets the underlying org.zeromq.Context associated with this ZContext wrapper object */ public void setContext(Context ctx) { this.context = ctx; } /** * @return the sockets */ public List getSockets() { return sockets; } @Override public void close() { destroy(); } } jeromq-0.3.5/src/main/java/org/zeromq/ZFrame.java000066400000000000000000000262441255150477200216230ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Arrays; import org.zeromq.ZMQ.Socket; /** * ZFrame * * The ZFrame class provides methods to send and receive single message * frames across 0MQ sockets. A 'frame' corresponds to one underlying zmq_msg_t in the libzmq code. * When you read a frame from a socket, the more() method indicates if the frame is part of an * unfinished multipart message. The send() method normally destroys the frame, but with the ZFRAME_REUSE flag, you can send * the same frame many times. Frames are binary, and this class has no special support for text data. * */ public class ZFrame { public static final int MORE = ZMQ.SNDMORE; public static final int REUSE = 128; // no effect at java public static final int DONTWAIT = ZMQ.DONTWAIT; private boolean more; private byte[] data; /** * Class Constructor * Creates an empty frame. * (Useful when reading frames from a 0MQ Socket) */ protected ZFrame() { } /** * Class Constructor * Copies message data into ZFrame object * @param data * Data to copy into ZFrame object */ public ZFrame(byte[] data) { if (data != null) { this.data = data; } } /** * Class Constructor * Copies String into frame data * @param data */ public ZFrame(String data) { if (data != null) { this.data = data.getBytes(ZMQ.CHARSET); } } /** * Destructor. */ public void destroy() { if (hasData()) { data = null; } } /** * @return the data */ public byte[] getData() { return data; } /** * @return More flag, true if last read had MORE message parts to come */ public boolean hasMore() { return more; } /** * Returns byte size of frame, if set, else 0 * @return * Number of bytes in frame data, else 0 */ public int size() { if (hasData()) { return data.length; } else { return 0; } } /** * Convenience method to ascertain if this frame contains some message data * @return * True if frame contains data */ public boolean hasData() { return data != null; } /** * Internal method to call org.zeromq.Socket send() method. * @param socket * 0MQ socket to send on * @param flags * Valid send() method flags, defined in org.zeromq.ZMQ class * @return * True if success, else False */ public boolean send(Socket socket, int flags) { if (socket == null) { throw new IllegalArgumentException("socket parameter must be set"); } return socket.send(data, flags); } /** * Sends frame to socket if it contains any data. * Frame contents are kept after the send. * @param socket * 0MQ socket to send frame * @param flags * Valid send() method flags, defined in org.zeromq.ZMQ class * @return * True if success, else False */ public boolean sendAndKeep(Socket socket, int flags) { return send(socket, flags); } /** * Sends frame to socket if it contains any data. * Frame contents are kept after the send. * Uses default behaviour of Socket.send() method, with no flags set * @param socket * 0MQ socket to send frame * @return * True if success, else False */ public boolean sendAndKeep(Socket socket) { return sendAndKeep(socket, 0); } /** * Sends frame to socket if it contains data. * Use this method to send a frame and destroy the data after. * @param socket * 0MQ socket to send frame * @param flags * Valid send() method flags, defined in org.zeromq.ZMQ class * @return * True if success, else False */ public boolean sendAndDestroy(Socket socket, int flags) { boolean ret = send(socket, flags); if (ret) { destroy(); } return ret; } /** * Sends frame to socket if it contains data. * Use this method to send an isolated frame and destroy the data after. * Uses default behaviour of Socket.send() method, with no flags set * @param socket * 0MQ socket to send frame * @return * True if success, else False */ public boolean sendAndDestroy(Socket socket) { return sendAndDestroy(socket, 0); } /** * Creates a new frame that duplicates an existing frame * @return * Duplicate of frame; message contents copied into new byte array */ public ZFrame duplicate() { return new ZFrame(this.data); } /** * Returns true if both frames have byte - for byte identical data * @param other * The other ZFrame to compare * @return * True if both ZFrames have same byte-identical data, else false */ public boolean hasSameData(ZFrame other) { if (other == null) { return false; } if (size() == other.size()) { return Arrays.equals(data, other.data); } return false; } /** * Sets new contents for frame * @param data * New byte array contents for frame */ public void reset(String data) { this.data = data.getBytes(ZMQ.CHARSET); } /** * Sets new contents for frame * @param data * New byte array contents for frame */ public void reset(byte[] data) { this.data = data; } /** * @return frame data as a printable hex string */ public String strhex() { String hexChar = "0123456789ABCDEF"; StringBuilder b = new StringBuilder(); for (byte aData : data) { int b1 = aData >>> 4 & 0xf; int b2 = aData & 0xf; b.append(hexChar.charAt(b1)); b.append(hexChar.charAt(b2)); } return b.toString(); } /** * String equals. * Uses String compareTo for the comparison (lexigraphical) * @param str * String to compare with frame data * @return * True if frame body data matches given string */ public boolean streq(String str) { if (!hasData()) { return false; } return new String(this.data, ZMQ.CHARSET).compareTo(str) == 0; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } ZFrame zFrame = (ZFrame) o; return Arrays.equals(data, zFrame.data); } @Override public int hashCode() { return Arrays.hashCode(data); } /** * Returns a human - readable representation of frame's data * @return * A text string or hex-encoded string if data contains any non-printable ASCII characters */ public String toString() { if (!hasData()) { return ""; } // Dump message as text or hex-encoded string boolean isText = true; for (byte aData : data) { if (aData < 32) { isText = false; break; } } if (isText) { return new String(data, ZMQ.CHARSET); } else { return strhex(); } } /** * Internal method to call recv on the socket. * Does not trap any ZMQExceptions but expects caling routine to handle them. * @param socket * 0MQ socket to read from * @return * byte[] data */ private byte[] recv(Socket socket, int flags) { if (socket == null) { throw new IllegalArgumentException("socket parameter must not be null"); } data = socket.recv(flags); more = socket.hasReceiveMore(); return data; } /** * Receives single frame from socket, returns the received frame object, or null if the recv * was interrupted. Does a blocking recv, if you want to not block then use * recvFrame(socket, ZMQ.DONTWAIT); * * @param socket * Socket to read from * @return * received frame, else null */ public static ZFrame recvFrame(Socket socket) { return ZFrame.recvFrame(socket, 0); } /** * Receive a new frame off the socket, Returns newly-allocated frame, or * null if there was no input waiting, or if the read was interrupted. * @param socket * Socket to read from * @param flags * Pass flags to 0MQ socket.recv call * @return * received frame, else null */ public static ZFrame recvFrame(Socket socket, int flags) { ZFrame f = new ZFrame(); byte [] data = f.recv(socket, flags); if (data == null) { return null; } return f; } public void print(String prefix) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); if (prefix != null) { pw.printf("%s", prefix); } byte []data = getData(); int size = size(); boolean isBin = false; int charNbr; for (charNbr = 0; charNbr < size; charNbr++) { if (data[charNbr] < 9 || data[charNbr] > 127) { isBin = true; } } pw.printf("[%03d] ", size); int maxSize = isBin ? 35 : 70; String elipsis = ""; if (size > maxSize) { size = maxSize; elipsis = "..."; } for (charNbr = 0; charNbr < size; charNbr++) { if (isBin) { pw.printf("%02X", data[charNbr]); } else { pw.printf("%c", data[charNbr]); } } pw.printf("%s\n", elipsis); pw.flush(); pw.close(); try { sw.close(); } catch (IOException e) { } System.out.print(sw.toString()); } } jeromq-0.3.5/src/main/java/org/zeromq/ZLoop.java000066400000000000000000000304211255150477200214720ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Poller; /** * The ZLoop class provides an event-driven reactor pattern. The reactor * handles zmq.PollItem items (pollers or writers, sockets or fds), and * once-off or repeated timers. Its resolution is 1 msec. It uses a tickless * timer to reduce CPU interrupts in inactive processes. */ public class ZLoop { public interface IZLoopHandler { public int handle(ZLoop loop, PollItem item, Object arg); } private class SPoller { PollItem item; IZLoopHandler handler; Object arg; int errors; // If too many errors, kill poller protected SPoller(PollItem item, IZLoopHandler handler, Object arg) { this.item = item; this.handler = handler; this.arg = arg; errors = 0; } }; private class STimer { int delay; int times; IZLoopHandler handler; Object arg; long when; // Clock time when alarm goes off public STimer(int delay, int times, IZLoopHandler handler, Object arg) { this.delay = delay; this.times = times; this.handler = handler; this.arg = arg; this.when = -1; } } private final List pollers; // List of poll items private final List timers; // List of timers private int pollSize; // Size of poll set private Poller pollset; // zmq_poll set private SPoller[] pollact; // Pollers for this poll set private boolean dirty; // True if pollset needs rebuilding private boolean verbose; // True if verbose tracing wanted private final List zombies; // List of timers to kill private final List newTimers; // List of timers to add public ZLoop() { pollers = new ArrayList(); timers = new ArrayList(); zombies = new ArrayList(); newTimers = new ArrayList(); } public void destroy() { // do nothing } // We hold an array of pollers that matches the pollset, so we can // register/cancel pollers orthogonally to executing the pollset // activity on pollers. Returns 0 on success, -1 on failure. private void rebuild() { pollact = null; pollSize = pollers.size(); pollset = new Poller(pollSize); pollact = new SPoller[pollSize]; int itemNbr = 0; for (SPoller poller : pollers) { pollset.register(poller.item); pollact[itemNbr] = poller; itemNbr++; } dirty = false; } private long ticklessTimer() { // Calculate tickless timer, up to 1 hour long tickless = System.currentTimeMillis() + 1000 * 3600; for (STimer timer : timers) { if (timer.when == -1) { timer.when = timer.delay + System.currentTimeMillis(); } if (tickless > timer.when) { tickless = timer.when; } } long timeout = tickless - System.currentTimeMillis(); if (timeout < 0) { timeout = 0; } if (verbose) { System.out.printf("I: zloop: polling for %d msec\n", timeout); } return timeout; } // -------------------------------------------------------------------------- // Register pollitem with the reactor. When the pollitem is ready, will call // the handler, passing the arg. Returns 0 if OK, -1 if there was an error. // If you register the pollitem more than once, each instance will invoke its // corresponding handler. public int addPoller(PollItem pollItem, IZLoopHandler handler, Object arg) { if (pollItem.getRawSocket() == null && pollItem.getSocket() == null) { return -1; } SPoller poller = new SPoller(pollItem, handler, arg); pollers.add(poller); dirty = true; if (verbose) { System.out.printf("I: zloop: register %s poller (%s, %s)\n", pollItem.getSocket() != null ? pollItem.getSocket().getType() : "RAW", pollItem.getSocket(), pollItem.getRawSocket()); } return 0; } // -------------------------------------------------------------------------- // Cancel a pollitem from the reactor, specified by socket or FD. If both // are specified, uses only socket. If multiple poll items exist for same // socket/FD, cancels ALL of them. public void removePoller(PollItem pollItem) { Iterator it = pollers.iterator(); while (it.hasNext()) { SPoller p = it.next(); if (pollItem.equals(p.item)) { it.remove(); dirty = true; } } if (verbose) { System.out.printf("I: zloop: cancel %s poller (%s, %s)", pollItem.getSocket() != null ? pollItem.getSocket().getType() : "RAW", pollItem.getSocket(), pollItem.getRawSocket()); } } // -------------------------------------------------------------------------- // Register a timer that expires after some delay and repeats some number of // times. At each expiry, will call the handler, passing the arg. To // run a timer forever, use 0 times. Returns 0 if OK, -1 if there was an // error. public int addTimer(int delay, int times, IZLoopHandler handler, Object arg) { STimer timer = new STimer(delay, times, handler, arg); // We cannot touch self->timers because we may be executing that // from inside the poll loop. So, we hold the new timer on the newTimers // list, and process that list when we're done executing timers. newTimers.add(timer); if (verbose) { System.out.printf("I: zloop: register timer delay=%d times=%d\n", delay, times); } return 0; } // -------------------------------------------------------------------------- // Cancel all timers for a specific argument (as provided in zloop_timer) // Returns 0 on success. public int removeTimer(Object arg) { assert (arg != null); // We cannot touch self->timers because we may be executing that // from inside the poll loop. So, we hold the arg on the zombie // list, and process that list when we're done executing timers. zombies.add(arg); if (verbose) { System.out.printf("I: zloop: cancel timer\n"); } return 0; } // -------------------------------------------------------------------------- // Set verbose tracing of reactor on/off public void verbose(boolean verbose) { this.verbose = verbose; } // -------------------------------------------------------------------------- // Start the reactor. Takes control of the thread and returns when the 0MQ // context is terminated or the process is interrupted, or any event handler // returns -1. Event handlers may register new sockets and timers, and // cancel sockets. Returns 0 if interrupted, -1 if cancelled by a // handler, positive on internal error public int start() { int rc = 0; timers.addAll(newTimers); newTimers.clear(); // Recalculate all timers now for (STimer timer : timers) { timer.when = timer.delay + System.currentTimeMillis(); } // Main reactor loop while (!Thread.currentThread().isInterrupted()) { if (dirty) { // If s_rebuild_pollset() fails, break out of the loop and // return its error rebuild(); } long wait = ticklessTimer(); rc = pollset.poll(wait); if (rc == -1) { if (verbose) { System.out.printf("I: zloop: interrupted (%d)\n", rc); } rc = 0; break; // Context has been shut down } // Handle any timers that have now expired Iterator it = timers.iterator(); while (it.hasNext()) { STimer timer = it.next(); if (System.currentTimeMillis() >= timer.when && timer.when != -1) { if (verbose) { System.out.println("I: zloop: call timer handler"); } rc = timer.handler.handle(this, null, timer.arg); if (rc == -1) { break; // Timer handler signalled break } if (timer.times != 0 && --timer.times == 0) { it.remove(); } else { timer.when = timer.delay + System.currentTimeMillis(); } } } if (rc == -1) { break; // Some timer signalled break from the reactor loop } // Handle any pollers that are ready for (int itemNbr = 0; itemNbr < pollSize; itemNbr++) { SPoller poller = pollact[itemNbr]; if (pollset.getItem(itemNbr).isError()) { if (verbose) { System.out.printf("I: zloop: can't poll %s socket (%s, %s)\n", poller.item.getSocket() != null ? poller.item.getSocket().getType() : "RAW", poller.item.getSocket(), poller.item.getRawSocket()); } // Give handler one chance to handle error, then kill // poller because it'll disrupt the reactor otherwise. if (poller.errors++ > 0) { removePoller(poller.item); } } else { poller.errors = 0; // A non-error happened } if (pollset.getItem(itemNbr).readyOps() > 0) { if (verbose) { System.out.printf("I: zloop: call %s socket handler (%s, %s)\n", poller.item.getSocket() != null ? poller.item.getSocket().getType() : "RAW", poller.item.getSocket(), poller.item.getRawSocket()); } rc = poller.handler.handle(this, poller.item, poller.arg); if (rc == -1) { break; // Poller handler signalled break } } } // Now handle any timer zombies // This is going to be slow if we have many zombies for (Object arg : zombies) { it = timers.iterator(); while (it.hasNext()) { STimer timer = it.next(); if (timer.arg == arg) { it.remove(); } } } // Now handle any new timers added inside the loop timers.addAll(newTimers); newTimers.clear(); if (rc == -1) { break; } } return rc; } } jeromq-0.3.5/src/main/java/org/zeromq/ZMQ.java000066400000000000000000002002201255150477200210720ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import java.io.Closeable; import java.nio.ByteBuffer; import java.nio.channels.SelectableChannel; import java.nio.charset.Charset; import java.util.concurrent.atomic.AtomicBoolean; import zmq.Ctx; import zmq.DecoderBase; import zmq.EncoderBase; import zmq.SocketBase; import zmq.ZError; import zmq.ZError.CtxTerminatedException; public class ZMQ { /** * Socket flag to indicate that more message parts are coming. */ public static final int SNDMORE = zmq.ZMQ.ZMQ_SNDMORE; // Values for flags in Socket's send and recv functions. /** * Socket flag to indicate a nonblocking send or recv mode. */ public static final int DONTWAIT = zmq.ZMQ.ZMQ_DONTWAIT; public static final int NOBLOCK = zmq.ZMQ.ZMQ_DONTWAIT; // Socket types, used when creating a Socket. /** * Flag to specify a exclusive pair of sockets. */ public static final int PAIR = zmq.ZMQ.ZMQ_PAIR; /** * Flag to specify a PUB socket, receiving side must be a SUB or XSUB. */ public static final int PUB = zmq.ZMQ.ZMQ_PUB; /** * Flag to specify the receiving part of the PUB or XPUB socket. */ public static final int SUB = zmq.ZMQ.ZMQ_SUB; /** * Flag to specify a REQ socket, receiving side must be a REP. */ public static final int REQ = zmq.ZMQ.ZMQ_REQ; /** * Flag to specify the receiving part of a REQ socket. */ public static final int REP = zmq.ZMQ.ZMQ_REP; /** * Flag to specify a DEALER socket (aka XREQ). * DEALER is really a combined ventilator / sink * that does load-balancing on output and fair-queuing on input * with no other semantics. It is the only socket type that lets * you shuffle messages out to N nodes and shuffle the replies * back, in a raw bidirectional asynch pattern. */ public static final int DEALER = zmq.ZMQ.ZMQ_DEALER; /** * Old alias for DEALER flag. * Flag to specify a XREQ socket, receiving side must be a XREP. * * @deprecated As of release 3.0 of zeromq, replaced by {@link #DEALER} */ public static final int XREQ = DEALER; /** * Flag to specify ROUTER socket (aka XREP). * ROUTER is the socket that creates and consumes request-reply * routing envelopes. It is the only socket type that lets you route * messages to specific connections if you know their identities. */ public static final int ROUTER = zmq.ZMQ.ZMQ_ROUTER; /** * Old alias for ROUTER flag. * Flag to specify the receiving part of a XREQ socket. * * @deprecated As of release 3.0 of zeromq, replaced by {@link #ROUTER} */ public static final int XREP = ROUTER; /** * Flag to specify the receiving part of a PUSH socket. */ public static final int PULL = zmq.ZMQ.ZMQ_PULL; /** * Flag to specify a PUSH socket, receiving side must be a PULL. */ public static final int PUSH = zmq.ZMQ.ZMQ_PUSH; /** * Flag to specify a XPUB socket, receiving side must be a SUB or XSUB. * Subscriptions can be received as a message. Subscriptions start with * a '1' byte. Unsubscriptions start with a '0' byte. */ public static final int XPUB = zmq.ZMQ.ZMQ_XPUB; /** * Flag to specify the receiving part of the PUB or XPUB socket. Allows */ public static final int XSUB = zmq.ZMQ.ZMQ_XSUB; /** * Flag to specify a STREAMER device. */ public static final int STREAMER = zmq.ZMQ.ZMQ_STREAMER; /** * Flag to specify a FORWARDER device. */ public static final int FORWARDER = zmq.ZMQ.ZMQ_FORWARDER; /** * Flag to specify a QUEUE device. */ public static final int QUEUE = zmq.ZMQ.ZMQ_QUEUE; /** * @see org.zeromq.ZMQ#PULL */ @Deprecated public static final int UPSTREAM = PULL; /** * @see org.zeromq.ZMQ#PUSH */ @Deprecated public static final int DOWNSTREAM = PUSH; /** * EVENT_CONNECTED: connection established. * The EVENT_CONNECTED event triggers when a connection has been * established to a remote peer. This can happen either synchronous * or asynchronous. Value is the FD of the newly connected socket. */ public static final int EVENT_CONNECTED = zmq.ZMQ.ZMQ_EVENT_CONNECTED; /** * EVENT_CONNECT_DELAYED: synchronous connect failed, it's being polled. * The EVENT_CONNECT_DELAYED event triggers when an immediate connection * attempt is delayed and its completion is being polled for. Value has * no meaning. */ public static final int EVENT_CONNECT_DELAYED = zmq.ZMQ.ZMQ_EVENT_CONNECT_DELAYED; /** * @see org.zeromq.ZMQ#EVENT_CONNECT_DELAYED */ @Deprecated public static final int EVENT_DELAYED = EVENT_CONNECT_DELAYED; /** * EVENT_CONNECT_RETRIED: asynchronous connect / reconnection attempt. * The EVENT_CONNECT_RETRIED event triggers when a connection attempt is * being handled by reconnect timer. The reconnect interval's recomputed * for each attempt. Value is the reconnect interval. */ public static final int EVENT_CONNECT_RETRIED = zmq.ZMQ.ZMQ_EVENT_CONNECT_RETRIED; /** * @see org.zeromq.ZMQ#EVENT_CONNECT_RETRIED */ @Deprecated public static final int EVENT_RETRIED = EVENT_CONNECT_RETRIED; /** * EVENT_LISTENING: socket bound to an address, ready to accept connections. * The EVENT_LISTENING event triggers when a socket's successfully bound to * a an interface. Value is the FD of the newly bound socket. */ public static final int EVENT_LISTENING = zmq.ZMQ.ZMQ_EVENT_LISTENING; /** * EVENT_BIND_FAILED: socket could not bind to an address. * The EVENT_BIND_FAILED event triggers when a socket could not bind to a * given interface. Value is the errno generated by the bind call. */ public static final int EVENT_BIND_FAILED = zmq.ZMQ.ZMQ_EVENT_BIND_FAILED; /** * EVENT_ACCEPTED: connection accepted to bound interface. * The EVENT_ACCEPTED event triggers when a connection from a remote peer * has been established with a socket's listen address. Value is the FD of * the accepted socket. */ public static final int EVENT_ACCEPTED = zmq.ZMQ.ZMQ_EVENT_ACCEPTED; /** * EVENT_ACCEPT_FAILED: could not accept client connection. * The EVENT_ACCEPT_FAILED event triggers when a connection attempt to a * socket's bound address fails. Value is the errno generated by accept. */ public static final int EVENT_ACCEPT_FAILED = zmq.ZMQ.ZMQ_EVENT_ACCEPT_FAILED; /** * EVENT_CLOSED: connection closed. * The EVENT_CLOSED event triggers when a connection's underlying * descriptor has been closed. Value is the former FD of the for the * closed socket. FD has been closed already! */ public static final int EVENT_CLOSED = zmq.ZMQ.ZMQ_EVENT_CLOSED; /** * EVENT_CLOSE_FAILED: connection couldn't be closed. * The EVENT_CLOSE_FAILED event triggers when a descriptor could not be * released back to the OS. Implementation note: ONLY FOR IPC SOCKETS. * Value is the errno generated by unlink. */ public static final int EVENT_CLOSE_FAILED = zmq.ZMQ.ZMQ_EVENT_CLOSE_FAILED; /** * EVENT_DISCONNECTED: broken session. * The EVENT_DISCONNECTED event triggers when the stream engine (tcp and * ipc specific) detects a corrupted / broken session. Value is the FD of * the socket. */ public static final int EVENT_DISCONNECTED = zmq.ZMQ.ZMQ_EVENT_DISCONNECTED; /** * EVENT_MONITOR_STOPPED: monitor has been stopped. * The EVENT_MONITOR_STOPPED event triggers when the monitor for a socket is * stopped. */ public static final int EVENT_MONITOR_STOPPED = zmq.ZMQ.ZMQ_EVENT_MONITOR_STOPPED; /** * EVENT_ALL: all events known. * The EVENT_ALL constant can be used to set up a monitor for all known events. */ public static final int EVENT_ALL = zmq.ZMQ.ZMQ_EVENT_ALL; public static final byte[] MESSAGE_SEPARATOR = new byte[0]; public static final byte[] SUBSCRIPTION_ALL = new byte[0]; public static final Charset CHARSET = Charset.forName("UTF-8"); private ZMQ() { } /** * Create a new Context. * * @param ioThreads * Number of threads to use, usually 1 is sufficient for most use cases. * @return the Context */ public static Context context(int ioThreads) { return new Context(ioThreads); } public static class Context implements Closeable { private final Ctx ctx; /** * Class constructor. * * @param ioThreads * size of the threads pool to handle I/O operations. */ protected Context(int ioThreads) { ctx = zmq.ZMQ.init(ioThreads); } /** * The size of the 0MQ thread pool to handle I/O operations. */ public int getIOThreads() { return ctx.get(zmq.ZMQ.ZMQ_IO_THREADS); } /** * Set the size of the 0MQ thread pool to handle I/O operations. */ public boolean setIOThreads(int ioThreads) { return ctx.set(zmq.ZMQ.ZMQ_IO_THREADS, ioThreads); } /** * The maximum number of sockets allowed on the context */ public int getMaxSockets() { return ctx.get(zmq.ZMQ.ZMQ_MAX_SOCKETS); } /** * Sets the maximum number of sockets allowed on the context */ public boolean setMaxSockets(int maxSockets) { return ctx.set(zmq.ZMQ.ZMQ_MAX_SOCKETS, maxSockets); } public boolean getBlocky() { return ctx.get(zmq.ZMQ.ZMQ_BLOCKY) != 0; } public boolean setBlocky(boolean block) { return ctx.set(zmq.ZMQ.ZMQ_BLOCKY, block ? 1 : 0); } /** * This is an explicit "destructor". It can be called to ensure the corresponding 0MQ * Context has been disposed of. */ public void term() { ctx.terminate(); } /** * Create a new Socket within this context. * * @param type * the socket type. * @return the newly created Socket. */ public Socket socket(int type) { return new Socket(this, type); } /** * Create a new Poller within this context, with a default size. * * @return the newly created Poller. * @deprecated Use poller constructor */ public Poller poller() { return new Poller(this); } /** * Create a new Poller within this context, with a specified initial size. * * @param size * the poller initial size. * @return the newly created Poller. * @deprecated Use poller constructor */ public Poller poller(int size) { return new Poller(this, size); } @Override public void close() { ctx.terminate(); } } public static class Socket implements Closeable { // This port range is defined by IANA for dynamic or private ports // We use this when choosing a port for dynamic binding. private static final int DYNFROM = 0xc000; private static final int DYNTO = 0xffff; private final Ctx ctx; private final SocketBase base; private final AtomicBoolean isClosed = new AtomicBoolean(false); /** * Class constructor. * * @param context * a 0MQ context previously created. * @param type * the socket type. */ protected Socket(Context context, int type) { ctx = context.ctx; base = ctx.createSocket(type); } protected Socket(SocketBase base) { ctx = null; this.base = base; } /** * DO NOT USE if you're trying to build a special proxy * * @return raw zmq.SocketBase */ public SocketBase base() { return base; } /** * This is an explicit "destructor". It can be called to ensure the corresponding 0MQ Socket * has been disposed of. */ @Override public void close() { if (isClosed.compareAndSet(false, true)) { base.close(); } } /** * The 'ZMQ_TYPE option shall retrieve the socket type for the specified * 'socket'. The socket type is specified at socket creation time and * cannot be modified afterwards. * * @return the socket type. */ public final int getType() { return base.getSocketOpt(zmq.ZMQ.ZMQ_TYPE); } /** * @see #setLinger(long) * * @return the linger period. */ public final long getLinger() { return base.getSocketOpt(zmq.ZMQ.ZMQ_LINGER); } private void setsockopt(int option, Object value) { try { base.setSocketOpt(option, value); } catch (CtxTerminatedException e) { } } /** * The 'ZMQ_LINGER' option shall retrieve the period for pending outbound * messages to linger in memory after closing the socket. Value of -1 means * infinite. Pending messages will be kept until they are fully transferred to * the peer. Value of 0 means that all the pending messages are dropped immediately * when socket is closed. Positive value means number of milliseconds to keep * trying to send the pending messages before discarding them. * * @param value * the linger period in milliseconds. */ public final void setLinger(long value) { base.setSocketOpt(zmq.ZMQ.ZMQ_LINGER, (int) value); } /** * @see #setReconnectIVL(long) * * @return the reconnectIVL. */ public final long getReconnectIVL() { return base.getSocketOpt(zmq.ZMQ.ZMQ_RECONNECT_IVL); } /** */ public final void setReconnectIVL(long value) { base.setSocketOpt(zmq.ZMQ.ZMQ_RECONNECT_IVL, (int) value); } /** * @see #setBacklog(long) * * @return the backlog. */ public final long getBacklog() { return base.getSocketOpt(zmq.ZMQ.ZMQ_BACKLOG); } /** */ public final void setBacklog(long value) { setsockopt(zmq.ZMQ.ZMQ_BACKLOG, (int) value); } /** * @see #setReconnectIVLMax(long) * * @return the reconnectIVLMax. */ public final long getReconnectIVLMax() { return base.getSocketOpt(zmq.ZMQ.ZMQ_RECONNECT_IVL_MAX); } /** */ public final void setReconnectIVLMax(long value) { setsockopt(zmq.ZMQ.ZMQ_RECONNECT_IVL_MAX, (int) value); } /** * @see #setMaxMsgSize(long) * * @return the maxMsgSize. */ public final long getMaxMsgSize() { return (Long) base.getsockoptx(zmq.ZMQ.ZMQ_MAXMSGSIZE); } /** */ public final void setMaxMsgSize(long value) { setsockopt(zmq.ZMQ.ZMQ_MAXMSGSIZE, value); } /** * @see #setSndHWM(long) * * @return the SndHWM. */ public final long getSndHWM() { return base.getSocketOpt(zmq.ZMQ.ZMQ_SNDHWM); } /** */ public final void setSndHWM(long value) { setsockopt(zmq.ZMQ.ZMQ_SNDHWM, (int) value); } /** * @see #setRcvHWM(long) * * @return the recvHWM period. */ public final long getRcvHWM() { return base.getSocketOpt(zmq.ZMQ.ZMQ_RCVHWM); } /** */ public final void setRcvHWM(long value) { setsockopt(zmq.ZMQ.ZMQ_RCVHWM, (int) value); } /** * @see #setHWM(long) * * @return the High Water Mark. */ @Deprecated public final long getHWM() { return -1; } /** * The 'ZMQ_HWM' option shall set the high water mark for the specified 'socket'. The high * water mark is a hard limit on the maximum number of outstanding messages 0MQ shall queue * in memory for any single peer that the specified 'socket' is communicating with. * * If this limit has been reached the socket shall enter an exceptional state and depending * on the socket type, 0MQ shall take appropriate action such as blocking or dropping sent * messages. Refer to the individual socket descriptions in the man page of zmq_socket[3] for * details on the exact action taken for each socket type. * * @param hwm * the number of messages to queue. */ public final void setHWM(long hwm) { setSndHWM(hwm); setRcvHWM(hwm); } /** * @see #setSwap(long) * * @return the number of messages to swap at most. */ @Deprecated public final long getSwap() { // not support at zeromq 3 return -1L; } /** * Get the Swap. The 'ZMQ_SWAP' option shall set the disk offload (swap) size for the * specified 'socket'. A socket which has 'ZMQ_SWAP' set to a non-zero value may exceed its * high water mark; in this case outstanding messages shall be offloaded to storage on disk * rather than held in memory. * * @param value * The value of 'ZMQ_SWAP' defines the maximum size of the swap space in bytes. */ @Deprecated public final void setSwap(long value) { throw new UnsupportedOperationException(); } /** * @see #setAffinity(long) * * @return the affinity. */ public final long getAffinity() { return (Long) base.getsockoptx(zmq.ZMQ.ZMQ_AFFINITY); } /** * Get the Affinity. The 'ZMQ_AFFINITY' option shall set the I/O thread affinity for newly * created connections on the specified 'socket'. * * Affinity determines which threads from the 0MQ I/O thread pool associated with the * socket's _context_ shall handle newly created connections. A value of zero specifies no * affinity, meaning that work shall be distributed fairly among all 0MQ I/O threads in the * thread pool. For non-zero values, the lowest bit corresponds to thread 1, second lowest * bit to thread 2 and so on. For example, a value of 3 specifies that subsequent * connections on 'socket' shall be handled exclusively by I/O threads 1 and 2. * * See also in the man page of init[3] for details on allocating the number of I/O threads for a * specific _context_. * * @param value * the io_thread affinity. */ public final void setAffinity(long value) { setsockopt(zmq.ZMQ.ZMQ_AFFINITY, value); } /** * @see #setIdentity(byte[]) * * @return the Identitiy. */ public final byte[] getIdentity() { return (byte[]) base.getsockoptx(zmq.ZMQ.ZMQ_IDENTITY); } /** * The 'ZMQ_IDENTITY' option shall set the identity of the specified 'socket'. Socket * identity determines if existing 0MQ infastructure (_message queues_, _forwarding * devices_) shall be identified with a specific application and persist across multiple * runs of the application. * * If the socket has no identity, each run of an application is completely separate from * other runs. However, with identity set the socket shall re-use any existing 0MQ * infrastructure configured by the previous run(s). Thus the application may receive * messages that were sent in the meantime, _message queue_ limits shall be shared with * previous run(s) and so on. * * Identity should be at least one byte and at most 255 bytes long. Identities starting with * binary zero are reserved for use by 0MQ infrastructure. * * @param identity */ public final void setIdentity(byte[] identity) { setsockopt(zmq.ZMQ.ZMQ_IDENTITY, identity); } /** * @see #setRate(long) * * @return the Rate. */ public final long getRate() { return base.getSocketOpt(zmq.ZMQ.ZMQ_RATE); } /** * The 'ZMQ_RATE' option shall set the maximum send or receive data rate for multicast * transports such as in the man page of zmq_pgm[7] using the specified 'socket'. * * @param value maximum send or receive data rate for multicast, default 100 */ public final void setRate(long value) { throw new UnsupportedOperationException(); } /** * @see #setRecoveryInterval(long) * * @return the RecoveryIntervall. */ public final long getRecoveryInterval() { return base.getSocketOpt(zmq.ZMQ.ZMQ_RECOVERY_IVL); } /** * The 'ZMQ_RECOVERY_IVL' option shall set the recovery interval for multicast transports * using the specified 'socket'. The recovery interval determines the maximum time in * seconds that a receiver can be absent from a multicast group before unrecoverable data * loss will occur. * * CAUTION: Excersize care when setting large recovery intervals as the data needed for * recovery will be held in memory. For example, a 1 minute recovery interval at a data rate * of 1Gbps requires a 7GB in-memory buffer. {Purpose of this Method} * * @param value recovery interval for multicast in milliseconds, default 10000 */ public final void setRecoveryInterval(long value) { throw new UnsupportedOperationException(); } /** * @see #setMulticastLoop(boolean) * * @return the Multicast Loop. */ @Deprecated public final boolean hasMulticastLoop() { return false; } /** * The 'ZMQ_MCAST_LOOP' option shall control whether data sent via multicast transports * using the specified 'socket' can also be received by the sending host via loopback. A * value of zero disables the loopback functionality, while the default value of 1 enables * the loopback functionality. Leaving multicast loopback enabled when it is not required * can have a negative impact on performance. Where possible, disable 'ZMQ_MCAST_LOOP' in * production environments. * * @param multicastLoop */ @Deprecated public final void setMulticastLoop(boolean multicastLoop) { throw new UnsupportedOperationException(); } /** * @see #setMulticastHops(long) * * @return the Multicast Hops. */ public final long getMulticastHops() { return base.getSocketOpt(zmq.ZMQ.ZMQ_MULTICAST_HOPS); } /** * Sets the time-to-live field in every multicast packet sent from this socket. * The default is 1 which means that the multicast packets don't leave the local * network. * * @param value time-to-live field in every multicast packet, default 1 */ public final void setMulticastHops(long value) { throw new UnsupportedOperationException(); } /** * @see #setReceiveTimeOut(int) * * @return the Receive Timeout in milliseconds. */ public final int getReceiveTimeOut() { return base.getSocketOpt(zmq.ZMQ.ZMQ_RCVTIMEO); } /** * Sets the timeout for receive operation on the socket. If the value is 0, recv * will return immediately, with null if there is no message to receive. * If the value is -1, it will block until a message is available. For all other * values, it will wait for a message for that amount of time before returning with * a null and an EAGAIN error. * * @param value Timeout for receive operation in milliseconds. Default -1 (infinite) */ public final void setReceiveTimeOut(int value) { setsockopt(zmq.ZMQ.ZMQ_RCVTIMEO, value); } /** * @see #setSendTimeOut(int) * * @return the Send Timeout in milliseconds. */ public final int getSendTimeOut() { return base.getSocketOpt(zmq.ZMQ.ZMQ_SNDTIMEO); } /** * Sets the timeout for send operation on the socket. If the value is 0, send * will return immediately, with a false if the message cannot be sent. * If the value is -1, it will block until the message is sent. For all other * values, it will try to send the message for that amount of time before * returning with false and an EAGAIN error. * * @param value Timeout for send operation in milliseconds. Default -1 (infinite) */ public final void setSendTimeOut(int value) { setsockopt(zmq.ZMQ.ZMQ_SNDTIMEO, value); } /** * Override SO_KEEPALIVE socket option (where supported by OS) to enable keep-alive packets for a socket * connection. Possible values are -1, 0, 1. The default value -1 will skip all overrides and do the OS default. * * @param value The value of 'ZMQ_TCP_KEEPALIVE' to turn TCP keepalives on (1) or off (0). */ public void setTCPKeepAlive(long value) { setsockopt(zmq.ZMQ.ZMQ_TCP_KEEPALIVE, value); } /** * @see #setTCPKeepAlive(long) * * @return the keep alive setting. */ public long getTCPKeepAliveSetting() { return base.getSocketOpt(zmq.ZMQ.ZMQ_TCP_KEEPALIVE); } /** * Override TCP_KEEPCNT socket option (where supported by OS). The default value -1 will skip all overrides and * do the OS default. * * @param value The value of 'ZMQ_TCP_KEEPALIVE_CNT' defines the number of keepalives before death. */ public void setTCPKeepAliveCount(long value) { setsockopt(zmq.ZMQ.ZMQ_TCP_KEEPALIVE_CNT, value); } /** * @see #setTCPKeepAliveCount(long) * * @return the keep alive count. */ public long getTCPKeepAliveCount() { return base.getSocketOpt(zmq.ZMQ.ZMQ_TCP_KEEPALIVE_CNT); } /** * Override TCP_KEEPINTVL socket option (where supported by OS). The default value -1 will skip all overrides * and do the OS default. * * @param value The value of 'ZMQ_TCP_KEEPALIVE_INTVL' defines the interval between keepalives. Unit is OS * dependant. */ public void setTCPKeepAliveInterval(long value) { setsockopt(zmq.ZMQ.ZMQ_TCP_KEEPALIVE_INTVL, value); } /** * @see #setTCPKeepAliveInterval(long) * * @return the keep alive interval. */ public long getTCPKeepAliveInterval() { return base.getSocketOpt(zmq.ZMQ.ZMQ_TCP_KEEPALIVE_INTVL); } /** * Override TCP_KEEPCNT (or TCP_KEEPALIVE on some OS) socket option (where supported by OS). The default value * -1 will skip all overrides and do the OS default. * * @param value The value of 'ZMQ_TCP_KEEPALIVE_IDLE' defines the interval between the last data packet sent * over the socket and the first keepalive probe. Unit is OS dependant. */ public void setTCPKeepAliveIdle(long value) { setsockopt(zmq.ZMQ.ZMQ_TCP_KEEPALIVE_IDLE, value); } /** * @see #setTCPKeepAliveIdle(long) * * @return the keep alive idle value. */ public long getTCPKeepAliveIdle() { return base.getSocketOpt(zmq.ZMQ.ZMQ_TCP_KEEPALIVE_IDLE); } /** * @see #setSendBufferSize(long) * * @return the kernel send buffer size. */ public final long getSendBufferSize() { return base.getSocketOpt(zmq.ZMQ.ZMQ_SNDBUF); } /** * The 'ZMQ_SNDBUF' option shall set the underlying kernel transmit buffer size for the * 'socket' to the specified size in bytes. A value of zero means leave the OS default * unchanged. For details please refer to your operating system documentation for the * 'SO_SNDBUF' socket option. * * @param value underlying kernel transmit buffer size for the 'socket' in bytes * A value of zero means leave the OS default unchanged. */ public final void setSendBufferSize(long value) { setsockopt(zmq.ZMQ.ZMQ_SNDBUF, (int) value); } /** * @see #setReceiveBufferSize(long) * * @return the kernel receive buffer size. */ public final long getReceiveBufferSize() { return base.getSocketOpt(zmq.ZMQ.ZMQ_RCVBUF); } /** * The 'ZMQ_RCVBUF' option shall set the underlying kernel receive buffer size for the * 'socket' to the specified size in bytes. * For details refer to your operating system documentation for the 'SO_RCVBUF' * socket option. * * @param value Underlying kernel receive buffer size for the 'socket' in bytes. * A value of zero means leave the OS default unchanged. */ public final void setReceiveBufferSize(long value) { setsockopt(zmq.ZMQ.ZMQ_RCVBUF, (int) value); } /** * The 'ZMQ_RCVMORE' option shall return a boolean value indicating if the multi-part * message currently being read from the specified 'socket' has more message parts to * follow. If there are no message parts to follow or if the message currently being read is * not a multi-part message a value of zero shall be returned. Otherwise, a value of 1 shall * be returned. * * @return true if there are more messages to receive. */ public final boolean hasReceiveMore() { return base.getSocketOpt(zmq.ZMQ.ZMQ_RCVMORE) == 1; } /** * The 'ZMQ_FD' option shall retrieve file descriptor associated with the 0MQ * socket. The descriptor can be used to integrate 0MQ socket into an existing * event loop. It should never be used for anything else than polling -- such as * reading or writing. The descriptor signals edge-triggered IN event when * something has happened within the 0MQ socket. It does not necessarily mean that * the messages can be read or written. Check ZMQ_EVENTS option to find out whether * the 0MQ socket is readable or writeable. * * @return the underlying file descriptor. */ public final SelectableChannel getFD() { return (SelectableChannel) base.getsockoptx(zmq.ZMQ.ZMQ_FD); } /** * The 'ZMQ_EVENTS' option shall retrieve event flags for the specified socket. * If a message can be read from the socket ZMQ_POLLIN flag is set. If message can * be written to the socket ZMQ_POLLOUT flag is set. * * @return the mask of outstanding events. */ public final int getEvents() { return base.getSocketOpt(zmq.ZMQ.ZMQ_EVENTS); } /** * The 'ZMQ_SUBSCRIBE' option shall establish a new message filter on a 'ZMQ_SUB' socket. * Newly created 'ZMQ_SUB' sockets shall filter out all incoming messages, therefore you * should call this option to establish an initial message filter. * * An empty 'option_value' of length zero shall subscribe to all incoming messages. A * non-empty 'option_value' shall subscribe to all messages beginning with the specified * prefix. Mutiple filters may be attached to a single 'ZMQ_SUB' socket, in which case a * message shall be accepted if it matches at least one filter. * * @param topic */ public final void subscribe(byte[] topic) { setsockopt(zmq.ZMQ.ZMQ_SUBSCRIBE, topic); } /** * The 'ZMQ_UNSUBSCRIBE' option shall remove an existing message filter on a 'ZMQ_SUB' * socket. The filter specified must match an existing filter previously established with * the 'ZMQ_SUBSCRIBE' option. If the socket has several instances of the same filter * attached the 'ZMQ_UNSUBSCRIBE' option shall remove only one instance, leaving the rest in * place and functional. * * @param topic */ public final void unsubscribe(byte[] topic) { setsockopt(zmq.ZMQ.ZMQ_UNSUBSCRIBE, topic); } /** * Set custom Encoder * @param cls */ public final void setEncoder(Class cls) { base.setSocketOpt(zmq.ZMQ.ZMQ_ENCODER, cls); } /** * Set custom Decoder * @param cls */ public final void setDecoder(Class cls) { base.setSocketOpt(zmq.ZMQ.ZMQ_DECODER, cls); } /** * Sets the ROUTER socket behavior when an unroutable message is encountered. * * @param mandatory A value of false is the default and discards the message silently when it cannot be routed. * A value of true returns an EHOSTUNREACH error code if the message cannot be routed. */ public final void setRouterMandatory(boolean mandatory) { setsockopt(zmq.ZMQ.ZMQ_ROUTER_MANDATORY, mandatory ? 1 : 0); } /** * If two clients use the same identity when connecting to a ROUTER, the * results shall depend on the ZMQ_ROUTER_HANDOVER option setting * * @param handlover A value of false, (default) the ROUTER socket shall reject clients trying to connect with an already-used identity * A value of true, the ROUTER socket shall hand-over the connection to the new client and disconnect the existing one */ public final void setRouterHandlover(boolean handlover) { setsockopt(zmq.ZMQ.ZMQ_ROUTER_HANDOVER, handlover ? 1 : 0); } /** * Sets the XPUB socket behavior on new subscriptions and unsubscriptions. * * @param verbose A value of false is the default and passes only new subscription messages to upstream. * A value of true passes all subscription messages upstream. */ public final void setXpubVerbose(boolean verbose) { setsockopt(zmq.ZMQ.ZMQ_XPUB_VERBOSE, verbose ? 1 : 0); } /** * @see #setIPv4Only (boolean) * * @return the IPV4ONLY */ public final boolean getIPv4Only() { return base.getSocketOpt(zmq.ZMQ.ZMQ_IPV4ONLY) == 1; } /** * The 'ZMQ_IPV4ONLY' option shall set the underlying native socket type. * An IPv6 socket lets applications connect to and accept connections from both IPv4 and IPv6 hosts. * * @param v4only A value of true will use IPv4 sockets, while the value of false will use IPv6 sockets */ public void setIPv4Only(boolean v4only) { setsockopt(zmq.ZMQ.ZMQ_IPV4ONLY, v4only ? 1 : 0); } /** * @see #setTCPKeepAlive(int) * * @return the keep alive setting. */ public int getTCPKeepAlive() { return base.getSocketOpt(zmq.ZMQ.ZMQ_TCP_KEEPALIVE); } /** * Override SO_KEEPALIVE socket option (where supported by OS) to enable keep-alive packets for a socket * connection. Possible values are -1, 0, 1. The default value -1 will skip all overrides and do the OS default. * * @param optVal The value of 'ZMQ_TCP_KEEPALIVE' to turn TCP keepalives on (1) or off (0). */ public void setTCPKeepAlive(int optVal) { setsockopt(zmq.ZMQ.ZMQ_TCP_KEEPALIVE, optVal); } /** * @see #setDelayAttachOnConnect(boolean) * * @return the keep alive setting. */ public boolean getDelayAttachOnConnect() { return base.getSocketOpt(zmq.ZMQ.ZMQ_DELAY_ATTACH_ON_CONNECT) == 1; } /** * Accept messages only when connections are made * * If set to true, will delay the attachment of a pipe on connect until the underlying connection * has completed. This will cause the socket to block if there are no other connections, but will * prevent queues from filling on pipes awaiting connection * * @param value The value of 'ZMQ_DELAY_ATTACH_ON_CONNECT'. Default false. */ public void setDelayAttachOnConnect(boolean value) { setsockopt(zmq.ZMQ.ZMQ_DELAY_ATTACH_ON_CONNECT, value ? 1 : 0); } /** * Bind to network interface. Start listening for new connections. * * @param addr * the endpoint to bind to. */ public final void bind(String addr) { bind(addr, DYNFROM, DYNTO); } /** * Bind to network interface. Start listening for new connections. * * @param addr * the endpoint to bind to. * @param min * The minimum port in the range of ports to try. * @param max * The maximum port in the range of ports to try. */ private int bind(String addr, int min, int max) { if (addr.endsWith(":*")) { int port = min; String prefix = addr.substring(0, addr.lastIndexOf(':') + 1); while (port <= max) { addr = prefix + port; // Try to bind on the next plausible port if (base.bind(addr)) { return port; } port++; } } else { if (base.bind(addr)) { int port = 0; try { port = Integer.parseInt( addr.substring(addr.lastIndexOf(':') + 1)); } catch (NumberFormatException e) { } return port; } } mayRaise(); return -1; } /** * Bind to network interface to a random port. Start listening for new * connections. * * @param addr * the endpoint to bind to. */ public int bindToRandomPort(String addr) { return bind(addr + ":*", DYNFROM, DYNTO); } /** * Bind to network interface to a random port. Start listening for new * connections. * * @param addr * the endpoint to bind to. * @param min * The minimum port in the range of ports to try. * @param max * The maximum port in the range of ports to try. */ public int bindToRandomPort(String addr, int min, int max) { return bind(addr + ":*", min, max); } /** * Connect to remote application. * * @param addr * the endpoint to connect to. */ public final void connect(String addr) { base.connect(addr); mayRaise(); } /** * Disconnect to remote application. * * @param addr * the endpoint to disconnect to. * @return true if successful. */ public final boolean disconnect(String addr) { return base.termEndpoint(addr); } /** * Stop accepting connections on a socket. * * @param addr * the endpoint to unbind from. * @return true if successful. */ public final boolean unbind(String addr) { return base.termEndpoint(addr); } public final boolean send(String data) { return send(data.getBytes(CHARSET), 0); } public final boolean sendMore(String data) { return send(data.getBytes(CHARSET), zmq.ZMQ.ZMQ_SNDMORE); } public final boolean send(String data, int flags) { return send(data.getBytes(CHARSET), flags); } public final boolean send(byte[] data) { return send(data, 0); } public final boolean sendMore(byte[] data) { return send(data, zmq.ZMQ.ZMQ_SNDMORE); } public final boolean send(byte[] data, int flags) { zmq.Msg msg = new zmq.Msg(data); if (base.send(msg, flags)) { return true; } mayRaise(); return false; } public final boolean send(byte[] data, int off, int length, int flags) { byte[] copy = new byte[length]; System.arraycopy(data, off, copy, 0, length); zmq.Msg msg = new zmq.Msg(copy); if (base.send(msg, flags)) { return true; } mayRaise(); return false; } /** * Send a message * * @param data ByteBuffer payload * @param flags the flags to apply to the send operation * @return the number of bytes sent, -1 on error */ public final int sendByteBuffer(ByteBuffer data, int flags) { zmq.Msg msg = new zmq.Msg(data); if (base.send(msg, flags)) { return msg.size(); } mayRaise(); return -1; } /** * Receive a message. * * @return the message received, as an array of bytes; null on error. */ public final byte[] recv() { return recv(0); } /** * Receive a message. * * @param flags * the flags to apply to the receive operation. * @return the message received, as an array of bytes; null on error. */ public final byte[] recv(int flags) { zmq.Msg msg = base.recv(flags); if (msg != null) { return msg.data(); } mayRaise(); return null; } /** * Receive a message in to a specified buffer. * * @param buffer * byte[] to copy zmq message payload in to. * @param offset * offset in buffer to write data * @param len * max bytes to write to buffer. * If len is smaller than the incoming message size, * the message will be truncated. * @param flags * the flags to apply to the receive operation. * @return the number of bytes read, -1 on error */ public final int recv(byte[] buffer, int offset, int len, int flags) { zmq.Msg msg = base.recv(flags); if (msg != null) { return msg.getBytes(0, buffer, offset, len); } return -1; } /** * Receive a message into the specified ByteBuffer * * @param buffer the buffer to copy the zmq message payload into * @param flags the flags to apply to the receive operation * @return the number of bytes read, -1 on error */ public final int recvByteBuffer(ByteBuffer buffer, int flags) { zmq.Msg msg = base.recv(flags); if (msg != null) { buffer.put(msg.data()); return msg.size(); } mayRaise(); return -1; } /** * * @return the message received, as a String object; null on no message. */ public final String recvStr() { return recvStr(0); } /** * * @param flags the flags to apply to the receive operation. * @return the message received, as a String object; null on no message. */ public final String recvStr(int flags) { byte[] msg = recv(flags); if (msg != null) { return new String(msg, CHARSET); } return null; } /** * Start a monitoring socket where events can be received. * * @param addr the endpoint to receive events from. (must be inproc transport) * @param events the events of interest. * @return true if monitor socket setup is successful * @throws ZMQException */ public boolean monitor(String addr, int events) { return base.monitor(addr, events); } private void mayRaise() { int errno = base.errno(); if (errno != 0 && errno != zmq.ZError.EAGAIN) { throw new ZMQException(errno); } } } public static class Poller { /** * These values can be ORed to specify what we want to poll for. */ public static final int POLLIN = zmq.ZMQ.ZMQ_POLLIN; public static final int POLLOUT = zmq.ZMQ.ZMQ_POLLOUT; public static final int POLLERR = zmq.ZMQ.ZMQ_POLLERR; private static final int SIZE_DEFAULT = 32; private static final int SIZE_INCREMENT = 16; private PollItem[] items; private long timeout; private int next; public Poller(int size) { this (null, size); } /** * Class constructor. * * @param context * a 0MQ context previously created. * @param size * the number of Sockets this poller will contain. */ protected Poller(Context context, int size) { items = new PollItem[size]; timeout = -1L; next = 0; } /** * Class constructor. * * @param context * a 0MQ context previously created. */ protected Poller(Context context) { this(context, SIZE_DEFAULT); } /** * Register a Socket for polling on all events. * * @param socket * the Socket we are registering. * @return the index identifying this Socket in the poll set. */ public int register(Socket socket) { return register(socket, POLLIN | POLLOUT | POLLERR); } /** * Register a Socket for polling on the specified events. * * Automatically grow the internal representation if needed. * * @param socket * the Socket we are registering. * @param events * a mask composed by XORing POLLIN, POLLOUT and POLLERR. * @return the index identifying this Socket in the poll set. */ public int register(Socket socket, int events) { return insert(new PollItem(socket, events)); } /** * Register a Socket for polling on the specified events. * * Automatically grow the internal representation if needed. * * @param channel * the Channel we are registering. * @param events * a mask composed by XORing POLLIN, POLLOUT and POLLERR. * @return the index identifying this Channel in the poll set. */ public int register(SelectableChannel channel, int events) { return insert(new PollItem(channel, events)); } /** * Register a Channel for polling on the specified events. * * Automatically grow the internal representation if needed. * * @param item * the PollItem we are registering. * @return the index identifying this Channel in the poll set. */ public int register(PollItem item) { return insert(item); } private int insert(PollItem item) { int pos = next++; if (pos == items.length) { PollItem[] nitems = new PollItem[items.length + SIZE_INCREMENT]; System.arraycopy(items, 0, nitems, 0, items.length); items = nitems; } items[pos] = item; return pos; } /** * Unregister a Socket for polling on the specified events. * * @param socket * the Socket to be unregistered */ public void unregister(Socket socket) { for (int pos = 0; pos < items.length; pos++) { PollItem item = items[pos]; if (item.getSocket() == socket) { remove(pos); break; } } } /** * Unregister a Socket for polling on the specified events. * * @param channel * the Socket to be unregistered */ public void unregister(SelectableChannel channel) { for (int pos = 0; pos < items.length; pos++) { PollItem item = items[pos]; if (item.getRawSocket() == channel) { remove(pos); break; } } } private void remove(int pos) { next--; if (pos != next) { items[pos] = items[next]; } items [next] = null; } /** * Get the PollItem associated with an index. * * @param index * the desired index. * @return the PollItem associated with that index (or null). */ public PollItem getItem(int index) { if (index < 0 || index >= this.next) { return null; } return this.items[index]; } /** * Get the socket associated with an index. * * @param index * the desired index. * @return the Socket associated with that index (or null). */ public Socket getSocket(int index) { if (index < 0 || index >= this.next) { return null; } return items[index].getSocket(); } /** * Get the current poll timeout. * * @return the current poll timeout in milliseconds. * @deprecated Timeout handling has been moved to the poll() methods. */ public long getTimeout() { return this.timeout; } /** * Set the poll timeout. * * @param timeout * the desired poll timeout in milliseconds. * @deprecated Timeout handling has been moved to the poll() methods. */ public void setTimeout(long timeout) { if (timeout < -1) { return; } this.timeout = timeout; } /** * Get the current poll set size. * * @return the current poll set size. */ public int getSize() { return items.length; } /** * Get the index for the next position in the poll set size. * * @return the index for the next position in the poll set size. */ public int getNext() { return this.next; } /** * Issue a poll call. If the poller's internal timeout value * has been set, use that value as timeout; otherwise, block * indefinitely. * * @return how many objects where signaled by poll (). */ public int poll() { long tout = -1L; if (this.timeout > -1L) { tout = this.timeout; } return poll(tout); } /** * Issue a poll call, using the specified timeout value. *

* Since ZeroMQ 3.0, the timeout parameter is in milliseconds, * but prior to this the unit was microseconds. * * @param tout * the timeout, as per zmq_poll (); * if -1, it will block indefinitely until an event * happens; if 0, it will return immediately; * otherwise, it will wait for at most that many * milliseconds/microseconds (see above). * * @see "http://api.zeromq.org/3-0:zmq-poll" * * @return how many objects where signaled by poll () */ public int poll(long tout) { zmq.PollItem[] pollItems = new zmq.PollItem[next]; for (int i = 0; i < next; i++) { pollItems[i] = items[i].base(); } return zmq.ZMQ.poll(pollItems, next, tout); } /** * Check whether the specified element in the poll set was signaled for input. * * @param index * * @return true if the element was signaled. */ public boolean pollin(int index) { if (index < 0 || index >= this.next) { return false; } return items[index].isReadable(); } /** * Check whether the specified element in the poll set was signaled for output. * * @param index * * @return true if the element was signaled. */ public boolean pollout(int index) { if (index < 0 || index >= this.next) { return false; } return items[index].isWritable(); } /** * Check whether the specified element in the poll set was signaled for error. * * @param index * * @return true if the element was signaled. */ public boolean pollerr(int index) { if (index < 0 || index >= this.next) { return false; } return items[index].isError(); } } public static class PollItem { private final zmq.PollItem base; private final Socket socket; public PollItem(Socket socket, int ops) { this.socket = socket; base = new zmq.PollItem(socket.base, ops); } public PollItem(SelectableChannel channel, int ops) { base = new zmq.PollItem(channel, ops); socket = null; } protected final zmq.PollItem base() { return base; } public final SelectableChannel getRawSocket() { return base.getRawSocket(); } public final Socket getSocket() { return socket; } public final boolean isReadable() { return base.isReadable(); } public final boolean isWritable() { return base.isWritable(); } public final boolean isError() { return base.isError(); } public final int readyOps() { return base.readyOps(); } @Override public int hashCode() { return base.hashCode(); } @Override public boolean equals(Object obj) { if (!(obj instanceof PollItem)) { return false; } PollItem target = (PollItem) obj; if (socket != null && socket == target.socket) { return true; } if (getRawSocket() != null && getRawSocket() == target.getRawSocket()) { return true; } return false; } } public enum Error { ENOTSUP(ZError.ENOTSUP), EPROTONOSUPPORT(ZError.EPROTONOSUPPORT), ENOBUFS(ZError.ENOBUFS), ENETDOWN(ZError.ENETDOWN), EADDRINUSE(ZError.EADDRINUSE), EADDRNOTAVAIL(ZError.EADDRNOTAVAIL), ECONNREFUSED(ZError.ECONNREFUSED), EINPROGRESS(ZError.EINPROGRESS), EMTHREAD(ZError.EMTHREAD), EFSM(ZError.EFSM), ENOCOMPATPROTO(ZError.ENOCOMPATPROTO), ETERM(ZError.ETERM), ENOTSOCK(ZError.ENOTSOCK), EAGAIN(ZError.EAGAIN); private final int code; Error(int code) { this.code = code; } public int getCode() { return code; } public static Error findByCode(int code) { for (Error e : Error.class.getEnumConstants()) { if (e.getCode() == code) { return e; } } throw new IllegalArgumentException("Unknown " + Error.class.getName() + " enum code:" + code); } } @Deprecated public static boolean device(int type, Socket frontend, Socket backend) { return zmq.ZMQ.proxy(frontend.base, backend.base, null); } /** * Starts the built-in 0MQ proxy in the current application thread. * The proxy connects a frontend socket to a backend socket. Conceptually, data flows from frontend to backend. * Depending on the socket types, replies may flow in the opposite direction. The direction is conceptual only; * the proxy is fully symmetric and there is no technical difference between frontend and backend. * * Before calling ZMQ.proxy() you must set any socket options, and connect or bind both frontend and backend sockets. * The two conventional proxy models are: * * ZMQ.proxy() runs in the current thread and returns only if/when the current context is closed. * @param frontend ZMQ.Socket * @param backend ZMQ.Socket * @param capture If the capture socket is not NULL, the proxy shall send all messages, received on both * frontend and backend, to the capture socket. The capture socket should be a * ZMQ_PUB, ZMQ_DEALER, ZMQ_PUSH, or ZMQ_PAIR socket. */ public static boolean proxy(Socket frontend, Socket backend, Socket capture) { return zmq.ZMQ.proxy(frontend.base, backend.base, capture != null ? capture.base : null); } public static int poll(PollItem[] items, long timeout) { return poll(items, items.length, timeout); } public static int poll(PollItem[] items, int count, long timeout) { zmq.PollItem[] pollItems = new zmq.PollItem[count]; for (int i = 0; i < count; i++) { pollItems[i] = items[i].base; } return zmq.ZMQ.poll(pollItems, count, timeout); } /** * @return Major version number of the ZMQ library. */ public static int getMajorVersion() { return zmq.ZMQ.ZMQ_VERSION_MAJOR; } /** * @return Major version number of the ZMQ library. */ public static int getMinorVersion() { return zmq.ZMQ.ZMQ_VERSION_MINOR; } /** * @return Major version number of the ZMQ library. */ public static int getPatchVersion() { return zmq.ZMQ.ZMQ_VERSION_PATCH; } /** * @return Full version number of the ZMQ library used for comparing versions. */ public static int getFullVersion() { return zmq.ZMQ.makeVersion(zmq.ZMQ.ZMQ_VERSION_MAJOR, zmq.ZMQ.ZMQ_VERSION_MINOR, zmq.ZMQ.ZMQ_VERSION_PATCH); } /** * @param major Version major component. * @param minor Version minor component. * @param patch Version patch component. * * @return Comparible single int version number. */ public static int makeVersion(final int major, final int minor, final int patch) { return zmq.ZMQ.makeVersion(major, minor, patch); } /** * @return String version number in the form major.minor.patch. */ public static String getVersionString() { return "" + zmq.ZMQ.ZMQ_VERSION_MAJOR + "." + zmq.ZMQ.ZMQ_VERSION_MINOR + "." + zmq.ZMQ.ZMQ_VERSION_PATCH; } /** * Inner class: Event. * Monitor socket event class */ public static class Event { private final int event; private final Object value; private final String address; public Event(int event, Object value, String address) { this.event = event; this.value = value; this.address = address; } public int getEvent() { return event; } public Object getValue() { return value; } public String getAddress() { return address; } /** * Receive an event from a monitor socket. * @param socket the socket * @param flags the flags to apply to the receive operation. * @return the received event or null if no message was received. * @throws ZMQException */ public static Event recv(Socket socket, int flags) { zmq.ZMQ.Event e = zmq.ZMQ.Event.read(socket.base, flags); return e != null ? new Event(e.event, e.arg, e.addr) : null; } /** * Receive an event from a monitor socket. * Does a blocking recv. * @param socket the socket * @return the received event. * @throws ZMQException */ public static Event recv(Socket socket) { return Event.recv(socket, 0); } } } jeromq-0.3.5/src/main/java/org/zeromq/ZMQException.java000066400000000000000000000033061255150477200227570ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import zmq.ZError; public class ZMQException extends RuntimeException { public static class IOException extends RuntimeException { private static final long serialVersionUID = 8440355423370109164L; public IOException(java.io.IOException cause) { super(cause); } } private static final long serialVersionUID = 5957233088499712341L; private final int code; public ZMQException(int errno) { super("Errno " + errno); code = errno; } public ZMQException(String message, int errno) { super(message); code = errno; } public ZMQException(ZMQException cause) { super(cause.getMessage(), cause); code = cause.code; } public int getErrorCode() { return code; } @Override public String toString() { return super.toString() + " : " + ZError.toString(code); } } jeromq-0.3.5/src/main/java/org/zeromq/ZMQQueue.java000066400000000000000000000026711255150477200221110ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; public class ZMQQueue implements Runnable { private final Socket inSocket; private final Socket outSocket; /** * Class constructor. * * @param context * a 0MQ context previously created. * @param inSocket * input socket * @param outSocket * output socket */ public ZMQQueue(Context context, Socket inSocket, Socket outSocket) { this.inSocket = inSocket; this.outSocket = outSocket; } @Override public void run() { zmq.ZMQ.proxy(inSocket.base(), outSocket.base(), null); } } jeromq-0.3.5/src/main/java/org/zeromq/ZMsg.java000066400000000000000000000433031255150477200213120ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayDeque; import java.util.Collection; import java.util.Deque; import java.util.Iterator; import java.util.NoSuchElementException; import org.zeromq.ZMQ.Socket; /** * The ZMsg class provides methods to send and receive multipart messages * across 0MQ sockets. This class provides a list-like container interface, * with methods to work with the overall container. ZMsg messages are * composed of zero or more ZFrame objects. * *

 * // Send a simple single-frame string message on a ZMQSocket "output" socket object
 * ZMsg.newStringMsg("Hello").send(output);
 *
 * // Add several frames into one message
 * ZMsg msg = new ZMsg();
 * for (int i = 0;i< 10;i++) {
 *     msg.addString("Frame" + i);
 * }
 * msg.send(output);
 *
 * // Receive message from ZMQSocket "input" socket object and iterate over frames
 * ZMsg receivedMessage = ZMsg.recvMsg(input);
 * for (ZFrame f : receivedMessage) {
 *     // Do something with frame f (of type ZFrame)
 * }
 * 
* * Based on zmsg.c in czmq * */ public class ZMsg implements Iterable, Deque { /** * Hold internal list of ZFrame objects */ private ArrayDeque frames; /** * Class Constructor */ public ZMsg() { frames = new ArrayDeque(); } /** * Destructor. * Explicitly destroys all ZFrames contains in the ZMsg */ public void destroy() { if (frames == null) { return; } for (ZFrame f : frames) { f.destroy(); } frames.clear(); frames = null; } /** * @return total number of bytes contained in all ZFrames in this ZMsg */ public long contentSize() { long size = 0; for (ZFrame f : frames) { size += f.size(); } return size; } /** * Add a String as a new ZFrame to the end of list * @param str * String to add to list */ public void addString(String str) { if (frames == null) { frames = new ArrayDeque(); } frames.add(new ZFrame(str)); } /** * Creates copy of this ZMsg. * Also duplicates all frame content. * @return * The duplicated ZMsg object, else null if this ZMsg contains an empty frame set */ public ZMsg duplicate() { if (frames != null) { ZMsg msg = new ZMsg(); for (ZFrame f : frames) { msg.add(f.duplicate()); } return msg; } else { return null; } } /** * Push frame plus empty frame to front of message, before 1st frame. * Message takes ownership of frame, will destroy it when message is sent. * @param frame */ public void wrap(ZFrame frame) { if (frame != null) { push(new ZFrame("")); push(frame); } } /** * Pop frame off front of message, caller now owns frame. * If next frame is empty, pops and destroys that empty frame * (e.g. useful when unwrapping ROUTER socket envelopes) * @return * Unwrapped frame */ public ZFrame unwrap() { if (size() == 0) { return null; } ZFrame f = pop(); ZFrame empty = getFirst(); if (empty.hasData() && empty.size() == 0) { empty = pop(); empty.destroy(); } return f; } /** * Send message to 0MQ socket. * * @param socket * 0MQ socket to send ZMsg on. * @return true if send is success, false otherwise */ public boolean send(Socket socket) { return send(socket, true); } /** * Send message to 0MQ socket, destroys contents after sending if destroy param is set to true. * If the message has no frames, sends nothing but still destroy()s the ZMsg object * @param socket * 0MQ socket to send ZMsg on. * @return true if send is success, false otherwise */ public boolean send(Socket socket, boolean destroy) { if (socket == null) { throw new IllegalArgumentException("socket is null"); } if (frames == null) { throw new IllegalArgumentException("destroyed message"); } if (frames.size() == 0) { return true; } boolean ret = true; Iterator i = frames.iterator(); while (i.hasNext()) { ZFrame f = i.next(); ret = f.sendAndKeep(socket, (i.hasNext()) ? ZFrame.MORE : 0); } if (destroy) { destroy(); } return ret; } /** * Receives message from socket, returns ZMsg object or null if the * recv was interrupted. Does a blocking recv, if you want not to block then use * the ZLoop class or ZMQ.Poller to check for socket input before receiving or recvMsg with flag ZMQ.DONTWAIT. * @param socket * @return * ZMsg object, null if interrupted */ public static ZMsg recvMsg(Socket socket) { return recvMsg(socket, 0); } /** * Receives message from socket, returns ZMsg object or null if the * recv was interrupted. Setting the flag to ZMQ.DONTWAIT does a non-blocking recv. * @param socket * @param flag see ZMQ constants * @return * ZMsg object, null if interrupted */ public static ZMsg recvMsg(Socket socket, int flag) { if (socket == null) { throw new IllegalArgumentException("socket is null"); } ZMsg msg = new ZMsg(); while (true) { ZFrame f = ZFrame.recvFrame(socket, flag); if (f == null) { // If receive failed or was interrupted msg.destroy(); msg = null; break; } msg.add(f); if (!f.hasMore()) { break; } } return msg; } /** * Save message to an open data output stream. * * Data saved as: * 4 bytes: number of frames * For every frame: * 4 bytes: byte size of frame data * + n bytes: frame byte data * * @param msg * ZMsg to save * @param file * DataOutputStream * @return * True if saved OK, else false */ public static boolean save(ZMsg msg, DataOutputStream file) { if (msg == null) { return false; } try { // Write number of frames file.writeInt(msg.size()); if (msg.size() > 0) { for (ZFrame f : msg) { // Write byte size of frame file.writeInt(f.size()); // Write frame byte data file.write(f.getData()); } } return true; } catch (IOException e) { return false; } } /** * Load / append a ZMsg from an open DataInputStream * * @param file * DataInputStream connected to file * @return * ZMsg object */ public static ZMsg load(DataInputStream file) { if (file == null) { return null; } ZMsg rcvMsg = new ZMsg(); try { int msgSize = file.readInt(); if (msgSize > 0) { int msgNbr = 0; while (++msgNbr <= msgSize) { int frameSize = file.readInt(); byte[] data = new byte[frameSize]; file.read(data); rcvMsg.add(new ZFrame(data)); } } return rcvMsg; } catch (IOException e) { return null; } } /** * Create a new ZMsg from one or more Strings * * @param strings * Strings to add as frames. * @return * ZMsg object */ public static ZMsg newStringMsg(String... strings) { ZMsg msg = new ZMsg(); for (String data : strings) { msg.addString(data); } return msg; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } ZMsg zMsg = (ZMsg) o; if (frames == null || zMsg.frames == null) { return false; } //based on AbstractList Iterator e1 = frames.iterator(); Iterator e2 = zMsg.frames.iterator(); while (e1.hasNext() && e2.hasNext()) { ZFrame o1 = e1.next(); ZFrame o2 = e2.next(); if (!(o1 == null ? o2 == null : o1.equals(o2))) { return false; } } return !(e1.hasNext() || e2.hasNext()); } @Override public int hashCode() { if (frames == null || frames.size() == 0) { return 0; } int result = 1; for (ZFrame frame : frames) { result = 31 * result + (frame == null ? 0 : frame.hashCode()); } return result; } /** * Dump the message in human readable format. This should only be used * for debugging and tracing, inefficient in handling large messages. **/ public void dump(Appendable out) { try { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); pw.printf("--------------------------------------\n"); for (ZFrame frame : frames) { pw.printf("[%03d] %s\n", frame.size(), frame.toString()); } out.append(sw.getBuffer()); sw.close(); } catch (IOException e) { throw new RuntimeException("Message dump exception " + super.toString(), e); } } public void dump() { dump(System.out); } // ********* Convenience Deque methods for common data types *** // public void addFirst(String stringValue) { addFirst(new ZFrame(stringValue)); } public void addFirst(byte[] data) { addFirst(new ZFrame(data)); } public void addLast(String stringValue) { addLast(new ZFrame(stringValue)); } public void addLast(byte[] data) { addLast(new ZFrame(data)); } // ********* Convenience Queue methods for common data types *** // public void push(String str) { push(new ZFrame(str)); } public void push(byte[] data) { push(new ZFrame(data)); } public boolean add(String stringValue) { return add(new ZFrame(stringValue)); } public boolean add(byte[] data) { return add(new ZFrame(data)); } // ********* Implement Iterable Interface *************** // @Override public Iterator iterator() { // TODO Auto-generated method stub return frames.iterator(); } // ********* Implement Deque Interface ****************** // @Override public boolean addAll(Collection arg0) { return frames.addAll(arg0); } @Override public void clear() { frames.clear(); } @Override public boolean containsAll(Collection arg0) { return frames.containsAll(arg0); } @Override public boolean isEmpty() { return frames.isEmpty(); } @Override public boolean removeAll(Collection arg0) { return frames.removeAll(arg0); } @Override public boolean retainAll(Collection arg0) { return frames.retainAll(arg0); } @Override public Object[] toArray() { return frames.toArray(); } @Override public T[] toArray(T[] arg0) { return frames.toArray(arg0); } @Override public boolean add(ZFrame e) { if (frames == null) { frames = new ArrayDeque(); } return frames.add(e); } @Override public void addFirst(ZFrame e) { if (frames == null) { frames = new ArrayDeque(); } frames.addFirst(e); } @Override public void addLast(ZFrame e) { if (frames == null) { frames = new ArrayDeque(); } frames.addLast(e); } @Override public boolean contains(Object o) { return frames.contains(o); } @Override public Iterator descendingIterator() { return frames.descendingIterator(); } @Override public ZFrame element() { return frames.element(); } @Override public ZFrame getFirst() { try { return frames.getFirst(); } catch (NoSuchElementException e) { return null; } } @Override public ZFrame getLast() { try { return frames.getLast(); } catch (NoSuchElementException e) { return null; } } @Override public boolean offer(ZFrame e) { if (frames == null) { frames = new ArrayDeque(); } return frames.offer(e); } @Override public boolean offerFirst(ZFrame e) { if (frames == null) { frames = new ArrayDeque(); } return frames.offerFirst(e); } @Override public boolean offerLast(ZFrame e) { if (frames == null) { frames = new ArrayDeque(); } return frames.offerLast(e); } @Override public ZFrame peek() { return frames.peek(); } @Override public ZFrame peekFirst() { try { return frames.peekFirst(); } catch (NoSuchElementException e) { return null; } } @Override public ZFrame peekLast() { try { return frames.peekLast(); } catch (NoSuchElementException e) { return null; } } @Override public ZFrame poll() { return frames.poll(); } @Override public ZFrame pollFirst() { return frames.pollFirst(); } @Override public ZFrame pollLast() { return frames.pollLast(); } @Override public ZFrame pop() { if (frames == null) { frames = new ArrayDeque(); } try { return frames.pop(); } catch (NoSuchElementException e) { return null; } } /** * Pop a ZFrame and return the toString() representation of it. * * @return toString version of pop'ed frame, or null if no frame exists. */ public String popString() { ZFrame frame = pop(); if (frame == null) { return null; } return frame.toString(); } @Override public void push(ZFrame e) { if (frames == null) { frames = new ArrayDeque(); } frames.push(e); } @Override public ZFrame remove() { return frames.remove(); } @Override public boolean remove(Object o) { return frames.remove(o); } @Override public ZFrame removeFirst() { try { return frames.removeFirst(); } catch (NoSuchElementException e) { return null; } } @Override public boolean removeFirstOccurrence(Object o) { return frames.removeFirstOccurrence(o); } @Override public ZFrame removeLast() { try { return frames.removeLast(); } catch (NoSuchElementException e) { return null; } } @Override public boolean removeLastOccurrence(Object o) { return frames.removeLastOccurrence(o); } @Override public int size() { return frames.size(); } /** * Returns pretty string representation of multipart message: * [ frame0, frame1, ..., frameN ] * * @return toString version of ZMsg object */ @Override public String toString() { StringBuilder out = new StringBuilder("[ "); Iterator frameIterator = frames.iterator(); while (frameIterator.hasNext()) { out.append(frameIterator.next()); if (frameIterator.hasNext()) { out.append(", "); // skip last iteration } } out.append(" ]"); return out.toString(); } } jeromq-0.3.5/src/main/java/org/zeromq/ZPoller.java000066400000000000000000000562511255150477200220270ustar00rootroot00000000000000package org.zeromq; import java.io.Closeable; import java.io.IOException; import java.nio.channels.SelectableChannel; import java.nio.channels.Selector; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.zeromq.ZMQ.Poller; import org.zeromq.ZMQ.Socket; /** * Rewritten poller for 0MQ. * * Polls selectable channels and sockets for specified events. * * This poller can be used in two ways: * *

* - the traditional one, where you make something like *

 * {@code
            ZPoller poller = ...
            poller.register(socket, ZPoller.POLLIN);
            poller.register(channel, ZPoller.OUT);

            int events = poller.poll(-1L);

            if (poller.isReadable(socket)) {
                ...
            }
            if (poller.writable(channel)) {
                ...
            }
}

* - the event-driven way *

 * {@code
 *
            ZPoller poller = ...

            poller.setGlobalHandler(...)
            ZPoller.EventsHandler handler = ...

            // The events method of the handler will be called
            poller.register(channel, handler, ZPoller.IN);

            // The events method of the global handler will be called
            poller.register(socket, ZPoller.POLLOUT);

            poller.poll(-1L);
            // handlers have been called
}

* The motivations of this rewriting are: *
* - the bare poller use {@link zmq.ZMQ#poll(zmq.PollItem[], int, long) this method} who does not allow * to choose the selector used for polling, relying on a ThreadLocal, which is dangerous. *
* - the bare poller use algorithms tailored for languages with manual allocation. * No need here as Java allows more flexibility. TODO There still may be a small penalty cost. * */ // Poller for 0MQ. public class ZPoller implements Closeable { // contract for events public static interface EventsHandler { /** * Called when the poller intercepts events. * * @param socket the socket with events * @param events the interesting events as an ORed combination of IN, OUT, ERR * @return true to continue the polling, false to stop it */ boolean events(Socket socket, int events); /** * Called when the poller intercepts events. * * @param channel the channel with events * @param events the interesting events as an ORed combination of IN, OUT, ERR * @return true to continue the polling, false to stop it */ boolean events(SelectableChannel channel, int events); } // contract for items. Useful for providing own implementation. public static interface ItemHolder { // the inner ZMQ poll item zmq.PollItem item(); // the related ZeroMQ socket Socket socket(); // the associated events handler EventsHandler handler(); } // contract for items creation. Useful for delegating. public static interface ItemCreator { /** * Creates a new holder for a poll item. * * @param socket the socket to poll * @param handler the optional handler for polled events * @param events the interested events * @return a new poll item holder */ ItemHolder create(Socket socket, EventsHandler handler, int events); /** * Creates a new holder for a poll item. * * @param channel the channel to poll * @param handler the optional handler for polled events. * @param events the interested events * @return a new poll item holder */ ItemHolder create(SelectableChannel channel, EventsHandler handler, int events); } // re-re-implementation of poll item public static class ZPollItem extends ZMQ.PollItem implements ItemHolder { private final EventsHandler handler; public ZPollItem(final Socket socket, final EventsHandler handler, int ops) { super(socket, ops); this.handler = handler; } public ZPollItem(final SelectableChannel channel, final EventsHandler handler, final int ops) { super(channel, ops); this.handler = handler; } @Override public zmq.PollItem item() { return base(); } @Override public Socket socket() { return getSocket(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((item() == null) ? 0 : item().hashCode()); result = prime * result + ((getRawSocket() == null) ? 0 : getRawSocket().hashCode()); result = prime * result + ((socket() == null) ? 0 : socket().hashCode()); result = prime * result + ((handler() == null) ? 0 : handler().hashCode()); return result; } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof ItemHolder)) { return false; } ItemHolder other = (ItemHolder) obj; if (item() == null) { if (other.item() != null) { return false; } } else if (!item().equals(other.item())) { return false; } if (item().getRawSocket() == null) { if (other.item().getRawSocket() != null) { return false; } } else if (!item().getRawSocket().equals(other.item().getRawSocket())) { return false; } if (socket() == null) { if (other.socket() != null) { return false; } } else if (!socket().equals(other.socket())) { return false; } if (handler() == null) { if (other.handler() != null) { return false; } } else if (!handler().equals(other.handler())) { return false; } return true; } @Override public EventsHandler handler() { return handler; } } /******************************************************************************/ /* 0MQ socket events */ /******************************************************************************/ /** * These values can be ORed to specify what we want to poll for. */ public static final int POLLIN = Poller.POLLIN; public static final int POLLOUT = Poller.POLLOUT; public static final int POLLERR = Poller.POLLERR; // same values with shorter writing public static final int IN = POLLIN; public static final int OUT = POLLOUT; public static final int ERR = POLLERR; /** * Creates a new poller based on the current one. * This will be a shadow poller, sharing the same selector and items creator. * The global events handler will not be shared. * * @param poller the main poller. */ public ZPoller(final ZPoller poller) { this(poller.creator, poller.selector); } /** * Creates a new poller with a given selector for operational polling. * * @param selector the selector to use for polling. */ public ZPoller(final Selector selector) { this(new SimpleCreator(), selector); } /** * Creates a new poller based on the current one. * This will be a shadow poller, sharing the same selector. * The global events handler will not be shared. * * @param creator the items creator * @param poller the main poller. */ public ZPoller(final ItemCreator creator, final ZPoller poller) { this(creator, poller.selector); } /** * Creates a new poller. * * @param creator the items creator * @param selector the selector to use for polling. */ public ZPoller(final ItemCreator creator, final Selector selector) { this.creator = creator; this.selector = selector; items = new HashMap>(); all = createContainer(0); } // creates a new poll item protected ItemHolder create(final Socket socket, final EventsHandler handler, final int events) { assert (socket != null); return creator.create(socket, handler, events); } // creates a new poll item protected ItemHolder create(final SelectableChannel channel, final EventsHandler handler, final int events) { assert (channel != null); return creator.create(channel, handler, events); } /** * Sets the global events handler for all registered sockets. * * @param globalHandler the events handler to set */ public void setGlobalHandler(final EventsHandler globalHandler) { this.globalHandler = globalHandler; } /** * Returns the global events handler for all registered sockets. * * @return the global events handler for all registered sockets. */ public EventsHandler getGlobalHandler() { return globalHandler; } /** * Register a Socket for polling on specified events. * * @param socket the registering socket. * @param handler the events handler for this socket * @param events the events to listen to, as a mask composed by ORing POLLIN, POLLOUT and POLLERR. * @return true if registered, otherwise false */ public final boolean register(final Socket socket, final EventsHandler handler, final int events) { if (socket == null) { return false; } return add(socket, create(socket, handler, events)); } public final boolean register(final Socket socket, final EventsHandler handler) { return register(socket, handler, POLLIN | POLLOUT | POLLERR); } public final boolean register(final Socket socket, final int events) { return register(socket, globalHandler, events); } /** * Register a SelectableChannel for polling on specified events. * * @param channel the registering channel. * @param handler the events handler for this socket * @param events the events to listen to, as a mask composed by XORing POLLIN, POLLOUT and POLLERR. * @return true if registered, otherwise false */ public final boolean register(final SelectableChannel channel, final EventsHandler handler, final int events) { if (channel == null) { return false; } return add(channel, create(channel, handler, events)); } public final boolean register(final SelectableChannel channel, final EventsHandler handler) { return register(channel, handler, IN | OUT | ERR); } public final boolean register(final SelectableChannel channel, final int events) { return register(channel, globalHandler, events); } /** * Register an ItemHolder for polling on specified events. * * @param item the registering item. * @return true if registered, otherwise false */ public final boolean register(final ItemHolder item) { return add(null, item); } /** * Unregister a Socket or SelectableChannel for polling on the specified events. * * @param socketOrChannel the Socket or SelectableChannel to be unregistered * @return true if unregistered, otherwise false * TODO would it be useful to unregister only for specific events ? */ public final boolean unregister(final Object socketOrChannel) { if (socketOrChannel == null) { return false; } Set items = this.items.remove(socketOrChannel); boolean rc = items != null; if (rc) { all.removeAll(items); } return rc; } /******************************************************************************/ /* POLLING | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |*/ /******************************************************************************/ /** * Issue a poll call, using the specified timeout value. *

* Since ZeroMQ 3.0, the timeout parameter is in milliseconds, * but prior to this the unit was microseconds. * * @param timeout * the timeout, as per zmq_poll (); * if -1, it will block indefinitely until an event * happens; if 0, it will return immediately; * otherwise, it will wait for at most that many * milliseconds/microseconds (see above). * * @see "http://api.zeromq.org/3-0:zmq-poll" * * @return how many objects where signaled by poll () */ public int poll(final long timeout) { return poll(timeout, true); } /** * Issue a poll call, using the specified timeout value. * * @param timeout the timeout, as per zmq_poll (); * @param dispatchEvents true to dispatch events using items handler and the global one. * @see "http://api.zeromq.org/3-0:zmq-poll" * * @return how many objects where signaled by poll () */ protected int poll(final long timeout, final boolean dispatchEvents) { // get all the raw items final Collection all = items(); final Set pollItems = new HashSet(all.size()); for (ItemHolder holder : all) { pollItems.add(holder.item()); } // polling time final int rc = poll(selector, timeout, pollItems); if (!dispatchEvents) { // raw result return rc; } if (dispatch(all, pollItems.size())) { // returns event counts after dispatch if everything went fine return rc; } // error in dispatching return -1; } // does the effective polling protected int poll(final Selector selector, final long tout, final Collection items) { final int size = items.size(); return zmq.ZMQ.poll(selector, items.toArray(new zmq.PollItem[size]), size, tout); } /** * Dispatches the polled events. * * @param all the items used for dispatching * @param size the number of items to dispatch * @return true if correctly dispatched, false in case of error */ protected boolean dispatch(final Collection all, int size) { ItemHolder[] array = all.toArray(new ItemHolder[all.size()]); // protected against handlers unregistering during this loop for (ItemHolder holder : array) { EventsHandler handler = holder.handler(); if (handler == null) { handler = globalHandler; } if (handler == null) { // no handler, short-circuit continue; } final zmq.PollItem item = holder.item(); final int events = item.readyOps(); if (events <= 0) { // no events, short-circuit continue; } final Socket socket = holder.socket(); final SelectableChannel channel = holder.item().getRawSocket(); if (socket != null) { assert (channel == null); // dispatch on socket if (!handler.events(socket, events)) { return false; } } if (channel != null) { // dispatch on channel assert (socket == null); if (!handler.events(channel, events)) { return false; } } } return true; } // dispatches all the polled events to their respective handlers public boolean dispatch() { return dispatch(all, all.size()); } /******************************************************************************/ /*| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | POLLING */ /******************************************************************************/ /** * Tells if a channel is readable from this poller. * * @param channel the channel to ask for. * @return true if readable, otherwise false */ public boolean isReadable(final SelectableChannel channel) { return readable((Object) channel); } public boolean readable(final SelectableChannel channel) { return readable((Object) channel); } /** * Tells if a socket is readable from this poller. * * @param socket the socket to ask for. * @return true if readable, otherwise false */ public boolean isReadable(final Socket socket) { return readable(socket); } public boolean readable(final Socket socket) { return readable((Object) socket); } // checks for read event public boolean readable(final Object socketOrChannel) { final zmq.PollItem it = filter(socketOrChannel, IN); if (it == null) { return false; } return it.isReadable(); } /** * Tells if a channel is writable from this poller. * * @param channel the channel to ask for. * @return true if writable, otherwise false */ public boolean isWritable(final SelectableChannel channel) { return writable((Object) channel); } public boolean writable(final SelectableChannel channel) { return writable((Object) channel); } /** * Tells if a socket is writable from this poller. * * @param socket the socket to ask for. * @return true if writable, otherwise false */ public boolean isWritable(final Socket socket) { return writable((Object) socket); } public boolean writable(final Socket socket) { return writable((Object) socket); } // checks for write event public boolean writable(final Object socketOrChannel) { final zmq.PollItem it = filter(socketOrChannel, OUT); if (it == null) { return false; } return it.isWritable(); } /** * Tells if a channel is in error from this poller. * * @param channel the channel to ask for. * @return true if in error, otherwise false */ public boolean isError(final SelectableChannel channel) { return error((Object) channel); } public boolean error(final SelectableChannel channel) { return error((Object) channel); } /** * Tells if a socket is in error from this poller. * * @param socket the socket to ask for. * @return true if in error, otherwise false */ public boolean isError(final Socket socket) { return error((Object) socket); } public boolean error(final Socket socket) { return error((Object) socket); } // checks for error event public boolean error(final Object socketOrChannel) { final zmq.PollItem it = filter(socketOrChannel, ERR); if (it == null) { return false; } return it.isError(); } /** * Destroys the poller. Does actually nothing. */ @Override public void close() throws IOException { // we didn't create the selector, // it is not our responsibility to close it. // selector.close(); } /** * Destroys the poller and the associated selector without exception. */ public void destroy() { try { close(); } catch (IOException e) { e.printStackTrace(); } } // selector used for polling private final Selector selector; // creator of items private final ItemCreator creator; // managed items private final Map> items; // all managed items to avoid penalty cost when dispatching private final Set all; // TODO set of handlers, each with its specified events? // optional global events handler private EventsHandler globalHandler; // simple creator for poll items private static class SimpleCreator implements ItemCreator { @Override public ItemHolder create(final Socket socket, final EventsHandler handler, final int events) { return new ZPollItem(socket, handler, events); } @Override public ItemHolder create(final SelectableChannel channel, final EventsHandler handler, final int events) { return new ZPollItem(channel, handler, events); } } // add an item to this poller protected boolean add(Object socketOrChannel, final ItemHolder holder) { if (socketOrChannel == null) { Socket socket = holder.socket(); SelectableChannel ch = holder.item().getRawSocket(); if (socket == null) { // not a socket assert (ch != null); socketOrChannel = ch; } if (ch == null) { // not a channel assert (socket != null); socketOrChannel = socket; } } assert (socketOrChannel != null); Set holders = items.get(socketOrChannel); if (holders == null) { holders = createContainer(1); items.put(socketOrChannel, holders); } final boolean rc = holders.add(holder); if (rc) { all.add(holder); } return rc; } // create the container of holders protected Set createContainer(int size) { return new HashSet(size); } // gets all the items of this poller protected Collection items() { return all; } // gets all the items of this poller regarding the given input protected Iterable items(final Object socketOrChannel) { final Set set = items.get(socketOrChannel); if (set == null) { return Collections.emptySet(); } return set; } // filters items to get the first one matching the criteria, or null if none found protected zmq.PollItem filter(final Object socketOrChannel, int events) { if (socketOrChannel == null) { return null; } final Iterable items = items(socketOrChannel); for (ItemHolder item : items) { final zmq.PollItem it = item.item(); if ((it.interestOps() & events) > 0) { return it; } } return null; } } jeromq-0.3.5/src/main/java/org/zeromq/ZProxy.java000066400000000000000000001121651255150477200217100ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import org.zeromq.ZActor.Actor; import org.zeromq.ZAgent.SelectorCreator; import org.zeromq.ZMQ.Socket; import zmq.Msg; import zmq.SocketBase; /** * Implementation of a remotely controlled proxy for 0MQ, using {@link ZActor}. *
* The goals of this implementation are to delegate the creation of sockets * in a background thread via a callback interface to ensure their correct use * and to provide ultimately to end-users the following features. *

* Basic features: *

    *
  • Remote Control *
      *
    • Start: if was paused, flushes the pending messages *
    • Pause: lets the socket queues accumulate messages according to their types *
    • Stop: Shutdowns the proxy, can be restarted *
    • Status: Retrieves the status of the proxy *
    • Cold Restart: Closes and recreates the connections *
    • {@link #restart(ZMsg) Hot Restart}: User-defined behavior with custom messages *
    • {@link #configure(ZMsg) Configure}: User-defined behavior with custom messages *
    • {@link #command(String, boolean) ...}: Custom commands of your own *
    • Exit: Definitive shutdown of the proxy and its control *
    * All the non-custom commands can be performed in asynchronous or synchronous mode. *
    *
    *
  • Proxy mechanism ensured by pluggable pumps *
      *
    • with built-in low-level {@link ZmqPump} (zmq.ZMQ): useful for performances *
    • with built-in high-level {@link ZPump} (ZeroMQ): useful for {@link ZPump.Transformer message transformation}, lower performances *
    • with your own-custom proxy pump implementing a {@link Pump 1-method interface} *
    *

*

* You can have all the above non-customizable features in about these lines of code: *

*

 * {@code
        final ZProxy.Proxy provider = new ZProxy.SimpleProxy()
        {
            public Socket create(ZContext ctx, ZProxy.Plug place, Object[] args)
            {
                assert ("TEST".equals(args[0]);
                Socket socket = null;
                if (place == ZProxy.Plug.FRONT) {
                    socket = ctx.createSocket(ZMQ.ROUTER);
                }
                if (place == ZProxy.Plug.BACK) {
                    socket = ctx.createSocket(ZMQ.DEALER);
                }
                return socket;
            }

            public void configure(Socket socket, ZProxy.Plug place, Object[] args)
            {
                assert ("TEST".equals(args[0]);
                int port = -1;
                if (place == ZProxy.Plug.FRONT) {
                    port = socket.bind("tcp://127.0.0.1:6660");
                }
                if (place == ZProxy.Plug.BACK) {
                    port = socket.bind("tcp://127.0.0.1:6661");
                }
                if (place == ZProxy.Plug.CAPTURE && socket != null) {
                    socket.bind("tcp://127.0.0.1:4263");
                }
            }
        };

        ZProxy proxy = ZProxy.newProxy("ProxyOne", provider, "ABRACADABRA", Arrays.asList("TEST"));
}
 * 

* Once created, the proxy is not started. You have to perform first a start command on it. * This choice was made because it is easier for a user to start it with one line of code than for the code to internally handle * different possible starting states (after all, someone may want the proxy started but paused at first or configured in a specific way?) * and because the a/sync stuff was funnier. Life is unfair ... * Or maybe an idea is floating in the air? *
* * You can then use it like this: *
 * {@code
        final boolean async = false, sync = true;
        String status = null;
        status = proxy.status();
        status = proxy.pause(sync);
        status = proxy.start(async);
        ZMsg msg = proxy.restart(new ZMsg());
        status = proxy.status(async);
        status = proxy.stop(sync);
        boolean here = proxy.sign();
        ZMsg cfg = new ZMsg();
        msg.add("CONFIG-1");
        ZMsg rcvd = proxy.configure(cfg);
        proxy.exit(async);
        status = proxy.status(sync);
        assert (!proxy.started());
   }
 * 

* * A {@link #command(Command, boolean) programmatic interface} with enums is also available. * * */ // Proxy for 0MQ. public class ZProxy { /** * Possible places for sockets in the proxy. */ public static enum Plug { FRONT, // The position of the frontend socket. BACK, // The position of the backend socket. CAPTURE; // The position of the capture socket. } // Contract for socket creation and customizable configuration in proxy threading. public static interface Proxy { /** * Creates and initializes (bind, options ...) the socket for the given plug in the proxy. * The proxy will close them afterwards, and the context as well if not provided in the constructor. * There is no need to keep a reference on the created socket or the context given in parameter. * * @param ctx the context used for initialization. * @param place the position for the future created socket in the proxy. * @param args the optional array of arguments that has been passed at the creation of the ZProxy. * @return the created socket. Possibly null only for capture. */ Socket create(ZContext ctx, Plug place, Object[] args); /** * Configures the given socket. * * @param socket the socket to configure * @param place the position for the socket in the proxy * @param args the optional array of arguments that has been passed at the creation of the ZProxy. */ void configure(Socket socket, Plug place, Object[] args); /** * Performs a hot restart of the given socket. * Usually an unbind/bind but you can use whatever method you like. * * @param cfg the custom configuration message sent by the control. * @param socket the socket to hot restart * @param place the position for the socket in the proxy * @param args the optional array of arguments that has been passed at the creation of the ZProxy. * @return true to perform a cold restart instead, false to do nothing. All the results will be collected from calls for all plugs. * If any of them returns true, the cold restart is performed. */ boolean restart(ZMsg cfg, Socket socket, Plug place, Object[] args); /** * Configures the proxy with a custom message. * * Note: you need to send one (1) mandatory custom response message with the pipe before the end of this call. * * @param pipe the control pipe * @param cfg the custom configuration message sent by the control * @param frontend the frontend socket * @param backend the backend socket * @param capture the optional capture socket * @param args the optional array of arguments that has been passed at the creation of the ZProxy. * @return true to continue the proxy, false to exit */ boolean configure(Socket pipe, ZMsg cfg, Socket frontend, Socket backend, Socket capture, Object[] args); /** * Handles a custom command not recognized by the proxy. * * Note: you need to send the current state at the end of the call. * * @param pipe the control pipe * @param cmd the unrecognized command * @param frontend the frontend socket * @param backend the backend socket * @param capture the optional capture socket * @param args the optional array of arguments that has been passed at the creation of the ZProxy. * * @return true to continue the proxy, false to exit */ boolean custom(Socket pipe, String cmd, Socket frontend, Socket backend, Socket capture, Object[] args); // this may be useful public abstract static class SimpleProxy implements Proxy { @Override public boolean restart(ZMsg cfg, Socket socket, Plug place, Object[] args) { return true; } @Override public boolean configure(Socket pipe, ZMsg cfg, Socket frontend, Socket backend, Socket capture, Object[] args) { return true; } @Override public boolean custom(Socket pipe, String cmd, Socket frontend, Socket backend, Socket capture, Object[] args) { return true; } } } /** * Creates a new proxy in a ZeroMQ way. * This proxy will be less efficient than the * {@link #newZProxy(ZContext, String, org.zeromq.ZProxy.Proxy, String, Object...) low-level one}. * * @param ctx the context used for the proxy. * Possibly null, in this case a new context will be created and automatically destroyed afterwards. * @param name the name of the proxy. Possibly null. * @param selector the creator of the selector used for the internal polling. Not null. * @param sockets the sockets creator of the proxy. Not null. * @param args an optional array of arguments that will be passed at the creation. * * @return the created proxy. */ // creates a new proxy public static ZProxy newZProxy(ZContext ctx, String name, SelectorCreator selector, Proxy sockets, String motdelafin, Object... args) { return new ZProxy(ctx, name, selector, sockets, new ZPump(), null, args); } public static ZProxy newZProxy(ZContext ctx, String name, Proxy sockets, String motdelafin, Object... args) { return new ZProxy(ctx, name, null, sockets, new ZPump(), motdelafin, args); } /** * Creates a new low-level proxy for better performances. * * @param ctx the context used for the proxy. * Possibly null, in this case a new context will be created and automatically destroyed afterwards. * @param name the name of the proxy. Possibly null. * @param selector the creator of the selector used for the internal polling. Not null. * @param sockets the sockets creator of the proxy. Not null. * @param args an optional array of arguments that will be passed at the creation. * * @return the created proxy. */ // creates a new low-level proxy public static ZProxy newProxy(ZContext ctx, String name, SelectorCreator selector, Proxy sockets, String motdelafin, Object... args) { return new ZProxy(ctx, name, selector, sockets, new ZmqPump(), motdelafin, args); } public static ZProxy newProxy(ZContext ctx, String name, Proxy sockets, String motdelafin, Object... args) { return new ZProxy(ctx, name, null, sockets, new ZmqPump(), motdelafin, args); } /** * Starts the proxy. * * @param sync true to read the status in synchronous way, false for asynchronous mode * @return the read status */ public String start(boolean sync) { return command(START, sync); } /** * Pauses the proxy. * A paused proxy will cease processing messages, causing * them to be queued up and potentially hit the high-water mark on the * frontend or backend socket, causing messages to be dropped, or writing * applications to block. * * @param sync true to read the status in synchronous way, false for asynchronous mode * @return the read status */ public String pause(boolean sync) { return command(PAUSE, sync); } /** * Stops the proxy. * * @param sync true to read the status in synchronous way, false for asynchronous mode * @return the read status */ public String stop(boolean sync) { return command(STOP, sync); } /** * Sends a command message to the proxy actor. * Can be useful for programmatic interfaces. * Does not works with commands {@link #CONFIG CONFIG} and {@link #RESTART RESTART}. * * @param command the command to execute. * @param sync true to read the status in synchronous way, false for asynchronous mode * @return the read status */ public String command(String command, boolean sync) { assert (!command.equals(CONFIG)); assert (!command.equals(RESTART)); if (command.equals(STATUS)) { return status(sync); } if (command.equals(EXIT)) { return exit(sync); } // consume the status in the pipe String status = recvStatus(); if (agent.send(command)) { // the pipe is refilled if (sync) { status(true); } } return status; } /** * Sends a command message to the proxy actor. * Can be useful for programmatic interfaces. * Does not works with commands {@link Command#CONFIG CONFIG} and {@link Command#RESTART RESTART}. * * @param command the command to execute. * @param sync true to read the status in synchronous way, false for asynchronous mode * @return the read state */ public State command(Command command, boolean sync) { return State.valueOf(command(command.name(), sync)); } /** * Sends a command message to the proxy actor. * Can be useful for programmatic interfaces. * Works only with commands {@link Command#CONFIG CONFIG} and {@link Command#RESTART RESTART}. * * @param command the command to execute. * @param msg the custom message to transmit. * @param sync true to read the status in synchronous way, false for asynchronous mode * @return the response message */ public ZMsg command(Command command, ZMsg msg, boolean sync) { if (command == Command.CONFIG) { return configure(msg); } if (command == Command.RESTART) { String status = restart(msg); msg = new ZMsg(); msg.add(status); return msg; } return null; } /** * Configures the proxy. * The distant side has to send back one (1) mandatory response message. * * @param msg the custom message sent as configuration tip * @return the mandatory response message of the configuration. */ public ZMsg configure(ZMsg msg) { msg.addFirst(CONFIG); if (agent.send(msg)) { // consume the status in the pipe recvStatus(); ZMsg reply = agent.recv(); assert (reply != null); // refill the pipe with status agent.send(STATUS); return reply; } return null; } /** * Restarts the proxy. Stays alive. * * @param hot null to make a cold restart (closing then re-creation of the sockets) * or a configuration message to perform a configurable hot restart, */ public String restart(ZMsg hot) { ZMsg msg = new ZMsg(); msg.add(RESTART); if (hot == null) { msg.add(Boolean.toString(false)); } else { msg.add(Boolean.toString(true)); // FIXME better way to append 1 message into another ? for (int index = 0; index < hot.size(); ++index) { ZFrame frame = hot.pop(); msg.add(frame); } } String status = EXITED; if (agent.send(msg)) { status = status(false); } return status; } /** * Stops the proxy and exits. * * @param sync true to read the status in synchronous way, false for asynchronous mode * @return the read status */ public String exit(boolean sync) { String status = EXITED; if (agent.send(EXIT)) { if (sync) { return await(); } status = status(false); } return status; } // Waits for the completion of this proxy, like in old style. private String await() { String status = status(true); while (!Thread.currentThread().isInterrupted()) { if (EXITED.equals(status)) { break; } if (!agent.sign()) { return EXITED; } status = status(false); } return status; } /** * Inquires for the status of the proxy. * This call is synchronous. */ public String status() { return status(true); } /** * Inquires for the status of the proxy. * * @param sync true to read the status in synchronous way, false for asynchronous mode. * If false, you get the last cached status of the proxy */ public String status(boolean sync) { String status = recvStatus(); if (agent.send(STATUS) && sync) { // wait for the response to emulate sync status = recvStatus(); // AND refill a status if (!agent.send(STATUS)) { // TODO and in case of error? Let's handle it with exception for now throw new RuntimeException("Unable to send the status message"); } } return status; } // receives the last known state of the proxy private String recvStatus() { if (!agent.sign()) { return EXITED; } // receive the status response final ZMsg msg = agent.recv(); if (msg == null) { return EXITED; } String status = msg.popString(); msg.destroy(); return status; } /** * Binary inquiry for the status of the proxy. */ public boolean isStarted() { return started(); } /** * Binary inquiry for the status of the proxy. */ public boolean started() { String status = status(true); return STARTED.equals(status); } // to handle commands in a more java-centric way public static enum Command { START, PAUSE, STOP, RESTART, EXIT, STATUS, CONFIG; } // commands for the control pipe private static final String START = Command.START.name(); private static final String PAUSE = Command.PAUSE.name(); private static final String STOP = Command.STOP.name(); private static final String RESTART = Command.RESTART.name(); private static final String EXIT = Command.EXIT.name(); private static final String STATUS = Command.STATUS.name(); private static final String CONFIG = Command.CONFIG.name(); // to handle states in a more java-centric way public static enum State { ALIVE, STARTED, PAUSED, STOPPED, EXITED; } // state responses from the control pipe public static final String STARTED = State.STARTED.name(); public static final String PAUSED = State.PAUSED.name(); public static final String STOPPED = State.STOPPED.name(); public static final String EXITED = State.EXITED.name(); // defines the very first time where no command changing the state has been issued public static final String ALIVE = State.ALIVE.name(); private static final AtomicInteger counter = new AtomicInteger(); // the endpoint to the distant proxy actor private final ZAgent agent; /** * Creates a new unnamed proxy. * * @param selector the creator of the selector used for the proxy. * @param creator the creator of the sockets of the proxy. */ public ZProxy(SelectorCreator selector, Proxy creator, String motdelafin, Object ... args) { this(null, null, selector, creator, null, motdelafin, args); } /** * Creates a new named proxy. * * @param name the name of the proxy (used in threads naming). * @param selector the creator of the selector used for the proxy. * @param creator the creator of the sockets of the proxy. */ public ZProxy(String name, SelectorCreator selector, Proxy creator, String motdelafin, Object... args) { this(null, name, selector, creator, null, motdelafin, args); } /** * Creates a new named proxy. * * @param ctx the main context used. * If null, a new context will be created and closed at the stop of the operation. * If not null, it is the responsibility of the call to close it. * @param name the name of the proxy (used in threads naming). * @param selector the creator of the selector used for the proxy. * @param sockets the creator of the sockets of the proxy. * @param pump the pump used for the proxy */ public ZProxy(ZContext ctx, String name, SelectorCreator selector, Proxy sockets, Pump pump, String motdelafin, Object... args) { super(); // arguments parsing if (pump == null) { pump = new ZmqPump(); } int count = 1; count += args.length; Object[] vars = null; vars = new Object[count]; vars[0] = sockets; Actor shadow = null; // copy the arguments and retrieve the last optional shadow given in input for (int index = 0; index < args.length; ++index) { Object arg = args[index]; if (arg instanceof Actor) { shadow = (Actor) arg; } vars[index + 1] = arg; } // handle the actor int id = counter.incrementAndGet(); Actor actor = new ProxyActor(name, pump, id); if (shadow != null) { actor = new ZActor.Duo(actor, shadow); } ZActor zactor = new ZActor(ctx, selector, actor, motdelafin, vars); agent = zactor.agent(); // the zactor is also its own agent } // defines a pump that will flow messages from one socket to another public static interface Pump { /** * Transfers a message from one source to one destination, with an optional capture. * * @param src the plug of the source socket * @param source the socket where to receive the message from. * @param capture the optional sockets where to send the message to. Possibly null. * @param dst the plug of the destination socket * @param destination the socket where to send the message to. * * @return false in case of error or interruption, true if successfully transferred the message */ boolean flow(Plug src, Socket source, Socket capture, Plug dst, Socket destination); } // acts in background to proxy messages private static final class ProxyActor extends ZActor.SimpleActor { // the states container of the proxy private static final class State { // are we alive ? private boolean alive = false; // are we started ? private boolean started = false; // are we paused ? private boolean paused = false; // controls creation of a new agent if asked of a cold restart private boolean restart = false; // one-shot configuration for hot restart private ZMsg hot; } // the state of the proxy private final State state = new State(); // used to transfer message from one socket to another private final Pump transport; // the nice name of the proxy private final String name; // the provider of the sockets private Proxy provider; // the sockets creator user arguments private Object[] args; private Socket frontend; private Socket backend; private Socket capture; // creates a new Proxy actor. public ProxyActor(String name, Pump transport, int id) { if (name == null) { // default basic name this.name = String.format("ZProxy-%sd", id); } else { this.name = name; } this.transport = transport; } @Override public String premiere(Socket pipe) { return name; } // creates the sockets before the start of the proxy @Override public List createSockets(ZContext ctx, Object[] args) { provider = (Proxy) args[0]; this.args = new Object[args.length - 1]; System.arraycopy(args, 1, this.args, 0, this.args.length); frontend = provider.create(ctx, Plug.FRONT, this.args); capture = provider.create(ctx, Plug.CAPTURE, this.args); backend = provider.create(ctx, Plug.BACK, this.args); assert (frontend != null); assert (backend != null); return Arrays.asList(frontend, backend); } @Override public void start(Socket pipe, List sockets, ZPoller poller) { // init the state machine state.alive = true; ZMsg reply = new ZMsg(); reply.add(ALIVE); reply.send(pipe); } // Process a control message @Override public boolean backstage(Socket pipe, ZPoller poller, int events) { assert (state.hot == null); String cmd = pipe.recvStr(); // a message has been received from the API if (START.equals(cmd)) { start(poller); return status().send(pipe); } else if (STOP.equals(cmd)) { stop(poller); return status().send(pipe); } else if (PAUSE.equals(cmd)) { pause(poller, true); return status().send(pipe); } else if (RESTART.equals(cmd)) { String val = pipe.recvStr(); boolean hot = Boolean.parseBoolean(val); return restart(pipe, poller, hot); } else if (STATUS.equals(cmd)) { return status().send(pipe); } else if (CONFIG.equals(cmd)) { ZMsg cfg = ZMsg.recvMsg(pipe); boolean rc = provider.configure(pipe, cfg, frontend, backend, capture, args); cfg.destroy(); return rc; } else if (EXIT.equals(cmd)) { // stops the proxy and the agent. // the status will be sent at the end of the loop } else { return provider.custom(pipe, cmd, frontend, backend, capture, args); } return false; } // returns the status private ZMsg status() { ZMsg reply = new ZMsg(); if (!state.alive) { reply.add(EXITED); return reply; } if (state.started) { if (state.paused) { reply.add(PAUSED); } else { reply.add(STARTED); } } else { reply.add(STOPPED); } return reply; } // starts the proxy sockets private boolean start(ZPoller poller) { if (!state.started) { state.started = true; provider.configure(frontend, Plug.FRONT, args); provider.configure(backend, Plug.BACK, args); provider.configure(capture, Plug.CAPTURE, args); } if (!state.paused) { pause(poller, false); } return true; } // pauses the proxy sockets private boolean pause(ZPoller poller, boolean pause) { state.paused = pause; if (pause) { poller.unregister(frontend); poller.unregister(backend); // TODO why not a mechanism for eventually flushing the sockets during the pause? } else { poller.register(frontend, ZPoller.POLLIN); poller.register(backend, ZPoller.POLLIN); // Now Wait also until there are either requests or replies to process. } return true; } private boolean stop(ZPoller poller) { // restart the actor in stopped state state.started = false; // close connections state.restart = true; return true; } // handles the restart command in both modes private boolean restart(Socket pipe, ZPoller poller, boolean hot) { if (hot) { assert (provider != null); state.hot = ZMsg.recvMsg(pipe); state.restart = true; // continue with the same agent return true; } else { state.restart = true; // stop the loop and restart a new agent // with the same started state // the next loop will refill the updated status return false; } } @Override public long looping(Socket pipe, ZPoller poller) { state.hot = null; return super.looping(pipe, poller); } // a message has been received for the proxy to process @Override public boolean stage(Socket socket, Socket pipe, ZPoller poller, int events) { if (socket == frontend) { // Process a request. return transport.flow( Plug.FRONT, frontend, capture, Plug.BACK, backend); } if (socket == backend) { // Process a reply. return transport.flow( Plug.BACK, backend, capture, Plug.FRONT, frontend); } return false; } @Override public boolean looped(Socket pipe, ZPoller poller) { if (state.restart && state.hot != null) { // caught the hot restart ZMsg cfg = state.hot; state.hot = null; state.restart = false; boolean cold; ZMsg dup = cfg.duplicate(); cold = provider.restart(dup, frontend, Plug.FRONT, this.args); dup.destroy(); dup = cfg.duplicate(); cold |= provider.restart(dup, backend, Plug.BACK, this.args); dup.destroy(); dup = cfg.duplicate(); cold |= provider.restart(dup, capture, Plug.CAPTURE, this.args); dup.destroy(); cfg.destroy(); // we perform a cold restart if the provider says so state.restart = cold; } return true; } // called in the proxy thread when it stopped. @Override public boolean destroyed(Socket pipe, ZPoller poller) { if (capture != null) { capture.close(); } if (!state.restart) { state.alive = false; status().send(pipe); } return state.restart; } } /** * A pump that reads a message as a whole before transmitting it. * It offers a way to transform messages for capture and destination. */ public static class ZPump implements Pump { private static final Identity IDENTITY = new Identity(); // the messages transformer private final Transformer transformer; // transforms one message into another public static interface Transformer { /** * Transforms a ZMsg into another ZMsg. * Please note that this will be used during the message transfer, * so lengthy operations will have a cost on performances by definition. * If you return back another message than the one given in input, then this one has to be destroyed by you. * @param msg the message to transform * @param src the source plug * @param dst the destination plug * @return the transformed message */ ZMsg transform(ZMsg msg, Plug src, Plug dst); } private static class Identity implements Transformer { @Override public ZMsg transform(ZMsg msg, Plug src, Plug dst) { return msg; } } public ZPump() { this(null); } public ZPump(Transformer transformer) { super(); this.transformer = transformer == null ? IDENTITY : transformer; } @Override public boolean flow(Plug splug, Socket source, Socket capture, Plug dplug, Socket destination) { boolean success = false; // we read the whole message ZMsg msg = ZMsg.recvMsg(source); if (msg == null) { return false; } if (capture != null) { // Copy transformed message to capture socket if any message // TODO what if the transformer modifies or destroys the original message ? ZMsg cpt = transformer.transform(msg, splug, Plug.CAPTURE); // boolean destroy = !msg.equals(cpt); // TODO ?? which one boolean destroy = msg != cpt; success = cpt.send(capture, destroy); if (!success) { // not successful, but we can still try to send it to the destination } } ZMsg dst = transformer.transform(msg, splug, dplug); // we send the whole transformed message success = dst.send(destination); // finished msg.destroy(); return success; } } /** * A specialized transport for better transmission purposes * that will send each packets individually instead of the whole message. */ private static final class ZmqPump implements Pump { // transfers each message as a whole by sending each packet received to the capture socket @Override public boolean flow(Plug splug, Socket source, Socket capture, Plug dplug, Socket destination) { boolean rc; SocketBase src = source.base(); SocketBase dst = destination.base(); SocketBase cpt = capture == null ? null : capture.base(); // we transfer the whole message while (true) { // we read the packet Msg msg = src.recv(0); if (msg == null) { return false; } long more = src.getSocketOpt(zmq.ZMQ.ZMQ_RCVMORE); if (more < 0) { return false; } // Copy message to capture socket if any packet if (cpt != null) { Msg ctrl = new Msg(msg); rc = cpt.send(ctrl, more > 0 ? zmq.ZMQ.ZMQ_SNDMORE : 0); if (!rc) { // not successful, but we can still try to send it to the destination } } // we send the packet rc = dst.send(msg, more > 0 ? zmq.ZMQ.ZMQ_SNDMORE : 0); if (!rc) { return false; } if (more == 0) { break; } } return true; } } } jeromq-0.3.5/src/main/java/org/zeromq/ZStar.java000066400000000000000000000504121255150477200214740ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import java.io.IOException; import java.nio.channels.Selector; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.LockSupport; import org.zeromq.ZMQ.Socket; import org.zeromq.ZThread.IAttachedRunnable; /** * First implementation for the base of a remotely controlled background service for 0MQ. * *

* A side or endpoint designates the same thing: the thread where lives one of the two parts of the system. *
* A {@link ZStar Star} has 2 sides (with a trial to use theater terms for fun (: and hopefully clarity :) *
* - the Corbeille side, or control side *
* This is where one can {@link ZAgent#send(ZMsg) send} and {@link ZAgent#recv() receive} control messages to the underneath star via the ZStar agent. *
* The ZStar lives on this side and is a way to safely communicate with the distant provided star. *
* Note: Corbeille is a french word designing the most privileged places in the theater where the King was standing, * 1st floor, just above the orchestra (Wikipedia...). * *

* - the Plateau side, or background side where all the performances are made by the provided star. *
* The provided star is living on the Plateau. *
* The Plateau is made of the Stage where effective acting takes place and of the Wings * where the provided star can perform control decisions to stop or continue the acting. *
* From this side, the work is done via callbacks using the template-method pattern, applied with interfaces (?) *

* Communication between the 2 sides is ensured by {@link #pipe() pipes} that SHALL NEVER be mixed between background and control sides. *
* Instead, each side use its own pipe to communicate with the other one, transmitting only 0MQ messages. * The main purpose of this class is to ease this separation and to provide contracts, responsibilities and action levers for each side. *
* For example, instead of using pipe() which is useful to have more control, fast users would want to call {@link #agent()} to get the agent * or directly call {@link #send(ZMsg)} or {@link #recv()} from the ZStar as the ZStar is itself an agent! *

* The ZStar takes care of the establishment of the background processing, calling the provided star * at appropriate times. It can also manage the {@link ZAgent#sign() exited} state on the control side, * if providing a non-null "Mot de la Fin". *
* It also takes care of the closing of sockets and context if it had to create one. *

* A {@link Star star} is basically a contract interface that anyone who uses this ZStar to create a background service SHALL comply to.
*

* PS: Je sais qu'il y a une différence entre acteur et comédien :) * PPS: I know nothing about theater! *

* For an example of code, please refer to the {@link ZActor} source code. * */ // remote controlled background message processing API for 0MQ. public class ZStar implements ZAgent { /** * Contract interface when acting in plain sight. */ // contract interface for acting with the spot lights on public static interface Star { /** * Called when the star is in the wings.
* Hint: Can be used to initialize the service, or ...
* Key point: no loop has started already. */ void prepare(); /** * Called when the star in on stage, just before acting.
* Hint: Can be used to poll events or get input/events from other sources, or ...
* Key point: a loop just started. * * @return the number of events to process */ int breathe(); /** * Where acting takes place ...
* Hint: Can be used to process the events or input acquired from the previous step, or ...
* Key point: in the middle of a loop.
* Decision: to act on the next loop or not * * @param events the number of events to process * @return true to continue till the end of the act, false to stop loopS here. */ boolean act(int events); /** * Called as an interval between each act.
* Hint: Can be used to perform decisions to continue next loop or not, or to send computed data to outputs, or ...
* Key point: at the end of a loop.
* Decision: to act on the next loop or not * * @return true to continue acting, false to stop loopS here. */ boolean entract(); /** * Does the star want to renew for a new performance ? * Hint: Can be used to perform decisions to continue looping or not, or to send computed data to outputs, or ...
* Key point: the inner looping mechanism just ended
* Decision: to exit or not * * @return true to restart acting, false to leave here */ boolean renews(); } /** * Utility class with callback for when the Star has finished its performances. */ public static interface TimeTaker { /** * Called when the show is finished but no cleaning is still done. * Useful to make the background thread wait a little bit, for example. * * @param ctx the shadow context */ void party(ZContext ctx); } // party time easily done. Wait for the specified amount of time public static void party(long time, TimeUnit unit) { LockSupport.parkNanos(TimeUnit.NANOSECONDS.convert(time, unit)); } // contract for a creator of stars public static interface Fortune extends TimeTaker { /** * This is the grand premiere! * Called when the star enters the plateau. * The show is about to begin. Inform the public about that. * Called before the creation of the first star and its sockets * * @param mic the pipe to the Corbeille side * @param args the arguments passed as parameters of the star constructor * * @return the name of the upcoming performance. */ String premiere(Socket mic, Object[] args); /** * Creates a star. * * @param ctx the context used for the creation of the sockets * @param mic the pipe to the Corbeille side * @param sel the selector used for polling * @param count the number of times a star was created. * @param previous the previous star if any (null at the first creation) * @param args the arguments passed as parameters of the star constructor * * @return a new star is born! */ Star create(ZContext ctx, Socket mic, Selector sel, int count, Star previous, Object[] args); /** * The show is over. * Called when the show is over. * * @param mic the pipe to the Corbeille side * @return true to allow to spread the word and close all future communications */ boolean interview(Socket mic); } /** * Returns the Corbeille endpoint. * Can be used to send or receive control messages to the distant star via Backstage. * * @return the agent/mailbox used to send and receive control messages to and from the star. */ public ZAgent agent() { return agent; } /** * Creates a new ZStar. * * @param actor the creator of stars on the Plateau * @param lock the final word used to mark the end of the star. Null to disable this mechanism. * @param args the optional arguments that will be passed to the distant star */ public ZStar(Fortune actor, String lock, Object... args) { this(null, new VerySimpleSelectorCreator(), actor, lock, args); } /** * Creates a new ZStar. * * @param selector the creator of the selector used on the Plateau. * @param fortune the creator of stars on the Plateau * @param motdelafin the final word used to mark the end of the star. Null to disable this mechanism. * @param args the optional arguments that will be passed to the distant star */ public ZStar(SelectorCreator selector, Fortune fortune, String motdelafin, Object... args) { this(null, selector, fortune, motdelafin, args); } /** * Creates a new ZStar. * * @param context * the main context used. If null, a new context will be created * and closed at the stop of the operation. * If not null, it is the responsibility of the caller to close it. * * @param selector the creator of the selector used on the Plateau. * @param fortune the creator of stars on the Plateau * @param motdelafin the final word used to mark the end of the star. Null to disable this mechanism. * @param bags the optional arguments that will be passed to the distant star */ public ZStar(final ZContext context, final SelectorCreator selector, final Fortune fortune, String motdelafin, final Object[] bags) { super(); assert (fortune != null); // entering platform to load trucks // the story writer SelectorCreator feather = selector; if (selector == null) { // initialize selector feather = new VerySimpleSelectorCreator(); } // initialize the context ZContext chef = context; ZContext producer = null; if (chef == null) { // no context provided, create one chef = new ZContext(); // it will be destroyed, so this is the main context producer = chef; } // retrieve the last optional set and entourage given in input Set set = null; Entourage entourage = null; for (Object bag : bags) { if (bag instanceof Set) { set = (Set) bag; } if (bag instanceof Entourage) { entourage = (Entourage) bag; } } if (set == null) { set = new SimpleSet(); } final List train = new ArrayList(6 + bags.length); train.add(set); train.add(fortune); train.add(feather); train.add(producer); train.add(entourage); train.add(motdelafin); // 6 mandatory wagons train.addAll(Arrays.asList(bags)); // now going to the plateau Socket phone = ZThread.fork(chef, new Plateau(), train.toArray()); agent = agent(phone, motdelafin); } // communicating agent with the star for the Corbeille side private final ZAgent agent; /** * Creates a new agent for the star. * * This method is called in the constructor so don't rely on private members to do the job. * Apart from that, it is the last call so can be safely overridden from the ZStar point-of-view * BUT if you don't make it final, one of your subclass could make you misery... * * @param phone the socket used to communicate with the star * @param secret the specific keyword indicating the death of the star and locking the agent. Null to override the lock mechanism. * @return the newly created agent for the star. */ protected ZAgent agent(Socket phone, String secret) { return ZAgent.Creator.create(phone, secret); } // the plateau where the acting will take place (stage and backstage), or // the forked runnable containing the loop processing all messages in the background private static final class Plateau implements IAttachedRunnable { private static final AtomicInteger shows = new AtomicInteger(); // id if unnamed private final int number = shows.incrementAndGet(); @Override public void run(final Object[] train, final ZContext chef, final Socket mic) { final int mandat = 6; // end of a trip can be a bit messy... Fortune star = (Fortune) train[1]; final Entourage entourage = (Entourage) train[4]; final ZContext producer = (ZContext) train[3]; final SelectorCreator feather = (SelectorCreator) train[2]; final Set set = (Set) train[0]; // the word informing the world that the plateau is closed and the star vanished final String gossip = (String) train[5]; // prune our mandatory transit variables from the arguments final Object[] bags = new Object[train.length - mandat]; System.arraycopy(train, mandat, bags, 0, bags.length); // leaving unloaded platform if (entourage != null) { entourage.breakaleg(chef, star, mic, bags); } Selector story = null; // now entering artistic zone try { // create the selector used for polling operations story = feather.create(); // Premiere ! String name = star.premiere(mic, bags); // put the name of the performance on the front door with lightnings set.lights(name, number); // star is entering the wings showMustGoOn(chef, set, story, mic, star, bags); // star is leaving the plateau } catch (IOException e) { // Who stole the story? There is no play if there is no story! C'est un scandale! e.printStackTrace(); // TODO enhance error } finally { // star is interviewed about this event boolean tell = star.interview(mic); if (tell && gossip != null) { // inform the Corbeille side of the future closing of the plateau and the vanishing of the star mic.send(gossip); } // we are not in a hurry at this point when cleaning up the remains of a good show ... star.party(chef); star = null; if (entourage != null) { entourage.party(chef); } // Sober again ... // show is over, time to close chef.close(); if (producer != null) { // this is a self-generated context, destroy it producer.close(); } try { feather.destroy(story); } catch (IOException e) { // really ? e.printStackTrace(); } } } /******************************************************************************/ /* TAP TAP TAP | | TAP | | TAP | | TAP | | | | | | | | | | | | | | | | | | | |*/ /******************************************************************************/ // starts the performance private void showMustGoOn(final ZContext chef, final Set set, final Selector story, final Socket phone, final Fortune fortune, final Object[] bags) { int shows = 0; /** on the spot lights, the star in only an actor **/ Star actor = null; /** double-while-loop enables the restarting of a new star for the same acting on the same stage **/ /// so existing sockets can be closed and recreated in order to perform a cold restart or a stop **/ do { actor = fortune.create(chef, phone, story, shows++, actor, bags); /** a new star is born! And an acting one! **/ actor.prepare(); /** actor is leaving the wings **/ while (!set.fire()) { /** actor decides when the act will begin **/ int events = actor.breathe(); /** perform a new act of the show **/ if (!actor.act(events)) { // Context has been shut down break; } /** end of the act, back to the wings **/ if (!actor.entract()) { // star has decided to stop acting break; } } } while (actor.renews()); // star is leaving the Plateau and the show } /******************************************************************************/ /* | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |*/ /******************************************************************************/ // NB: never use green color on the stage floor of a french theater. Or something bad will happen... } @Override public ZMsg recv() { return agent.recv(); } @Override public ZMsg recv(boolean wait) { return agent.recv(wait); } @Override public boolean send(ZMsg message) { return agent.send(message); } @Override public boolean send(ZMsg msg, boolean destroy) { return agent.send(msg, destroy); } @Override public boolean send(String word) { return agent.send(word); } @Override public boolean send(String word, boolean more) { return agent.send(word, more); } @Override public Socket pipe() { return agent.pipe(); } @Override public boolean sign() { return agent.sign(); } @Override public void nova() { agent.nova(); } public static interface Set { /** * Puts the performance name on the front door with big lights. * @param name the name of the performance. * @param id the performance number. */ void lights(String name, int id); /** * Is the set on fire ? * @return true if it is time to leave the place. */ boolean fire(); } public static class SimpleSet implements Set { @Override public boolean fire() { return Thread.currentThread().isInterrupted(); } @Override public void lights(String name, int id) { if (name == null) { name = createDefaultName("Star-%d", id); } Thread.currentThread().setName(name); } public static String createDefaultName(final String format, final int id) { return String.format(format, id); } } /** * Utility class with calls surrounding the execution of the Star. */ public static interface Entourage extends TimeTaker { /** * Called when the show is about to start. * Can be a useful point in the whole process from time to time. * * @param ctx the context provided in the creation step * @param fortune the creator of stars * @param phone the socket used to communicate with the Agent * @param bags the optional arguments that were passed at the creation */ void breakaleg(ZContext ctx, Fortune fortune, Socket phone, Object[] bags); // well ... } } jeromq-0.3.5/src/main/java/org/zeromq/ZThread.java000066400000000000000000000072451255150477200220000ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import org.zeromq.ZMQ.Socket; public class ZThread { private ZThread() { } public interface IAttachedRunnable { public void run(Object[] args, ZContext ctx, Socket pipe); } public interface IDetachedRunnable { public void run(Object[] args); } private static class ShimThread extends Thread { private ZContext ctx; private IAttachedRunnable attachedRunnable; private IDetachedRunnable detachedRunnable; private Object[] args; private Socket pipe; protected ShimThread(ZContext ctx, IAttachedRunnable runnable, Object [] args, Socket pipe) { assert (ctx != null); assert (pipe != null); assert (runnable != null); this.ctx = ctx; this.attachedRunnable = runnable; this.args = args; this.pipe = pipe; } public ShimThread(IDetachedRunnable runnable, Object[] args) { assert (runnable != null); this.detachedRunnable = runnable; this.args = args; } @Override public void run() { if (attachedRunnable != null) { attachedRunnable.run(args, ctx, pipe); ctx.destroy(); } else { detachedRunnable.run(args); } } } // -------------------------------------------------------------------------- // Create a detached thread. A detached thread operates autonomously // and is used to simulate a separate process. It gets no ctx, and no // pipe. public static void start(IDetachedRunnable runnable, Object ... args) { // Prepare child thread Thread shim = new ShimThread(runnable, args); shim.setDaemon(true); shim.start(); } // -------------------------------------------------------------------------- // Create an attached thread. An attached thread gets a ctx and a PAIR // pipe back to its parent. It must monitor its pipe, and exit if the // pipe becomes unreadable. Returns pipe, or null if there was an error. public static Socket fork(ZContext ctx, IAttachedRunnable runnable, Object ... args) { Socket pipe = ctx.createSocket(ZMQ.PAIR); if (pipe != null) { pipe.bind(String.format("inproc://zctx-pipe-%d", pipe.hashCode())); } else { return null; } // Connect child pipe to our pipe ZContext ccontext = ZContext.shadow(ctx); Socket cpipe = ccontext.createSocket(ZMQ.PAIR); if (cpipe == null) { return null; } cpipe.connect(String.format("inproc://zctx-pipe-%d", pipe.hashCode())); // Prepare child thread Thread shim = new ShimThread(ccontext, runnable, args, cpipe); shim.start(); return pipe; } } jeromq-0.3.5/src/main/java/zmq/000077500000000000000000000000001255150477200162675ustar00rootroot00000000000000jeromq-0.3.5/src/main/java/zmq/Address.java000066400000000000000000000055221255150477200205230ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.net.Inet6Address; import java.net.InetSocketAddress; import java.net.SocketAddress; public class Address { public interface IZAddress { String toString(); void resolve(String name, boolean ip4only); SocketAddress address(); }; private final String protocol; private final String address; private final boolean ipv4only; private IZAddress resolved; public Address(final String protocol, final String address, final boolean ipv4only) { this.protocol = protocol; this.address = address; this.ipv4only = ipv4only; resolved = null; } public Address(SocketAddress socketAddress) { InetSocketAddress sockAddr = (InetSocketAddress) socketAddress; this.address = sockAddr.getAddress().getHostAddress() + ":" + sockAddr.getPort(); protocol = "tcp"; resolved = null; ipv4only = !(sockAddr.getAddress() instanceof Inet6Address); } @Override public String toString() { if (protocol.equals("tcp") && isResolved()) { return resolved.toString(); } else if (protocol.equals("ipc") && isResolved()) { return resolved.toString(); } else if (!protocol.isEmpty() && !address.isEmpty()) { return protocol + "://" + address; } else { return ""; } } public String protocol() { return protocol; } public String address() { return address; } public IZAddress resolved() { return resolved; } public boolean isResolved() { return resolved != null; } public boolean resolve() { if (protocol.equals("tcp")) { resolved = new TcpAddress(); resolved.resolve(address, ipv4only); return true; } else if (protocol.equals("ipc")) { resolved = new IpcAddress(); resolved.resolve(address, true); return true; } else { return false; } } } jeromq-0.3.5/src/main/java/zmq/Blob.java000066400000000000000000000031141255150477200200070ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.util.Arrays; public class Blob { private final byte[] buf; private Blob(byte[] data) { buf = data; } public static Blob createBlob(byte[] data, boolean copy) { if (copy) { byte[] b = new byte[data.length]; System.arraycopy(data, 0, b, 0, data.length); return new Blob(b); } else { return new Blob(data); } } public int size() { return buf.length; } public byte[] data() { return buf; } @Override public boolean equals(Object t) { if (t instanceof Blob) { return Arrays.equals(buf, ((Blob) t).buf); } return false; } @Override public int hashCode() { return Arrays.hashCode(buf); } } jeromq-0.3.5/src/main/java/zmq/Clock.java000066400000000000000000000027341255150477200201730ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; public class Clock { // TSC timestamp of when last time measurement was made. // private long last_tsc; // Physical time corresponding to the TSC above (in milliseconds). // private long last_time; private Clock() { } // High precision timestamp. public static long nowUS() { return System.nanoTime() * 1000L; } // Low precision timestamp. In tight loops generating it can be // 10 to 100 times faster than the high precision timestamp. public static long nowMS() { return System.currentTimeMillis(); } // CPU's timestamp counter. Returns 0 if it's not available. public static long rdtsc() { return 0; } } jeromq-0.3.5/src/main/java/zmq/Command.java000066400000000000000000000066111255150477200205140ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; // This structure defines the commands that can be sent between threads. class Command { // Object to process the command. private final ZObject destination; private final Type type; public enum Type { // Sent to I/O thread to let it know that it should // terminate itself. STOP, // Sent to I/O object to make it register with its I/O thread PLUG, // Sent to socket to let it know about the newly created object. OWN, // Attach the engine to the session. If engine is NULL, it informs // session that the connection have failed. ATTACH, // Sent from session to socket to establish pipe(s) between them. // Caller have used inc_seqnum beforehand sending the command. BIND, // Sent by pipe writer to inform dormant pipe reader that there // are messages in the pipe. ACTIVATE_READ, // Sent by pipe reader to inform pipe writer about how many // messages it has read so far. ACTIVATE_WRITE, // Sent by pipe reader to writer after creating a new inpipe. // The parameter is actually of type pipe_t::upipe_t, however, // its definition is private so we'll have to do with void*. HICCUP, // Sent by pipe reader to pipe writer to ask it to terminate // its end of the pipe. PIPE_TERM, // Pipe writer acknowledges pipe_term command. PIPE_TERM_ACK, // Sent by I/O object ot the socket to request the shutdown of // the I/O object. TERM_REQ, // Sent by socket to I/O object to start its shutdown. TERM, // Sent by I/O object to the socket to acknowledge it has // shut down. TERM_ACK, // Transfers the ownership of the closed socket // to the reaper thread. REAP, // Closed socket notifies the reaper that it's already deallocated. REAPED, // Sent by reaper thread to the term thread when all the sockets // are successfully deallocated. DONE } Object arg; public Command(ZObject destination, Type type) { this(destination, type, null); } public Command(ZObject destination, Type type, Object arg) { this.destination = destination; this.type = type; this.arg = arg; } public ZObject destination() { return destination; } public Type type() { return type; } @Override public String toString() { return super.toString() + "[" + type + ", " + destination + "]"; } } jeromq-0.3.5/src/main/java/zmq/Config.java000066400000000000000000000064731255150477200203510ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; public enum Config { // Number of new messages in message pipe needed to trigger new memory // allocation. Setting this parameter to 256 decreases the impact of // memory allocation by approximately 99.6% MESSAGE_PIPE_GRANULARITY (256), // Commands in pipe per allocation event. COMMAND_PIPE_GRANULARITY (16), // Determines how often does socket poll for new commands when it // still has unprocessed messages to handle. Thus, if it is set to 100, // socket will process 100 inbound messages before doing the poll. // If there are no unprocessed messages available, poll is done // immediately. Decreasing the value trades overall latency for more // real-time behaviour (less latency peaks). INBOUND_POLL_RATE (100), // Maximal batching size for engines with receiving functionality. // So, if there are 10 messages that fit into the batch size, all of // them may be read by a single 'recv' system call, thus avoiding // unnecessary network stack traversals. IN_BATCH_SIZE (8192), // Maximal batching size for engines with sending functionality. // So, if there are 10 messages that fit into the batch size, all of // them may be written by a single 'send' system call, thus avoiding // unnecessary network stack traversals. OUT_BATCH_SIZE (8192), // Maximal delta between high and low watermark. MAX_WM_DELTA (1024), // Maximum number of events the I/O thread can process in one go. MAX_IO_EVENTS (256), // Maximal delay to process command in API thread (in CPU ticks). // 3,000,000 ticks equals to 1 - 2 milliseconds on current CPUs. // Note that delay is only applied when there is continuous stream of // messages to process. If not so, commands are processed immediately. MAX_COMMAND_DELAY (3000000), // Low-precision clock precision in CPU ticks. 1ms. Value of 1000000 // should be OK for CPU frequencies above 1GHz. If should work // reasonably well for CPU frequencies above 500MHz. For lower CPU // frequencies you may consider lowering this value to get best // possible latencies. CLOCK_PRECISION (1000000), // Maximum transport data unit size for PGM (TPDU). PGM_MAX_TPDU (1500), // On some OSes the signaler has to be emulated using a TCP // connection. In such cases following port is used. SIGNALER_PORT (5905); private final int value; private Config(int value) { this.value = value; } public int getValue() { return value; } } jeromq-0.3.5/src/main/java/zmq/Ctx.java000066400000000000000000000336101255150477200176730ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.io.IOException; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; //Context object encapsulates all the global state associated with // the library. public class Ctx { // Information associated with inproc endpoint. Note that endpoint options // are registered as well so that the peer can access them without a need // for synchronisation, handshaking or similar. static class Endpoint { public final SocketBase socket; public final Options options; public Endpoint(SocketBase socket, Options options) { this.socket = socket; this.options = options; } } // Used to check whether the object is a context. private int tag; // Sockets belonging to this context. We need the list so that // we can notify the sockets when zmq_term() is called. The sockets // will return ETERM then. private final List sockets; // List of unused thread slots. private final Deque emptySlots; // If true, init has been called but no socket has been created // yet. Launching of I/O threads is delayed. private AtomicBoolean starting = new AtomicBoolean(true); // If true, zmq_term was already called. private boolean terminating; // Synchronisation of accesses to global slot-related data: // sockets, emptySlots, terminating. It also synchronises // access to zombie sockets as such (as opposed to slots) and provides // a memory barrier to ensure that all CPU cores see the same data. private final Lock slotSync; // The reaper thread. private Reaper reaper; // I/O threads. private final List ioThreads; // Array of pointers to mailboxes for both application and I/O threads. private int slotCount; private Mailbox[] slots; // Mailbox for zmq_term thread. private final Mailbox termMailbox; // List of inproc endpoints within this context. private final Map endpoints; // Synchronisation of access to the list of inproc endpoints. private final Lock endpointsSync; // Maximum socket ID. private static AtomicInteger maxSocketId = new AtomicInteger(0); // Maximum number of sockets that can be opened at the same time. private int maxSockets; // Number of I/O threads to launch. private int ioThreadCount; // Does context wait (possibly forever) on termination? private boolean blocky; // Synchronisation of access to context options. private final Lock optSync; public static final int TERM_TID = 0; public static final int REAPER_TID = 1; public Ctx() { tag = 0xabadcafe; terminating = false; reaper = null; slotCount = 0; slots = null; maxSockets = ZMQ.ZMQ_MAX_SOCKETS_DFLT; ioThreadCount = ZMQ.ZMQ_IO_THREADS_DFLT; blocky = true; slotSync = new ReentrantLock(); endpointsSync = new ReentrantLock(); optSync = new ReentrantLock(); termMailbox = new Mailbox("terminater"); emptySlots = new ArrayDeque(); ioThreads = new ArrayList(); sockets = new ArrayList(); endpoints = new HashMap(); } private void destroy() throws IOException { for (IOThread it : ioThreads) { it.stop(); } for (IOThread it : ioThreads) { it.close(); } if (reaper != null) { reaper.close(); } termMailbox.close(); tag = 0xdeadbeef; } // Returns false if object is not a context. public boolean checkTag() { return tag == 0xabadcafe; } // This function is called when user invokes zmq_term. If there are // no more sockets open it'll cause all the infrastructure to be shut // down. If there are open sockets still, the deallocation happens // after the last one is closed. public void terminate() { tag = 0xdeadbeef; if (!starting.get()) { slotSync.lock(); try { // Check whether termination was already underway, but interrupted and now // restarted. boolean restarted = terminating; terminating = true; // First attempt to terminate the context. if (!restarted) { // First send stop command to sockets so that any blocking calls // can be interrupted. If there are no sockets we can ask reaper // thread to stop. for (SocketBase socket : sockets) { socket.stop(); } if (sockets.isEmpty()) { reaper.stop(); } } } finally { slotSync.unlock(); } // Wait till reaper thread closes all the sockets. Command cmd = termMailbox.recv(-1); if (cmd == null) { throw new IllegalStateException(); } assert (cmd.type() == Command.Type.DONE); slotSync.lock(); try { assert (sockets.isEmpty()); } finally { slotSync.unlock(); } } // Deallocate the resources. try { destroy(); } catch (IOException e) { throw new RuntimeException(e); } } public boolean set(int option, int optval) { if (option == ZMQ.ZMQ_MAX_SOCKETS && optval >= 1) { optSync.lock(); try { maxSockets = optval; } finally { optSync.unlock(); } } else if (option == ZMQ.ZMQ_IO_THREADS && optval >= 0) { optSync.lock(); try { ioThreadCount = optval; } finally { optSync.unlock(); } } else if (option == ZMQ.ZMQ_BLOCKY && optval >= 0) { optSync.lock(); try { blocky = (optval != 0); } finally { optSync.unlock(); } } else { return false; } return true; } public int get(int option) { int rc = 0; if (option == ZMQ.ZMQ_MAX_SOCKETS) { rc = maxSockets; } else if (option == ZMQ.ZMQ_IO_THREADS) { rc = ioThreadCount; } else if (option == ZMQ.ZMQ_BLOCKY) { rc = blocky ? 1 : 0; } else { throw new IllegalArgumentException("option = " + option); } return rc; } public SocketBase createSocket(int type) { SocketBase s = null; slotSync.lock(); try { if (starting.compareAndSet(true, false)) { // Initialize the array of mailboxes. Additional three slots are for // zmq_term thread and reaper thread. int mazmq; int ios; optSync.lock(); try { mazmq = maxSockets; ios = ioThreadCount; } finally { optSync.unlock(); } slotCount = mazmq + ios + 2; slots = new Mailbox[slotCount]; //alloc_assert (slots); // Initialize the infrastructure for zmq_term thread. slots[TERM_TID] = termMailbox; // Create the reaper thread. reaper = new Reaper(this, REAPER_TID); //alloc_assert (reaper); slots[REAPER_TID] = reaper.getMailbox(); reaper.start(); // Create I/O thread objects and launch them. for (int i = 2; i != ios + 2; i++) { IOThread ioThread = new IOThread(this, i); //alloc_assert (io_thread); ioThreads.add(ioThread); slots[i] = ioThread.getMailbox(); ioThread.start(); } // In the unused part of the slot array, create a list of empty slots. for (int i = (int) slotCount - 1; i >= (int) ios + 2; i--) { emptySlots.add(i); slots[i] = null; } } // Once zmq_term() was called, we can't create new sockets. if (terminating) { throw new ZError.CtxTerminatedException(); } // If maxSockets limit was reached, return error. if (emptySlots.isEmpty()) { throw new IllegalStateException("EMFILE"); } // Choose a slot for the socket. int slot = emptySlots.pollLast(); // Generate new unique socket ID. int sid = maxSocketId.incrementAndGet(); // Create the socket and register its mailbox. s = SocketBase.create(type, this, slot, sid); if (s == null) { emptySlots.addLast(slot); return null; } sockets.add(s); slots[slot] = s.getMailbox(); } finally { slotSync.unlock(); } return s; } public void destroySocket(SocketBase socket) { slotSync.lock(); // Free the associated thread slot. try { int tid = socket.getTid(); emptySlots.add(tid); slots[tid] = null; // Remove the socket from the list of sockets. sockets.remove(socket); // If zmq_term() was already called and there are no more socket // we can ask reaper thread to terminate. if (terminating && sockets.isEmpty()) { reaper.stop(); } } finally { slotSync.unlock(); } } // Returns reaper thread object. ZObject getReaper() { return reaper; } // Send command to the destination thread. void sendCommand(int tid, final Command command) { slots[tid].send(command); } // Returns the I/O thread that is the least busy at the moment. // Affinity specifies which I/O threads are eligible (0 = all). // Returns NULL if no I/O thread is available. IOThread chooseIoThread(long affinity) { if (ioThreads.isEmpty()) { return null; } // Find the I/O thread with minimum load. int minLoad = -1; IOThread selectedIoThread = null; for (int i = 0; i != ioThreads.size(); i++) { if (affinity == 0 || (affinity & (1L << i)) > 0) { int load = ioThreads.get(i).getLoad(); if (selectedIoThread == null || load < minLoad) { minLoad = load; selectedIoThread = ioThreads.get(i); } } } return selectedIoThread; } // Management of inproc endpoints. boolean registerEndpoint(String addr, Endpoint endpoint) { endpointsSync.lock(); Endpoint inserted = null; try { inserted = endpoints.put(addr, endpoint); } finally { endpointsSync.unlock(); } if (inserted != null) { return false; } return true; } void unregisterEndpoints(SocketBase socket) { endpointsSync.lock(); try { Iterator> it = endpoints.entrySet().iterator(); while (it.hasNext()) { Entry e = it.next(); if (e.getValue().socket == socket) { it.remove(); } } } finally { endpointsSync.unlock(); } } Endpoint findEndpoint(String addr) { Endpoint endpoint = null; endpointsSync.lock(); try { endpoint = endpoints.get(addr); if (endpoint == null) { //ZError.errno(ZError.ECONNREFUSED); return new Endpoint(null, new Options()); } // Increment the command sequence number of the peer so that it won't // get deallocated until "bind" command is issued by the caller. // The subsequent 'bind' has to be called with inc_seqnum parameter // set to false, so that the seqnum isn't incremented twice. endpoint.socket.incSeqnum(); } finally { endpointsSync.unlock(); } return endpoint; } } jeromq-0.3.5/src/main/java/zmq/Dealer.java000066400000000000000000000072361255150477200203360ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; public class Dealer extends SocketBase { public static class DealerSession extends SessionBase { public DealerSession(IOThread ioThread, boolean connect, SocketBase socket, final Options options, final Address addr) { super(ioThread, connect, socket, options, addr); } } // Messages are fair-queued from inbound pipes. And load-balanced to // the outbound pipes. private final FQ fq; private final LB lb; // Have we prefetched a message. private boolean prefetched; private Msg prefetchedMsg; // Holds the prefetched message. public Dealer(Ctx parent, int tid, int sid) { super(parent, tid, sid); prefetched = false; options.type = ZMQ.ZMQ_DEALER; fq = new FQ(); lb = new LB(); // TODO: Uncomment the following line when DEALER will become true DEALER // rather than generic dealer socket. // If the socket is closing we can drop all the outbound requests. There'll // be noone to receive the replies anyway. // options.delayOnClose = false; options.recvIdentity = true; } @Override protected void xattachPipe(Pipe pipe, boolean icanhasall) { assert (pipe != null); fq.attach(pipe); lb.attach(pipe); } @Override protected boolean xsend(Msg msg) { return lb.send(msg, errno); } @Override protected Msg xrecv() { return xxrecv(); } private Msg xxrecv() { Msg msg = null; // If there is a prefetched message, return it. if (prefetched) { msg = prefetchedMsg; prefetched = false; prefetchedMsg = null; return msg; } // DEALER socket doesn't use identities. We can safely drop it and while (true) { msg = fq.recv(errno); if (msg == null) { return null; } if ((msg.flags() & Msg.IDENTITY) == 0) { break; } } return msg; } @Override protected boolean xhasIn() { // We may already have a message pre-fetched. if (prefetched) { return true; } // Try to read the next message to the pre-fetch buffer. prefetchedMsg = xxrecv(); if (prefetchedMsg == null) { return false; } prefetched = true; return true; } @Override protected boolean xhasOut() { return lb.hasOut(); } @Override protected void xreadActivated(Pipe pipe) { fq.activated(pipe); } @Override protected void xwriteActivated(Pipe pipe) { lb.activated(pipe); } @Override protected void xpipeTerminated(Pipe pipe) { fq.terminated(pipe); lb.terminated(pipe); } } jeromq-0.3.5/src/main/java/zmq/Decoder.java000066400000000000000000000132031255150477200204760ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.nio.ByteBuffer; // Helper base class for decoders that know the amount of data to read // in advance at any moment. Knowing the amount in advance is a property // of the protocol used. 0MQ framing protocol is based size-prefixed // paradigm, which qualifies it to be parsed by this class. // On the other hand, XML-based transports (like XMPP or SOAP) don't allow // for knowing the size of data to read in advance and should use different // decoding algorithms. // // This class implements the state machine that parses the incoming buffer. // Derived class should implement individual state machine actions. public class Decoder extends DecoderBase { private static final int ONE_BYTE_SIZE_READY = 0; private static final int EIGHT_BYTE_SIZE_READY = 1; private static final int FLAGS_READY = 2; private static final int MESSAGE_READY = 3; private final byte[] tmpbuf; private Msg inProgress; private final long maxmsgsize; private IMsgSink msgSink; public Decoder(int bufsize, long maxmsgsize) { super(bufsize); this.maxmsgsize = maxmsgsize; tmpbuf = new byte[8]; // At the beginning, read one byte and go to oneByteSizeReady state. nextStep(tmpbuf, 1, ONE_BYTE_SIZE_READY); } // Set the receiver of decoded messages. @Override public void setMsgSink(IMsgSink msgSink) { this.msgSink = msgSink; } @Override protected boolean next() { switch(state()) { case ONE_BYTE_SIZE_READY: return oneByteSizeReady(); case EIGHT_BYTE_SIZE_READY: return eightByteSizeReady(); case FLAGS_READY: return flagsReady(); case MESSAGE_READY: return messageReady(); default: return false; } } private boolean oneByteSizeReady() { // First byte of size is read. If it is 0xff(-1 for java byte) read 8-byte size. // Otherwise allocate the buffer for message data and read the // message data into it. byte first = tmpbuf[0]; if (first == -1) { nextStep(tmpbuf, 8, EIGHT_BYTE_SIZE_READY); } else { // There has to be at least one byte (the flags) in the message). if (first == 0) { decodingError(); return false; } int size = (int) first; if (size < 0) { size = (0xFF) & first; } // inProgress is initialised at this point so in theory we should // close it before calling msgInitWithSize, however, it's a 0-byte // message and thus we can treat it as uninitialised... if (maxmsgsize >= 0 && (long) (size - 1) > maxmsgsize) { decodingError(); return false; } else { inProgress = new Msg(size - 1); } nextStep(tmpbuf, 1, FLAGS_READY); } return true; } private boolean eightByteSizeReady() { // 8-byte payload length is read. Allocate the buffer // for message body and read the message data into it. final long payloadLength = ByteBuffer.wrap(tmpbuf).getLong(); // There has to be at least one byte (the flags) in the message). if (payloadLength <= 0) { decodingError(); return false; } // Message size must not exceed the maximum allowed size. if (maxmsgsize >= 0 && payloadLength - 1 > maxmsgsize) { decodingError(); return false; } // Message size must fit within range of size_t data type. if (payloadLength - 1 > Integer.MAX_VALUE) { decodingError(); return false; } final int msgSize = (int) (payloadLength - 1); // inProgress is initialized at this point so in theory we should // close it before calling init_size, however, it's a 0-byte // message and thus we can treat it as uninitialized... inProgress = new Msg(msgSize); nextStep(tmpbuf, 1, FLAGS_READY); return true; } private boolean flagsReady() { // Store the flags from the wire into the message structure. int first = tmpbuf[0]; inProgress.setFlags(first & Msg.MORE); nextStep(inProgress, MESSAGE_READY); return true; } private boolean messageReady() { // Message is completely read. Push it further and start reading // new message. (inProgress is a 0-byte message after this point.) if (msgSink == null) { return false; } int rc = msgSink.pushMsg(inProgress); if (rc != 0) { return false; } nextStep(tmpbuf, 1, ONE_BYTE_SIZE_READY); return true; } } jeromq-0.3.5/src/main/java/zmq/DecoderBase.java000066400000000000000000000131241255150477200212730ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.nio.ByteBuffer; // Helper base class for decoders that know the amount of data to read // in advance at any moment. Knowing the amount in advance is a property // of the protocol used. 0MQ framing protocol is based size-prefixed // paradigm, which qualifies it to be parsed by this class. // On the other hand, XML-based transports (like XMPP or SOAP) don't allow // for knowing the size of data to read in advance and should use different // decoding algorithms. // // This class implements the state machine that parses the incoming buffer. // Derived class should implement individual state machine actions. public abstract class DecoderBase implements IDecoder { // Where to store the read data. private byte[] readBuf; private int readPos; // How much data to read before taking next step. protected int toRead; // The buffer for data to decode. private int bufsize; private ByteBuffer buf; private int state; boolean zeroCopy; public DecoderBase(int bufsize) { state = -1; toRead = 0; this.bufsize = bufsize; if (bufsize > 0) { buf = ByteBuffer.allocateDirect(bufsize); } readBuf = null; zeroCopy = false; } // Returns a buffer to be filled with binary data. public ByteBuffer getBuffer() { // If we are expected to read large message, we'll opt for zero- // copy, i.e. we'll ask caller to fill the data directly to the // message. Note that subsequent read(s) are non-blocking, thus // each single read reads at most SO_RCVBUF bytes at once not // depending on how large is the chunk returned from here. // As a consequence, large messages being received won't block // other engines running in the same I/O thread for excessive // amounts of time. ByteBuffer b; if (toRead >= bufsize) { zeroCopy = true; b = ByteBuffer.wrap(readBuf); b.position(readPos); } else { zeroCopy = false; b = buf; b.clear(); } return b; } // Processes the data in the buffer previously allocated using // get_buffer function. size_ argument specifies nemuber of bytes // actually filled into the buffer. Function returns number of // bytes actually processed. public int processBuffer(ByteBuffer buf, int size) { // Check if we had an error in previous attempt. if (state() < 0) { return -1; } // In case of zero-copy simply adjust the pointers, no copying // is required. Also, run the state machine in case all the data // were processed. if (zeroCopy) { readPos += size; toRead -= size; while (toRead == 0) { if (!next()) { if (state() < 0) { return -1; } return size; } } return size; } int pos = 0; while (true) { // Try to get more space in the message to fill in. // If none is available, return. while (toRead == 0) { if (!next()) { if (state() < 0) { return -1; } return pos; } } // If there are no more data in the buffer, return. if (pos == size) { return pos; } // Copy the data from buffer to the message. int toCopy = Math.min(toRead, size - pos); buf.get(readBuf, readPos, toCopy); readPos += toCopy; pos += toCopy; toRead -= toCopy; } } protected void nextStep(Msg msg, int state) { nextStep(msg.data(), msg.size(), state); } protected void nextStep(byte[] buf, int toRead, int state) { readBuf = buf; readPos = 0; this.toRead = toRead; this.state = state; } protected int state() { return state; } protected void state(int state) { this.state = state; } protected void decodingError() { state(-1); } // Returns true if the decoder has been fed all required data // but cannot proceed with the next decoding step. // False is returned if the decoder has encountered an error. @Override public boolean stalled() { // Check whether there was decoding error. if (!next()) { return false; } while (toRead == 0) { if (!next()) { return next(); } } return false; } protected abstract boolean next(); } jeromq-0.3.5/src/main/java/zmq/Dist.java000066400000000000000000000136311255150477200200410ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.util.ArrayList; import java.util.List; class Dist { // List of outbound pipes. //typedef array_t pipes_t; private final List pipes; // Number of all the pipes to send the next message to. private int matching; // Number of active pipes. All the active pipes are located at the // beginning of the pipes array. These are the pipes the messages // can be sent to at the moment. private int active; // Number of pipes eligible for sending messages to. This includes all // the active pipes plus all the pipes that we can in theory send // messages to (the HWM is not yet reached), but sending a message // to them would result in partial message being delivered, ie. message // with initial parts missing. private int eligible; // True if last we are in the middle of a multipart message. private boolean more; public Dist() { matching = 0; active = 0; eligible = 0; more = false; pipes = new ArrayList(); } // Adds the pipe to the distributor object. public void attach(Pipe pipe) { // If we are in the middle of sending a message, we'll add new pipe // into the list of eligible pipes. Otherwise we add it to the list // of active pipes. if (more) { pipes.add(pipe); //pipes.swap (eligible, pipes.size() - 1); Utils.swap(pipes, eligible, pipes.size() - 1); eligible++; } else { pipes.add(pipe); //pipes.swap (active, pipes.size() - 1); Utils.swap(pipes, active, pipes.size() - 1); active++; eligible++; } } // Mark the pipe as matching. Subsequent call to sendToMatching // will send message also to this pipe. public void match(Pipe pipe) { int idx = pipes.indexOf(pipe); // If pipe is already matching do nothing. if (idx < matching) { return; } // If the pipe isn't eligible, ignore it. if (idx >= eligible) { return; } // Mark the pipe as matching. Utils.swap(pipes, idx, matching); matching++; } // Mark all pipes as non-matching. public void unmatch() { matching = 0; } // Removes the pipe from the distributor object. public void terminated(Pipe pipe) { // Remove the pipe from the list; adjust number of matching, active and/or // eligible pipes accordingly. if (pipes.indexOf(pipe) < matching) { Utils.swap(pipes, pipes.indexOf(pipe), matching - 1); matching--; } if (pipes.indexOf(pipe) < active) { Utils.swap(pipes, pipes.indexOf(pipe), active - 1); active--; } if (pipes.indexOf(pipe) < eligible) { Utils.swap(pipes, pipes.indexOf(pipe), eligible - 1); eligible--; } pipes.remove(pipe); } // Activates pipe that have previously reached high watermark. public void activated(Pipe pipe) { // Move the pipe from passive to eligible state. Utils.swap(pipes, pipes.indexOf(pipe), eligible); eligible++; // If there's no message being sent at the moment, move it to // the active state. if (!more) { Utils.swap(pipes, eligible - 1, active); active++; } } // Send the message to all the outbound pipes. public boolean sendToAll(Msg msg) { matching = active; return sendToMatching(msg); } // Send the message to the matching outbound pipes. public boolean sendToMatching(Msg msg) { // Is this end of a multipart message? boolean msgMore = msg.hasMore(); // Push the message to matching pipes. distribute(msg); // If mutlipart message is fully sent, activate all the eligible pipes. if (!msgMore) { active = eligible; } more = msgMore; return true; } // Put the message to all active pipes. private void distribute(Msg msg) { // If there are no matching pipes available, simply drop the message. if (matching == 0) { return; } for (int i = 0; i < matching; ++i) { if (!write(pipes.get(i), msg)) { --i; // Retry last write because index will have been swapped } } } public boolean hasOut() { return true; } // Write the message to the pipe. Make the pipe inactive if writing // fails. In such a case false is returned. private boolean write(Pipe pipe, Msg msg) { if (!pipe.write(msg)) { Utils.swap(pipes, pipes.indexOf(pipe), matching - 1); matching--; Utils.swap(pipes, pipes.indexOf(pipe), active - 1); active--; Utils.swap(pipes, active, eligible - 1); eligible--; return false; } if (!msg.hasMore()) { pipe.flush(); } return true; } } jeromq-0.3.5/src/main/java/zmq/Encoder.java000066400000000000000000000062341255150477200205160ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.nio.ByteBuffer; public class Encoder extends EncoderBase { private static final int SIZE_READY = 0; private static final int MESSAGE_READY = 1; private Msg inProgress; private final byte[] tmpbuf; private IMsgSource msgSource; public Encoder(int bufsize) { super(bufsize); tmpbuf = new byte[10]; // Write 0 bytes to the batch and go to messageReady state. nextStep((byte[]) null, 0, MESSAGE_READY, true); } @Override public void setMsgSource(IMsgSource msgSource) { this.msgSource = msgSource; } @Override protected boolean next() { switch(state()) { case SIZE_READY: return sizeReady(); case MESSAGE_READY: return messageReady(); default: return false; } } private boolean sizeReady() { // Write message body into the buffer. nextStep(inProgress.data(), inProgress.size(), MESSAGE_READY, !inProgress.hasMore()); return true; } private boolean messageReady() { // Destroy content of the old message. //inProgress.close (); // Read new message. If there is none, return false. // Note that new state is set only if write is successful. That way // unsuccessful write will cause retry on the next state machine // invocation. if (msgSource == null) { return false; } inProgress = msgSource.pullMsg(); if (inProgress == null) { return false; } // Get the message size. int size = inProgress.size(); // Account for the 'flags' byte. size++; // For messages less than 255 bytes long, write one byte of message size. // For longer messages write 0xff escape character followed by 8-byte // message size. In both cases 'flags' field follows. if (size < 255) { tmpbuf[0] = (byte) size; tmpbuf[1] = (byte) (inProgress.flags() & Msg.MORE); nextStep(tmpbuf, 2, SIZE_READY, false); } else { ByteBuffer b = ByteBuffer.wrap(tmpbuf); b.put((byte) 0xff); b.putLong(size); b.put((byte) (inProgress.flags() & Msg.MORE)); nextStep(tmpbuf, 10, SIZE_READY, false); } return true; } } jeromq-0.3.5/src/main/java/zmq/EncoderBase.java000066400000000000000000000130121255150477200213010ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public abstract class EncoderBase implements IEncoder { // Where to get the data to write from. private byte[] writeBuf; private FileChannel writeChannel; private int writePos; // Next step. If set to -1, it means that associated data stream // is dead. private int next; // If true, first byte of the message is being written. @SuppressWarnings("unused") private boolean beginning; // How much data to write before next step should be executed. private int toWrite; // The buffer for encoded data. private ByteBuffer buffer; private int bufferSize; private boolean error; protected EncoderBase(int bufferSize) { this.bufferSize = bufferSize; buffer = ByteBuffer.allocateDirect(bufferSize); error = false; } // The function returns a batch of binary data. The data // are filled to a supplied buffer. If no buffer is supplied (data_ // points to NULL) decoder object will provide buffer of its own. @Override public Transfer getData(ByteBuffer buffer) { if (buffer == null) { buffer = this.buffer; } buffer.clear(); while (buffer.hasRemaining()) { // If there are no more data to return, run the state machine. // If there are still no data, return what we already have // in the buffer. if (toWrite == 0) { // If we are to encode the beginning of a new message, // adjust the message offset. if (!next()) { break; } } // If there is file channel to send, // send current buffer and the channel together if (writeChannel != null) { buffer.flip(); Transfer t = new Transfer.FileChannelTransfer(buffer, writeChannel, (long) writePos, (long) toWrite); writePos = 0; toWrite = 0; return t; } // If there are no data in the buffer yet and we are able to // fill whole buffer in a single go, let's use zero-copy. // There's no disadvantage to it as we cannot stuck multiple // messages into the buffer anyway. Note that subsequent // write(s) are non-blocking, thus each single write writes // at most SO_SNDBUF bytes at once not depending on how large // is the chunk returned from here. // As a consequence, large messages being sent won't block // other engines running in the same I/O thread for excessive // amounts of time. if (this.buffer.position() == 0 && toWrite >= bufferSize) { Transfer t; ByteBuffer b = ByteBuffer.wrap(writeBuf); b.position(writePos); t = new Transfer.ByteBufferTransfer(b); writePos = 0; toWrite = 0; return t; } // Copy data to the buffer. If the buffer is full, return. int toCopy = Math.min(toWrite, buffer.remaining()); if (toCopy > 0) { buffer.put(writeBuf, writePos, toCopy); writePos += toCopy; toWrite -= toCopy; } } buffer.flip(); return new Transfer.ByteBufferTransfer(buffer); } @Override public boolean hasData() { return toWrite > 0; } protected int state() { return next; } protected void state(int state) { next = state; } protected void encodingError() { error = true; } public final boolean isError() { return error; } protected abstract boolean next(); protected void nextStep(Msg msg, int state, boolean beginning) { if (msg == null) { nextStep(null, 0, state, beginning); } else { nextStep(msg.data(), msg.size(), state, beginning); } } protected void nextStep(byte[] buf, int toWrite, int next, boolean beginning) { writeBuf = buf; writeChannel = null; writePos = 0; this.toWrite = toWrite; this.next = next; this.beginning = beginning; } protected void nextStep(FileChannel ch, long pos, long toWrite, int next, boolean beginning) { writeBuf = null; writeChannel = ch; writePos = (int) pos; this.toWrite = (int) toWrite; this.next = next; this.beginning = beginning; } } jeromq-0.3.5/src/main/java/zmq/FQ.java000066400000000000000000000112211255150477200174350ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.util.ArrayList; import java.util.List; // Class manages a set of inbound pipes. On receive it performs fair // queueing so that senders gone berserk won't cause denial of // service for decent senders. class FQ { // Inbound pipes. private final List pipes; // Number of active pipes. All the active pipes are located at the // beginning of the pipes array. private int active; // Index of the next bound pipe to read a message from. private int current; // If true, part of a multipart message was already received, but // there are following parts still waiting in the current pipe. private boolean more; public FQ() { active = 0; current = 0; more = false; pipes = new ArrayList(); } public void attach(Pipe pipe) { pipes.add(pipe); Utils.swap(pipes, active, pipes.size() - 1); active++; } public void terminated(Pipe pipe) { final int index = pipes.indexOf(pipe); // Remove the pipe from the list; adjust number of active pipes // accordingly. if (index < active) { active--; Utils.swap(pipes, index, active); if (current == active) { current = 0; } } pipes.remove(pipe); } public void activated(Pipe pipe) { // Move the pipe to the list of active pipes. Utils.swap(pipes, pipes.indexOf(pipe), active); active++; } public Msg recv(ValueReference errno) { return recvPipe(errno, null); } public Msg recvPipe(ValueReference errno, ValueReference pipe) { // Round-robin over the pipes to get the next message. while (active > 0) { // Try to fetch new message. If we've already read part of the message // subsequent part should be immediately available. Msg msg = pipes.get(current).read(); boolean fetched = msg != null; // Note that when message is not fetched, current pipe is deactivated // and replaced by another active pipe. Thus we don't have to increase // the 'current' pointer. if (fetched) { if (pipe != null) { pipe.set(pipes.get(current)); } more = msg.hasMore(); if (!more) { current = (current + 1) % active; } return msg; } // Check the atomicity of the message. // If we've already received the first part of the message // we should get the remaining parts without blocking. assert (!more); active--; Utils.swap(pipes, current, active); if (current == active) { current = 0; } } // No message is available. Initialise the output parameter // to be a 0-byte message. errno.set(ZError.EAGAIN); return null; } public boolean hasIn() { // There are subsequent parts of the partly-read message available. if (more) { return true; } // Note that messing with current doesn't break the fairness of fair // queueing algorithm. If there are no messages available current will // get back to its original value. Otherwise it'll point to the first // pipe holding messages, skipping only pipes with no messages available. while (active > 0) { if (pipes.get(current).checkRead()) { return true; } // Deactivate the pipe. active--; Utils.swap(pipes, current, active); if (current == active) { current = 0; } } return false; } } jeromq-0.3.5/src/main/java/zmq/IDecoder.java000066400000000000000000000017621255150477200206160ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.nio.ByteBuffer; public interface IDecoder { public void setMsgSink(IMsgSink msgSink); public ByteBuffer getBuffer(); public int processBuffer(ByteBuffer buffer, int size); public boolean stalled(); } jeromq-0.3.5/src/main/java/zmq/IEncoder.java000066400000000000000000000022471255150477200206270ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.nio.ByteBuffer; public interface IEncoder { // Set message producer. public void setMsgSource(IMsgSource msgSource); // The function returns a batch of binary data. The data // are filled to a supplied buffer. If no buffer is supplied (data_ // is null) encoder will provide buffer of its own. public Transfer getData(ByteBuffer buffer); public boolean hasData(); } jeromq-0.3.5/src/main/java/zmq/IEngine.java000066400000000000000000000025301255150477200204500ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; // Abstract interface to be implemented by various engines. public interface IEngine { // Plug the engine to the session. void plug(IOThread ioThread, SessionBase session); // Terminate and deallocate the engine. Note that 'detached' // events are not fired on termination. void terminate(); // This method is called by the session to signalise that more // messages can be written to the pipe. void activateIn(); // This method is called by the session to signalise that there // are messages to send available. void activateOut(); } jeromq-0.3.5/src/main/java/zmq/IMsgSink.java000066400000000000000000000017161255150477200206230ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; public interface IMsgSink { // Delivers a message. Returns true if successful; false otherwise. // The function takes ownership of the passed message. public int pushMsg(Msg msg); } jeromq-0.3.5/src/main/java/zmq/IMsgSource.java000066400000000000000000000016231255150477200211540ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; public interface IMsgSource { // Fetch a message. Returns a Msg instance if successful; null otherwise. public Msg pullMsg(); } jeromq-0.3.5/src/main/java/zmq/IOObject.java000066400000000000000000000066121255150477200205750ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.nio.channels.SelectableChannel; // Simple base class for objects that live in I/O threads. // It makes communication with the poller object easier and // makes defining unneeded event handlers unnecessary. public class IOObject implements IPollEvents { private Poller poller; private IPollEvents handler; public IOObject(IOThread ioThread) { if (ioThread != null) { plug(ioThread); } } // When migrating an object from one I/O thread to another, first // unplug it, then migrate it, then plug it to the new thread. public void plug(IOThread ioThread) { assert (ioThread != null); assert (poller == null); // Retrieve the poller from the thread we are running in. poller = ioThread.getPoller(); } public void unplug() { assert (poller != null); // Forget about old poller in preparation to be migrated // to a different I/O thread. poller = null; handler = null; } public final void addHandle(SelectableChannel handle) { poller.addHandle(handle, this); } public final void removeHandle(SelectableChannel handle) { poller.removeHandle(handle); } public final void setPollIn(SelectableChannel handle) { poller.setPollIn(handle); } public final void setPollOut(SelectableChannel handle) { poller.setPollOut(handle); } public final void setPollConnect(SelectableChannel handle) { poller.setPollConnect(handle); } public final void setPollAccept(SelectableChannel handle) { poller.setPollAccept(handle); } public final void resetPollIn(SelectableChannel handle) { poller.resetPollOn(handle); } public final void resetPollOut(SelectableChannel handle) { poller.resetPollOut(handle); } @Override public final void inEvent() { handler.inEvent(); } @Override public final void outEvent() { handler.outEvent(); } @Override public final void connectEvent() { handler.connectEvent(); } @Override public final void acceptEvent() { handler.acceptEvent(); } @Override public final void timerEvent(int id) { handler.timerEvent(id); } public final void addTimer(long timeout, int id) { poller.addTimer(timeout, this, id); } public final void setHandler(IPollEvents handler) { this.handler = handler; } public void cancelTimer(int id) { poller.cancelTimer(this, id); } } jeromq-0.3.5/src/main/java/zmq/IOThread.java000066400000000000000000000060041255150477200205710ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.io.Closeable; import java.io.IOException; import java.nio.channels.SelectableChannel; public class IOThread extends ZObject implements IPollEvents, Closeable { // I/O thread accesses incoming commands via this mailbox. private final Mailbox mailbox; // Handle associated with mailbox' file descriptor. private final SelectableChannel mailboxHandle; // I/O multiplexing is performed using a poller object. private final Poller poller; final String name; public IOThread(Ctx ctx, int tid) { super(ctx, tid); name = "iothread-" + tid; poller = new Poller(name); mailbox = new Mailbox(name); mailboxHandle = mailbox.getFd(); poller.addHandle(mailboxHandle, this); poller.setPollIn(mailboxHandle); } public void start() { poller.start(); } @Override public void close() throws IOException { poller.destroy(); mailbox.close(); } public void stop() { sendStop(); } public Mailbox getMailbox() { return mailbox; } public int getLoad() { return poller.getLoad(); } @Override public void inEvent() { // TODO: Do we want to limit number of commands I/O thread can // process in a single go? while (true) { // Get the next command. If there is none, exit. Command cmd = mailbox.recv(0); if (cmd == null) { break; } // Process the command. cmd.destination().processCommand(cmd); } } @Override public void outEvent() { throw new UnsupportedOperationException(); } @Override public void connectEvent() { throw new UnsupportedOperationException(); } @Override public void acceptEvent() { throw new UnsupportedOperationException(); } @Override public void timerEvent(int id) { throw new UnsupportedOperationException(); } public Poller getPoller() { assert (poller != null); return poller; } protected void processStop() { poller.removeHandle(mailboxHandle); poller.stop(); } } jeromq-0.3.5/src/main/java/zmq/IPollEvents.java000066400000000000000000000023541255150477200213420ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; public interface IPollEvents { // Called by I/O thread when file descriptor is ready for reading. void inEvent(); // Called by I/O thread when file descriptor is ready for writing. void outEvent(); // Called by I/O thread when file descriptor might be ready for connecting. void connectEvent(); // Called by I/O thread when file descriptor is ready for accept. void acceptEvent(); // Called when timer expires. void timerEvent(int id); } jeromq-0.3.5/src/main/java/zmq/IpcAddress.java000066400000000000000000000033041255150477200211530ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.UnknownHostException; public class IpcAddress implements Address.IZAddress { private String name; private InetSocketAddress address; @Override public String toString() { if (name == null) { return ""; } return "ipc://" + name; } @Override public void resolve(String name, boolean ip4only) { this.name = name; int hash = name.hashCode(); if (hash < 0) { hash = -hash; } hash = hash % 55536; hash += 10000; try { address = new InetSocketAddress(InetAddress.getByName(null), hash); } catch (UnknownHostException e) { throw new IllegalArgumentException(e); } } @Override public SocketAddress address() { return address; } } jeromq-0.3.5/src/main/java/zmq/IpcConnecter.java000066400000000000000000000020211255150477200215010ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; public class IpcConnecter extends TcpConnecter { public IpcConnecter(IOThread ioThread, SessionBase session, final Options options, final Address addr, boolean wait) { super(ioThread, session, options, addr, wait); } } jeromq-0.3.5/src/main/java/zmq/IpcListener.java000066400000000000000000000030201255150477200213460ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.net.InetSocketAddress; // fake Unix domain socket public class IpcListener extends TcpListener { private final IpcAddress address; public IpcListener(IOThread ioThread, SocketBase socket, final Options options) { super(ioThread, socket, options); address = new IpcAddress(); } // Get the bound address for use with wildcards public String getAddress() { return address.toString(); } // Set address to listen on. public int setAddress(String addr) { address.resolve(addr, false); InetSocketAddress sock = (InetSocketAddress) address.address(); String fake = sock.getAddress().getHostAddress() + ":" + sock.getPort(); return super.setAddress(fake); } } jeromq-0.3.5/src/main/java/zmq/LB.java000066400000000000000000000101731255150477200174310ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.util.ArrayList; import java.util.List; public class LB { // List of outbound pipes. private final List pipes; // Number of active pipes. All the active pipes are located at the // beginning of the pipes array. private int active; // Points to the last pipe that the most recent message was sent to. private int current; // True if last we are in the middle of a multipart message. private boolean more; // True if we are dropping current message. private boolean dropping; public LB() { active = 0; current = 0; more = false; dropping = false; pipes = new ArrayList(); } public void attach(Pipe pipe) { pipes.add(pipe); activated(pipe); } public void terminated(Pipe pipe) { int index = pipes.indexOf(pipe); // If we are in the middle of multipart message and current pipe // have disconnected, we have to drop the remainder of the message. if (index == current && more) { dropping = true; } // Remove the pipe from the list; adjust number of active pipes // accordingly. if (index < active) { active--; Utils.swap(pipes, index, active); if (current == active) { current = 0; } } pipes.remove(pipe); } public void activated(Pipe pipe) { // Move the pipe to the list of active pipes. Utils.swap(pipes, pipes.indexOf(pipe), active); active++; } public boolean send(Msg msg, ValueReference errno) { // Drop the message if required. If we are at the end of the message // switch back to non-dropping mode. if (dropping) { more = msg.hasMore(); dropping = more; // msg_.close(); return true; } while (active > 0) { if (pipes.get(current).write(msg)) { break; } assert (!more); active--; if (current < active) { Utils.swap(pipes, current, active); } else { current = 0; } } // If there are no pipes we cannot send the message. if (active == 0) { errno.set(ZError.EAGAIN); return false; } // If it's final part of the message we can flush it downstream and // continue round-robining (load balance). more = msg.hasMore(); if (!more) { pipes.get(current).flush(); if (++current >= active) { current = 0; } } return true; } public boolean hasOut() { // If one part of the message was already written we can definitely // write the rest of the message. if (more) { return true; } while (active > 0) { // Check whether a pipe has room for another message. if (pipes.get(current).checkWrite()) { return true; } // Deactivate the pipe. active--; Utils.swap(pipes, current, active); if (current == active) { current = 0; } } return false; } } jeromq-0.3.5/src/main/java/zmq/Mailbox.java000066400000000000000000000073621255150477200205350ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.io.Closeable; import java.io.IOException; import java.nio.channels.SelectableChannel; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Mailbox implements Closeable { // The pipe to store actual commands. private final YPipe cpipe; // Signaler to pass signals from writer thread to reader thread. private final Signaler signaler; // There's only one thread receiving from the mailbox, but there // is arbitrary number of threads sending. Given that ypipe requires // synchronised access on both of its endpoints, we have to synchronise // the sending side. private final Lock sync; // True if the underlying pipe is active, ie. when we are allowed to // read commands from it. private boolean active; // mailbox name, for better debugging private final String name; public Mailbox(String name) { cpipe = new YPipe(Config.COMMAND_PIPE_GRANULARITY.getValue()); sync = new ReentrantLock(); signaler = new Signaler(); // Get the pipe into passive state. That way, if the users starts by // polling on the associated file descriptor it will get woken up when // new command is posted. Command cmd = cpipe.read(); assert (cmd == null); active = false; this.name = name; } public SelectableChannel getFd() { return signaler.getFd(); } public void send(final Command cmd) { boolean ok = false; sync.lock(); try { cpipe.write(cmd, false); ok = cpipe.flush(); } finally { sync.unlock(); } if (!ok) { signaler.send(); } } public Command recv(long timeout) { Command cmd = null; // Try to get the command straight away. if (active) { cmd = cpipe.read(); if (cmd != null) { return cmd; } // If there are no more commands available, switch into passive state. active = false; signaler.recv(); } // Wait for signal from the command sender. boolean rc = signaler.waitEvent(timeout); if (!rc) { return null; } // We've got the signal. Now we can switch into active state. active = true; // Get a command. cmd = cpipe.read(); assert (cmd != null); return cmd; } @Override public void close() throws IOException { // TODO: Retrieve and deallocate commands inside the cpipe. // Work around problem that other threads might still be in our // send() method, by waiting on the mutex before disappearing. sync.lock(); sync.unlock(); signaler.close(); } @Override public String toString() { return super.toString() + "[" + name + "]"; } } jeromq-0.3.5/src/main/java/zmq/Msg.java000066400000000000000000000123711255150477200176640ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.nio.ByteBuffer; import java.nio.ByteOrder; public class Msg { enum Type { DATA, DELIMITER } public static final int MORE = 1; public static final int COMMAND = 2; public static final int IDENTITY = 64; public static final int SHARED = 128; private int flags; private Type type; private int size; private byte[] data; private ByteBuffer buf; public Msg() { this.type = Type.DATA; this.flags = 0; this.size = 0; this.buf = ByteBuffer.wrap(new byte[0]).order(ByteOrder.BIG_ENDIAN); this.data = buf.array(); } public Msg(int capacity) { this.type = Type.DATA; this.flags = 0; this.size = capacity; this.buf = ByteBuffer.wrap(new byte[capacity]).order(ByteOrder.BIG_ENDIAN); this.data = buf.array(); } public Msg(byte[] src) { if (src == null) { src = new byte[0]; } this.type = Type.DATA; this.flags = 0; this.size = src.length; this.data = src; this.buf = ByteBuffer.wrap(src).order(ByteOrder.BIG_ENDIAN); } public Msg(final ByteBuffer src) { if (src == null) { throw new IllegalArgumentException("ByteBuffer cannot be null"); } if (src.position() > 0) { throw new IllegalArgumentException("ByteBuffer position is not zero, did you forget to flip it?"); } this.type = Type.DATA; this.flags = 0; this.buf = src.duplicate(); if (buf.hasArray()) { this.data = buf.array(); } else { this.data = null; } this.size = buf.remaining(); } public Msg(final Msg m) { if (m == null) { throw new IllegalArgumentException("Msg cannot be null"); } this.type = m.type; this.flags = m.flags; this.size = m.size; this.buf = m.buf != null ? m.buf.duplicate() : null; this.data = new byte[this.size]; System.arraycopy(m.data, 0, this.data, 0, m.size); } public boolean isIdentity() { return (flags & IDENTITY) == IDENTITY; } public boolean isDelimiter() { return type == Type.DELIMITER; } public boolean check() { return true; // type >= TYPE_MIN && type <= TYPE_MAX; } public int flags() { return flags; } public boolean hasMore() { return (flags & MORE) > 0; } public void setFlags(int flags) { this.flags |= flags; } public void initDelimiter() { type = Type.DELIMITER; flags = 0; } public byte[] data() { if (buf.isDirect()) { int length = buf.remaining(); byte[] bytes = new byte[length]; buf.duplicate().get(bytes); return bytes; } return data; } public ByteBuffer buf() { return buf.duplicate(); } public int size() { return size; } public void resetFlags(int f) { flags = flags & ~f; } public byte get() { return buf.get(); } public byte get(int index) { return buf.get(index); } public Msg put(byte b) { buf.put(b); return this; } public Msg put(int index, byte b) { buf.put(index, b); return this; } public Msg put(byte[] src) { return put(src, 0, src.length); } public Msg put(byte[] src, int off, int len) { if (src == null) { return this; } buf.put(src, off, len); return this; } public Msg put(ByteBuffer src) { buf.put(src); return this; } public int getBytes(int index, byte[] dst, int off, int len) { int count = Math.min(len, size); if (buf.isDirect()) { ByteBuffer dup = buf.duplicate(); dup.position(index); dup.put(dst, off, count); return count; } System.arraycopy(data, index, dst, off, count); return count; } public int getBytes(int index, ByteBuffer bb, int len) { int count = Math.min(bb.remaining(), size - index); count = Math.min(count, len); bb.put(buf); return count; } @Override public String toString() { return String.format("#zmq.Msg{type=%s, size=%s, flags=%s}", type, size, flags); } } jeromq-0.3.5/src/main/java/zmq/Mtrie.java000066400000000000000000000306461255150477200202230ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.util.HashSet; import java.util.Set; //Multi-trie. Each node in the trie is a set of pointers to pipes. public class Mtrie { private Set pipes; private int min; private int count; private int liveNodes; private Mtrie[] next; public interface IMtrieHandler { void invoke(Pipe pipe, byte[] data, int size, Object arg); } public Mtrie() { min = 0; count = 0; liveNodes = 0; pipes = null; next = null; } public boolean add(byte[] prefix, Pipe pipe) { return addHelper(prefix, 0, pipe); } // Add key to the trie. Returns true if it's a new subscription // rather than a duplicate. public boolean add(byte[] prefix, int start, Pipe pipe) { return addHelper(prefix, start, pipe); } private boolean addHelper(byte[] prefix, int start, Pipe pipe) { // We are at the node corresponding to the prefix. We are done. if (prefix == null || prefix.length == start) { boolean result = pipes == null; if (pipes == null) { pipes = new HashSet(); } pipes.add(pipe); return result; } byte c = prefix[start]; if (c < min || c >= min + count) { // The character is out of range of currently handled // characters. We have to extend the table. if (count == 0) { min = c; count = 1; next = null; } else if (count == 1) { int oldc = min; Mtrie oldp = next[0]; count = (min < c ? c - min : min - c) + 1; next = new Mtrie[count]; min = Math.min(min, c); next[oldc - min] = oldp; } else if (min < c) { // The new character is above the current character range. count = c - min + 1; next = realloc(next, count, true); } else { // The new character is below the current character range. count = (min + count) - c; next = realloc(next, count, false); min = c; } } // If next node does not exist, create one. if (count == 1) { if (next == null) { next = new Mtrie[1]; next[0] = new Mtrie(); ++liveNodes; //alloc_assert (next.node); } return next[0].addHelper(prefix, start + 1, pipe); } else { if (next[c - min] == null) { next[c - min] = new Mtrie(); ++liveNodes; //alloc_assert (next.table [c - min]); } return next[c - min].addHelper(prefix, start + 1, pipe); } } private Mtrie[] realloc(Mtrie[] table, int size, boolean ended) { return Utils.realloc(Mtrie.class, table, size, ended); } // Remove all subscriptions for a specific peer from the trie. // If there are no subscriptions left on some topics, invoke the // supplied callback function. public boolean rm(Pipe pipe, IMtrieHandler func, Object arg) { return rmHelper(pipe, new byte[0], 0, 0, func, arg); } private boolean rmHelper(Pipe pipe, byte[] buff, int buffsize, int maxBuffSize, IMtrieHandler func, Object arg) { // Remove the subscription from this node. if (pipes != null && pipes.remove(pipe) && pipes.isEmpty()) { func.invoke(null, buff, buffsize, arg); pipes = null; } // Adjust the buffer. if (buffsize >= maxBuffSize) { maxBuffSize = buffsize + 256; buff = Utils.realloc(buff, maxBuffSize); } // If there are no subnodes in the trie, return. if (count == 0) { return true; } // If there's one subnode (optimisation). if (count == 1) { buff[buffsize] = (byte) min; buffsize++; next[0].rmHelper(pipe, buff, buffsize, maxBuffSize, func, arg); // Prune the node if it was made redundant by the removal if (next[0].isRedundant()) { next = null; count = 0; --liveNodes; assert (liveNodes == 0); } return true; } // If there are multiple subnodes. // // New min non-null character in the node table after the removal int newMin = min + count - 1; // New max non-null character in the node table after the removal int newMax = min; for (int c = 0; c != count; c++) { buff[buffsize] = (byte) (min + c); if (next[c] != null) { next[c].rmHelper(pipe, buff, buffsize + 1, maxBuffSize, func, arg); // Prune redundant nodes from the mtrie if (next[c].isRedundant()) { next[c] = null; assert (liveNodes > 0); --liveNodes; } else { // The node is not redundant, so it's a candidate for being // the new min/max node. // // We loop through the node array from left to right, so the // first non-null, non-redundant node encountered is the new // minimum index. Conversely, the last non-redundant, non-null // node encountered is the new maximum index. if (c + min < newMin) { newMin = c + min; } if (c + min > newMax) { newMax = c + min; } } } } assert (count > 1); // Free the node table if it's no longer used. if (liveNodes == 0) { next = null; count = 0; } // Compact the node table if possible else if (liveNodes == 1) { // If there's only one live node in the table we can // switch to using the more compact single-node // representation assert (newMin == newMax); assert (newMin >= min && newMin < min + count); Mtrie node = next [newMin - min]; assert (node != null); next = null; next = new Mtrie[]{node}; count = 1; min = newMin; } else if (newMin > min || newMax < min + count - 1) { assert (newMax - newMin + 1 > 1); Mtrie[] oldTable = next; assert (newMin > min || newMax < min + count - 1); assert (newMin >= min); assert (newMax <= min + count - 1); assert (newMax - newMin + 1 < count); count = newMax - newMin + 1; next = new Mtrie[count]; System.arraycopy(oldTable, (newMin - min), next, 0, count); min = newMin; } return true; } // Remove specific subscription from the trie. Return true is it was // actually removed rather than de-duplicated. public boolean rm(byte[] prefix, int start, Pipe pipe) { return rmHelper(prefix, start, pipe); } private boolean rmHelper(byte[] prefix, int start, Pipe pipe) { if (prefix == null || prefix.length == start) { if (pipes != null) { boolean erased = pipes.remove(pipe); assert (erased); if (pipes.isEmpty()) { pipes = null; } } return pipes == null; } byte c = prefix[start]; if (count == 0 || c < min || c >= min + count) { return false; } Mtrie nextNode = count == 1 ? next[0] : next[c - min]; if (nextNode == null) { return false; } boolean ret = nextNode.rmHelper(prefix, start + 1, pipe); if (nextNode.isRedundant()) { assert (count > 0); if (count == 1) { next = null; count = 0; --liveNodes; assert (liveNodes == 0); } else { next[c - min] = null; assert (liveNodes > 1); --liveNodes; // Compact the table if possible if (liveNodes == 1) { // If there's only one live node in the table we can // switch to using the more compact single-node // representation int i; for (i = 0; i < count; ++i) { if (next[i] != null) { break; } } assert (i < count); min += i; count = 1; Mtrie old = next [i]; next = new Mtrie [] { old }; } else if (c == min) { // We can compact the table "from the left" int i; for (i = 1; i < count; ++i) { if (next[i] != null) { break; } } assert (i < count); min += i; count -= i; next = realloc(next, count, true); } else if (c == min + count - 1) { // We can compact the table "from the right" int i; for (i = 1; i < count; ++i) { if (next[count - 1 - i] != null) { break; } } assert (i < count); count -= i; next = realloc(next, count, false); } } } return ret; } // Signal all the matching pipes. public void match(byte[] data, int size, IMtrieHandler func, Object arg) { Mtrie current = this; int idx = 0; while (true) { // Signal the pipes attached to this node. if (current.pipes != null) { for (Pipe it : current.pipes) { func.invoke(it, null, 0, arg); } } // If we are at the end of the message, there's nothing more to match. if (size == 0) { break; } // If there are no subnodes in the trie, return. if (current.count == 0) { break; } byte c = data[idx]; // If there's one subnode (optimisation). if (current.count == 1) { if (c != current.min) { break; } current = current.next[0]; idx++; size--; continue; } // If there are multiple subnodes. if (c < current.min || c >= current.min + current.count) { break; } if (current.next[c - current.min] == null) { break; } current = current.next[c - current.min]; idx++; size--; } } private boolean isRedundant() { return pipes == null && liveNodes == 0; } } jeromq-0.3.5/src/main/java/zmq/MultiMap.java000066400000000000000000000151061255150477200206650ustar00rootroot00000000000000/* Copyright other contributors as noted in the AUTHORS file. This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; public class MultiMap, V> implements Map { private long id; private final HashMap values; private final TreeMap> keys; public MultiMap() { id = 0; values = new HashMap(); keys = new TreeMap>(); } public class MultiMapEntry implements Map.Entry { private K key; private V value; public MultiMapEntry(K key, V value) { this.key = key; this.value = value; } @Override public K getKey() { return key; } @Override public V getValue() { return value; } @Override public V setValue(V value) { V old = this.value; this.value = value; return old; } } public class MultiMapEntrySet implements Set>, Iterator> { private MultiMap map; private Iterator>> it; private Iterator iit; private K key; private long id; public MultiMapEntrySet(MultiMap map) { this.map = map; } @Override public boolean add(Map.Entry arg0) { throw new UnsupportedOperationException(); } @Override public boolean addAll(Collection> arg0) { throw new UnsupportedOperationException(); } @Override public void clear() { throw new UnsupportedOperationException(); } @Override public boolean contains(Object arg0) { throw new UnsupportedOperationException(); } @Override public boolean containsAll(Collection arg0) { throw new UnsupportedOperationException(); } @Override public boolean isEmpty() { throw new UnsupportedOperationException(); } @Override public Iterator> iterator() { it = map.keys.entrySet().iterator(); return this; } @Override public boolean remove(Object arg0) { throw new UnsupportedOperationException(); } @Override public boolean removeAll(Collection arg0) { throw new UnsupportedOperationException(); } @Override public boolean retainAll(Collection arg0) { throw new UnsupportedOperationException(); } @Override public int size() { throw new UnsupportedOperationException(); } @Override public Object[] toArray() { throw new UnsupportedOperationException(); } @Override public T[] toArray(T[] arg0) { throw new UnsupportedOperationException(); } @Override public boolean hasNext() { if (iit == null || !iit.hasNext()) { if (!it.hasNext()) { return false; } Map.Entry> item = it.next(); key = item.getKey(); iit = item.getValue().iterator(); } return true; } @Override public Map.Entry next() { id = iit.next(); return new MultiMapEntry(key, map.values.get(id)); } @Override public void remove() { iit.remove(); map.values.remove(id); if (map.keys.get(key).isEmpty()) { it.remove(); } } } @Override public void clear() { keys.clear(); values.clear(); } @Override public boolean containsKey(Object key) { return keys.containsKey(key); } @Override public boolean containsValue(Object value) { return values.containsValue(value); } @Override public Set> entrySet() { return new MultiMapEntrySet(this); } @Override public V get(Object key) { ArrayList l = keys.get(key); if (l == null) { return null; } return values.get(l.get(0)); } @Override public boolean isEmpty() { return keys.isEmpty(); } @Override public Set keySet() { return keys.keySet(); } @Override public V put(K key, V value) { ArrayList ids = keys.get(key); if (ids == null) { ids = new ArrayList(); ids.add(id); keys.put(key, ids); } else { ids.add(id); } values.put(id, value); id++; return null; } @Override public void putAll(Map src) { for (Entry o : src.entrySet()) { put(o.getKey(), o.getValue()); } } @Override public V remove(Object key) { ArrayList l = keys.get(key); if (l == null) { return null; } V old = values.remove(l.remove(0)); if (l.isEmpty()) { keys.remove(key); } return old; } @Override public int size() { return values.size(); } @Override public Collection values() { return values.values(); } } jeromq-0.3.5/src/main/java/zmq/Options.java000066400000000000000000000267461255150477200206040ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import zmq.TcpAddress.TcpAddressMask; public class Options { // High-water marks for message pipes. int sendHwm; int recvHwm; // I/O thread affinity. long affinity; // Socket identity byte identitySize; byte[] identity; // [256]; // Last socket endpoint resolved URI String lastEndpoint; // Maximum tranfer rate [kb/s]. Default 100kb/s. int rate; // Reliability time interval [ms]. Default 10 seconds. int recoveryIvl; // Sets the time-to-live field in every multicast packet sent. int multicastHops; // SO_SNDBUF and SO_RCVBUF to be passed to underlying transport sockets. int sndbuf; int rcvbuf; // Socket type. int type; // Linger time, in milliseconds. int linger; // Minimum interval between attempts to reconnect, in milliseconds. // Default 100ms int reconnectIvl; // Maximum interval between attempts to reconnect, in milliseconds. // Default 0 (unused) int reconnectIvlMax; // Maximum backlog for pending connections. int backlog; // Maximal size of message to handle. long maxMsgSize; // The timeout for send/recv operations for this socket. int recvTimeout; int sendTimeout; // If 1, indicates the use of IPv4 sockets only, it will not be // possible to communicate with IPv6-only hosts. If 0, the socket can // connect to and accept connections from both IPv4 and IPv6 hosts. int ipv4only; // If 1, connecting pipes are not attached immediately, meaning a send() // on a socket with only connecting pipes would block int delayAttachOnConnect; // If true, session reads all the pending messages from the pipe and // sends them to the network when socket is closed. boolean delayOnClose; // If true, socket reads all the messages from the pipe and delivers // them to the user when the peer terminates. boolean delayOnDisconnect; // If 1, (X)SUB socket should filter the messages. If 0, it should not. boolean filter; // If true, the identity message is forwarded to the socket. boolean recvIdentity; // TCP keep-alive settings. // Defaults to -1 = do not change socket options int tcpKeepAlive; int tcpKeepAliveCnt; int tcpKeepAliveIdle; int tcpKeepAliveIntvl; // TCP accept() filters //typedef std::vector tcp_accept_filters_t; final List tcpAcceptFilters; // ID of the socket. int socketId; Class decoder; Class encoder; public Options() { sendHwm = 1000; recvHwm = 1000; affinity = 0; identitySize = 0; rate = 100; recoveryIvl = 10000; multicastHops = 1; sndbuf = 0; rcvbuf = 0; type = -1; linger = -1; reconnectIvl = 100; reconnectIvlMax = 0; backlog = 100; maxMsgSize = -1; recvTimeout = -1; sendTimeout = -1; ipv4only = 1; delayAttachOnConnect = 0; delayOnClose = true; delayOnDisconnect = true; filter = false; recvIdentity = false; tcpKeepAlive = -1; tcpKeepAliveCnt = -1; tcpKeepAliveIdle = -1; tcpKeepAliveIntvl = -1; socketId = 0; identity = null; tcpAcceptFilters = new ArrayList(); decoder = null; encoder = null; } @SuppressWarnings("unchecked") public void setSocketOpt(int option, Object optval) { switch (option) { case ZMQ.ZMQ_SNDHWM: sendHwm = (Integer) optval; if (sendHwm < 0) { throw new IllegalArgumentException("sendHwm " + optval); } return; case ZMQ.ZMQ_RCVHWM: recvHwm = (Integer) optval; if (recvHwm < 0) { throw new IllegalArgumentException("recvHwm " + optval); } return; case ZMQ.ZMQ_AFFINITY: affinity = (Long) optval; return; case ZMQ.ZMQ_IDENTITY: byte[] val; if (optval instanceof String) { val = ((String) optval).getBytes(ZMQ.CHARSET); } else if (optval instanceof byte[]) { val = (byte[]) optval; } else { throw new IllegalArgumentException("identity " + optval); } if (val == null || val.length > 255) { throw new IllegalArgumentException("identity must not be null or less than 255 " + optval); } identity = Arrays.copyOf(val, val.length); identitySize = (byte) identity.length; return; case ZMQ.ZMQ_RATE: rate = (Integer) optval; return; case ZMQ.ZMQ_RECOVERY_IVL: recoveryIvl = (Integer) optval; return; case ZMQ.ZMQ_SNDBUF: sndbuf = (Integer) optval; return; case ZMQ.ZMQ_RCVBUF: rcvbuf = (Integer) optval; return; case ZMQ.ZMQ_LINGER: linger = (Integer) optval; return; case ZMQ.ZMQ_RECONNECT_IVL: reconnectIvl = (Integer) optval; if (reconnectIvl < -1) { throw new IllegalArgumentException("reconnectIvl " + optval); } return; case ZMQ.ZMQ_RECONNECT_IVL_MAX: reconnectIvlMax = (Integer) optval; if (reconnectIvlMax < 0) { throw new IllegalArgumentException("reconnectIvlMax " + optval); } return; case ZMQ.ZMQ_BACKLOG: backlog = (Integer) optval; return; case ZMQ.ZMQ_MAXMSGSIZE: maxMsgSize = (Long) optval; return; case ZMQ.ZMQ_MULTICAST_HOPS: multicastHops = (Integer) optval; return; case ZMQ.ZMQ_RCVTIMEO: recvTimeout = (Integer) optval; return; case ZMQ.ZMQ_SNDTIMEO: sendTimeout = (Integer) optval; return; case ZMQ.ZMQ_IPV4ONLY: ipv4only = (Integer) optval; if (ipv4only != 0 && ipv4only != 1) { throw new IllegalArgumentException("ipv4only only accepts 0 or 1 " + optval); } return; case ZMQ.ZMQ_TCP_KEEPALIVE: tcpKeepAlive = (Integer) optval; if (tcpKeepAlive != -1 && tcpKeepAlive != 0 && tcpKeepAlive != 1) { throw new IllegalArgumentException("tcpKeepAlive only accepts one of -1,0,1 " + optval); } return; case ZMQ.ZMQ_DELAY_ATTACH_ON_CONNECT: delayAttachOnConnect = (Integer) optval; if (delayAttachOnConnect != 0 && delayAttachOnConnect != 1) { throw new IllegalArgumentException("delayAttachOnConnect only accept 0 or 1 " + optval); } return; case ZMQ.ZMQ_TCP_KEEPALIVE_CNT: case ZMQ.ZMQ_TCP_KEEPALIVE_IDLE: case ZMQ.ZMQ_TCP_KEEPALIVE_INTVL: // not supported return; case ZMQ.ZMQ_TCP_ACCEPT_FILTER: String filterStr = (String) optval; if (filterStr == null) { tcpAcceptFilters.clear(); } else if (filterStr.length() == 0 || filterStr.length() > 255) { throw new IllegalArgumentException("tcp_accept_filter " + optval); } else { TcpAddressMask filter = new TcpAddressMask(); filter.resolve(filterStr, ipv4only == 1); tcpAcceptFilters.add(filter); } return; case ZMQ.ZMQ_ENCODER: if (optval instanceof String) { try { encoder = Class.forName((String) optval).asSubclass(EncoderBase.class); } catch (ClassNotFoundException e) { throw new IllegalArgumentException(e); } } else if (optval instanceof Class) { encoder = (Class) optval; } else { throw new IllegalArgumentException("encoder " + optval); } return; case ZMQ.ZMQ_DECODER: if (optval instanceof String) { try { decoder = Class.forName((String) optval).asSubclass(DecoderBase.class); } catch (ClassNotFoundException e) { throw new IllegalArgumentException(e); } } else if (optval instanceof Class) { decoder = (Class) optval; } else { throw new IllegalArgumentException("decoder " + optval); } return; default: throw new IllegalArgumentException("Unknown Option " + option); } } public Object getsockopt(int option) { switch (option) { case ZMQ.ZMQ_SNDHWM: return sendHwm; case ZMQ.ZMQ_RCVHWM: return recvHwm; case ZMQ.ZMQ_AFFINITY: return affinity; case ZMQ.ZMQ_IDENTITY: return identity; case ZMQ.ZMQ_RATE: return rate; case ZMQ.ZMQ_RECOVERY_IVL: return recoveryIvl; case ZMQ.ZMQ_SNDBUF: return sndbuf; case ZMQ.ZMQ_RCVBUF: return rcvbuf; case ZMQ.ZMQ_TYPE: return type; case ZMQ.ZMQ_LINGER: return linger; case ZMQ.ZMQ_RECONNECT_IVL: return reconnectIvl; case ZMQ.ZMQ_RECONNECT_IVL_MAX: return reconnectIvlMax; case ZMQ.ZMQ_BACKLOG: return backlog; case ZMQ.ZMQ_MAXMSGSIZE: return maxMsgSize; case ZMQ.ZMQ_MULTICAST_HOPS: return multicastHops; case ZMQ.ZMQ_RCVTIMEO: return recvTimeout; case ZMQ.ZMQ_SNDTIMEO: return sendTimeout; case ZMQ.ZMQ_IPV4ONLY: return ipv4only; case ZMQ.ZMQ_TCP_KEEPALIVE: return tcpKeepAlive; case ZMQ.ZMQ_DELAY_ATTACH_ON_CONNECT: return delayAttachOnConnect; case ZMQ.ZMQ_TCP_KEEPALIVE_CNT: case ZMQ.ZMQ_TCP_KEEPALIVE_IDLE: case ZMQ.ZMQ_TCP_KEEPALIVE_INTVL: // not supported return 0; case ZMQ.ZMQ_LAST_ENDPOINT: return lastEndpoint; default: throw new IllegalArgumentException("option=" + option); } } } jeromq-0.3.5/src/main/java/zmq/Own.java000066400000000000000000000177261255150477200177120ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.util.HashSet; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; // Base class for objects forming a part of ownership hierarchy. // It handles initialisation and destruction of such objects. abstract class Own extends ZObject { protected final Options options; // True if termination was already initiated. If so, we can destroy // the object if there are no more child objects or pending term acks. private boolean terminating; // Sequence number of the last command sent to this object. private final AtomicLong sendSeqnum; // Sequence number of the last command processed by this object. private long processedSeqnum; // Socket owning this object. It's responsible for shutting down // this object. private Own owner; // List of all objects owned by this socket. We are responsible // for deallocating them before we quit. //typedef std::set owned_t; private final Set owned; // Number of events we have to get before we can destroy the object. private int termAcks; // Note that the owner is unspecified in the constructor. // It'll be supplied later on when the object is plugged in. // The object is not living within an I/O thread. It has it's own // thread outside of 0MQ infrastructure. public Own(Ctx parent, int tid) { super(parent, tid); terminating = false; sendSeqnum = new AtomicLong(0); processedSeqnum = 0; owner = null; termAcks = 0; options = new Options(); owned = new HashSet(); } // The object is living within I/O thread. public Own(IOThread ioThread, Options options) { super(ioThread); this.options = options; terminating = false; sendSeqnum = new AtomicLong(0); processedSeqnum = 0; owner = null; termAcks = 0; owned = new HashSet(); } public abstract void destroy(); // A place to hook in when phyicallal destruction of the object // is to be delayed. protected void processDestroy() { destroy(); } private void setOwner(Own owner) { assert (this.owner == null); this.owner = owner; } // When another owned object wants to send command to this object // it calls this function to let it know it should not shut down // before the command is delivered. void incSeqnum() { // This function may be called from a different thread! sendSeqnum.incrementAndGet(); } protected void processSeqnum() { // Catch up with counter of processed commands. processedSeqnum++; // We may have catched up and still have pending terms acks. checkTermAcks(); } // Launch the supplied object and become its owner. protected void launchChild(Own object) { // Specify the owner of the object. object.setOwner(this); // Plug the object into the I/O thread. sendPlug(object); // Take ownership of the object. sendOwn(this, object); } // Terminate owned object protected void termChild(Own object) { processTermReq(object); } @Override protected void processTermReq(Own object) { // When shutting down we can ignore termination requests from owned // objects. The termination request was already sent to the object. if (terminating) { return; } // If I/O object is well and alive let's ask it to terminate. // If not found, we assume that termination request was already sent to // the object so we can safely ignore the request. if (!owned.contains(object)) { return; } owned.remove(object); registerTermAcks(1); // Note that this object is the root of the (partial shutdown) thus, its // value of linger is used, rather than the value stored by the children. sendTerm(object, options.linger); } protected void processOwn(Own object) { // If the object is already being shut down, new owned objects are // immediately asked to terminate. Note that linger is set to zero. if (terminating) { registerTermAcks(1); sendTerm(object, 0); return; } // Store the reference to the owned object. owned.add(object); } // Ask owner object to terminate this object. It may take a while // while actual termination is started. This function should not be // called more than once. protected void terminate() { // If termination is already underway, there's no point // in starting it anew. if (terminating) { return; } // As for the root of the ownership tree, there's noone to terminate it, // so it has to terminate itself. if (owner == null) { processTerm(options.linger); return; } // If I am an owned object, I'll ask my owner to terminate me. sendTermReq(owner, this); } // Returns true if the object is in process of termination. protected boolean isTerminating() { return terminating; } // Term handler is protocted rather than private so that it can // be intercepted by the derived class. This is useful to add custom // steps to the beginning of the termination process. @Override protected void processTerm(int linger) { // Double termination should never happen. assert (!terminating); // Send termination request to all owned objects. for (Own it : owned) { sendTerm(it, linger); } registerTermAcks(owned.size()); owned.clear(); // Start termination process and check whether by chance we cannot // terminate immediately. terminating = true; checkTermAcks(); } // Use following two functions to wait for arbitrary events before // terminating. Just add number of events to wait for using // register_tem_acks functions. When event occurs, call // remove_term_ack. When number of pending acks reaches zero // object will be deallocated. public void registerTermAcks(int count) { termAcks += count; } public void unregisterTermAck() { assert (termAcks > 0); termAcks--; // This may be a last ack we are waiting for before termination... checkTermAcks(); } @Override protected void processTermAck() { unregisterTermAck(); } private void checkTermAcks() { if (terminating && processedSeqnum == sendSeqnum.get() && termAcks == 0) { // Sanity check. There should be no active children at this point. assert (owned.isEmpty()); // The root object has nobody to confirm the termination to. // Other nodes will confirm the termination to the owner. if (owner != null) { sendTermAck(owner); } // Deallocate the resources. processDestroy(); } } } jeromq-0.3.5/src/main/java/zmq/Pair.java000066400000000000000000000057351255150477200200370ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; public class Pair extends SocketBase { public static class PairSession extends SessionBase { public PairSession(IOThread ioThread, boolean connect, SocketBase socket, final Options options, final Address addr) { super(ioThread, connect, socket, options, addr); } } private Pipe pipe; public Pair(Ctx parent, int tid, int sid) { super(parent, tid, sid); options.type = ZMQ.ZMQ_PAIR; } @Override protected void xattachPipe(Pipe pipe, boolean icanhasall) { assert (pipe != null); // ZMQ_PAIR socket can only be connected to a single peer. // The socket rejects any further connection requests. if (this.pipe == null) { this.pipe = pipe; } else { pipe.terminate(false); } } @Override protected void xpipeTerminated(Pipe pipe) { if (this.pipe == pipe) { this.pipe = null; } } @Override protected void xreadActivated(Pipe pipe) { // There's just one pipe. No lists of active and inactive pipes. // There's nothing to do here. } @Override protected void xwriteActivated(Pipe pipe) { // There's just one pipe. No lists of active and inactive pipes. // There's nothing to do here. } @Override protected boolean xsend(Msg msg) { if (pipe == null || !pipe.write(msg)) { errno.set(ZError.EAGAIN); return false; } if ((msg.flags() & ZMQ.ZMQ_SNDMORE) == 0) { pipe.flush(); } return true; } @Override protected Msg xrecv() { // Deallocate old content of the message. Msg msg = pipe == null ? null : pipe.read(); if (msg == null) { // Initialise the output parameter to be a 0-byte message. errno.set(ZError.EAGAIN); return null; } return msg; } @Override protected boolean xhasIn() { return pipe != null && pipe.checkRead(); } @Override protected boolean xhasOut() { return pipe != null && pipe.checkWrite(); } } jeromq-0.3.5/src/main/java/zmq/Pipe.java000066400000000000000000000420101255150477200200240ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; // Note that pipe can be stored in three different arrays. // The array of inbound pipes (1), the array of outbound pipes (2) and // the generic array of pipes to deallocate (3). class Pipe extends ZObject { interface IPipeEvents { void readActivated(Pipe pipe); void writeActivated(Pipe pipe); void hiccuped(Pipe pipe); void pipeTerminated(Pipe pipe); } // Underlying pipes for both directions. private YPipe inpipe; private YPipe outpipe; // Can the pipe be read from / written to? private boolean inActive; private boolean outActive; // High watermark for the outbound pipe. private int hwm; // Low watermark for the inbound pipe. private int lwm; // Number of messages read and written so far. private long msgsRead; private long msgsWritten; // Last received peer's msgsRead. The actual number in the peer // can be higher at the moment. private long peersMsgsRead; // The pipe object on the other side of the pipepair. private Pipe peer; // Sink to send events to. private IPipeEvents sink; // State of the pipe endpoint. Active is common state before any // termination begins. Delimited means that delimiter was read from // pipe before term command was received. Pending means that term // command was already received from the peer but there are still // pending messages to read. Terminating means that all pending // messages were already read and all we are waiting for is ack from // the peer. Terminated means that 'terminate' was explicitly called // by the user. Double_terminated means that user called 'terminate' // and then we've got term command from the peer as well. enum State { ACTIVE, DELIMITED, PENDING, TERMINATING, TERMINATED, DOUBLE_TERMINATED } private State state; // If true, we receive all the pending inbound messages before // terminating. If false, we terminate immediately when the peer // asks us to. private boolean delay; // Identity of the writer. Used uniquely by the reader side. private Blob identity; // JeroMQ only private ZObject parent; // Constructor is private. Pipe can only be created using // pipepair function. private Pipe(ZObject parent, YPipe inpipe, YPipe outpipe, int inhwm, int outhwm, boolean delay) { super(parent); this.inpipe = inpipe; this.outpipe = outpipe; inActive = true; outActive = true; hwm = outhwm; lwm = computeLwm(inhwm); msgsRead = 0; msgsWritten = 0; peersMsgsRead = 0; peer = null; sink = null; state = State.ACTIVE; this.delay = delay; this.parent = parent; } // Create a pipepair for bi-directional transfer of messages. // First HWM is for messages passed from first pipe to the second pipe. // Second HWM is for messages passed from second pipe to the first pipe. // Delay specifies how the pipe behaves when the peer terminates. If true // pipe receives all the pending messages before terminating, otherwise it // terminates straight away. public static void pipepair(ZObject[] parents, Pipe[] pipes, int[] hwms, boolean[] delays) { // Creates two pipe objects. These objects are connected by two ypipes, // each to pass messages in one direction. YPipe upipe1 = new YPipe(Config.MESSAGE_PIPE_GRANULARITY.getValue()); YPipe upipe2 = new YPipe(Config.MESSAGE_PIPE_GRANULARITY.getValue()); pipes[0] = new Pipe(parents[0], upipe1, upipe2, hwms[1], hwms[0], delays[0]); pipes[1] = new Pipe(parents[1], upipe2, upipe1, hwms[0], hwms[1], delays[1]); pipes[0].setPeer(pipes[1]); pipes[1].setPeer(pipes[0]); } // Pipepair uses this function to let us know about // the peer pipe object. private void setPeer(Pipe peer) { // Peer can be set once only. assert (peer != null); this.peer = peer; } // Specifies the object to send events to. public void setEventSink(IPipeEvents sink) { assert (this.sink == null); this.sink = sink; } // Pipe endpoint can store an opaque ID to be used by its clients. public void setIdentity(Blob identity) { this.identity = identity; } public Blob getIdentity() { return identity; } // Returns true if there is at least one message to read in the pipe. public boolean checkRead() { if (!inActive || (state != State.ACTIVE && state != State.PENDING)) { return false; } // Check if there's an item in the pipe. if (!inpipe.checkRead()) { inActive = false; return false; } // If the next item in the pipe is message delimiter, // initiate termination process. if (isDelimiter(inpipe.probe())) { Msg msg = inpipe.read(); assert (msg != null); delimit(); return false; } return true; } // Reads a message to the underlying pipe. public Msg read() { if (!inActive || (state != State.ACTIVE && state != State.PENDING)) { return null; } Msg msg = inpipe.read(); if (msg == null) { inActive = false; return null; } // If delimiter was read, start termination process of the pipe. if (msg.isDelimiter()) { delimit(); return null; } if (!msg.hasMore()) { msgsRead++; } if (lwm > 0 && msgsRead % lwm == 0) { sendActivateWrite(peer, msgsRead); } return msg; } // Checks whether messages can be written to the pipe. If writing // the message would cause high watermark the function returns false. public boolean checkWrite() { if (!outActive || state != State.ACTIVE) { return false; } boolean full = hwm > 0 && msgsWritten - peersMsgsRead == (long) (hwm); if (full) { outActive = false; return false; } return true; } // Writes a message to the underlying pipe. Returns false if the // message cannot be written because high watermark was reached. public boolean write(Msg msg) { if (!checkWrite()) { return false; } boolean more = msg.hasMore(); outpipe.write(msg, more); if (!more) { msgsWritten++; } return true; } // Remove unfinished parts of the outbound message from the pipe. public void rollback() { // Remove incomplete message from the outbound pipe. Msg msg; if (outpipe != null) { while ((msg = outpipe.unwrite()) != null) { assert ((msg.flags() & Msg.MORE) > 0); } } } // Flush the messages downsteam. public void flush() { // The peer does not exist anymore at this point. if (state == State.TERMINATING) { return; } if (outpipe != null && !outpipe.flush()) { sendActivateRead(peer); } } @Override protected void processActivateRead() { if (!inActive && (state == State.ACTIVE || state == State.PENDING)) { inActive = true; sink.readActivated(this); } } @Override protected void processActivateWrite(long msgsRead) { // Remember the peers's message sequence number. peersMsgsRead = msgsRead; if (!outActive && state == State.ACTIVE) { outActive = true; sink.writeActivated(this); } } @SuppressWarnings("unchecked") @Override protected void processHiccup(Object pipe) { // Destroy old outpipe. Note that the read end of the pipe was already // migrated to this thread. assert (outpipe != null); outpipe.flush(); while (outpipe.read() != null) { // do nothing } // Plug in the new outpipe. assert (pipe != null); outpipe = (YPipe) pipe; outActive = true; // If appropriate, notify the user about the hiccup. if (state == State.ACTIVE) { sink.hiccuped(this); } } @Override protected void processPipeTerm() { // This is the simple case of peer-induced termination. If there are no // more pending messages to read, or if the pipe was configured to drop // pending messages, we can move directly to the terminating state. // Otherwise we'll hang up in pending state till all the pending messages // are sent. if (state == State.ACTIVE) { if (!delay) { state = State.TERMINATING; outpipe = null; sendPipeTermAck(peer); } else { state = State.PENDING; } return; } // Delimiter happened to arrive before the term command. Now we have the // term command as well, so we can move straight to terminating state. if (state == State.DELIMITED) { state = State.TERMINATING; outpipe = null; sendPipeTermAck(peer); return; } // This is the case where both ends of the pipe are closed in parallel. // We simply reply to the request by ack and continue waiting for our // own ack. if (state == State.TERMINATED) { state = State.DOUBLE_TERMINATED; outpipe = null; sendPipeTermAck(peer); return; } // pipe_term is invalid in other states. assert (false); } @Override protected void processPipeTermAck() { // Notify the user that all the references to the pipe should be dropped. assert (sink != null); sink.pipeTerminated(this); // In terminating and double_terminated states there's nothing to do. // Simply deallocate the pipe. In terminated state we have to ack the // peer before deallocating this side of the pipe. All the other states // are invalid. if (state == State.TERMINATED) { outpipe = null; sendPipeTermAck(peer); } else { assert (state == State.TERMINATING || state == State.DOUBLE_TERMINATED); } // We'll deallocate the inbound pipe, the peer will deallocate the outbound // pipe (which is an inbound pipe from its point of view). // First, delete all the unread messages in the pipe. We have to do it by // hand because msg_t doesn't have automatic destructor. Then deallocate // the ypipe itself. while (inpipe.read() != null) { // do nothing } inpipe = null; // Deallocate the pipe object } // Ask pipe to terminate. The termination will happen asynchronously // and user will be notified about actual deallocation by 'terminated' // event. If delay is true, the pending messages will be processed // before actual shutdown. public void terminate(boolean delay) { // Overload the value specified at pipe creation. this.delay = delay; // If terminate was already called, we can ignore the duplicit invocation. if (state == State.TERMINATED || state == State.DOUBLE_TERMINATED) { return; } // If the pipe is in the final phase of async termination, it's going to // closed anyway. No need to do anything special here. else if (state == State.TERMINATING) { return; } // The simple sync termination case. Ask the peer to terminate and wait // for the ack. else if (state == State.ACTIVE) { sendPipeTerm(peer); state = State.TERMINATED; } // There are still pending messages available, but the user calls // 'terminate'. We can act as if all the pending messages were read. else if (state == State.PENDING && !this.delay) { outpipe = null; sendPipeTermAck(peer); state = State.TERMINATING; } // If there are pending messages still available, do nothing. else if (state == State.PENDING) { // do nothing } // We've already got delimiter, but not term command yet. We can ignore // the delimiter and ack synchronously terminate as if we were in // active state. else if (state == State.DELIMITED) { sendPipeTerm(peer); state = State.TERMINATED; } // There are no other states. else { assert (false); } // Stop outbound flow of messages. outActive = false; if (outpipe != null) { // Drop any unfinished outbound messages. rollback(); // Write the delimiter into the pipe. Note that watermarks are not // checked; thus the delimiter can be written even when the pipe is full. Msg msg = new Msg(); msg.initDelimiter(); outpipe.write(msg, false); flush(); } } // Returns true if the message is delimiter; false otherwise. private static boolean isDelimiter(Msg msg) { return msg.isDelimiter(); } // Computes appropriate low watermark from the given high watermark. private static int computeLwm(int hwm) { // Compute the low water mark. Following point should be taken // into consideration: // // 1. LWM has to be less than HWM. // 2. LWM cannot be set to very low value (such as zero) as after filling // the queue it would start to refill only after all the messages are // read from it and thus unnecessarily hold the progress back. // 3. LWM cannot be set to very high value (such as HWM-1) as it would // result in lock-step filling of the queue - if a single message is // read from a full queue, writer thread is resumed to write exactly one // message to the queue and go back to sleep immediately. This would // result in low performance. // // Given the 3. it would be good to keep HWM and LWM as far apart as // possible to reduce the thread switching overhead to almost zero, // say HWM-LWM should be max_wm_delta. // // That done, we still we have to account for the cases where // HWM < max_wm_delta thus driving LWM to negative numbers. // Let's make LWM 1/2 of HWM in such cases. return (hwm > Config.MAX_WM_DELTA.getValue() * 2) ? hwm - Config.MAX_WM_DELTA.getValue() : (hwm + 1) / 2; } // Handler for delimiter read from the pipe. private void delimit() { if (state == State.ACTIVE) { state = State.DELIMITED; return; } if (state == State.PENDING) { outpipe = null; sendPipeTermAck(peer); state = State.TERMINATING; return; } // Delimiter in any other state is invalid. assert (false); } // Temporaraily disconnects the inbound message stream and drops // all the messages on the fly. Causes 'hiccuped' event to be generated // in the peer. public void hiccup() { // If termination is already under way do nothing. if (state != State.ACTIVE) { return; } // We'll drop the pointer to the inpipe. From now on, the peer is // responsible for deallocating it. inpipe = null; // Create new inpipe. inpipe = new YPipe(Config.MESSAGE_PIPE_GRANULARITY.getValue()); inActive = true; // Notify the peer about the hiccup. sendHiccup(peer, inpipe); } @Override public String toString() { return super.toString() + "[" + parent + "]"; } } jeromq-0.3.5/src/main/java/zmq/PollItem.java000066400000000000000000000073361255150477200206700ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; public class PollItem { private SocketBase socket; private SelectableChannel channel; private int zinterest; private int interest; private int ready; public PollItem(SocketBase socket) { this.socket = socket; channel = null; zinterest = -1; interest = -1; } public PollItem(SocketBase socket, int ops) { this.socket = socket; channel = null; init(ops); } public PollItem(SelectableChannel channel, int ops) { socket = null; this.channel = channel; init(ops); } private void init(int ops) { zinterest = ops; int interest = 0; if ((ops & ZMQ.ZMQ_POLLIN) > 0) { interest |= SelectionKey.OP_READ; } if ((ops & ZMQ.ZMQ_POLLOUT) > 0) { if (socket != null) { // ZMQ Socket get readiness from the mailbox interest |= SelectionKey.OP_READ; } else { interest |= SelectionKey.OP_WRITE; } } this.interest = interest; ready = 0; } public final boolean isReadable() { return (ready & ZMQ.ZMQ_POLLIN) > 0; } public final boolean isWritable() { return (ready & ZMQ.ZMQ_POLLOUT) > 0; } public final boolean isError() { return (ready & ZMQ.ZMQ_POLLERR) > 0; } public final SocketBase getSocket() { return socket; } public final SelectableChannel getRawSocket() { return channel; } protected final SelectableChannel getChannel() { if (socket != null) { return socket.getFD(); } else { return channel; } } public final int interestOps() { return interest; } public final int interestOps(int ops) { init(ops); return interest; } public final int readyOps(SelectionKey key, int nevents) { ready = 0; if (socket != null) { int events = socket.getSocketOpt(ZMQ.ZMQ_EVENTS); if (events < 0) { return -1; } if ((zinterest & ZMQ.ZMQ_POLLOUT) > 0 && (events & ZMQ.ZMQ_POLLOUT) > 0) { ready |= ZMQ.ZMQ_POLLOUT; } if ((zinterest & ZMQ.ZMQ_POLLIN) > 0 && (events & ZMQ.ZMQ_POLLIN) > 0) { ready |= ZMQ.ZMQ_POLLIN; } } else if (nevents > 0) { if (key.isReadable()) { ready |= ZMQ.ZMQ_POLLIN; } if (key.isWritable()) { ready |= ZMQ.ZMQ_POLLOUT; } if (!key.isValid() || key.isAcceptable() || key.isConnectable()) { ready |= ZMQ.ZMQ_POLLERR; } } return ready; } public final int readyOps() { return ready; } } jeromq-0.3.5/src/main/java/zmq/Poller.java000066400000000000000000000174231255150477200203760ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.io.IOException; import java.nio.channels.CancelledKeyException; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; public class Poller extends PollerBase implements Runnable { private static class PollSet { protected IPollEvents handler; protected SelectionKey key; protected int ops; protected boolean cancelled; protected PollSet(IPollEvents handler) { this.handler = handler; key = null; cancelled = false; ops = 0; } } // This table stores data for registered descriptors. private final Map fdTable; // If true, there's at least one retired event source. private final AtomicBoolean retired = new AtomicBoolean(false); // If true, thread is in the process of shutting down. private volatile boolean stopping; private volatile boolean stopped; private Thread worker; private Selector selector; private final String name; public Poller() { this("poller"); } public Poller(String name) { this.name = name; stopping = false; stopped = false; fdTable = new HashMap(); try { selector = Selector.open(); } catch (IOException e) { throw new ZError.IOException(e); } } public void destroy() { if (!stopped) { try { worker.join(); } catch (InterruptedException e) { } } try { selector.close(); } catch (IOException e) { e.printStackTrace(); } } public final void addHandle(SelectableChannel fd, IPollEvents events) { fdTable.put(fd, new PollSet(events)); adjustLoad(1); } public final void removeHandle(SelectableChannel handle) { fdTable.get(handle).cancelled = true; retired.set(true); // Decrease the load metric of the thread. adjustLoad(-1); } public final void setPollIn(SelectableChannel handle) { register(handle, SelectionKey.OP_READ, false); } public final void resetPollOn(SelectableChannel handle) { register(handle, SelectionKey.OP_READ, true); } public final void setPollOut(SelectableChannel handle) { register(handle, SelectionKey.OP_WRITE, false); } public final void resetPollOut(SelectableChannel handle) { register(handle, SelectionKey.OP_WRITE, true); } public final void setPollConnect(SelectableChannel handle) { register(handle, SelectionKey.OP_CONNECT, false); } public final void setPollAccept(SelectableChannel handle) { register(handle, SelectionKey.OP_ACCEPT, false); } private final void register(SelectableChannel handle, int ops, boolean negate) { PollSet pollset = fdTable.get(handle); if (negate) { pollset.ops = pollset.ops & ~ops; } else { pollset.ops = pollset.ops | ops; } if (pollset.key != null) { pollset.key.interestOps(pollset.ops); } else { retired.set(true); } } public void start() { worker = new Thread(this, name); worker.setDaemon(true); worker.start(); } public void stop() { stopping = true; selector.wakeup(); } @Override public void run() { int returnsImmediately = 0; while (!stopping) { // Execute any due timers. long timeout = executeTimers(); while (retired.compareAndSet(true, false)) { Iterator> it = fdTable.entrySet().iterator(); while (it.hasNext()) { Map.Entry entry = it.next(); SelectableChannel ch = entry.getKey(); PollSet pollset = entry.getValue(); if (pollset.key == null) { try { pollset.key = ch.register(selector, pollset.ops, pollset.handler); } catch (ClosedChannelException e) { } } if (pollset.cancelled || !ch.isOpen()) { if (pollset.key != null) { pollset.key.cancel(); } it.remove(); } } } // Wait for events. int rc; long start = System.currentTimeMillis(); try { rc = selector.select(timeout); } catch (IOException e) { throw new ZError.IOException(e); } if (rc == 0) { // Guess JDK epoll bug if (timeout == 0 || System.currentTimeMillis() - start < timeout / 2) { returnsImmediately++; } else { returnsImmediately = 0; } if (returnsImmediately > 10) { rebuildSelector(); returnsImmediately = 0; } continue; } Iterator it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey key = it.next(); IPollEvents evt = (IPollEvents) key.attachment(); it.remove(); try { if (key.isReadable()) { evt.inEvent(); } else if (key.isAcceptable()) { evt.acceptEvent(); } else if (key.isConnectable()) { evt.connectEvent(); } if (key.isWritable()) { evt.outEvent(); } } catch (CancelledKeyException e) { // channel might have been closed } } } stopped = true; } private void rebuildSelector() { Selector newSelector; try { newSelector = Selector.open(); } catch (IOException e) { throw new ZError.IOException(e); } try { selector.close(); } catch (IOException e) { } selector = newSelector; for (PollSet pollSet : fdTable.values()) { pollSet.key = null; } retired.set(true); } } jeromq-0.3.5/src/main/java/zmq/PollerBase.java000066400000000000000000000104171255150477200211650ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicInteger; abstract class PollerBase { // Load of the poller. Currently the number of file descriptors // registered. private final AtomicInteger load; private final class TimerInfo { IPollEvents sink; int id; public TimerInfo(IPollEvents sink, int id) { this.sink = sink; this.id = id; } } private final Map timers; private final Map addingTimers; protected PollerBase() { load = new AtomicInteger(0); timers = new MultiMap(); addingTimers = new MultiMap(); } // Returns load of the poller. Note that this function can be // invoked from a different thread! public final int getLoad() { return load.get(); } // Called by individual poller implementations to manage the load. protected void adjustLoad(int amount) { load.addAndGet(amount); } // Add a timeout to expire in timeout_ milliseconds. After the // expiration timerEvent on sink_ object will be called with // argument set to id_. public void addTimer(long timeout, IPollEvents sink, int id) { long expiration = Clock.nowMS() + timeout; TimerInfo info = new TimerInfo(sink, id); addingTimers.put(expiration, info); } // Cancel the timer created by sink_ object with ID equal to id_. public void cancelTimer(IPollEvents sink, int id) { // Complexity of this operation is O(n). We assume it is rarely used. if (!addingTimers.isEmpty()) { timers.putAll(addingTimers); addingTimers.clear(); } Iterator> it = timers.entrySet().iterator(); while (it.hasNext()) { TimerInfo v = it.next().getValue(); if (v.sink == sink && v.id == id) { it.remove(); return; } } // Timer not found. assert (false); } // Executes any timers that are due. Returns number of milliseconds // to wait to match the next timer or 0 meaning "no timers". protected long executeTimers() { if (!addingTimers.isEmpty()) { timers.putAll(addingTimers); addingTimers.clear(); } // Fast track. if (timers.isEmpty()) { return 0L; } // Get the current time. long current = Clock.nowMS(); // Execute the timers that are already due. Iterator> it = timers.entrySet().iterator(); while (it.hasNext()) { Entry o = it.next(); // If we have to wait to execute the item, same will be true about // all the following items (multimap is sorted). Thus we can stop // checking the subsequent timers and return the time to wait for // the next timer (at least 1ms). if (o.getKey() > current) { return o.getKey() - current; } // Trigger the timer. o.getValue().sink.timerEvent(o.getValue().id); // Remove it from the list of active timers. it.remove(); } if (!addingTimers.isEmpty()) { return executeTimers(); } // There are no more timers. return 0L; } } jeromq-0.3.5/src/main/java/zmq/Proxy.java000066400000000000000000000106761255150477200202650ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.io.IOException; import java.nio.channels.Selector; public class Proxy { private Proxy() { } public static boolean proxy(SocketBase frontend, SocketBase backend, SocketBase capture) { // The algorithm below assumes ratio of requests and replies processed // under full load to be 1:1. // TODO: The current implementation drops messages when // any of the pipes becomes full. boolean success = true; int rc; long more; Msg msg; PollItem[] items = new PollItem[2]; items[0] = new PollItem(frontend, ZMQ.ZMQ_POLLIN); items[1] = new PollItem(backend, ZMQ.ZMQ_POLLIN); Selector selector; try { selector = Selector.open(); } catch (IOException e) { throw new ZError.IOException(e); } try { while (!Thread.currentThread().isInterrupted()) { // Wait while there are either requests or replies to process. rc = ZMQ.poll(selector, items, -1); if (rc < 0) { return false; } // Process a request. if (items[0].isReadable()) { while (true) { msg = frontend.recv(0); if (msg == null) { return false; } more = frontend.getSocketOpt(ZMQ.ZMQ_RCVMORE); if (more < 0) { return false; } // Copy message to capture socket if any if (capture != null) { Msg ctrl = new Msg(msg); success = capture.send(ctrl, more > 0 ? ZMQ.ZMQ_SNDMORE : 0); if (!success) { return false; } } success = backend.send(msg, more > 0 ? ZMQ.ZMQ_SNDMORE : 0); if (!success) { return false; } if (more == 0) { break; } } } // Process a reply. if (items[1].isReadable()) { while (true) { msg = backend.recv(0); if (msg == null) { return false; } more = backend.getSocketOpt(ZMQ.ZMQ_RCVMORE); if (more < 0) { return false; } // Copy message to capture socket if any if (capture != null) { Msg ctrl = new Msg(msg); success = capture.send(ctrl, more > 0 ? ZMQ.ZMQ_SNDMORE : 0); if (!success) { return false; } } success = frontend.send(msg, more > 0 ? ZMQ.ZMQ_SNDMORE : 0); if (!success) { return false; } if (more == 0) { break; } } } } } finally { try { selector.close(); } catch (Exception e) { } } return true; } } jeromq-0.3.5/src/main/java/zmq/Pub.java000066400000000000000000000026651255150477200176710ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; public class Pub extends XPub { public static class PubSession extends XPub.XPubSession { public PubSession(IOThread ioThread, boolean connect, SocketBase socket, Options options, Address addr) { super(ioThread, connect, socket, options, addr); } } public Pub(Ctx parent, int tid, int sid) { super(parent, tid, sid); options.type = ZMQ.ZMQ_PUB; } @Override protected Msg xrecv() { // Messages cannot be received from PUB socket. throw new UnsupportedOperationException(); } @Override protected boolean xhasIn() { return false; } } jeromq-0.3.5/src/main/java/zmq/Pull.java000066400000000000000000000034721255150477200200540ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; class Pull extends SocketBase { public static class PullSession extends SessionBase { public PullSession(IOThread ioThread, boolean connect, SocketBase socket, final Options options, final Address addr) { super(ioThread, connect, socket, options, addr); } } // Fair queueing object for inbound pipes. private final FQ fq; public Pull(Ctx parent, int tid, int sid) { super(parent, tid, sid); options.type = ZMQ.ZMQ_PULL; fq = new FQ(); } @Override protected void xattachPipe(Pipe pipe, boolean icanhasall) { assert (pipe != null); fq.attach(pipe); } @Override protected void xreadActivated(Pipe pipe) { fq.activated(pipe); } @Override protected void xpipeTerminated(Pipe pipe) { fq.terminated(pipe); } @Override public Msg xrecv() { return fq.recv(errno); } @Override protected boolean xhasIn() { return fq.hasIn(); } } jeromq-0.3.5/src/main/java/zmq/Push.java000066400000000000000000000035271255150477200200600ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; public class Push extends SocketBase { public static class PushSession extends SessionBase { public PushSession(IOThread ioThread, boolean connect, SocketBase socket, final Options options, final Address addr) { super(ioThread, connect, socket, options, addr); } } // Load balancer managing the outbound pipes. private final LB lb; public Push(Ctx parent, int tid, int sid) { super(parent, tid, sid); options.type = ZMQ.ZMQ_PUSH; lb = new LB(); } @Override protected void xattachPipe(Pipe pipe, boolean icanhasall) { assert (pipe != null); lb.attach(pipe); } @Override protected void xwriteActivated(Pipe pipe) { lb.activated(pipe); } @Override protected void xpipeTerminated(Pipe pipe) { lb.terminated(pipe); } @Override public boolean xsend(Msg msg) { return lb.send(msg, errno); } @Override protected boolean xhasOut() { return lb.hasOut(); } } jeromq-0.3.5/src/main/java/zmq/Reaper.java000066400000000000000000000072651255150477200203620ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.io.Closeable; import java.io.IOException; import java.nio.channels.SelectableChannel; public class Reaper extends ZObject implements IPollEvents, Closeable { // Reaper thread accesses incoming commands via this mailbox. private final Mailbox mailbox; // Handle associated with mailbox' file descriptor. private SelectableChannel mailboxHandle; // I/O multiplexing is performed using a poller object. private final Poller poller; // Number of sockets being reaped at the moment. private int sockets; // If true, we were already asked to terminate. private volatile boolean terminating; private String name; public Reaper(Ctx ctx, int tid) { super(ctx, tid); sockets = 0; terminating = false; name = "reaper-" + tid; poller = new Poller(name); mailbox = new Mailbox(name); mailboxHandle = mailbox.getFd(); poller.addHandle(mailboxHandle, this); poller.setPollIn(mailboxHandle); } @Override public void close() throws IOException { poller.destroy(); mailbox.close(); } public Mailbox getMailbox() { return mailbox; } public void start() { poller.start(); } public void stop() { if (!terminating) { sendStop(); } } @Override public void inEvent() { while (true) { // Get the next command. If there is none, exit. Command cmd = mailbox.recv(0); if (cmd == null) { break; } // Process the command. cmd.destination().processCommand(cmd); } } @Override public void outEvent() { throw new UnsupportedOperationException(); } @Override public void connectEvent() { throw new UnsupportedOperationException(); } @Override public void acceptEvent() { throw new UnsupportedOperationException(); } @Override public void timerEvent(int id) { throw new UnsupportedOperationException(); } @Override protected void processStop() { terminating = true; // If there are no sockets being reaped finish immediately. if (sockets == 0) { sendDone(); poller.removeHandle(mailboxHandle); poller.stop(); } } @Override protected void processReap(SocketBase socket) { // Add the socket to the poller. socket.startReaping(poller); ++sockets; } @Override protected void processReaped() { --sockets; // If reaped was already asked to terminate and there are no more sockets, // finish immediately. if (sockets == 0 && terminating) { sendDone(); poller.removeHandle(mailboxHandle); poller.stop(); } } } jeromq-0.3.5/src/main/java/zmq/Rep.java000066400000000000000000000077261255150477200176740ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; public class Rep extends Router { public static class RepSession extends Router.RouterSession { public RepSession(IOThread ioThread, boolean connect, SocketBase socket, final Options options, final Address addr) { super(ioThread, connect, socket, options, addr); } } // If true, we are in process of sending the reply. If false we are // in process of receiving a request. private boolean sendingReply; // If true, we are starting to receive a request. The beginning // of the request is the backtrace stack. private boolean requestBegins; public Rep(Ctx parent, int tid, int sid) { super(parent, tid, sid); sendingReply = false; requestBegins = true; options.type = ZMQ.ZMQ_REP; } @Override protected boolean xsend(Msg msg) { // If we are in the middle of receiving a request, we cannot send reply. if (!sendingReply) { throw new IllegalStateException("Cannot send another reply"); } boolean more = msg.hasMore(); // Push message to the reply pipe. boolean rc = super.xsend(msg); if (!rc) { return rc; } // If the reply is complete flip the FSM back to request receiving state. if (!more) { sendingReply = false; } return true; } @Override protected Msg xrecv() { // If we are in middle of sending a reply, we cannot receive next request. if (sendingReply) { throw new IllegalStateException("Cannot receive another request"); } Msg msg = null; // First thing to do when receiving a request is to copy all the labels // to the reply pipe. if (requestBegins) { while (true) { msg = super.xrecv(); if (msg == null) { return null; } if (msg.hasMore()) { // Empty message part delimits the traceback stack. boolean bottom = (msg.size() == 0); // Push it to the reply pipe. boolean rc = super.xsend(msg); assert (rc); if (bottom) { break; } } else { // If the traceback stack is malformed, discard anything // already sent to pipe (we're at end of invalid message). super.rollback(); } } requestBegins = false; } // Get next message part to return to the user. msg = super.xrecv(); if (msg == null) { return null; } // If whole request is read, flip the FSM to reply-sending state. if (!msg.hasMore()) { sendingReply = true; requestBegins = true; } return msg; } @Override protected boolean xhasIn() { return !sendingReply && super.xhasIn(); } @Override protected boolean xhasOut() { return sendingReply && super.xhasOut(); } } jeromq-0.3.5/src/main/java/zmq/Req.java000066400000000000000000000121711255150477200176630ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; public class Req extends Dealer { // If true, request was already sent and reply wasn't received yet or // was raceived partially. private boolean receivingReply; // If true, we are starting to send/recv a message. The first part // of the message must be empty message part (backtrace stack bottom). private boolean messageBegins; public Req(Ctx parent, int tid, int sid) { super(parent, tid, sid); receivingReply = false; messageBegins = true; options.type = ZMQ.ZMQ_REQ; } @Override public boolean xsend(Msg msg) { // If we've sent a request and we still haven't got the reply, // we can't send another request. if (receivingReply) { errno.set(ZError.EFSM); return false; } // First part of the request is the request identity. if (messageBegins) { Msg bottom = new Msg(); bottom.setFlags(Msg.MORE); boolean rc = super.xsend(bottom); if (!rc) { return rc; } messageBegins = false; } boolean more = msg.hasMore(); boolean rc = super.xsend(msg); if (!rc) { return rc; } // If the request was fully sent, flip the FSM into reply-receiving state. if (!more) { receivingReply = true; messageBegins = true; } return true; } @Override protected Msg xrecv() { // If request wasn't send, we can't wait for reply. if (!receivingReply) { errno.set(ZError.EFSM); return null; } Msg msg = null; // First part of the reply should be the original request ID. if (messageBegins) { msg = super.xrecv(); if (msg == null) { return null; } // TODO: This should also close the connection with the peer! if (!msg.hasMore() || msg.size() != 0) { while (true) { msg = super.xrecv(); assert (msg != null); if (!msg.hasMore()) { break; } } errno.set(ZError.EAGAIN); return null; } messageBegins = false; } msg = super.xrecv(); if (msg == null) { return null; } // If the reply is fully received, flip the FSM into request-sending state. if (!msg.hasMore()) { receivingReply = false; messageBegins = true; } return msg; } @Override public boolean xhasIn() { // TODO: Duplicates should be removed here. return receivingReply && super.xhasIn(); } @Override public boolean xhasOut() { return !receivingReply && super.xhasOut(); } public static class ReqSession extends Dealer.DealerSession { enum State { IDENTITY, BOTTOM, BODY }; private State state; public ReqSession(IOThread ioThread, boolean connect, SocketBase socket, final Options options, final Address addr) { super(ioThread, connect, socket, options, addr); state = State.IDENTITY; } @Override public int pushMsg(Msg msg) { switch (state) { case BOTTOM: if (msg.hasMore() && msg.size() == 0) { state = State.BODY; return super.pushMsg(msg); } break; case BODY: if (msg.hasMore()) { return super.pushMsg(msg); } if (msg.flags() == 0) { state = State.BOTTOM; return super.pushMsg(msg); } break; case IDENTITY: if (msg.flags() == 0) { state = State.BOTTOM; return super.pushMsg(msg); } break; } socket.errno.set(ZError.EFAULT); return -1; } public void reset() { super.reset(); state = State.IDENTITY; } } } jeromq-0.3.5/src/main/java/zmq/Router.java000066400000000000000000000305071255150477200204170ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; //TODO: This class uses O(n) scheduling. Rewrite it to use O(1) algorithm. public class Router extends SocketBase { public static class RouterSession extends SessionBase { public RouterSession(IOThread ioThread, boolean connect, SocketBase socket, final Options options, final Address addr) { super(ioThread, connect, socket, options, addr); } } // Fair queueing object for inbound pipes. private final FQ fq; // True iff there is a message held in the pre-fetch buffer. private boolean prefetched; // If true, the receiver got the message part with // the peer's identity. private boolean identitySent; // Holds the prefetched identity. private Msg prefetchedId; // Holds the prefetched message. private Msg prefetchedMsg; // If true, more incoming message parts are expected. private boolean moreIn; class Outpipe { private Pipe pipe; private boolean active; public Outpipe(Pipe pipe, boolean active) { this.pipe = pipe; this.active = active; } }; // We keep a set of pipes that have not been identified yet. private final Set anonymousPipes; // Outbound pipes indexed by the peer IDs. private final Map outpipes; // The pipe we are currently writing to. private Pipe currentOut; // If true, more outgoing message parts are expected. private boolean moreOut; // Peer ID are generated. It's a simple increment and wrap-over // algorithm. This value is the next ID to use (if not used already). private int nextPeerId; // If true, report EHOSTUNREACH to the caller instead of silently dropping // the message targeting an unknown peer. private boolean mandatory; private boolean handover; public Router(Ctx parent, int tid, int sid) { super(parent, tid, sid); prefetched = false; identitySent = false; moreIn = false; currentOut = null; moreOut = false; nextPeerId = Utils.generateRandom(); mandatory = false; handover = false; options.type = ZMQ.ZMQ_ROUTER; fq = new FQ(); prefetchedId = new Msg(); prefetchedMsg = new Msg(); anonymousPipes = new HashSet(); outpipes = new HashMap(); // TODO: Uncomment the following line when ROUTER will become true ROUTER // rather than generic router socket. // If peer disconnect there's noone to send reply to anyway. We can drop // all the outstanding requests from that peer. // options.delayOnDisconnect = false; options.recvIdentity = true; } @Override public void xattachPipe(Pipe pipe, boolean icanhasall) { assert (pipe != null); boolean identityOk = identifyPeer(pipe); if (identityOk) { fq.attach(pipe); } else { anonymousPipes.add(pipe); } } @Override public boolean xsetsockopt(int option, Object optval) { if (option == ZMQ.ZMQ_ROUTER_MANDATORY) { mandatory = (Integer) optval == 1; return true; } if (option == ZMQ.ZMQ_ROUTER_HANDOVER) { handover = (Integer) optval == 1; return true; } return false; } @Override public void xpipeTerminated(Pipe pipe) { if (!anonymousPipes.remove(pipe)) { Outpipe old = outpipes.remove(pipe.getIdentity()); assert (old != null); fq.terminated(pipe); if (pipe == currentOut) { currentOut = null; } } } @Override public void xreadActivated(Pipe pipe) { if (!anonymousPipes.contains(pipe)) { fq.activated(pipe); } else { boolean identityOk = identifyPeer(pipe); if (identityOk) { anonymousPipes.remove(pipe); fq.attach(pipe); } } } @Override public void xwriteActivated(Pipe pipe) { for (Map.Entry it : outpipes.entrySet()) { if (it.getValue().pipe == pipe) { assert (!it.getValue().active); it.getValue().active = true; return; } } assert (false); } @Override protected boolean xsend(Msg msg) { // If this is the first part of the message it's the ID of the // peer to send the message to. if (!moreOut) { assert (currentOut == null); // If we have malformed message (prefix with no subsequent message) // then just silently ignore it. // TODO: The connections should be killed instead. if (msg.hasMore()) { moreOut = true; // Find the pipe associated with the identity stored in the prefix. // If there's no such pipe just silently ignore the message, unless // mandatory is set. Blob identity = Blob.createBlob(msg.data(), true); Outpipe op = outpipes.get(identity); if (op != null) { currentOut = op.pipe; if (!currentOut.checkWrite()) { op.active = false; currentOut = null; if (mandatory) { moreOut = false; errno.set(ZError.EAGAIN); return false; } } } else if (mandatory) { moreOut = false; errno.set(ZError.EHOSTUNREACH); return false; } } return true; } // Check whether this is the last part of the message. moreOut = msg.hasMore(); // Push the message into the pipe. If there's no out pipe, just drop it. if (currentOut != null) { boolean ok = currentOut.write(msg); if (!ok) { currentOut = null; } else if (!moreOut) { currentOut.flush(); currentOut = null; } } return true; } @Override protected Msg xrecv() { Msg msg = null; if (prefetched) { if (!identitySent) { msg = prefetchedId; prefetchedId = null; identitySent = true; } else { msg = prefetchedMsg; prefetchedMsg = null; prefetched = false; } moreIn = msg.hasMore(); return msg; } ValueReference pipe = new ValueReference(); msg = fq.recvPipe(errno, pipe); // It's possible that we receive peer's identity. That happens // after reconnection. The current implementation assumes that // the peer always uses the same identity. // TODO: handle the situation when the peer changes its identity. while (msg != null && msg.isIdentity()) { msg = fq.recvPipe(errno, pipe); } if (msg == null) { return null; } assert (pipe.get() != null); // If we are in the middle of reading a message, just return the next part. if (moreIn) { moreIn = msg.hasMore(); } else { // We are at the beginning of a message. // Keep the message part we have in the prefetch buffer // and return the ID of the peer instead. prefetchedMsg = msg; prefetched = true; Blob identity = pipe.get().getIdentity(); msg = new Msg(identity.data()); msg.setFlags(Msg.MORE); identitySent = true; } return msg; } // Rollback any message parts that were sent but not yet flushed. protected void rollback() { if (currentOut != null) { currentOut.rollback(); currentOut = null; moreOut = false; } } @Override protected boolean xhasIn() { // If we are in the middle of reading the messages, there are // definitely more parts available. if (moreIn) { return true; } // We may already have a message pre-fetched. if (prefetched) { return true; } // Try to read the next message. // The message, if read, is kept in the pre-fetch buffer. ValueReference pipe = new ValueReference(); prefetchedMsg = fq.recvPipe(errno, pipe); // It's possible that we receive peer's identity. That happens // after reconnection. The current implementation assumes that // the peer always uses the same identity. // TODO: handle the situation when the peer changes its identity. while (prefetchedMsg != null && prefetchedMsg.isIdentity()) { prefetchedMsg = fq.recvPipe(errno, pipe); } if (prefetchedMsg == null) { return false; } assert (pipe.get() != null); Blob identity = pipe.get().getIdentity(); prefetchedId = new Msg(identity.data()); prefetchedId.setFlags(Msg.MORE); prefetched = true; identitySent = false; return true; } @Override protected boolean xhasOut() { // In theory, ROUTER socket is always ready for writing. Whether actual // attempt to write succeeds depends on whitch pipe the message is going // to be routed to. return true; } private boolean identifyPeer(Pipe pipe) { Blob identity; Msg msg = pipe.read(); if (msg == null) { return false; } if (msg.size() == 0) { // Fall back on the auto-generation ByteBuffer buf = ByteBuffer.allocate(5); buf.put((byte) 0); buf.putInt(nextPeerId++); identity = Blob.createBlob(buf.array(), false); } else { identity = Blob.createBlob(msg.data(), true); if (outpipes.containsKey(identity)) { if (!handover) { return false; } // We will allow the new connection to take over this // identity. Temporarily assign a new identity to the // existing pipe so we can terminate it asynchronously. ByteBuffer buf = ByteBuffer.allocate(5); buf.put((byte) 0); buf.putInt(nextPeerId++); Blob newIdentity = Blob.createBlob(buf.array(), false); // Remove the existing identity entry to allow the new // connection to take the identity. Outpipe existingOutpipe = outpipes.remove(identity); existingOutpipe.pipe.setIdentity(newIdentity); outpipes.put(newIdentity, existingOutpipe); existingOutpipe.pipe.terminate(true); } } pipe.setIdentity(identity); // Add the record into output pipes lookup table Outpipe outpipe = new Outpipe(pipe, true); outpipes.put(identity, outpipe); return true; } } jeromq-0.3.5/src/main/java/zmq/SessionBase.java000066400000000000000000000350241255150477200213540ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.util.HashSet; import java.util.Set; class SessionBase extends Own implements Pipe.IPipeEvents, IPollEvents, IMsgSink, IMsgSource { // If true, this session (re)connects to the peer. Otherwise, it's // a transient session created by the listener. private boolean connect; // Pipe connecting the session to its socket. private Pipe pipe; // This set is added to with pipes we are disconnecting, but haven't yet completed private final Set terminatingPipes; // This flag is true if the remainder of the message being processed // is still in the in pipe. private boolean incompleteIn; // True if termination have been suspended to push the pending // messages to the network. private boolean pending; // The protocol I/O engine connected to the session. private IEngine engine; // The socket the session belongs to. protected SocketBase socket; // I/O thread the session is living in. It will be used to plug in // the engines into the same thread. private IOThread ioThread; // ID of the linger timer private static final int LINGER_TIMER_ID = 0x20; // True is linger timer is running. private boolean hasLingerTimer; // If true, identity has been sent/received from the network. private boolean identitySent; private boolean identityReceived; // Protocol and address to use when connecting. private final Address addr; private IOObject ioObject; public static SessionBase create(IOThread ioThread, boolean connect, SocketBase socket, Options options, Address addr) { SessionBase s = null; switch (options.type) { case ZMQ.ZMQ_REQ: s = new Req.ReqSession(ioThread, connect, socket, options, addr); break; case ZMQ.ZMQ_DEALER: s = new Dealer.DealerSession(ioThread, connect, socket, options, addr); break; case ZMQ.ZMQ_REP: s = new Rep.RepSession(ioThread, connect, socket, options, addr); break; case ZMQ.ZMQ_ROUTER: s = new Router.RouterSession(ioThread, connect, socket, options, addr); break; case ZMQ.ZMQ_PUB: s = new Pub.PubSession(ioThread, connect, socket, options, addr); break; case ZMQ.ZMQ_XPUB: s = new XPub.XPubSession(ioThread, connect, socket, options, addr); break; case ZMQ.ZMQ_SUB: s = new Sub.SubSession(ioThread, connect, socket, options, addr); break; case ZMQ.ZMQ_XSUB: s = new XSub.XSubSession(ioThread, connect, socket, options, addr); break; case ZMQ.ZMQ_PUSH: s = new Push.PushSession(ioThread, connect, socket, options, addr); break; case ZMQ.ZMQ_PULL: s = new Pull.PullSession(ioThread, connect, socket, options, addr); break; case ZMQ.ZMQ_PAIR: s = new Pair.PairSession(ioThread, connect, socket, options, addr); break; default: throw new IllegalArgumentException("type=" + options.type); } return s; } public SessionBase(IOThread ioThread, boolean connect, SocketBase socket, Options options, Address addr) { super(ioThread, options); ioObject = new IOObject(ioThread); this.connect = connect; pipe = null; incompleteIn = false; pending = false; engine = null; this.socket = socket; this.ioThread = ioThread; hasLingerTimer = false; identitySent = false; identityReceived = false; this.addr = addr; terminatingPipes = new HashSet(); } @Override public void destroy() { assert (pipe == null); // If there's still a pending linger timer, remove it. if (hasLingerTimer) { ioObject.cancelTimer(LINGER_TIMER_ID); hasLingerTimer = false; } // Close the engine. if (engine != null) { engine.terminate(); } } // To be used once only, when creating the session. public void attachPipe(Pipe pipe) { assert (!isTerminating()); assert (this.pipe == null); assert (pipe != null); this.pipe = pipe; this.pipe.setEventSink(this); } public Msg pullMsg() { // First message to send is identity if (!identitySent) { Msg msg = new Msg(options.identitySize); msg.put(options.identity, 0, options.identitySize); identitySent = true; incompleteIn = false; return msg; } if (pipe == null) { return null; } Msg msg = pipe.read(); if (msg == null) { return null; } incompleteIn = msg.hasMore(); return msg; } @Override public int pushMsg(Msg msg) { // First message to receive is identity (if required). if (!identityReceived) { msg.setFlags(Msg.IDENTITY); identityReceived = true; if (!options.recvIdentity) { return 0; } } if (pipe != null && pipe.write(msg)) { return 0; } return ZError.EAGAIN; } protected void reset() { // Restore identity flags. identitySent = false; identityReceived = false; } public void flush() { if (pipe != null) { pipe.flush(); } } // Remove any half processed messages. Flush unflushed messages. // Call this function when engine disconnect to get rid of leftovers. private void cleanPipes() { if (pipe != null) { // Get rid of half-processed messages in the out pipe. Flush any // unflushed messages upstream. pipe.rollback(); pipe.flush(); // Remove any half-read message from the in pipe. while (incompleteIn) { Msg msg = pullMsg(); if (msg == null) { assert (!incompleteIn); break; } // msg.close (); } } } @Override public void pipeTerminated(Pipe pipe) { // Drop the reference to the deallocated pipe. assert (this.pipe == pipe || terminatingPipes.contains(pipe)); if (this.pipe == pipe) { // If this is our current pipe, remove it this.pipe = null; if (hasLingerTimer) { ioObject.cancelTimer(LINGER_TIMER_ID); hasLingerTimer = false; } } else { // Remove the pipe from the detached pipes set terminatingPipes.remove(pipe); } // If we are waiting for pending messages to be sent, at this point // we are sure that there will be no more messages and we can proceed // with termination safely. if (pending && this.pipe == null && terminatingPipes.isEmpty()) { pending = false; super.processTerm(0); } } @Override public void readActivated(Pipe pipe) { // Skip activating if we're detaching this pipe if (this.pipe != pipe) { assert (terminatingPipes.contains(pipe)); return; } if (engine != null) { engine.activateOut(); } else { this.pipe.checkRead(); } } @Override public void writeActivated(Pipe pipe) { // Skip activating if we're detaching this pipe if (this.pipe != pipe) { assert (terminatingPipes.contains(pipe)); return; } if (engine != null) { engine.activateIn(); } } @Override public void hiccuped(Pipe pipe) { // Hiccups are always sent from session to socket, not the other // way round. throw new UnsupportedOperationException("Must Override"); } public SocketBase getSocket() { return socket; } @Override protected void processPlug() { ioObject.setHandler(this); if (connect) { startConnecting(false); } } @Override protected void processAttach(IEngine engine) { assert (engine != null); // Create the pipe if it does not exist yet. if (pipe == null && !isTerminating()) { ZObject[] parents = {this, socket}; Pipe[] pipes = {null, null}; int[] hwms = {options.recvHwm, options.sendHwm}; boolean[] delays = {options.delayOnClose, options.delayOnDisconnect}; Pipe.pipepair(parents, pipes, hwms, delays); // Plug the local end of the pipe. pipes[0].setEventSink(this); // Remember the local end of the pipe. assert (pipe == null); pipe = pipes[0]; // Ask socket to plug into the remote end of the pipe. sendBind(socket, pipes[1]); } // Plug in the engine. assert (this.engine == null); this.engine = engine; this.engine.plug(ioThread, this); } public void detach() { // Engine is dead. Let's forget about it. engine = null; // Remove any half-done messages from the pipes. cleanPipes(); // Send the event to the derived class. detached(); // Just in case there's only a delimiter in the pipe. if (pipe != null) { pipe.checkRead(); } } protected void processTerm(int linger) { assert (!pending); // If the termination of the pipe happens before the term command is // delivered there's nothing much to do. We can proceed with the // stadard termination immediately. if (pipe == null && terminatingPipes.isEmpty()) { super.processTerm(0); return; } pending = true; // If there's finite linger value, delay the termination. // If linger is infinite (negative) we don't even have to set // the timer. if (linger > 0) { assert (!hasLingerTimer); ioObject.addTimer(linger, LINGER_TIMER_ID); hasLingerTimer = true; } // Start pipe termination process. Delay the termination till all messages // are processed in case the linger time is non-zero. if (pipe != null) { pipe.terminate(linger != 0); // TODO: Should this go into pipe_t::terminate ? // In case there's no engine and there's only delimiter in the // pipe it wouldn't be ever read. Thus we check for it explicitly. pipe.checkRead(); } } @Override public void timerEvent(int id) { // Linger period expired. We can proceed with termination even though // there are still pending messages to be sent. assert (id == LINGER_TIMER_ID); hasLingerTimer = false; // Ask pipe to terminate even though there may be pending messages in it. assert (pipe != null); pipe.terminate(false); } private void detached() { // Transient session self-destructs after peer disconnects. if (!connect) { terminate(); return; } // For delayed connect situations, terminate the pipe // and reestablish later on if (pipe != null && options.delayAttachOnConnect == 1 && !addr.protocol().equals("pgm") && !addr.protocol().equals("epgm")) { pipe.hiccup(); pipe.terminate(false); terminatingPipes.add(pipe); pipe = null; } reset(); // Reconnect. if (options.reconnectIvl != -1) { startConnecting(true); } // For subscriber sockets we hiccup the inbound pipe, which will cause // the socket object to resend all the subscriptions. if (pipe != null && (options.type == ZMQ.ZMQ_SUB || options.type == ZMQ.ZMQ_XSUB)) { pipe.hiccup(); } } private void startConnecting(boolean wait) { assert (connect); // Choose I/O thread to run connecter in. Given that we are already // running in an I/O thread, there must be at least one available. IOThread ioThread = chooseIoThread(options.affinity); assert (ioThread != null); // Create the connecter object. if (addr.protocol().equals("tcp")) { TcpConnecter connecter = new TcpConnecter( ioThread, this, options, addr, wait); launchChild(connecter); return; } if (addr.protocol().equals("ipc")) { IpcConnecter connecter = new IpcConnecter( ioThread, this, options, addr, wait); launchChild(connecter); return; } assert (false); } @Override public String toString() { return super.toString() + "[" + options.socketId + "]"; } @Override public void inEvent() { throw new UnsupportedOperationException(); } @Override public void outEvent() { throw new UnsupportedOperationException(); } @Override public void connectEvent() { throw new UnsupportedOperationException(); } @Override public void acceptEvent() { throw new UnsupportedOperationException(); } } jeromq-0.3.5/src/main/java/zmq/Signaler.java000066400000000000000000000111341255150477200206760ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.io.Closeable; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.Pipe; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.util.concurrent.atomic.AtomicInteger; // This is a cross-platform equivalent to signal_fd. However, as opposed // to signal_fd there can be at most one signal in the signaler at any // given moment. Attempt to send a signal before receiving the previous // one will result in undefined behaviour. public class Signaler implements Closeable { // Underlying write & read file descriptor. private final Pipe.SinkChannel w; private final Pipe.SourceChannel r; private final Selector selector; // Selector.selectNow at every sending message doesn't show enough performance private final AtomicInteger wcursor = new AtomicInteger(0); private int rcursor = 0; public Signaler() { // Create the socketpair for signaling. Pipe pipe; try { pipe = Pipe.open(); } catch (IOException e) { throw new ZError.IOException(e); } r = pipe.source(); w = pipe.sink(); // Set both fds to non-blocking mode. try { Utils.unblockSocket(w); Utils.unblockSocket(r); } catch (IOException e) { throw new ZError.IOException(e); } try { selector = Selector.open(); r.register(selector, SelectionKey.OP_READ); } catch (IOException e) { throw new ZError.IOException(e); } } @Override public void close() throws IOException { IOException exception = null; try { r.close(); } catch (IOException e) { exception = e; } try { w.close(); } catch (IOException e) { exception = e; } try { selector.close(); } catch (IOException e) { exception = e; } if (exception != null) { throw exception; } } public SelectableChannel getFd() { return r; } public void send() { int nbytes = 0; ByteBuffer dummy = ByteBuffer.allocate(1); while (true) { try { Thread.interrupted(); nbytes = w.write(dummy); } catch (IOException e) { throw new ZError.IOException(e); } if (nbytes == 0) { continue; } assert (nbytes == 1); wcursor.incrementAndGet(); break; } } public boolean waitEvent(long timeout) { int rc = 0; try { if (timeout == 0) { // waitEvent(0) is called every read/send of SocketBase // instant readiness is not strictly required // On the other hand, we can save lots of system call and increase performance return rcursor < wcursor.get(); } else if (timeout < 0) { rc = selector.select(0); } else { rc = selector.select(timeout); } } catch (IOException e) { throw new ZError.IOException(e); } if (rc == 0) { return false; } selector.selectedKeys().clear(); return true; } public void recv() { int nbytes = 0; try { ByteBuffer dummy = ByteBuffer.allocate(1); nbytes = r.read(dummy); assert nbytes == 1; } catch (IOException e) { throw new ZError.IOException(e); } rcursor++; } } jeromq-0.3.5/src/main/java/zmq/SocketBase.java000066400000000000000000001127471255150477200211710ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.nio.channels.SelectableChannel; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; public abstract class SocketBase extends Own implements IPollEvents, Pipe.IPipeEvents { // Map of open endpoints. private final Map endpoints; // Map of open inproc endpoints. private final Map inprocs; // Used to check whether the object is a socket. private int tag; // If true, associated context was already terminated. private boolean ctxTerminated; // If true, object should have been already destroyed. However, // destruction is delayed while we unwind the stack to the point // where it doesn't intersect the object being destroyed. private boolean destroyed; // Socket's mailbox object. private final Mailbox mailbox; // List of attached pipes. private final List pipes; // Reaper's poller and handle of this socket within it. private Poller poller; private SelectableChannel handle; // Timestamp of when commands were processed the last time. private long lastTsc; // Number of messages received since last command processing. private int ticks; // True if the last message received had MORE flag set. private boolean rcvmore; // Monitor socket private SocketBase monitorSocket; // Bitmask of events being monitored private int monitorEvents; protected ValueReference errno; protected SocketBase(Ctx parent, int tid, int sid) { super(parent, tid); tag = 0xbaddecaf; ctxTerminated = false; destroyed = false; lastTsc = 0; ticks = 0; rcvmore = false; monitorSocket = null; monitorEvents = 0; options.socketId = sid; options.linger = parent.get(ZMQ.ZMQ_BLOCKY) != 0 ? -1 : 0; endpoints = new MultiMap(); inprocs = new MultiMap(); pipes = new ArrayList(); mailbox = new Mailbox("socket-" + sid); errno = new ValueReference(0); } // Concrete algorithms for the x- methods are to be defined by // individual socket types. protected abstract void xattachPipe(Pipe pipe, boolean icanhasall); protected abstract void xpipeTerminated(Pipe pipe); // Returns false if object is not a socket. public boolean checkTag() { return tag == 0xbaddecaf; } // Create a socket of a specified type. public static SocketBase create(int type, Ctx parent, int tid, int sid) { SocketBase s = null; switch (type) { case ZMQ.ZMQ_PAIR: s = new Pair(parent, tid, sid); break; case ZMQ.ZMQ_PUB: s = new Pub(parent, tid, sid); break; case ZMQ.ZMQ_SUB: s = new Sub(parent, tid, sid); break; case ZMQ.ZMQ_REQ: s = new Req(parent, tid, sid); break; case ZMQ.ZMQ_REP: s = new Rep(parent, tid, sid); break; case ZMQ.ZMQ_DEALER: s = new Dealer(parent, tid, sid); break; case ZMQ.ZMQ_ROUTER: s = new Router(parent, tid, sid); break; case ZMQ.ZMQ_PULL: s = new Pull(parent, tid, sid); break; case ZMQ.ZMQ_PUSH: s = new Push(parent, tid, sid); break; case ZMQ.ZMQ_XPUB: s = new XPub(parent, tid, sid); break; case ZMQ.ZMQ_XSUB: s = new XSub(parent, tid, sid); break; default: throw new IllegalArgumentException("type=" + type); } return s; } public void destroy() { try { mailbox.close(); } catch (IOException ignore) { } stopMonitor(); assert (destroyed); } // Returns the mailbox associated with this socket. public Mailbox getMailbox() { return mailbox; } // Interrupt blocking call if the socket is stuck in one. // This function can be called from a different thread! public void stop() { // Called by ctx when it is terminated (zmq_term). // 'stop' command is sent from the threads that called zmq_term to // the thread owning the socket. This way, blocking call in the // owner thread can be interrupted. sendStop(); } // Check whether transport protocol, as specified in connect or // bind, is available and compatible with the socket type. private void checkProtocol(String protocol) { // First check out whether the protcol is something we are aware of. if (!protocol.equals("inproc") && !protocol.equals("ipc") && !protocol.equals("tcp") /*&& !protocol.equals("pgm") && !protocol.equals("epgm")*/) { throw new UnsupportedOperationException(protocol); } // Check whether socket type and transport protocol match. // Specifically, multicast protocols can't be combined with // bi-directional messaging patterns (socket types). if ((protocol.equals("pgm") || protocol.equals("epgm")) && options.type != ZMQ.ZMQ_PUB && options.type != ZMQ.ZMQ_SUB && options.type != ZMQ.ZMQ_XPUB && options.type != ZMQ.ZMQ_XSUB) { throw new UnsupportedOperationException(protocol + ",type=" + options.type); } // Protocol is available. } // Register the pipe with this socket. private void attachPipe(Pipe pipe) { attachPipe(pipe, false); } private void attachPipe(Pipe pipe, boolean icanhasall) { // First, register the pipe so that we can terminate it later on. pipe.setEventSink(this); pipes.add(pipe); // Let the derived socket type know about new pipe. xattachPipe(pipe, icanhasall); // If the socket is already being closed, ask any new pipes to terminate // straight away. if (isTerminating()) { registerTermAcks(1); pipe.terminate(false); } } public void setSocketOpt(int option, Object optval) { if (ctxTerminated) { throw new ZError.CtxTerminatedException(); } // First, check whether specific socket type overloads the option. if (xsetsockopt(option, optval)) { return; } // If the socket type doesn't support the option, pass it to // the generic option parser. options.setSocketOpt(option, optval); } public int getSocketOpt(int option) { if (option != ZMQ.ZMQ_EVENTS && ctxTerminated) { throw new ZError.CtxTerminatedException(); } // fast track to avoid boxing if (option == ZMQ.ZMQ_RCVMORE) { return rcvmore ? 1 : 0; } if (option == ZMQ.ZMQ_EVENTS) { boolean rc = processCommands(0, false); if (!rc && errno.get() == ZError.ETERM) { return -1; } assert (rc); int val = 0; if (hasOut()) { val |= ZMQ.ZMQ_POLLOUT; } if (hasIn()) { val |= ZMQ.ZMQ_POLLIN; } return val; } return (Integer) getsockoptx(option); } public Object getsockoptx(int option) { if (ctxTerminated) { throw new ZError.CtxTerminatedException(); } if (option == ZMQ.ZMQ_RCVMORE) { return rcvmore ? 1 : 0; } if (option == ZMQ.ZMQ_FD) { return mailbox.getFd(); } if (option == ZMQ.ZMQ_EVENTS) { boolean rc = processCommands(0, false); if (!rc && errno.get() == ZError.ETERM) { return -1; } assert (rc); int val = 0; if (hasOut()) { val |= ZMQ.ZMQ_POLLOUT; } if (hasIn()) { val |= ZMQ.ZMQ_POLLIN; } return val; } // If the socket type doesn't support the option, pass it to // the generic option parser. return options.getsockopt(option); } public boolean bind(final String addr) { if (ctxTerminated) { throw new ZError.CtxTerminatedException(); } // Process pending commands, if any. boolean brc = processCommands(0, false); if (!brc) { return false; } // Parse addr_ string. URI uri; try { uri = new URI(addr); } catch (URISyntaxException e) { throw new IllegalArgumentException(e); } String protocol = uri.getScheme(); String address = uri.getAuthority(); String path = uri.getPath(); if (address == null) { address = path; } checkProtocol(protocol); if (protocol.equals("inproc")) { Ctx.Endpoint endpoint = new Ctx.Endpoint(this, options); boolean rc = registerEndpoint(addr, endpoint); if (rc) { // Save last endpoint URI options.lastEndpoint = addr; } else { errno.set(ZError.EADDRINUSE); } return rc; } if (protocol.equals("pgm") || protocol.equals("epgm")) { // For convenience's sake, bind can be used interchageable with // connect for PGM and EPGM transports. return connect(addr); } // Remaining trasnports require to be run in an I/O thread, so at this // point we'll choose one. IOThread ioThread = chooseIoThread(options.affinity); if (ioThread == null) { throw new IllegalStateException("EMTHREAD"); } if (protocol.equals("tcp")) { TcpListener listener = new TcpListener(ioThread, this, options); int rc = listener.setAddress(address); if (rc != 0) { listener.destroy(); eventBindFailed(address, rc); errno.set(rc); return false; } // Save last endpoint URI options.lastEndpoint = listener.getAddress(); addEndpoint(options.lastEndpoint, listener); return true; } if (protocol.equals("ipc")) { IpcListener listener = new IpcListener(ioThread, this, options); int rc = listener.setAddress(address); if (rc != 0) { listener.destroy(); eventBindFailed(address, rc); errno.set(rc); return false; } // Save last endpoint URI options.lastEndpoint = listener.getAddress(); addEndpoint(addr, listener); return true; } throw new IllegalArgumentException(addr); } public boolean connect(String addr) { if (ctxTerminated) { throw new ZError.CtxTerminatedException(); } // Process pending commands, if any. boolean brc = processCommands(0, false); if (!brc) { return false; } // Parse addr_ string. URI uri; try { uri = new URI(addr); } catch (URISyntaxException e) { throw new IllegalArgumentException(e); } String protocol = uri.getScheme(); String address = uri.getAuthority(); String path = uri.getPath(); if (address == null) { address = path; } checkProtocol(protocol); if (protocol.equals("inproc")) { // TODO: inproc connect is specific with respect to creating pipes // as there's no 'reconnect' functionality implemented. Once that // is in place we should follow generic pipe creation algorithm. // Find the peer endpoint. Ctx.Endpoint peer = findEndpoint(addr); if (peer.socket == null) { return false; } // The total HWM for an inproc connection should be the sum of // the binder's HWM and the connector's HWM. int sndhwm = 0; if (options.sendHwm != 0 && peer.options.recvHwm != 0) { sndhwm = options.sendHwm + peer.options.recvHwm; } int rcvhwm = 0; if (options.recvHwm != 0 && peer.options.sendHwm != 0) { rcvhwm = options.recvHwm + peer.options.sendHwm; } // Create a bi-directional pipe to connect the peers. ZObject[] parents = {this, peer.socket}; Pipe[] pipes = {null, null}; int[] hwms = {sndhwm, rcvhwm}; boolean[] delays = {options.delayOnDisconnect, options.delayOnClose}; Pipe.pipepair(parents, pipes, hwms, delays); // Attach local end of the pipe to this socket object. attachPipe(pipes[0]); // If required, send the identity of the peer to the local socket. if (peer.options.recvIdentity) { Msg id = new Msg(options.identitySize); id.put(options.identity, 0 , options.identitySize); id.setFlags(Msg.IDENTITY); boolean written = pipes[0].write(id); assert (written); pipes[0].flush(); } // If required, send the identity of the local socket to the peer. if (options.recvIdentity) { Msg id = new Msg(peer.options.identitySize); id.put(peer.options.identity, 0 , peer.options.identitySize); id.setFlags(Msg.IDENTITY); boolean written = pipes[1].write(id); assert (written); pipes[1].flush(); } // Attach remote end of the pipe to the peer socket. Note that peer's // seqnum was incremented in findEndpoint function. We don't need it // increased here. sendBind(peer.socket, pipes[1], false); // Save last endpoint URI options.lastEndpoint = addr; // remember inproc connections for disconnect inprocs.put(addr, pipes[0]); return true; } // Choose the I/O thread to run the session in. IOThread ioThread = chooseIoThread(options.affinity); if (ioThread == null) { throw new IllegalStateException("Empty IO Thread"); } boolean ipv4only = options.ipv4only != 0; Address paddr = new Address(protocol, address, ipv4only); // Resolve address (if needed by the protocol) paddr.resolve(); // Create session. SessionBase session = SessionBase.create(ioThread, true, this, options, paddr); assert (session != null); // PGM does not support subscription forwarding; ask for all data to be // sent to this pipe. boolean icanhasall = false; if (protocol.equals("pgm") || protocol.equals("epgm")) { icanhasall = true; } if (options.delayAttachOnConnect != 1 || icanhasall) { // Create a bi-directional pipe. ZObject[] parents = {this, session}; Pipe[] pipes = {null, null}; int[] hwms = {options.sendHwm, options.recvHwm}; boolean[] delays = {options.delayOnDisconnect, options.delayOnClose}; Pipe.pipepair(parents, pipes, hwms, delays); // Attach local end of the pipe to the socket object. attachPipe(pipes[0], icanhasall); // Attach remote end of the pipe to the session object later on. session.attachPipe(pipes[1]); } // Save last endpoint URI options.lastEndpoint = paddr.toString(); addEndpoint(addr, session); return true; } // Creates new endpoint ID and adds the endpoint to the map. private void addEndpoint(String addr, Own endpoint) { // Activate the session. Make it a child of this socket. launchChild(endpoint); endpoints.put(addr, endpoint); } public boolean termEndpoint(String addr) { if (ctxTerminated) { throw new ZError.CtxTerminatedException(); } // Check whether endpoint address passed to the function is valid. if (addr == null) { throw new IllegalArgumentException(); } // Process pending commands, if any, since there could be pending unprocessed processOwn()'s // (from launchChild() for example) we're asked to terminate now. boolean rc = processCommands(0, false); if (!rc) { return false; } // Parse addr_ string. URI uri; try { uri = new URI(addr); } catch (URISyntaxException e) { throw new IllegalArgumentException(e); } String protocol = uri.getScheme(); // Disconnect an inproc socket if (protocol.equals("inproc")) { if (!inprocs.containsKey(addr)) { return false; } Iterator> it = inprocs.entrySet().iterator(); while (it.hasNext()) { it.next().getValue().terminate(true); it.remove(); } return true; } if (!endpoints.containsKey(addr)) { return false; } // Find the endpoints range (if any) corresponding to the addr_ string. Iterator> it = endpoints.entrySet().iterator(); while (it.hasNext()) { Entry e = it.next(); if (!e.getKey().equals(addr)) { continue; } termChild(e.getValue()); it.remove(); } return true; } public boolean send(Msg msg, int flags) { if (ctxTerminated) { errno.set(ZError.ETERM); return false; } // Check whether message passed to the function is valid. if (msg == null) { throw new IllegalArgumentException(); } // Process pending commands, if any. boolean brc = processCommands(0, true); if (!brc) { return false; } // Clear any user-visible flags that are set on the message. msg.resetFlags(Msg.MORE); // At this point we impose the flags on the message. if ((flags & ZMQ.ZMQ_SNDMORE) > 0) { msg.setFlags(Msg.MORE); } // Try to send the message. boolean rc = xsend(msg); if (rc) { return true; } if (errno.get() != ZError.EAGAIN) { return false; } // In case of non-blocking send we'll simply propagate // the error - including EAGAIN - up the stack. if ((flags & ZMQ.ZMQ_DONTWAIT) > 0 || options.sendTimeout == 0) { return false; } // Compute the time when the timeout should occur. // If the timeout is infite, don't care. int timeout = options.sendTimeout; long end = timeout < 0 ? 0 : (Clock.nowMS() + timeout); // Oops, we couldn't send the message. Wait for the next // command, process it and try to send the message again. // If timeout is reached in the meantime, return EAGAIN. while (true) { if (!processCommands(timeout, false)) { return false; } rc = xsend(msg); if (rc) { break; } if (errno.get() != ZError.EAGAIN) { return false; } if (timeout > 0) { timeout = (int) (end - Clock.nowMS()); if (timeout <= 0) { errno.set(ZError.EAGAIN); return false; } } } return true; } public Msg recv(int flags) { if (ctxTerminated) { errno.set(ZError.ETERM); return null; } // Once every inbound_poll_rate messages check for signals and process // incoming commands. This happens only if we are not polling altogether // because there are messages available all the time. If poll occurs, // ticks is set to zero and thus we avoid this code. // // Note that 'recv' uses different command throttling algorithm (the one // described above) from the one used by 'send'. This is because counting // ticks is more efficient than doing RDTSC all the time. if (++ticks == Config.INBOUND_POLL_RATE.getValue()) { if (!processCommands(0, false)) { return null; } ticks = 0; } // Get the message. Msg msg = xrecv(); if (msg == null && errno.get() != ZError.EAGAIN) { return null; } // If we have the message, return immediately. if (msg != null) { extractFlags(msg); return msg; } // If the message cannot be fetched immediately, there are two scenarios. // For non-blocking recv, commands are processed in case there's an // activate_reader command already waiting int a command pipe. // If it's not, return EAGAIN. if ((flags & ZMQ.ZMQ_DONTWAIT) > 0 || options.recvTimeout == 0) { if (!processCommands(0, false)) { return null; } ticks = 0; msg = xrecv(); if (msg == null) { return null; } extractFlags(msg); return msg; } // Compute the time when the timeout should occur. // If the timeout is infite, don't care. int timeout = options.recvTimeout; long end = timeout < 0 ? 0 : (Clock.nowMS() + timeout); // In blocking scenario, commands are processed over and over again until // we are able to fetch a message. boolean block = (ticks != 0); while (true) { if (!processCommands(block ? timeout : 0, false)) { return null; } msg = xrecv(); if (msg != null) { ticks = 0; break; } if (errno.get() != ZError.EAGAIN) { return null; } block = true; if (timeout > 0) { timeout = (int) (end - Clock.nowMS()); if (timeout <= 0) { errno.set(ZError.EAGAIN); return null; } } } extractFlags(msg); return msg; } public void close() { // Mark the socket as dead tag = 0xdeadbeef; // Transfer the ownership of the socket from this application thread // to the reaper thread which will take care of the rest of shutdown // process. sendReap(this); } // These functions are used by the polling mechanism to determine // which events are to be reported from this socket. boolean hasIn() { return xhasIn(); } boolean hasOut() { return xhasOut(); } // Using this function reaper thread ask the socket to register with // its poller. public void startReaping(Poller poller) { // Plug the socket to the reaper thread. this.poller = poller; handle = mailbox.getFd(); this.poller.addHandle(handle, this); this.poller.setPollIn(handle); // Initialise the termination and check whether it can be deallocated // immediately. terminate(); checkDestroy(); } // Processes commands sent to this socket (if any). If timeout is -1, // returns only after at least one command was processed. // If throttle argument is true, commands are processed at most once // in a predefined time period. private boolean processCommands(int timeout, boolean throttle) { Command cmd; if (timeout != 0) { // If we are asked to wait, simply ask mailbox to wait. cmd = mailbox.recv(timeout); } else { // If we are asked not to wait, check whether we haven't processed // commands recently, so that we can throttle the new commands. // Get the CPU's tick counter. If 0, the counter is not available. long tsc = 0; // save cpu Clock.rdtsc (); // Optimised version of command processing - it doesn't have to check // for incoming commands each time. It does so only if certain time // elapsed since last command processing. Command delay varies // depending on CPU speed: It's ~1ms on 3GHz CPU, ~2ms on 1.5GHz CPU // etc. The optimisation makes sense only on platforms where getting // a timestamp is a very cheap operation (tens of nanoseconds). if (tsc != 0 && throttle) { // Check whether TSC haven't jumped backwards (in case of migration // between CPU cores) and whether certain time have elapsed since // last command processing. If it didn't do nothing. if (tsc >= lastTsc && tsc - lastTsc <= Config.MAX_COMMAND_DELAY.getValue()) { return true; } lastTsc = tsc; } // Check whether there are any commands pending for this thread. cmd = mailbox.recv(0); } // Process all the commands available at the moment. while (true) { if (cmd == null) { break; } cmd.destination().processCommand(cmd); cmd = mailbox.recv(0); } if (ctxTerminated) { errno.set(ZError.ETERM); // Do not raise exception at the blocked operation return false; } return true; } @Override protected void processStop() { // Here, someone have called zmq_term while the socket was still alive. // We'll remember the fact so that any blocking call is interrupted and any // further attempt to use the socket will return ETERM. The user is still // responsible for calling zmq_close on the socket though! stopMonitor(); ctxTerminated = true; } @Override protected void processBind(Pipe pipe) { attachPipe(pipe); } @Override protected void processTerm(int linger) { // Unregister all inproc endpoints associated with this socket. // Doing this we make sure that no new pipes from other sockets (inproc) // will be initiated. unregisterEndpoints(this); // Ask all attached pipes to terminate. for (int i = 0; i != pipes.size(); ++i) { pipes.get(i).terminate(false); } registerTermAcks(pipes.size()); // Continue the termination process immediately. super.processTerm(linger); } // Delay actual destruction of the socket. @Override protected void processDestroy() { destroyed = true; } // The default implementation assumes there are no specific socket // options for the particular socket type. If not so, overload this // method. protected boolean xsetsockopt(int option, Object optval) { return false; } protected boolean xhasOut() { return false; } protected boolean xsend(Msg msg) { throw new UnsupportedOperationException("Must Override"); } protected boolean xhasIn() { return false; } protected Msg xrecv() { throw new UnsupportedOperationException("Must Override"); } protected void xreadActivated(Pipe pipe) { throw new UnsupportedOperationException("Must Override"); } protected void xwriteActivated(Pipe pipe) { throw new UnsupportedOperationException("Must Override"); } protected void xhiccuped(Pipe pipe) { throw new UnsupportedOperationException("Must override"); } @Override public void inEvent() { // This function is invoked only once the socket is running in the context // of the reaper thread. Process any commands from other threads/sockets // that may be available at the moment. Ultimately, the socket will // be destroyed. try { processCommands(0, false); } catch (ZError.CtxTerminatedException e) { } checkDestroy(); } @Override public void outEvent() { throw new UnsupportedOperationException(); } @Override public void connectEvent() { throw new UnsupportedOperationException(); } @Override public void acceptEvent() { throw new UnsupportedOperationException(); } @Override public void timerEvent(int id) { throw new UnsupportedOperationException(); } // To be called after processing commands or invoking any command // handlers explicitly. If required, it will deallocate the socket. private void checkDestroy() { // If the object was already marked as destroyed, finish the deallocation. if (destroyed) { // Remove the socket from the reaper's poller. poller.removeHandle(handle); // Remove the socket from the context. destroySocket(this); // Notify the reaper about the fact. sendReaped(); // Deallocate. super.processDestroy(); } } @Override public void readActivated(Pipe pipe) { xreadActivated(pipe); } @Override public void writeActivated(Pipe pipe) { xwriteActivated(pipe); } @Override public void hiccuped(Pipe pipe) { if (options.delayAttachOnConnect == 1) { pipe.terminate(false); } else { // Notify derived sockets of the hiccup xhiccuped(pipe); } } @Override public void pipeTerminated(Pipe pipe) { // Notify the specific socket type about the pipe termination. xpipeTerminated(pipe); // Remove pipe from inproc pipes Iterator> it = inprocs.entrySet().iterator(); while (it.hasNext()) { if (it.next().getValue() == pipe) { it.remove(); break; } } // Remove the pipe from the list of attached pipes and confirm its // termination if we are already shutting down. pipes.remove(pipe); if (isTerminating()) { unregisterTermAck(); } } // Moves the flags from the message to local variables, // to be later retrieved by getSocketOpt. private void extractFlags(Msg msg) { // Test whether IDENTITY flag is valid for this socket type. if ((msg.flags() & Msg.IDENTITY) > 0) { assert (options.recvIdentity); } // Remove MORE flag. rcvmore = msg.hasMore(); } public boolean monitor(final String addr, int events) { boolean rc; if (ctxTerminated) { throw new ZError.CtxTerminatedException(); } // Support deregistering monitoring endpoints as well if (addr == null) { stopMonitor(); return true; } // Parse addr_ string. URI uri; try { uri = new URI(addr); } catch (URISyntaxException e) { throw new IllegalArgumentException(e); } String protocol = uri.getScheme(); String address = uri.getAuthority(); String path = uri.getPath(); if (address == null) { address = path; } checkProtocol(protocol); // Event notification only supported over inproc:// if (!protocol.equals("inproc")) { stopMonitor(); throw new IllegalArgumentException("inproc socket required"); } // Register events to monitor monitorEvents = events; monitorSocket = getCtx().createSocket(ZMQ.ZMQ_PAIR); if (monitorSocket == null) { return false; } // Never block context termination on pending event messages int linger = 0; try { monitorSocket.setSocketOpt(ZMQ.ZMQ_LINGER, linger); } catch (IllegalArgumentException e) { stopMonitor(); throw e; } // Spawn the monitor socket endpoint rc = monitorSocket.bind(addr); if (!rc) { stopMonitor(); } return rc; } public void eventConnected(String addr, SelectableChannel ch) { if ((monitorEvents & ZMQ.ZMQ_EVENT_CONNECTED) == 0) { return; } monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_CONNECTED, addr, ch)); } public void eventConnectDelayed(String addr, int errno) { if ((monitorEvents & ZMQ.ZMQ_EVENT_CONNECT_DELAYED) == 0) { return; } monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_CONNECT_DELAYED, addr, errno)); } public void eventConnectRetried(String addr, int interval) { if ((monitorEvents & ZMQ.ZMQ_EVENT_CONNECT_RETRIED) == 0) { return; } monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_CONNECT_RETRIED, addr, interval)); } public void eventListening(String addr, SelectableChannel ch) { if ((monitorEvents & ZMQ.ZMQ_EVENT_LISTENING) == 0) { return; } monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_LISTENING, addr, ch)); } public void eventBindFailed(String addr, int errno) { if ((monitorEvents & ZMQ.ZMQ_EVENT_BIND_FAILED) == 0) { return; } monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_BIND_FAILED, addr, errno)); } public void eventAccepted(String addr, SelectableChannel ch) { if ((monitorEvents & ZMQ.ZMQ_EVENT_ACCEPTED) == 0) { return; } monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_ACCEPTED, addr, ch)); } public void eventAcceptFailed(String addr, int errno) { if ((monitorEvents & ZMQ.ZMQ_EVENT_ACCEPT_FAILED) == 0) { return; } monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_ACCEPT_FAILED, addr, errno)); } public void eventClosed(String addr, SelectableChannel ch) { if ((monitorEvents & ZMQ.ZMQ_EVENT_CLOSED) == 0) { return; } monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_CLOSED, addr, ch)); } public void eventCloseFailed(String addr, int errno) { if ((monitorEvents & ZMQ.ZMQ_EVENT_CLOSE_FAILED) == 0) { return; } monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_CLOSE_FAILED, addr, errno)); } public void eventDisconnected(String addr, SelectableChannel ch) { if ((monitorEvents & ZMQ.ZMQ_EVENT_DISCONNECTED) == 0) { return; } monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_DISCONNECTED, addr, ch)); } protected void monitorEvent(ZMQ.Event event) { if (monitorSocket == null) { return; } event.write(monitorSocket); } protected void stopMonitor() { if (monitorSocket != null) { if ((monitorEvents & ZMQ.ZMQ_EVENT_MONITOR_STOPPED) != 0) { monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_MONITOR_STOPPED, "", 0)); } monitorSocket.close(); monitorSocket = null; monitorEvents = 0; } } @Override public String toString() { return super.toString() + "[" + options.socketId + "]"; } public SelectableChannel getFD() { return mailbox.getFd(); } public String typeString() { switch (options.type) { case ZMQ.ZMQ_PAIR: return "PAIR"; case ZMQ.ZMQ_PUB: return "PUB"; case ZMQ.ZMQ_SUB: return "SUB"; case ZMQ.ZMQ_REQ: return "REQ"; case ZMQ.ZMQ_REP: return "REP"; case ZMQ.ZMQ_DEALER: return "DEALER"; case ZMQ.ZMQ_ROUTER: return "ROUTER"; case ZMQ.ZMQ_PULL: return "PULL"; case ZMQ.ZMQ_PUSH: return "PUSH"; default: return "UNKOWN"; } } public int errno() { return errno.get(); } } jeromq-0.3.5/src/main/java/zmq/StreamEngine.java000066400000000000000000000466101255150477200215220ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.SocketChannel; public class StreamEngine implements IEngine, IPollEvents, IMsgSink { // Size of the greeting message: // Preamble (10 bytes) + version (1 byte) + socket type (1 byte). private static final int GREETING_SIZE = 12; // True iff we are registered with an I/O poller. private boolean ioEnabled; //final private IOObject ioObject; private SocketChannel handle; private ByteBuffer inbuf; private int insize; private DecoderBase decoder; private Transfer outbuf; private int outsize; private EncoderBase encoder; // When true, we are still trying to determine whether // the peer is using versioned protocol, and if so, which // version. When false, normal message flow has started. private boolean handshaking; // The receive buffer holding the greeting message // that we are receiving from the peer. private final ByteBuffer greeting; // The send buffer holding the greeting message // that we are sending to the peer. private final ByteBuffer greetingOutputBuffer; // The session this engine is attached to. private SessionBase session; // Detached transient session. //private SessionBase leftover_session; private Options options; // String representation of endpoint private String endpoint; private boolean plugged; // Socket private SocketBase socket; private IOObject ioObject; public StreamEngine(SocketChannel handle, final Options options, final String endpoint) { this.handle = handle; inbuf = null; insize = 0; ioEnabled = false; outbuf = null; outsize = 0; handshaking = true; session = null; this.options = options; plugged = false; this.endpoint = endpoint; socket = null; greeting = ByteBuffer.allocate(GREETING_SIZE).order(ByteOrder.BIG_ENDIAN); greetingOutputBuffer = ByteBuffer.allocate(GREETING_SIZE).order(ByteOrder.BIG_ENDIAN); encoder = null; decoder = null; // Put the socket into non-blocking mode. try { Utils.unblockSocket(this.handle); // Set the socket buffer limits for the underlying socket. if (this.options.sndbuf != 0) { this.handle.socket().setSendBufferSize(this.options.sndbuf); } if (this.options.rcvbuf != 0) { this.handle.socket().setReceiveBufferSize(this.options.rcvbuf); } } catch (IOException e) { throw new ZError.IOException(e); } } private DecoderBase newDecoder(int size, long max, SessionBase session, int version) { if (options.decoder == null) { if (version == V1Protocol.VERSION) { return new V1Decoder(size, max, session); } return new Decoder(size, max); } try { Constructor dcon; if (version == 0) { dcon = options.decoder.getConstructor(int.class, long.class); return dcon.newInstance(size, max); } else { dcon = options.decoder.getConstructor(int.class, long.class, IMsgSink.class, int.class); return dcon.newInstance(size, max, session, version); } } catch (SecurityException e) { throw new ZError.InstantiationException(e); } catch (NoSuchMethodException e) { throw new ZError.InstantiationException(e); } catch (InvocationTargetException e) { throw new ZError.InstantiationException(e); } catch (IllegalAccessException e) { throw new ZError.InstantiationException(e); } catch (InstantiationException e) { throw new ZError.InstantiationException(e); } } private EncoderBase newEncoder(int size, SessionBase session, int version) { if (options.encoder == null) { if (version == V1Protocol.VERSION) { return new V1Encoder(size, session); } return new Encoder(size); } try { Constructor econ; if (version == 0) { econ = options.encoder.getConstructor(int.class); return econ.newInstance(size); } else { econ = options.encoder.getConstructor(int.class, IMsgSource.class, int.class); return econ.newInstance(size, session, version); } } catch (SecurityException e) { throw new ZError.InstantiationException(e); } catch (NoSuchMethodException e) { throw new ZError.InstantiationException(e); } catch (InvocationTargetException e) { throw new ZError.InstantiationException(e); } catch (IllegalAccessException e) { throw new ZError.InstantiationException(e); } catch (InstantiationException e) { throw new ZError.InstantiationException(e); } } public void destroy() { assert (!plugged); if (handle != null) { try { handle.close(); } catch (IOException e) { } handle = null; } } public void plug(IOThread ioThread, SessionBase session) { assert (!plugged); plugged = true; // Connect to session object. assert (this.session == null); assert (session != null); this.session = session; socket = this.session.getSocket(); ioObject = new IOObject(null); ioObject.setHandler(this); // Connect to I/O threads poller object. ioObject.plug(ioThread); ioObject.addHandle(handle); ioEnabled = true; // Send the 'length' and 'flags' fields of the identity message. // The 'length' field is encoded in the long format. greetingOutputBuffer.put((byte) 0xff); greetingOutputBuffer.putLong(options.identitySize + 1); greetingOutputBuffer.put((byte) 0x7f); ioObject.setPollIn(handle); // When there's a raw custom encoder, we don't send 10 bytes frame boolean custom = false; try { custom = options.encoder != null && options.encoder.getDeclaredField("RAW_ENCODER") != null; } catch (SecurityException e) { } catch (NoSuchFieldException e) { } if (!custom) { outsize = greetingOutputBuffer.position(); greetingOutputBuffer.flip(); outbuf = new Transfer.ByteBufferTransfer(greetingOutputBuffer); ioObject.setPollOut(handle); } // Flush all the data that may have been already received downstream. inEvent(); } private void unplug() { assert (plugged); plugged = false; // Cancel all fd subscriptions. if (ioEnabled) { ioObject.removeHandle(handle); ioEnabled = false; } // Disconnect from I/O threads poller object. ioObject.unplug(); // Disconnect from session object. if (encoder != null) { encoder.setMsgSource(null); } if (decoder != null) { decoder.setMsgSink(null); } session = null; } @Override public void terminate() { unplug(); destroy(); } @Override public void inEvent() { // If still handshaking, receive and process the greeting message. if (handshaking) { if (!handshake()) { return; } } assert (decoder != null); boolean disconnection = false; // If there's no data to process in the buffer... if (insize == 0) { // Retrieve the buffer and read as much data as possible. // Note that buffer can be arbitrarily large. However, we assume // the underlying TCP layer has fixed buffer size and thus the // number of bytes read will be always limited. inbuf = decoder.getBuffer(); insize = read(inbuf); inbuf.flip(); // Check whether the peer has closed the connection. if (insize == -1) { insize = 0; disconnection = true; } } // Push the data to the decoder. int processed = decoder.processBuffer(inbuf, insize); if (processed == -1) { disconnection = true; } else { // Stop polling for input if we got stuck. if (processed < insize) { ioObject.resetPollIn(handle); } // Adjust the buffer. insize -= processed; } // Flush all messages the decoder may have produced. session.flush(); // An input error has occurred. If the last decoded message // has already been accepted, we terminate the engine immediately. // Otherwise, we stop waiting for socket events and postpone // the termination until after the message is accepted. if (disconnection) { if (decoder.stalled()) { ioObject.removeHandle(handle); ioEnabled = false; } else { error(); } } } @Override public void outEvent() { // If write buffer is empty, try to read new data from the encoder. if (outsize == 0) { // Even when we stop polling as soon as there is no // data to send, the poller may invoke outEvent one // more time due to 'speculative write' optimisation. if (encoder == null) { assert (handshaking); return; } outbuf = encoder.getData(null); outsize = outbuf.remaining(); // If there is no data to send, stop polling for output. if (outbuf.remaining() == 0) { ioObject.resetPollOut(handle); // when we use custom encoder, we might want to close if (encoder.isError()) { error(); } return; } } // If there are any data to write in write buffer, write as much as // possible to the socket. Note that amount of data to write can be // arbitratily large. However, we assume that underlying TCP layer has // limited transmission buffer and thus the actual number of bytes // written should be reasonably modest. int nbytes = write(outbuf); // IO error has occurred. We stop waiting for output events. // The engine is not terminated until we detect input error; // this is necessary to prevent losing incomming messages. if (nbytes == -1) { ioObject.resetPollOut(handle); return; } outsize -= nbytes; // If we are still handshaking and there are no data // to send, stop polling for output. if (handshaking) { if (outsize == 0) { ioObject.resetPollOut(handle); } } // when we use custom encoder, we might want to close after sending a response if (outsize == 0) { if (encoder != null && encoder.isError()) { error(); } } } @Override public void connectEvent() { throw new UnsupportedOperationException(); } @Override public void acceptEvent() { throw new UnsupportedOperationException(); } @Override public void timerEvent(int id) { throw new UnsupportedOperationException(); } @Override public void activateOut() { ioObject.setPollOut(handle); // Speculative write: The assumption is that at the moment new message // was sent by the user the socket is probably available for writing. // Thus we try to write the data to socket avoiding polling for POLLOUT. // Consequently, the latency should be better in request/reply scenarios. outEvent(); } @Override public void activateIn() { if (!ioEnabled) { // There was an input error but the engine could not // be terminated (due to the stalled decoder). // Flush the pending message and terminate the engine now. decoder.processBuffer(inbuf, 0); assert (!decoder.stalled()); session.flush(); error(); return; } ioObject.setPollIn(handle); // Speculative read. ioObject.inEvent(); } private boolean handshake() { assert (handshaking); // Receive the greeting. while (greeting.position() < GREETING_SIZE) { final int n = read(greeting); if (n == -1) { error(); return false; } if (n == 0) { return false; } // We have received at least one byte from the peer. // If the first byte is not 0xff, we know that the // peer is using unversioned protocol. if ((greeting.get(0) & 0xff) != 0xff) { break; } if (greeting.position() < 10) { continue; } // Inspect the right-most bit of the 10th byte (which coincides // with the 'flags' field if a regular message was sent). // Zero indicates this is a header of identity message // (i.e. the peer is using the unversioned protocol). if ((greeting.get(9) & 0x01) == 0) { break; } // The peer is using versioned protocol. // Send the rest of the greeting, if necessary. if (greetingOutputBuffer.limit() < GREETING_SIZE) { if (outsize == 0) { ioObject.setPollOut(handle); } int pos = greetingOutputBuffer.position(); greetingOutputBuffer.position(10).limit(GREETING_SIZE); greetingOutputBuffer.put((byte) 1); // Protocol version greetingOutputBuffer.put((byte) options.type); // Socket type greetingOutputBuffer.position(pos); outsize += 2; } } // Position of the version field in the greeting. final int versionPos = 10; // Is the peer using the unversioned protocol? // If so, we send and receive rests of identity // messages. if ((greeting.get(0) & 0xff) != 0xff || (greeting.get(9) & 0x01) == 0) { encoder = newEncoder(Config.OUT_BATCH_SIZE.getValue(), null, 0); encoder.setMsgSource(session); decoder = newDecoder(Config.IN_BATCH_SIZE.getValue(), options.maxMsgSize, null, 0); decoder.setMsgSink(session); // We have already sent the message header. // Since there is no way to tell the encoder to // skip the message header, we simply throw that // header data away. final int headerSize = options.identitySize + 1 >= 255 ? 10 : 2; ByteBuffer tmp = ByteBuffer.allocate(headerSize); encoder.getData(tmp); if (tmp.remaining() != headerSize) { return false; } // Make sure the decoder sees the data we have already received. inbuf = greeting; greeting.flip(); insize = greeting.remaining(); // To allow for interoperability with peers that do not forward // their subscriptions, we inject a phony subsription // message into the incomming message stream. To put this // message right after the identity message, we temporarily // divert the message stream from session to ourselves. if (options.type == ZMQ.ZMQ_PUB || options.type == ZMQ.ZMQ_XPUB) { decoder.setMsgSink(this); } } else if (greeting.get(versionPos) == 0) { // ZMTP/1.0 framing. encoder = newEncoder(Config.OUT_BATCH_SIZE.getValue(), null, 0); encoder.setMsgSource(session); decoder = newDecoder(Config.IN_BATCH_SIZE.getValue(), options.maxMsgSize, null, 0); decoder.setMsgSink(session); } else { // v1 framing protocol. encoder = newEncoder(Config.OUT_BATCH_SIZE.getValue(), session, V1Protocol.VERSION); decoder = newDecoder(Config.IN_BATCH_SIZE.getValue(), options.maxMsgSize, session, V1Protocol.VERSION); } // Start polling for output if necessary. if (outsize == 0) { ioObject.setPollOut(handle); } // Handshaking was successful. // Switch into the normal message flow. handshaking = false; return true; } @Override public int pushMsg(Msg msg) { assert (options.type == ZMQ.ZMQ_PUB || options.type == ZMQ.ZMQ_XPUB); // The first message is identity. // Let the session process it. int rc = session.pushMsg(msg); assert (rc == 0); // Inject the subscription message so that the ZMQ 2.x peer // receives our messages. msg = new Msg(new byte[] { 1 }); rc = session.pushMsg(msg); session.flush(); // Once we have injected the subscription message, we can // Divert the message flow back to the session. assert (decoder != null); decoder.setMsgSink(session); return rc; } private void error() { assert (session != null); socket.eventDisconnected(endpoint, handle); session.detach(); unplug(); destroy(); } private int write(Transfer buf) { int nbytes; try { nbytes = buf.transferTo(handle); } catch (IOException e) { return -1; } return nbytes; } private int read(ByteBuffer buf) { int nbytes; try { nbytes = handle.read(buf); } catch (IOException e) { return -1; } return nbytes; } } jeromq-0.3.5/src/main/java/zmq/Sub.java000066400000000000000000000051321255150477200176640ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; public class Sub extends XSub { public static class SubSession extends XSub.XSubSession { public SubSession(IOThread ioThread, boolean connect, SocketBase socket, Options options, Address addr) { super(ioThread, connect, socket, options, addr); } } public Sub(Ctx parent, int tid, int sid) { super(parent, tid, sid); options.type = ZMQ.ZMQ_SUB; // Switch filtering messages on (as opposed to XSUB which where the // filtering is off). options.filter = true; } @Override public boolean xsetsockopt(int option, Object optval) { if (option != ZMQ.ZMQ_SUBSCRIBE && option != ZMQ.ZMQ_UNSUBSCRIBE) { return false; } byte[] val; if (optval instanceof String) { val = ((String) optval).getBytes(ZMQ.CHARSET); } else if (optval instanceof byte[]) { val = (byte[]) optval; } else { throw new IllegalArgumentException(); } // Create the subscription message. Msg msg = new Msg(val.length + 1); if (option == ZMQ.ZMQ_SUBSCRIBE) { msg.put((byte) 1); } else { // option = ZMQ.ZMQ_UNSUBSCRIBE msg.put((byte) 0); } msg.put(val); // Pass it further on in the stack. boolean rc = super.xsend(msg); if (!rc) { throw new IllegalStateException("Failed to send subscribe/unsubscribe message"); } return true; } @Override protected boolean xsend(Msg msg) { // Overload the XSUB's send. throw new UnsupportedOperationException(); } @Override protected boolean xhasOut() { // Overload the XSUB's send. return false; } } jeromq-0.3.5/src/main/java/zmq/TcpAddress.java000066400000000000000000000077021255150477200211740ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.UnknownHostException; public class TcpAddress implements Address.IZAddress { public static class TcpAddressMask extends TcpAddress { public boolean matchAddress(SocketAddress addr) { return address.equals(addr); } } protected InetSocketAddress address; public TcpAddress(String addr) { resolve(addr, false); } public TcpAddress() { } @Override public String toString() { if (address == null) { return ""; } if (address.getAddress() instanceof Inet6Address) { return "tcp://[" + address.getAddress().getHostAddress() + "]:" + address.getPort(); } else { return "tcp://" + address.getAddress().getHostAddress() + ":" + address.getPort(); } } public int getPort() { if (address != null) { return address.getPort(); } return -1; } //Used after binding to ephemeral port to update ephemeral port (0) to actual port protected void updatePort(int port) { address = new InetSocketAddress(address.getAddress(), port); } @Override public void resolve(String name, boolean ipv4only) { // Find the ':' at end that separates address from the port number. int delimiter = name.lastIndexOf(':'); if (delimiter < 0) { throw new IllegalArgumentException(name); } // Separate the address/port. String addrStr = name.substring(0, delimiter); String portStr = name.substring(delimiter + 1); // Remove square brackets around the address, if any. if (addrStr.length() >= 2 && addrStr.charAt(0) == '[' && addrStr.charAt(addrStr.length() - 1) == ']') { addrStr = addrStr.substring(1, addrStr.length() - 1); } int port; // Allow 0 specifically, to detect invalid port error in atoi if not if (portStr.equals("*") || portStr.equals("0")) { // Resolve wildcard to 0 to allow autoselection of port port = 0; } else { // Parse the port number (0 is not a valid port). port = Integer.parseInt(portStr); if (port == 0) { throw new IllegalArgumentException(name); } } InetAddress addrNet = null; if (addrStr.equals("*")) { addrStr = "0.0.0.0"; } try { for (InetAddress ia : InetAddress.getAllByName(addrStr)) { if (ipv4only && (ia instanceof Inet6Address)) { continue; } addrNet = ia; break; } } catch (UnknownHostException e) { throw new IllegalArgumentException(e); } if (addrNet == null) { throw new IllegalArgumentException(name); } address = new InetSocketAddress(addrNet, port); } @Override public SocketAddress address() { return address; } } jeromq-0.3.5/src/main/java/zmq/TcpConnecter.java000066400000000000000000000235461255150477200215330ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.io.IOException; import java.net.ConnectException; import java.net.SocketAddress; import java.net.SocketException; import java.net.SocketTimeoutException; import java.nio.channels.SocketChannel; // If 'delay' is true connecter first waits for a while, then starts // connection process. public class TcpConnecter extends Own implements IPollEvents { // ID of the timer used to delay the reconnection. private static final int RECONNECT_TIMER_ID = 1; private final IOObject ioObject; // Address to connect to. Owned by session_base_t. private final Address addr; // Underlying socket. private SocketChannel handle; // If true file descriptor is registered with the poller and 'handle' // contains valid value. private boolean handleValid; // If true, connecter is waiting a while before trying to connect. private boolean delayedStart; // True iff a timer has been started. private boolean timerStarted; // Reference to the session we belong to. private SessionBase session; // Current reconnect ivl, updated for backoff strategy private int currentReconnectIvl; // String representation of endpoint to connect to private Address address; // Socket private SocketBase socket; public TcpConnecter(IOThread ioThread, SessionBase session, final Options options, final Address addr, boolean delayedStart) { super(ioThread, options); ioObject = new IOObject(ioThread); this.addr = addr; handle = null; handleValid = false; this.delayedStart = delayedStart; timerStarted = false; this.session = session; currentReconnectIvl = this.options.reconnectIvl; assert (this.addr != null); address = this.addr; socket = session.getSocket(); } public void destroy() { assert (!timerStarted); assert (!handleValid); assert (handle == null); } @Override protected void processPlug() { ioObject.setHandler(this); if (delayedStart) { addreconnectTimer(); } else { startConnecting(); } } @Override public void processTerm(int linger) { if (timerStarted) { ioObject.cancelTimer(RECONNECT_TIMER_ID); timerStarted = false; } if (handleValid) { ioObject.removeHandle(handle); handleValid = false; } if (handle != null) { close(); } super.processTerm(linger); } @Override public void inEvent() { // connected but attaching to stream engine is not completed. do nothing } @Override public void outEvent() { // connected but attaching to stream engine is not completed. do nothing } @Override public void acceptEvent() { throw new UnsupportedOperationException(); } @Override public void connectEvent() { boolean err = false; SocketChannel fd = null; try { fd = connect(); } catch (ConnectException e) { err = true; } catch (SocketException e) { err = true; } catch (SocketTimeoutException e) { err = true; } catch (IOException e) { throw new ZError.IOException(e); } ioObject.removeHandle(handle); handleValid = false; if (err) { // Handle the error condition by attempt to reconnect. close(); addreconnectTimer(); return; } handle = null; try { Utils.tuneTcpSocket(fd); Utils.tuneTcpKeepalives(fd, options.tcpKeepAlive, options.tcpKeepAliveCnt, options.tcpKeepAliveIdle, options.tcpKeepAliveIntvl); } catch (SocketException e) { throw new RuntimeException(e); } // Create the engine object for this connection. StreamEngine engine = null; try { engine = new StreamEngine(fd, options, address.toString()); } catch (ZError.InstantiationException e) { socket.eventConnectDelayed(address.toString(), -1); return; } // Attach the engine to the corresponding session object. sendAttach(session, engine); // Shut the connecter down. terminate(); socket.eventConnected(address.toString(), fd); } @Override public void timerEvent(int id) { timerStarted = false; startConnecting(); } // Internal function to start the actual connection establishment. private void startConnecting() { // Open the connecting socket. try { boolean rc = open(); // Connect may succeed in synchronous manner. if (rc) { ioObject.addHandle(handle); handleValid = true; ioObject.connectEvent(); } // Connection establishment may be delayed. Poll for its completion. else { ioObject.addHandle(handle); handleValid = true; ioObject.setPollConnect(handle); socket.eventConnectDelayed(address.toString(), -1); } } catch (IOException e) { // Handle any other error condition by eventual reconnect. if (handle != null) { close(); } addreconnectTimer(); } } // Internal function to add a reconnect timer private void addreconnectTimer() { int rcIvl = getNewReconnectIvl(); ioObject.addTimer(rcIvl, RECONNECT_TIMER_ID); // resolve address again to take into account other addresses // besides the failing one (e.g. multiple dns entries). try { address.resolve(); } catch (Exception ignored) { // This will fail if the network goes away and the // address cannot be resolved for some reason. Try // not to fail as the event loop will quit } socket.eventConnectRetried(address.toString(), rcIvl); timerStarted = true; } // Internal function to return a reconnect backoff delay. // Will modify the currentReconnectIvl used for next call // Returns the currently used interval private int getNewReconnectIvl() { // The new interval is the current interval + random value. int thisInterval = currentReconnectIvl + (Utils.generateRandom() % options.reconnectIvl); // Only change the current reconnect interval if the maximum reconnect // interval was set and if it's larger than the reconnect interval. if (options.reconnectIvlMax > 0 && options.reconnectIvlMax > options.reconnectIvl) { // Calculate the next interval currentReconnectIvl = currentReconnectIvl * 2; if (currentReconnectIvl >= options.reconnectIvlMax) { currentReconnectIvl = options.reconnectIvlMax; } } return thisInterval; } // Open TCP connecting socket. Returns -1 in case of error, // true if connect was successfull immediately. Returns false with // if async connect was launched. private boolean open() throws IOException { assert (handle == null); // Create the socket. handle = SocketChannel.open(); // Set the socket to non-blocking mode so that we get async connect(). Utils.unblockSocket(handle); // Connect to the remote peer. if (addr == null) { throw new IOException("Null address"); } Address.IZAddress resolved = addr.resolved(); if (resolved == null) { throw new IOException("Address not resolved"); } SocketAddress sa = resolved.address(); if (sa == null) { throw new IOException("Socket address not resolved"); } boolean rc = false; try { rc = handle.connect(sa); } catch (IllegalArgumentException e) { // this will happen if sa is bad. Address validation is not documented but // I've found that IAE is thrown in openjdk as well as on android. throw new IOException(e.getMessage(), e); } return rc; } // Get the file descriptor of newly created connection. Returns // retired_fd if the connection was unsuccessfull. private SocketChannel connect() throws IOException { boolean finished = handle.finishConnect(); assert finished; SocketChannel ret = handle; return ret; } // Close the connecting socket. private void close() { assert (handle != null); try { handle.close(); socket.eventClosed(address.toString(), handle); } catch (IOException e) { socket.eventCloseFailed(address.toString(), ZError.exccode(e)); } handle = null; } } jeromq-0.3.5/src/main/java/zmq/TcpListener.java000066400000000000000000000144201255150477200213670ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.io.IOException; import java.net.Socket; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; public class TcpListener extends Own implements IPollEvents { private static boolean isWindows; static { String os = System.getProperty("os.name").toLowerCase(); isWindows = os.indexOf("win") >= 0; } // Address to listen on. private final TcpAddress address; // Underlying socket. private ServerSocketChannel handle; // Socket the listerner belongs to. private SocketBase socket; // String representation of endpoint to bind to private String endpoint; private final IOObject ioObject; public TcpListener(IOThread ioThread, SocketBase socket, final Options options) { super(ioThread, options); ioObject = new IOObject(ioThread); address = new TcpAddress(); handle = null; this.socket = socket; } @Override public void destroy() { assert (handle == null); } @Override protected void processPlug() { // Start polling for incoming connections. ioObject.setHandler(this); ioObject.addHandle(handle); ioObject.setPollAccept(handle); } @Override protected void processTerm(int linger) { ioObject.setHandler(this); ioObject.removeHandle(handle); close(); super.processTerm(linger); } @Override public void acceptEvent() { SocketChannel fd = null; try { fd = accept(); Utils.tuneTcpSocket(fd); Utils.tuneTcpKeepalives(fd, options.tcpKeepAlive, options.tcpKeepAliveCnt, options.tcpKeepAliveIdle, options.tcpKeepAliveIntvl); } catch (IOException e) { // If connection was reset by the peer in the meantime, just ignore it. // TODO: Handle specific errors like ENFILE/EMFILE etc. socket.eventAcceptFailed(endpoint, ZError.exccode(e)); return; } // Create the engine object for this connection. StreamEngine engine = null; try { engine = new StreamEngine(fd, options, endpoint); } catch (ZError.InstantiationException e) { socket.eventAcceptFailed(endpoint, ZError.EINVAL); return; } // Choose I/O thread to run connecter in. Given that we are already // running in an I/O thread, there must be at least one available. IOThread ioThread = chooseIoThread(options.affinity); // Create and launch a session object. SessionBase session = SessionBase.create(ioThread, false, socket, options, new Address(fd.socket().getRemoteSocketAddress())); session.incSeqnum(); launchChild(session); sendAttach(session, engine, false); socket.eventAccepted(endpoint, fd); } // Close the listening socket. private void close() { if (handle == null) { return; } try { handle.close(); socket.eventClosed(endpoint, handle); } catch (IOException e) { socket.eventCloseFailed(endpoint, ZError.exccode(e)); } handle = null; } public String getAddress() { return address.toString(); } // Set address to listen on. public int setAddress(final String addr) { address.resolve(addr, options.ipv4only > 0); try { handle = ServerSocketChannel.open(); handle.configureBlocking(false); if (!isWindows) { handle.socket().setReuseAddress(true); } handle.socket().bind(address.address(), options.backlog); if (address.getPort() == 0) { address.updatePort(handle.socket().getLocalPort()); } } catch (IOException e) { close(); return ZError.EADDRINUSE; } endpoint = address.toString(); socket.eventListening(endpoint, handle); return 0; } // Accept the new connection. Returns the file descriptor of the // newly created connection. The function may return retired_fd // if the connection was dropped while waiting in the listen backlog // or was denied because of accept filters. private SocketChannel accept() { Socket sock = null; try { sock = handle.socket().accept(); } catch (IOException e) { return null; } if (!options.tcpAcceptFilters.isEmpty()) { boolean matched = false; for (TcpAddress.TcpAddressMask am : options.tcpAcceptFilters) { if (am.matchAddress(address.address())) { matched = true; break; } } if (!matched) { try { sock.close(); } catch (IOException e) { } return null; } } return sock.getChannel(); } @Override public void inEvent() { throw new UnsupportedOperationException(); } @Override public void outEvent() { throw new UnsupportedOperationException(); } @Override public void connectEvent() { throw new UnsupportedOperationException(); } @Override public void timerEvent(int id) { throw new UnsupportedOperationException(); } } jeromq-0.3.5/src/main/java/zmq/Transfer.java000066400000000000000000000054021255150477200207170ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.WritableByteChannel; public interface Transfer { public int transferTo(WritableByteChannel s) throws IOException; public int remaining(); public static class ByteBufferTransfer implements Transfer { private ByteBuffer buf; public ByteBufferTransfer(ByteBuffer buf) { this.buf = buf; } @Override public final int transferTo(WritableByteChannel s) throws IOException { return s.write(buf); } @Override public final int remaining() { return buf.remaining(); } } public static class FileChannelTransfer implements Transfer { private Transfer parent; private FileChannel channel; private long position; private long count; private int remaining; public FileChannelTransfer(ByteBuffer buf, FileChannel channel, long position, long count) { parent = new ByteBufferTransfer(buf); this.channel = channel; this.position = position; this.count = count; remaining = parent.remaining() + (int) this.count; } @Override public final int transferTo(WritableByteChannel s) throws IOException { int sent = 0; if (parent.remaining() > 0) { sent = parent.transferTo(s); } if (parent.remaining() == 0) { long fileSent = channel.transferTo(position, count, s); position += fileSent; count -= fileSent; sent += fileSent; } remaining -= sent; if (remaining == 0) { channel.close(); } return sent; } @Override public final int remaining() { return remaining; } } } jeromq-0.3.5/src/main/java/zmq/Trie.java000066400000000000000000000220651255150477200200420ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; public class Trie { private int refcnt; private byte min; private int count; private int liveNodes; public interface ITrieHandler { void added(byte[] data, int size, Object arg); } Trie[] next; public Trie() { min = 0; count = 0; liveNodes = 0; refcnt = 0; next = null; } // Add key to the trie. Returns true if this is a new item in the trie // rather than a duplicate. public boolean add(byte[] prefix) { return add(prefix, 0); } public boolean add(byte[] prefix, int start) { // We are at the node corresponding to the prefix. We are done. if (prefix == null || prefix.length == start) { ++refcnt; return refcnt == 1; } byte c = prefix[start]; if (c < min || c >= min + count) { // The character is out of range of currently handled // charcters. We have to extend the table. if (count == 0) { min = c; count = 1; next = null; } else if (count == 1) { byte oldc = min; Trie oldp = next[0]; count = (min < c ? c - min : min - c) + 1; next = new Trie[count]; min = (byte) Math.min(min, c); next[oldc - min] = oldp; } else if (min < c) { // The new character is above the current character range. count = c - min + 1; next = realloc(next, count, true); } else { // The new character is below the current character range. count = (min + count) - c; next = realloc(next, count, false); min = c; } } // If next node does not exist, create one. if (count == 1) { if (next == null) { next = new Trie[1]; next[0] = new Trie(); ++liveNodes; //alloc_assert (next.node); } return next[0].add(prefix, start + 1); } else { if (next[c - min] == null) { next[c - min] = new Trie(); ++liveNodes; //alloc_assert (next.table [c - min]); } return next[c - min].add(prefix, start + 1); } } private Trie[] realloc(Trie[] table, int size, boolean ended) { return Utils.realloc(Trie.class, table, size, ended); } // Remove key from the trie. Returns true if the item is actually // removed from the trie. public boolean rm(byte[] prefix, int start) { if (prefix == null || prefix.length == start) { if (refcnt == 0) { return false; } refcnt--; return refcnt == 0; } byte c = prefix[start]; if (count == 0 || c < min || c >= min + count) { return false; } Trie nextNode = count == 1 ? next[0] : next[c - min]; if (nextNode == null) { return false; } boolean ret = nextNode.rm(prefix , start + 1); if (nextNode.isRedundant()) { //delete next_node; assert (count > 0); if (count == 1) { next = null; count = 0; --liveNodes; assert (liveNodes == 0); } else { next[c - min] = null; assert (liveNodes > 1); --liveNodes; // Compact the table if possible if (liveNodes == 1) { // If there's only one live node in the table we can // switch to using the more compact single-node // representation Trie node = null; for (int i = 0; i < count; ++i) { if (next[i] != null) { node = next[i]; min = (byte) (i + min); break; } } assert (node != null); //free (next.table); next = null; next = new Trie[]{node}; count = 1; } else if (c == min) { // We can compact the table "from the left" byte newMin = min; for (int i = 1; i < count; ++i) { if (next[i] != null) { newMin = (byte) (i + min); break; } } assert (newMin != min); assert (newMin > min); assert (count > newMin - min); count = count - (newMin - min); next = realloc(next, count, true); min = newMin; } else if (c == min + count - 1) { // We can compact the table "from the right" int newCount = count; for (int i = 1; i < count; ++i) { if (next[count - 1 - i] != null) { newCount = count - i; break; } } assert (newCount != count); count = newCount; next = realloc(next, count, false); } } } return ret; } // Check whether particular key is in the trie. public boolean check(byte[] data) { // This function is on critical path. It deliberately doesn't use // recursion to get a bit better performance. Trie current = this; int start = 0; while (true) { // We've found a corresponding subscription! if (current.refcnt > 0) { return true; } // We've checked all the data and haven't found matching subscription. if (data.length == start) { return false; } // If there's no corresponding slot for the first character // of the prefix, the message does not match. byte c = data[start]; if (c < current.min || c >= current.min + current.count) { return false; } // Move to the next character. if (current.count == 1) { current = current.next[0]; } else { current = current.next[c - current.min]; if (current == null) { return false; } } start++; } } // Apply the function supplied to each subscription in the trie. public void apply(ITrieHandler func, Object arg) { applyHelper(null, 0, 0, func, arg); } private void applyHelper(byte[] buff, int buffsize, int maxBuffsize, ITrieHandler func, Object arg) { // If this node is a subscription, apply the function. if (refcnt > 0) { func.added(buff, buffsize, arg); } // Adjust the buffer. if (buffsize >= maxBuffsize) { maxBuffsize = buffsize + 256; buff = Utils.realloc(buff, maxBuffsize); assert (buff != null); } // If there are no subnodes in the trie, return. if (count == 0) { return; } // If there's one subnode (optimisation). if (count == 1) { buff [buffsize] = min; buffsize++; next[0].applyHelper(buff, buffsize, maxBuffsize, func, arg); return; } // If there are multiple subnodes. for (int c = 0; c != count; c++) { buff [buffsize] = (byte) (min + c); if (next[c] != null) { next[c].applyHelper(buff, buffsize + 1, maxBuffsize, func, arg); } } } private boolean isRedundant() { return refcnt == 0 && liveNodes == 0; } } jeromq-0.3.5/src/main/java/zmq/Utils.java000066400000000000000000000110631255150477200202330ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.io.File; import java.io.IOException; import java.lang.reflect.Array; import java.net.Socket; import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.channels.SelectableChannel; import java.nio.channels.SocketChannel; import java.security.SecureRandom; import java.util.List; class Utils { private Utils() { } private static SecureRandom random = new SecureRandom(); public static int generateRandom() { return random.nextInt(); } public static void tuneTcpSocket(SocketChannel ch) throws SocketException { tuneTcpSocket(ch.socket()); } public static void tuneTcpSocket(Socket fd) throws SocketException { // Disable Nagle's algorithm. We are doing data batching on 0MQ level, // so using Nagle wouldn't improve throughput in anyway, but it would // hurt latency. try { fd.setTcpNoDelay(true); } catch (SocketException e) { } } public static void tuneTcpKeepalives(SocketChannel ch, int tcpKeepalive, int tcpKeepaliveCnt, int tcpKeepaliveIdle, int tcpKeepaliveIntvl) throws SocketException { tuneTcpKeepalives(ch.socket(), tcpKeepalive, tcpKeepaliveCnt, tcpKeepaliveIdle, tcpKeepaliveIntvl); } public static void tuneTcpKeepalives(Socket fd, int tcpKeepalive, int tcpKeepaliveCnt, int tcpKeepaliveIdle, int tcpKeepaliveIntvl) throws SocketException { if (tcpKeepalive == 1) { fd.setKeepAlive(true); } else if (tcpKeepalive == 0) { fd.setKeepAlive(false); } } public static void unblockSocket(SelectableChannel s) throws IOException { s.configureBlocking(false); } @SuppressWarnings("unchecked") public static T[] realloc(Class klass, T[] src, int size, boolean ended) { T[] dest; if (size > src.length) { dest = (T[]) Array.newInstance(klass, size); if (ended) { System.arraycopy(src, 0, dest, 0, src.length); } else { System.arraycopy(src, 0, dest, size - src.length, src.length); } } else if (size < src.length) { dest = (T[]) Array.newInstance(klass, size); if (ended) { System.arraycopy(src, src.length - size, dest, 0, size); } else { System.arraycopy(src, 0, dest, 0, size); } } else { dest = src; } return dest; } public static void swap(List items, int index1, int index2) { if (index1 == index2) { return; } T item1 = items.get(index1); T item2 = items.get(index2); if (item1 != null) { items.set(index2, item1); } if (item2 != null) { items.set(index1, item2); } } public static byte[] bytes(ByteBuffer buf) { byte[] d = new byte[buf.limit()]; buf.get(d); return d; } public static byte[] realloc(byte[] src, int size) { byte[] dest = new byte[size]; if (src != null) { System.arraycopy(src, 0, dest, 0, src.length); } return dest; } public static boolean delete(File path) { if (!path.exists()) { return false; } boolean ret = true; if (path.isDirectory()) { File[] files = path.listFiles(); if (files != null) { for (File f : files) { ret = ret && delete(f); } } } return ret && path.delete(); } } jeromq-0.3.5/src/main/java/zmq/V1Decoder.java000066400000000000000000000116551255150477200207160ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.nio.ByteBuffer; public class V1Decoder extends DecoderBase { private static final int ONE_BYTE_SIZE_READY = 0; private static final int EIGHT_BYTE_SIZE_READY = 1; private static final int FLAGS_READY = 2; private static final int MESSAGE_READY = 3; private final byte[] tmpbuf; private Msg inProgress; private IMsgSink msgSink; private final long maxmsgsize; private int msgFlags; public V1Decoder(int bufsize, long maxmsgsize, IMsgSink session) { super(bufsize); this.maxmsgsize = maxmsgsize; msgSink = session; tmpbuf = new byte[8]; // At the beginning, read one byte and go to ONE_BYTE_SIZE_READY state. nextStep(tmpbuf, 1, FLAGS_READY); } // Set the receiver of decoded messages. @Override public void setMsgSink(IMsgSink msgSink) { this.msgSink = msgSink; } @Override protected boolean next() { switch(state()) { case ONE_BYTE_SIZE_READY: return oneByteSizeReady(); case EIGHT_BYTE_SIZE_READY: return eightByteSizeReady(); case FLAGS_READY: return flagsReady(); case MESSAGE_READY: return messageReady(); default: return false; } } private boolean oneByteSizeReady() { int size = tmpbuf[0]; if (size < 0) { size = (0xff) & size; } // Message size must not exceed the maximum allowed size. if (maxmsgsize >= 0) { if (size > maxmsgsize) { decodingError(); return false; } } // inProgress is initialised at this point so in theory we should // close it before calling msgInitWithSize, however, it's a 0-byte // message and thus we can treat it as uninitialised... inProgress = new Msg(size); inProgress.setFlags(msgFlags); nextStep(inProgress.data(), inProgress.size(), MESSAGE_READY); return true; } private boolean eightByteSizeReady() { // The payload size is encoded as 64-bit unsigned integer. // The most significant byte comes first. final long msgSize = ByteBuffer.wrap(tmpbuf).getLong(); // Message size must not exceed the maximum allowed size. if (maxmsgsize >= 0) { if (msgSize > maxmsgsize) { decodingError(); return false; } } // Message size must fit within range of size_t data type. if (msgSize > Integer.MAX_VALUE) { decodingError(); return false; } // inProgress is initialised at this point so in theory we should // close it before calling init_size, however, it's a 0-byte // message and thus we can treat it as uninitialised. inProgress = new Msg((int) msgSize); inProgress.setFlags(msgFlags); nextStep(inProgress.data(), inProgress.size(), MESSAGE_READY); return true; } private boolean flagsReady() { // Store the flags from the wire into the message structure. msgFlags = 0; int first = tmpbuf[0]; if ((first & V1Protocol.MORE_FLAG) > 0) { msgFlags |= Msg.MORE; } // The payload length is either one or eight bytes, // depending on whether the 'large' bit is set. if ((first & V1Protocol.LARGE_FLAG) > 0) { nextStep(tmpbuf, 8, EIGHT_BYTE_SIZE_READY); } else { nextStep(tmpbuf, 1, ONE_BYTE_SIZE_READY); } return true; } private boolean messageReady() { // Message is completely read. Push it further and start reading // new message. (inProgress is a 0-byte message after this point.) if (msgSink == null) { return false; } int rc = msgSink.pushMsg(inProgress); if (rc != 0) { if (rc != ZError.EAGAIN) { decodingError(); } return false; } nextStep(tmpbuf, 1, FLAGS_READY); return true; } } jeromq-0.3.5/src/main/java/zmq/V1Encoder.java000066400000000000000000000063771255150477200207350ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.nio.ByteBuffer; // Encoder for 0MQ framing protocol. Converts messages into data stream. public class V1Encoder extends EncoderBase { private static final int SIZE_READY = 0; private static final int MESSAGE_READY = 1; private Msg inProgress; private final byte[] tmpbuf; private IMsgSource msgSource; public V1Encoder(int bufsize, IMsgSource session) { super(bufsize); tmpbuf = new byte[9]; msgSource = session; // Write 0 bytes to the batch and go to messageReady state. nextStep((byte[]) null, 0, MESSAGE_READY, true); } @Override public void setMsgSource(IMsgSource msgSource) { this.msgSource = msgSource; } @Override protected boolean next() { switch(state()) { case SIZE_READY: return sizeReady(); case MESSAGE_READY: return messageReady(); default: return false; } } private boolean sizeReady() { // Write message body into the buffer. nextStep(inProgress.data(), inProgress.size(), MESSAGE_READY, !inProgress.hasMore()); return true; } private boolean messageReady() { // Read new message. If there is none, return false. // Note that new state is set only if write is successful. That way // unsuccessful write will cause retry on the next state machine // invocation. if (msgSource == null) { return false; } inProgress = msgSource.pullMsg(); if (inProgress == null) { return false; } int protocolFlags = 0; if (inProgress.hasMore()) { protocolFlags |= V1Protocol.MORE_FLAG; } if (inProgress.size() > 255) { protocolFlags |= V1Protocol.LARGE_FLAG; } tmpbuf[0] = (byte) protocolFlags; // Encode the message length. For messages less then 256 bytes, // the length is encoded as 8-bit unsigned integer. For larger // messages, 64-bit unsigned integer in network byte order is used. final int size = inProgress.size(); if (size > 255) { ByteBuffer b = ByteBuffer.wrap(tmpbuf); b.position(1); b.putLong(size); nextStep(tmpbuf, 9, SIZE_READY, false); } else { tmpbuf[1] = (byte) (size); nextStep(tmpbuf, 2, SIZE_READY, false); } return true; } } jeromq-0.3.5/src/main/java/zmq/V1Protocol.java000066400000000000000000000017051255150477200211450ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; class V1Protocol { private V1Protocol() { } public static final int VERSION = 1; public static final int MORE_FLAG = 1; public static final int LARGE_FLAG = 2; } jeromq-0.3.5/src/main/java/zmq/ValueReference.java000066400000000000000000000020771255150477200220330ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; public class ValueReference { private V value; public ValueReference(V value) { this.value = value; } public ValueReference() { } public final V get() { return value; } public final void set(V value) { this.value = value; } } jeromq-0.3.5/src/main/java/zmq/XPub.java000066400000000000000000000155541255150477200200220ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.util.ArrayDeque; import java.util.Deque; class XPub extends SocketBase { public static class XPubSession extends SessionBase { public XPubSession(IOThread ioThread, boolean connect, SocketBase socket, Options options, Address addr) { super(ioThread, connect, socket, options, addr); } } // List of all subscriptions mapped to corresponding pipes. private final Mtrie subscriptions; // Distributor of messages holding the list of outbound pipes. private final Dist dist; // If true, send all subscription messages upstream, not just // unique ones boolean verbose; // True if we are in the middle of sending a multi-part message. private boolean more; // List of pending (un)subscriptions, ie. those that were already // applied to the trie, but not yet received by the user. private final Deque pendingData; private final Deque pendingFlags; private static Mtrie.IMtrieHandler markAsMatching; private static Mtrie.IMtrieHandler sendUnsubscription; static { markAsMatching = new Mtrie.IMtrieHandler() { @Override public void invoke(Pipe pipe, byte[] data, int size, Object arg) { XPub self = (XPub) arg; self.dist.match(pipe); } }; sendUnsubscription = new Mtrie.IMtrieHandler() { @Override public void invoke(Pipe pipe, byte[] data, int size, Object arg) { XPub self = (XPub) arg; if (self.options.type != ZMQ.ZMQ_PUB) { // Place the unsubscription to the queue of pending (un)sunscriptions // to be retrived by the user later on. byte[] unsub = new byte[size + 1]; unsub[0] = 0; System.arraycopy(data, 0, unsub, 1, size); self.pendingData.add(Blob.createBlob(unsub, false)); self.pendingFlags.add(0); } } }; } public XPub(Ctx parent, int tid, int sid) { super(parent, tid, sid); options.type = ZMQ.ZMQ_XPUB; verbose = false; more = false; subscriptions = new Mtrie(); dist = new Dist(); pendingData = new ArrayDeque(); pendingFlags = new ArrayDeque(); } @Override protected void xattachPipe(Pipe pipe, boolean icanhasall) { assert (pipe != null); dist.attach(pipe); // If icanhasall_ is specified, the caller would like to subscribe // to all data on this pipe, implicitly. if (icanhasall) { subscriptions.add(null, pipe); } // The pipe is active when attached. Let's read the subscriptions from // it, if any. xreadActivated(pipe); } @Override protected void xreadActivated(Pipe pipe) { // There are some subscriptions waiting. Let's process them. Msg sub = null; while ((sub = pipe.read()) != null) { // Apply the subscription to the trie byte[] data = sub.data(); int size = sub.size(); if (size > 0 && (data[0] == 0 || data[0] == 1)) { boolean unique; if (data[0] == 0) { unique = subscriptions.rm(data, 1, pipe); } else { unique = subscriptions.add(data, 1, pipe); } // If the subscription is not a duplicate, store it so that it can be // passed to used on next recv call. (Unsubscribe is not verbose.) if (options.type == ZMQ.ZMQ_XPUB && (unique || (data[0] == 1 && verbose))) { pendingData.add(Blob.createBlob(data, true)); pendingFlags.add(0); } } else { // Process user message coming upstream from xsub socket pendingData.add(Blob.createBlob(data, true)); pendingFlags.add(sub.flags()); } } } @Override protected void xwriteActivated(Pipe pipe) { dist.activated(pipe); } @Override public boolean xsetsockopt(int option, Object optval) { if (option != ZMQ.ZMQ_XPUB_VERBOSE) { return false; } verbose = (Integer) optval == 1; return true; } @Override protected void xpipeTerminated(Pipe pipe) { // Remove the pipe from the trie. If there are topics that nobody // is interested in anymore, send corresponding unsubscriptions // upstream. subscriptions.rm(pipe, sendUnsubscription, this); dist.terminated(pipe); } @Override protected boolean xsend(Msg msg) { boolean msgMore = msg.hasMore(); // For the first part of multi-part message, find the matching pipes. if (!more) { subscriptions.match(msg.data(), msg.size(), markAsMatching, this); } // Send the message to all the pipes that were marked as matching // in the previous step. boolean rc = dist.sendToMatching(msg); if (!rc) { return false; } // If we are at the end of multi-part message we can mark all the pipes // as non-matching. if (!msgMore) { dist.unmatch(); } more = msgMore; return true; } @Override protected boolean xhasOut() { return dist.hasOut(); } @Override protected Msg xrecv() { // If there is at least one if (pendingData.isEmpty()) { errno.set(ZError.EAGAIN); return null; } Blob first = pendingData.pollFirst(); Msg msg = new Msg(first.data()); int flags = pendingFlags.pollFirst(); msg.setFlags(flags); return msg; } @Override protected boolean xhasIn() { return !pendingData.isEmpty(); } } jeromq-0.3.5/src/main/java/zmq/XSub.java000066400000000000000000000164231255150477200200210ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; public class XSub extends SocketBase { public static class XSubSession extends SessionBase { public XSubSession(IOThread ioThread, boolean connect, SocketBase socket, Options options, Address addr) { super(ioThread, connect, socket, options, addr); } } // Fair queueing object for inbound pipes. private final FQ fq; // Object for distributing the subscriptions upstream. private final Dist dist; // The repository of subscriptions. private final Trie subscriptions; // If true, 'message' contains a matching message to return on the // next recv call. private boolean hashMessage; private Msg message; // If true, part of a multipart message was already received, but // there are following parts still waiting. private boolean more; private static Trie.ITrieHandler sendSubscription; static { sendSubscription = new Trie.ITrieHandler() { @Override public void added(byte[] data, int size, Object arg) { Pipe pipe = (Pipe) arg; // Create the subsctription message. Msg msg = new Msg(size + 1); msg.put((byte) 1).put(data, 0, size); // Send it to the pipe. boolean sent = pipe.write(msg); // If we reached the SNDHWM, and thus cannot send the subscription, drop // the subscription message instead. This matches the behaviour of // setSocketOption(ZMQ_SUBSCRIBE, ...), which also drops subscriptions // when the SNDHWM is reached. // if (!sent) // msg.close (); } }; } public XSub(Ctx parent, int tid, int sid) { super(parent, tid, sid); options.type = ZMQ.ZMQ_XSUB; hashMessage = false; more = false; options.linger = 0; fq = new FQ(); dist = new Dist(); subscriptions = new Trie(); } @Override protected void xattachPipe(Pipe pipe, boolean icanhasall) { assert (pipe != null); fq.attach(pipe); dist.attach(pipe); // Send all the cached subscriptions to the new upstream peer. subscriptions.apply(sendSubscription, pipe); pipe.flush(); } @Override protected void xreadActivated(Pipe pipe) { fq.activated(pipe); } @Override protected void xwriteActivated(Pipe pipe) { dist.activated(pipe); } @Override protected void xpipeTerminated(Pipe pipe) { fq.terminated(pipe); dist.terminated(pipe); } @Override protected void xhiccuped(Pipe pipe) { // Send all the cached subscriptions to the hiccuped pipe. subscriptions.apply(sendSubscription, pipe); pipe.flush(); } @Override protected boolean xsend(Msg msg) { byte[] data = msg.data(); // Malformed subscriptions. if (data.length < 1 || (data[0] != 0 && data[0] != 1)) { throw new IllegalArgumentException("subscription flag"); } // Process the subscription. if (data[0] == 1) { // this used to filter out duplicate subscriptions, // however this is alread done on the XPUB side and // doing it here as well breaks ZMQ_XPUB_VERBOSE // when there are forwarding devices involved // subscriptions.add(data , 1); return dist.sendToAll(msg); } else { if (subscriptions.rm(data, 1)) { return dist.sendToAll(msg); } } return true; } @Override protected boolean xhasOut() { // Subscription can be added/removed anytime. return true; } @Override protected Msg xrecv() { Msg msg = null; // If there's already a message prepared by a previous call to zmq_poll, // return it straight ahead. if (hashMessage) { msg = message; hashMessage = false; more = msg.hasMore(); return msg; } // TODO: This can result in infinite loop in the case of continuous // stream of non-matching messages which breaks the non-blocking recv // semantics. while (true) { // Get a message using fair queueing algorithm. msg = fq.recv(errno); // If there's no message available, return immediately. // The same when error occurs. if (msg == null) { return null; } // Check whether the message matches at least one subscription. // Non-initial parts of the message are passed if (more || !options.filter || match(msg)) { more = msg.hasMore(); return msg; } // Message doesn't match. Pop any remaining parts of the message // from the pipe. while (msg.hasMore()) { msg = fq.recv(errno); assert (msg != null); } } } @Override protected boolean xhasIn() { // There are subsequent parts of the partly-read message available. if (more) { return true; } // If there's already a message prepared by a previous call to zmq_poll, // return straight ahead. if (hashMessage) { return true; } // TODO: This can result in infinite loop in the case of continuous // stream of non-matching messages. while (true) { // Get a message using fair queueing algorithm. message = fq.recv(errno); // If there's no message available, return immediately. // The same when error occurs. if (message == null) { return false; } // Check whether the message matches at least one subscription. if (!options.filter || match(message)) { hashMessage = true; return true; } // Message doesn't match. Pop any remaining parts of the message // from the pipe. while (message.hasMore()) { message = fq.recv(errno); assert (message != null); } } } private boolean match(Msg msg) { return subscriptions.check(msg.data()); } } jeromq-0.3.5/src/main/java/zmq/YPipe.java000066400000000000000000000125151255150477200201640ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.util.concurrent.atomic.AtomicInteger; public class YPipe { // Allocation-efficient queue to store pipe items. // Front of the queue points to the first prefetched item, back of // the pipe points to last un-flushed item. Front is used only by // reader thread, while back is used only by writer thread. private final YQueue queue; // Points to the first un-flushed item. This variable is used // exclusively by writer thread. private int w; // Points to the first un-prefetched item. This variable is used // exclusively by reader thread. private int r; // Points to the first item to be flushed in the future. private int f; // The single point of contention between writer and reader thread. // Points past the last flushed item. If it is NULL, // reader is asleep. This pointer should be always accessed using // atomic operations. private final AtomicInteger c; public YPipe(int qsize) { queue = new YQueue(qsize); int pos = queue.backPos(); f = pos; r = pos; w = pos; c = new AtomicInteger(queue.backPos()); } // Write an item to the pipe. Don't flush it yet. If incomplete is // set to true the item is assumed to be continued by items // subsequently written to the pipe. Incomplete items are never // flushed down the stream. public void write(final T value, boolean incomplete) { // Place the value to the queue, add new terminator element. queue.push(value); // Move the "flush up to here" poiter. if (!incomplete) { f = queue.backPos(); } } // Pop an incomplete item from the pipe. Returns true is such // item exists, false otherwise. public T unwrite() { if (f == queue.backPos()) { return null; } queue.unpush(); return queue.back(); } // Flush all the completed items into the pipe. Returns false if // the reader thread is sleeping. In that case, caller is obliged to // wake the reader up before using the pipe again. public boolean flush() { // If there are no un-flushed items, do nothing. if (w == f) { return true; } // Try to set 'c' to 'f'. if (!c.compareAndSet(w, f)) { // Compare-and-swap was unseccessful because 'c' is NULL. // This means that the reader is asleep. Therefore we don't // care about thread-safeness and update c in non-atomic // manner. We'll return false to let the caller know // that reader is sleeping. c.set(f); w = f; return false; } // Reader is alive. Nothing special to do now. Just move // the 'first un-flushed item' pointer to 'f'. w = f; return true; } // Check whether item is available for reading. public boolean checkRead() { // Was the value prefetched already? If so, return. int h = queue.frontPos(); if (h != r) { return true; } // There's no prefetched value, so let us prefetch more values. // Prefetching is to simply retrieve the // pointer from c in atomic fashion. If there are no // items to prefetch, set c to -1 (using compare-and-swap). if (c.compareAndSet(h, -1)) { // nothing to read, h == r must be the same } else { // something to have been written r = c.get(); } // If there are no elements prefetched, exit. // During pipe's lifetime r should never be NULL, however, // it can happen during pipe shutdown when items // are being deallocated. if (h == r || r == -1) { return false; } // There was at least one value prefetched. return true; } // Reads an item from the pipe. Returns false if there is no value. // available. public T read() { // Try to prefetch a value. if (!checkRead()) { return null; } // There was at least one value prefetched. // Return it to the caller. return queue.pop(); } // Applies the function fn to the first elemenent in the pipe // and returns the value returned by the fn. // The pipe mustn't be empty or the function crashes. public T probe() { boolean rc = checkRead(); assert (rc); return queue.front(); } } jeromq-0.3.5/src/main/java/zmq/YQueue.java000066400000000000000000000116711255150477200203550ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; public class YQueue { // Individual memory chunk to hold N elements. private static class Chunk { final T[] values; final int[] pos; Chunk prev; Chunk next; @SuppressWarnings("unchecked") public Chunk(int size, int memoryPtr) { values = (T[]) new Object[size]; pos = new int[size]; for (int i = 0; i != values.length; i++) { pos[i] = memoryPtr; memoryPtr++; } } }; // Back position may point to invalid memory if the queue is empty, // while begin & end positions are always valid. Begin position is // accessed exclusively be queue reader (front/pop), while back and // end positions are accessed exclusively by queue writer (back/push). private Chunk beginChunk; private int beginPos; private Chunk backChunk; private int backPos; private Chunk endChunk; private int endPos; private volatile Chunk spareChunk; private final int size; // People are likely to produce and consume at similar rates. In // this scenario holding onto the most recently freed chunk saves // us from having to call malloc/free. private int memoryPtr; public YQueue(int size) { this.size = size; memoryPtr = 0; beginChunk = new Chunk(size, memoryPtr); memoryPtr += size; beginPos = 0; backPos = 0; backChunk = beginChunk; spareChunk = beginChunk; endChunk = beginChunk; endPos = 1; } public int frontPos() { return beginChunk.pos[beginPos]; } // Returns reference to the front element of the queue. // If the queue is empty, behaviour is undefined. public T front() { return beginChunk.values[beginPos]; } public int backPos() { return backChunk.pos[backPos]; } // Returns reference to the back element of the queue. // If the queue is empty, behaviour is undefined. public T back() { return backChunk.values[backPos]; } public T pop() { T val = beginChunk.values[beginPos]; beginChunk.values[beginPos] = null; beginPos++; if (beginPos == size) { beginChunk = beginChunk.next; beginChunk.prev = null; beginPos = 0; } return val; } // Adds an element to the back end of the queue. public void push(T val) { backChunk.values[backPos] = val; backChunk = endChunk; backPos = endPos; endPos++; if (endPos != size) { return; } Chunk sc = spareChunk; if (sc != beginChunk) { spareChunk = spareChunk.next; endChunk.next = sc; sc.prev = endChunk; } else { endChunk.next = new Chunk(size, memoryPtr); memoryPtr += size; endChunk.next.prev = endChunk; } endChunk = endChunk.next; endPos = 0; } // Removes element from the back end of the queue. In other words // it rollbacks last push to the queue. Take care: Caller is // responsible for destroying the object being unpushed. // The caller must also guarantee that the queue isn't empty when // unpush is called. It cannot be done automatically as the read // side of the queue can be managed by different, completely // unsynchronised thread. public void unpush() { // First, move 'back' one position backwards. if (backPos > 0) { backPos--; } else { backPos = size - 1; backChunk = backChunk.prev; } // Now, move 'end' position backwards. Note that obsolete end chunk // is not used as a spare chunk. The analysis shows that doing so // would require free and atomic operation per chunk deallocated // instead of a simple free. if (endPos > 0) { endPos--; } else { endPos = size - 1; endChunk = endChunk.prev; endChunk.next = null; } } } jeromq-0.3.5/src/main/java/zmq/ZError.java000066400000000000000000000071561255150477200203660ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.net.SocketException; import java.nio.channels.ClosedChannelException; public class ZError { private ZError() { } public static class CtxTerminatedException extends RuntimeException { private static final long serialVersionUID = -4404921838608052956L; public CtxTerminatedException() { super(); } } public static class InstantiationException extends RuntimeException { private static final long serialVersionUID = -4404921838608052955L; public InstantiationException(Throwable cause) { super(cause); } } public static class IOException extends RuntimeException { private static final long serialVersionUID = 9202470691157986262L; public IOException(java.io.IOException e) { super(e); } } public static final int EINTR = 4; public static final int EACCESS = 13; public static final int EFAULT = 14; public static final int EINVAL = 22; public static final int EAGAIN = 35; public static final int EINPROGRESS = 36; public static final int EPROTONOSUPPORT = 43; public static final int ENOTSUP = 45; public static final int EADDRINUSE = 48; public static final int EADDRNOTAVAIL = 49; public static final int ENETDOWN = 50; public static final int ENOBUFS = 55; public static final int EISCONN = 56; public static final int ENOTCONN = 57; public static final int ECONNREFUSED = 61; public static final int EHOSTUNREACH = 65; private static final int ZMQ_HAUSNUMERO = 156384712; public static final int ENOTSOCK = ZMQ_HAUSNUMERO + 5; public static final int EFSM = ZMQ_HAUSNUMERO + 51; public static final int ENOCOMPATPROTO = ZMQ_HAUSNUMERO + 52; public static final int ETERM = ZMQ_HAUSNUMERO + 53; public static final int EMTHREAD = ZMQ_HAUSNUMERO + 54; public static final int EIOEXC = ZMQ_HAUSNUMERO + 105; public static final int ESOCKET = ZMQ_HAUSNUMERO + 106; public static final int EMFILE = ZMQ_HAUSNUMERO + 107; static int exccode(java.io.IOException e) { if (e instanceof SocketException) { return ESOCKET; } else if (e instanceof ClosedChannelException) { return ENOTCONN; } else { return EIOEXC; } } public static String toString(int code) { switch (code) { case EADDRINUSE: return "Address already in use"; case EFSM: return "Operation cannot be accomplished in current state"; case ENOCOMPATPROTO: return "The protocol is not compatible with the socket type"; case ETERM: return "Context was terminated"; case EMTHREAD: return "No thread available"; } return ""; } } jeromq-0.3.5/src/main/java/zmq/ZMQ.java000066400000000000000000000623371255150477200176140ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.charset.Charset; import java.util.HashMap; public class ZMQ { /******************************************************************************/ /* 0MQ versioning support. */ /******************************************************************************/ /* Version macros for compile-time API version detection */ public static final int ZMQ_VERSION_MAJOR = 3; public static final int ZMQ_VERSION_MINOR = 2; public static final int ZMQ_VERSION_PATCH = 5; /* Context options */ public static final int ZMQ_IO_THREADS = 1; public static final int ZMQ_MAX_SOCKETS = 2; /* Default for new contexts */ public static final int ZMQ_IO_THREADS_DFLT = 1; public static final int ZMQ_MAX_SOCKETS_DFLT = 1024; /******************************************************************************/ /* 0MQ socket definition. */ /******************************************************************************/ /* Socket types. */ public static final int ZMQ_PAIR = 0; public static final int ZMQ_PUB = 1; public static final int ZMQ_SUB = 2; public static final int ZMQ_REQ = 3; public static final int ZMQ_REP = 4; public static final int ZMQ_DEALER = 5; public static final int ZMQ_ROUTER = 6; public static final int ZMQ_PULL = 7; public static final int ZMQ_PUSH = 8; public static final int ZMQ_XPUB = 9; public static final int ZMQ_XSUB = 10; /* Deprecated aliases */ @Deprecated public static final int ZMQ_XREQ = ZMQ_DEALER; @Deprecated public static final int ZMQ_XREP = ZMQ_ROUTER; /* Socket options. */ public static final int ZMQ_AFFINITY = 4; public static final int ZMQ_IDENTITY = 5; public static final int ZMQ_SUBSCRIBE = 6; public static final int ZMQ_UNSUBSCRIBE = 7; public static final int ZMQ_RATE = 8; public static final int ZMQ_RECOVERY_IVL = 9; public static final int ZMQ_SNDBUF = 11; public static final int ZMQ_RCVBUF = 12; public static final int ZMQ_RCVMORE = 13; public static final int ZMQ_FD = 14; public static final int ZMQ_EVENTS = 15; public static final int ZMQ_TYPE = 16; public static final int ZMQ_LINGER = 17; public static final int ZMQ_RECONNECT_IVL = 18; public static final int ZMQ_BACKLOG = 19; public static final int ZMQ_RECONNECT_IVL_MAX = 21; public static final int ZMQ_MAXMSGSIZE = 22; public static final int ZMQ_SNDHWM = 23; public static final int ZMQ_RCVHWM = 24; public static final int ZMQ_MULTICAST_HOPS = 25; public static final int ZMQ_RCVTIMEO = 27; public static final int ZMQ_SNDTIMEO = 28; public static final int ZMQ_IPV4ONLY = 31; public static final int ZMQ_LAST_ENDPOINT = 32; public static final int ZMQ_ROUTER_MANDATORY = 33; public static final int ZMQ_TCP_KEEPALIVE = 34; public static final int ZMQ_TCP_KEEPALIVE_CNT = 35; public static final int ZMQ_TCP_KEEPALIVE_IDLE = 36; public static final int ZMQ_TCP_KEEPALIVE_INTVL = 37; public static final int ZMQ_TCP_ACCEPT_FILTER = 38; public static final int ZMQ_DELAY_ATTACH_ON_CONNECT = 39; public static final int ZMQ_XPUB_VERBOSE = 40; // TODO: more constants public static final int ZMQ_ROUTER_HANDOVER = 56; public static final int ZMQ_BLOCKY = 70; /* Custom options */ public static final int ZMQ_ENCODER = 1001; public static final int ZMQ_DECODER = 1002; /* Message options */ public static final int ZMQ_MORE = 1; /* Send/recv options. */ public static final int ZMQ_DONTWAIT = 1; public static final int ZMQ_SNDMORE = 2; /* Deprecated aliases */ public static final int ZMQ_NOBLOCK = ZMQ_DONTWAIT; public static final int ZMQ_FAIL_UNROUTABLE = ZMQ_ROUTER_MANDATORY; public static final int ZMQ_ROUTER_BEHAVIOR = ZMQ_ROUTER_MANDATORY; /******************************************************************************/ /* 0MQ socket events and monitoring */ /******************************************************************************/ /* Socket transport events (tcp and ipc only) */ public static final int ZMQ_EVENT_CONNECTED = 1; public static final int ZMQ_EVENT_CONNECT_DELAYED = 2; public static final int ZMQ_EVENT_CONNECT_RETRIED = 4; public static final int ZMQ_EVENT_LISTENING = 8; public static final int ZMQ_EVENT_BIND_FAILED = 16; public static final int ZMQ_EVENT_ACCEPTED = 32; public static final int ZMQ_EVENT_ACCEPT_FAILED = 64; public static final int ZMQ_EVENT_CLOSED = 128; public static final int ZMQ_EVENT_CLOSE_FAILED = 256; public static final int ZMQ_EVENT_DISCONNECTED = 512; public static final int ZMQ_EVENT_MONITOR_STOPPED = 1024; public static final int ZMQ_EVENT_ALL = ZMQ_EVENT_CONNECTED | ZMQ_EVENT_CONNECT_DELAYED | ZMQ_EVENT_CONNECT_RETRIED | ZMQ_EVENT_LISTENING | ZMQ_EVENT_BIND_FAILED | ZMQ_EVENT_ACCEPTED | ZMQ_EVENT_ACCEPT_FAILED | ZMQ_EVENT_CLOSED | ZMQ_EVENT_CLOSE_FAILED | ZMQ_EVENT_DISCONNECTED | ZMQ_EVENT_MONITOR_STOPPED; public static final int ZMQ_POLLIN = 1; public static final int ZMQ_POLLOUT = 2; public static final int ZMQ_POLLERR = 4; public static final int ZMQ_STREAMER = 1; public static final int ZMQ_FORWARDER = 2; public static final int ZMQ_QUEUE = 3; public static final byte[] MESSAGE_SEPARATOR = new byte[0]; public static final byte[] SUBSCRIPTION_ALL = new byte[0]; public static final Charset CHARSET = Charset.forName("UTF-8"); public static class Event { private static final int VALUE_INTEGER = 1; private static final int VALUE_CHANNEL = 2; public final int event; public final String addr; public final Object arg; private final int flag; public Event(int event, String addr, Object arg) { this.event = event; this.addr = addr; this.arg = arg; if (arg instanceof Integer) { flag = VALUE_INTEGER; } else if (arg instanceof SelectableChannel) { flag = VALUE_CHANNEL; } else { flag = 0; } } public boolean write(SocketBase s) { int size = 4 + 1 + addr.length() + 1; // event + len(addr) + addr + flag if (flag == VALUE_INTEGER) { size += 4; } ByteBuffer buffer = ByteBuffer.allocate(size).order(ByteOrder.BIG_ENDIAN); buffer.putInt(event); buffer.put((byte) addr.length()); buffer.put(addr.getBytes(CHARSET)); buffer.put((byte) flag); if (flag == VALUE_INTEGER) { buffer.putInt((Integer) arg); } buffer.flip(); Msg msg = new Msg(buffer); return s.send(msg, 0); } public static Event read(SocketBase s, int flags) { Msg msg = s.recv(flags); if (msg == null) { return null; } ByteBuffer buffer = msg.buf(); int event = buffer.getInt(); int len = buffer.get(); byte [] addr = new byte [len]; buffer.get(addr); int flag = buffer.get(); Object arg = null; if (flag == VALUE_INTEGER) { arg = buffer.getInt(); } return new Event(event, new String(addr, CHARSET), arg); } public static Event read(SocketBase s) { return read(s, 0); } } // New context API public static Ctx createContext() { // Create 0MQ context. Ctx ctx = new Ctx(); return ctx; } private static void destroyContext(Ctx ctx) { if (ctx == null || !ctx.checkTag()) { throw new IllegalStateException(); } ctx.terminate(); } public static void setContextOption(Ctx ctx, int option, int optval) { if (ctx == null || !ctx.checkTag()) { throw new IllegalStateException(); } ctx.set(option, optval); } public static int getContextOption(Ctx ctx, int option) { if (ctx == null || !ctx.checkTag()) { throw new IllegalStateException(); } return ctx.get(option); } // Stable/legacy context API public static Ctx init(int ioThreads) { if (ioThreads >= 0) { Ctx ctx = createContext(); setContextOption(ctx, ZMQ_IO_THREADS, ioThreads); return ctx; } throw new IllegalArgumentException("io_threds must not be negative"); } public static void term(Ctx ctx) { destroyContext(ctx); } // Sockets public static SocketBase socket(Ctx ctx, int type) { if (ctx == null || !ctx.checkTag()) { throw new IllegalStateException(); } SocketBase s = ctx.createSocket(type); return s; } public static void close(SocketBase s) { if (s == null || !s.checkTag()) { throw new IllegalStateException(); } s.close(); } public static void setSocketOption(SocketBase s, int option, Object optval) { if (s == null || !s.checkTag()) { throw new IllegalStateException(); } s.setSocketOpt(option, optval); } public static Object getSocketOptionExt(SocketBase s, int option) { if (s == null || !s.checkTag()) { throw new IllegalStateException(); } return s.getsockoptx(option); } public static int getSocketOption(SocketBase s, int opt) { return s.getSocketOpt(opt); } public static boolean monitorSocket(SocketBase s, final String addr, int events) { if (s == null || !s.checkTag()) { throw new IllegalStateException(); } return s.monitor(addr, events); } public static boolean bind(SocketBase s, final String addr) { if (s == null || !s.checkTag()) { throw new IllegalStateException(); } return s.bind(addr); } public static boolean connect(SocketBase s, String addr) { if (s == null || !s.checkTag()) { throw new IllegalStateException(); } return s.connect(addr); } public static boolean unbind(SocketBase s, String addr) { if (s == null || !s.checkTag()) { throw new IllegalStateException(); } return s.termEndpoint(addr); } public static boolean disconnect(SocketBase s, String addr) { if (s == null || !s.checkTag()) { throw new IllegalStateException(); } return s.termEndpoint(addr); } // Sending functions. public static int send(SocketBase s, String str, int flags) { byte [] data = str.getBytes(CHARSET); return send(s, data, data.length, flags); } public static int send(SocketBase s, Msg msg, int flags) { int rc = sendMsg(s, msg, flags); if (rc < 0) { return -1; } return rc; } public static int send(SocketBase s, byte[] buf, int len, int flags) { if (s == null || !s.checkTag()) { throw new IllegalStateException(); } Msg msg = new Msg(len); msg.put(buf, 0, len); int rc = sendMsg(s, msg, flags); if (rc < 0) { return -1; } return rc; } // Send multiple messages. // // If flag bit ZMQ_SNDMORE is set the vector is treated as // a single multi-part message, i.e. the last message has // ZMQ_SNDMORE bit switched off. // public int sendiov(SocketBase s, byte[][] a, int count, int flags) { if (s == null || !s.checkTag()) { throw new IllegalStateException(); } int rc = 0; Msg msg; for (int i = 0; i < count; ++i) { msg = new Msg(a[i]); if (i == count - 1) { flags = flags & ~ZMQ_SNDMORE; } rc = sendMsg(s, msg, flags); if (rc < 0) { rc = -1; break; } } return rc; } public static int sendMsg(SocketBase s, Msg msg, int flags) { int sz = msgSize(msg); boolean rc = s.send(msg, flags); if (!rc) { return -1; } return sz; } // Receiving functions. public static Msg recv(SocketBase s, int flags) { if (s == null || !s.checkTag()) { throw new IllegalStateException(); } Msg msg = recvMsg(s, flags); if (msg == null) { return null; } // At the moment an oversized message is silently truncated. // TODO: Build in a notification mechanism to report the overflows. //int to_copy = nbytes < len_ ? nbytes : len_; return msg; } // Receive a multi-part message // // Receives up to *count_ parts of a multi-part message. // Sets *count_ to the actual number of parts read. // ZMQ_RCVMORE is set to indicate if a complete multi-part message was read. // Returns number of message parts read, or -1 on error. // // Note: even if -1 is returned, some parts of the message // may have been read. Therefore the client must consult // *count_ to retrieve message parts successfully read, // even if -1 is returned. // // The iov_base* buffers of each iovec *a_ filled in by this // function may be freed using free(). // // Implementation note: We assume zmq::msg_t buffer allocated // by zmq::recvmsg can be freed by free(). // We assume it is safe to steal these buffers by simply // not closing the zmq::msg_t. // public int recviov(SocketBase s, byte[][] a, int count, int flags) { if (s == null || !s.checkTag()) { throw new IllegalStateException(); } int nread = 0; boolean recvmore = true; for (int i = 0; recvmore && i < count; ++i) { // Cheat! We never close any msg // because we want to steal the buffer. Msg msg = recvMsg(s, flags); if (msg == null) { nread = -1; break; } // Cheat: acquire zmq_msg buffer. a[i] = msg.data(); // Assume zmq_socket ZMQ_RVCMORE is properly set. recvmore = msg.hasMore(); } return nread; } public static Msg recvMsg(SocketBase s, int flags) { return s.recv(flags); } public static Msg msgInit() { return new Msg(); } public static Msg msgInitWithSize(int messageSize) { return new Msg(messageSize); } public static int msgSize(Msg msg) { return msg.size(); } public static int getMessageOption(Msg msg, int option) { switch (option) { case ZMQ_MORE: return msg.hasMore() ? 1 : 0; default: throw new IllegalArgumentException(); } } public static void sleep(int s) { try { Thread.sleep(s * (1000L)); } catch (InterruptedException e) { } } // The proxy functionality public static boolean proxy(SocketBase frontend, SocketBase backend, SocketBase control) { if (frontend == null || backend == null) { throw new IllegalArgumentException(); } return Proxy.proxy( frontend, backend, control); } @Deprecated public static boolean device(int device, SocketBase insocket, SocketBase outsocket) { return Proxy.proxy(insocket, outsocket, null); } /** * Polling on items. This has very poor performance. * Try to use zmq_poll with selector * CAUTION: This could be affected by jdk epoll bug * * @param items * @param timeout * @return number of events */ public static int poll(PollItem[] items, long timeout) { return poll(items, items.length, timeout); } /** * Polling on items. This has very poor performance. * Try to use zmq_poll with selector * CAUTION: This could be affected by jdk epoll bug * * @param items * @param timeout * @return number of events */ public static int poll(PollItem[] items, int count, long timeout) { Selector selector = null; try { selector = PollSelector.open(); } catch (IOException e) { throw new ZError.IOException(e); } int ret = poll(selector, items, count, timeout); // Do not close selector return ret; } /** * Polling on items with given selector * CAUTION: This could be affected by jdk epoll bug * * @param selector Open and reuse this selector and do not forget to close when it is not used. * @param items * @param timeout * @return number of events */ public static int poll(Selector selector, PollItem[] items, long timeout) { return poll(selector, items, items.length, timeout); } /** * Polling on items with given selector * CAUTION: This could be affected by jdk epoll bug * * @param selector Open and reuse this selector and do not forget to close when it is not used. * @param items * @param count * @param timeout * @return number of events */ public static int poll(Selector selector, PollItem[] items, int count, long timeout) { if (items == null) { throw new IllegalArgumentException(); } if (count == 0) { if (timeout <= 0) { return 0; } try { Thread.sleep(timeout); } catch (InterruptedException e) { } return 0; } long now = 0L; long end = 0L; HashMap saved = new HashMap(); for (SelectionKey key : selector.keys()) { if (key.isValid()) { saved.put(key.channel(), key); } } for (int i = 0; i < count; i++) { PollItem item = items[i]; if (item == null) { continue; } SelectableChannel ch = item.getChannel(); // mailbox channel if ZMQ socket SelectionKey key = saved.remove(ch); if (key != null) { if (key.interestOps() != item.interestOps()) { key.interestOps(item.interestOps()); } key.attach(item); } else { try { ch.register(selector, item.interestOps(), item); } catch (ClosedChannelException e) { throw new ZError.IOException(e); } } } if (!saved.isEmpty()) { for (SelectionKey deprecated : saved.values()) { deprecated.cancel(); } } boolean firstPass = true; int nevents = 0; int ready; while (true) { // Compute the timeout for the subsequent poll. long waitMillis; if (firstPass) { waitMillis = 0L; } else if (timeout < 0L) { waitMillis = -1L; } else { waitMillis = end - now; } // Wait for events. try { int rc = 0; if (waitMillis < 0) { rc = selector.select(0); } else if (waitMillis == 0) { rc = selector.selectNow(); } else { rc = selector.select(waitMillis); } for (SelectionKey key : selector.keys()) { PollItem item = (PollItem) key.attachment(); ready = item.readyOps(key, rc); if (ready < 0) { return -1; } if (ready > 0) { nevents++; } } selector.selectedKeys().clear(); } catch (IOException e) { throw new ZError.IOException(e); } // If timeout is zero, exit immediately whether there are events or not. if (timeout == 0) { break; } if (nevents > 0) { break; } // At this point we are meant to wait for events but there are none. // If timeout is infinite we can just loop until we get some events. if (timeout < 0) { if (firstPass) { firstPass = false; } continue; } // The timeout is finite and there are no events. In the first pass // we get a timestamp of when the polling have begun. (We assume that // first pass have taken negligible time). We also compute the time // when the polling should time out. if (firstPass) { now = Clock.nowMS(); end = now + timeout; if (now == end) { break; } firstPass = false; continue; } // Find out whether timeout have expired. now = Clock.nowMS(); if (now >= end) { break; } } return nevents; } public static long startStopwatch() { return System.nanoTime(); } public static long stopStopwatch(long watch) { return (System.nanoTime() - watch) / 1000; } public static int makeVersion(int major, int minor, int patch) { return ((major) * 10000 + (minor) * 100 + (patch)); } public static String strerror(int errno) { return "Errno = " + errno; } private static final ThreadLocal POLL_SELECTOR = new ThreadLocal(); // GC closes selector handle private static class PollSelector { private Selector selector; private PollSelector(Selector selector) { this.selector = selector; } public static Selector open() throws IOException { PollSelector polls = POLL_SELECTOR.get(); if (polls == null) { synchronized (POLL_SELECTOR) { polls = POLL_SELECTOR.get(); try { if (polls == null) { polls = new PollSelector(Selector.open()); POLL_SELECTOR.set(polls); } } catch (IOException e) { throw new ZError.IOException(e); } } } return polls.get(); } public Selector get() { assert (selector != null); assert (selector.isOpen()); return selector; } @Override public void finalize() { try { selector.close(); } catch (IOException e) { } try { super.finalize(); } catch (Throwable e) { } } } } jeromq-0.3.5/src/main/java/zmq/ZObject.java000066400000000000000000000211771255150477200205020ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; // Base class for all objects that participate in inter-thread // communication. public abstract class ZObject { // Context provides access to the global state. private final Ctx ctx; // Thread ID of the thread the object belongs to. private final int tid; protected ZObject(Ctx ctx, int tid) { this.ctx = ctx; this.tid = tid; } protected ZObject(ZObject parent) { this(parent.ctx, parent.tid); } protected int getTid() { return tid; } protected Ctx getCtx() { return ctx; } protected void processCommand(Command cmd) { switch (cmd.type()) { case ACTIVATE_READ: processActivateRead(); break; case ACTIVATE_WRITE: processActivateWrite((Long) cmd.arg); break; case STOP: processStop(); break; case PLUG: processPlug(); processSeqnum(); break; case OWN: processOwn((Own) cmd.arg); processSeqnum(); break; case ATTACH: processAttach((IEngine) cmd.arg); processSeqnum(); break; case BIND: processBind((Pipe) cmd.arg); processSeqnum(); break; case HICCUP: processHiccup(cmd.arg); break; case PIPE_TERM: processPipeTerm(); break; case PIPE_TERM_ACK: processPipeTermAck(); break; case TERM_REQ: processTermReq((Own) cmd.arg); break; case TERM: processTerm((Integer) cmd.arg); break; case TERM_ACK: processTermAck(); break; case REAP: processReap((SocketBase) cmd.arg); break; case REAPED: processReaped(); break; default: throw new IllegalArgumentException(); } } protected boolean registerEndpoint(String addr, Ctx.Endpoint endpoint) { return ctx.registerEndpoint(addr, endpoint); } protected void unregisterEndpoints(SocketBase socket) { ctx.unregisterEndpoints(socket); } protected Ctx.Endpoint findEndpoint(String addr) { return ctx.findEndpoint(addr); } protected void destroySocket(SocketBase socket) { ctx.destroySocket(socket); } // Chooses least loaded I/O thread. protected IOThread chooseIoThread(long affinity) { return ctx.chooseIoThread(affinity); } protected void sendStop() { // 'stop' command goes always from administrative thread to // the current object. Command cmd = new Command(this, Command.Type.STOP); ctx.sendCommand(tid, cmd); } protected void sendPlug(Own destination) { sendPlug(destination, true); } protected void sendPlug(Own destination, boolean incSeqnum) { if (incSeqnum) { destination.incSeqnum(); } Command cmd = new Command(destination, Command.Type.PLUG); sendCommand(cmd); } protected void sendOwn(Own destination, Own object) { destination.incSeqnum(); Command cmd = new Command(destination, Command.Type.OWN, object); sendCommand(cmd); } protected void sendAttach(SessionBase destination, IEngine engine) { sendAttach(destination, engine, true); } protected void sendAttach(SessionBase destination, IEngine engine, boolean incSeqnum) { if (incSeqnum) { destination.incSeqnum(); } Command cmd = new Command(destination, Command.Type.ATTACH, engine); sendCommand(cmd); } protected void sendBind(Own destination, Pipe pipe) { sendBind(destination, pipe, true); } protected void sendBind(Own destination, Pipe pipe, boolean incSeqnum) { if (incSeqnum) { destination.incSeqnum(); } Command cmd = new Command(destination, Command.Type.BIND, pipe); sendCommand(cmd); } protected void sendActivateRead(Pipe destination) { Command cmd = new Command(destination, Command.Type.ACTIVATE_READ); sendCommand(cmd); } protected void sendActivateWrite(Pipe destination, long msgsRead) { Command cmd = new Command(destination, Command.Type.ACTIVATE_WRITE, msgsRead); sendCommand(cmd); } protected void sendHiccup(Pipe destination, Object pipe) { Command cmd = new Command(destination, Command.Type.HICCUP, pipe); sendCommand(cmd); } protected void sendPipeTerm(Pipe destination) { Command cmd = new Command(destination, Command.Type.PIPE_TERM); sendCommand(cmd); } protected void sendPipeTermAck(Pipe destination) { Command cmd = new Command(destination, Command.Type.PIPE_TERM_ACK); sendCommand(cmd); } protected void sendTermReq(Own destination, Own object) { Command cmd = new Command(destination, Command.Type.TERM_REQ, object); sendCommand(cmd); } protected void sendTerm(Own destination, int linger) { Command cmd = new Command(destination, Command.Type.TERM, linger); sendCommand(cmd); } protected void sendTermAck(Own destination) { Command cmd = new Command(destination, Command.Type.TERM_ACK); sendCommand(cmd); } protected void sendReap(SocketBase socket) { Command cmd = new Command(ctx.getReaper(), Command.Type.REAP, socket); sendCommand(cmd); } protected void sendReaped() { Command cmd = new Command(ctx.getReaper(), Command.Type.REAPED); sendCommand(cmd); } protected void sendDone() { Command cmd = new Command(null, Command.Type.DONE); ctx.sendCommand(Ctx.TERM_TID, cmd); } protected void processStop() { throw new UnsupportedOperationException(); } protected void processPlug() { throw new UnsupportedOperationException(); } protected void processOwn(Own object) { throw new UnsupportedOperationException(); } protected void processAttach(IEngine engine) { throw new UnsupportedOperationException(); } protected void processBind(Pipe pipe) { throw new UnsupportedOperationException(); } protected void processActivateRead() { throw new UnsupportedOperationException(); } protected void processActivateWrite(long msgsRead) { throw new UnsupportedOperationException(); } protected void processHiccup(Object hiccupPipe) { throw new UnsupportedOperationException(); } protected void processPipeTerm() { throw new UnsupportedOperationException(); } protected void processPipeTermAck() { throw new UnsupportedOperationException(); } protected void processTermReq(Own object) { throw new UnsupportedOperationException(); } protected void processTerm(int linger) { throw new UnsupportedOperationException(); } protected void processTermAck() { throw new UnsupportedOperationException(); } protected void processReap(SocketBase socket) { throw new UnsupportedOperationException(); } protected void processReaped() { throw new UnsupportedOperationException(); } // Special handler called after a command that requires a seqnum // was processed. The implementation should catch up with its counter // of processed commands here. protected void processSeqnum() { throw new UnsupportedOperationException(); } private void sendCommand(Command cmd) { ctx.sendCommand(cmd.destination().getTid(), cmd); } } jeromq-0.3.5/src/test/000077500000000000000000000000001255150477200145725ustar00rootroot00000000000000jeromq-0.3.5/src/test/java/000077500000000000000000000000001255150477200155135ustar00rootroot00000000000000jeromq-0.3.5/src/test/java/guide/000077500000000000000000000000001255150477200166105ustar00rootroot00000000000000jeromq-0.3.5/src/test/java/guide/MDP.java000066400000000000000000000032421255150477200200740ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.Arrays; import org.zeromq.ZMQ; import org.zeromq.ZFrame; /** * Majordomo Protocol definitions, Java version */ public enum MDP { /** * This is the version of MDP/Client we implement */ C_CLIENT("MDPC01"), /** * This is the version of MDP/Worker we implement */ W_WORKER("MDPW01"), // MDP/Server commands, as byte values W_READY(1), W_REQUEST(2), W_REPLY(3), W_HEARTBEAT(4), W_DISCONNECT(5); private final byte[] data; MDP(String value) { this.data = value.getBytes(ZMQ.CHARSET); } MDP(int value) { //watch for ints>255, will be truncated byte b = (byte) (value & 0xFF); this.data = new byte[] { b }; } public ZFrame newFrame () { return new ZFrame(data); } public boolean frameEquals (ZFrame frame) { return Arrays.equals(data, frame.getData()); } } jeromq-0.3.5/src/test/java/guide/ZHelper.java000066400000000000000000000047101255150477200210260ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; import java.math.BigInteger; import java.util.Arrays; import java.util.List; import java.util.Random; public class ZHelper { private static Random rand = new Random(System.currentTimeMillis ()); /** * Receives all message parts from socket, prints neatly */ public static void dump (Socket sock) { System.out.println("----------------------------------------"); while(true) { byte [] msg = sock.recv (0); boolean isText = true; String data = ""; for (int i = 0; i< msg.length; i++) { if (msg[i] < 32 || msg[i] > 127) isText = false; data += String.format ("%02X", msg[i]); } if (isText) data = new String (msg, ZMQ.CHARSET); System.out.println (String.format ("[%03d] %s", msg.length, data)); if (!sock.hasReceiveMore ()) break; } } public static void setId (Socket sock) { String identity = String.format ("%04X-%04X", rand.nextInt (), rand.nextInt ()); sock.setIdentity (identity.getBytes (ZMQ.CHARSET)); } public static List buildZPipe(Context ctx) { Socket socket1 = ctx.socket(ZMQ.PAIR); socket1.setLinger(0); socket1.setHWM(1); Socket socket2 = ctx.socket(ZMQ.PAIR); socket2.setLinger(0); socket2.setHWM(1); String iface = "inproc://" + new BigInteger(130, rand).toString(32); socket1.bind(iface); socket2.connect(iface); return Arrays.asList(socket1, socket2); } } jeromq-0.3.5/src/test/java/guide/asyncsrv.java000066400000000000000000000134251255150477200213300ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; import org.zeromq.ZMQ.Poller; import java.util.Random; // //Asynchronous client-to-server (DEALER to ROUTER) // //While this example runs in a single process, that is just to make //it easier to start and stop the example. Each task has its own //context and conceptually acts as a separate process. public class asyncsrv { //--------------------------------------------------------------------- //This is our client task //It connects to the server, and then sends a request once per second //It collects responses as they arrive, and it prints them out. We will //run several client tasks in parallel, each with a different random ID. private static Random rand = new Random(System.nanoTime()); private static class client_task implements Runnable { public void run() { ZContext ctx = new ZContext(); Socket client = ctx.createSocket(ZMQ.DEALER); // Set random identity to make tracing easier String identity = String.format("%04X-%04X", rand.nextInt(), rand.nextInt()); client.setIdentity(identity.getBytes(ZMQ.CHARSET)); client.connect("tcp://localhost:5570"); PollItem[] items = new PollItem[] { new PollItem(client, Poller.POLLIN) }; int requestNbr = 0; while (!Thread.currentThread().isInterrupted()) { // Tick once per second, pulling in arriving messages for (int centitick = 0; centitick < 100; centitick++) { ZMQ.poll(items, 10); if (items[0].isReadable()) { ZMsg msg = ZMsg.recvMsg(client); msg.getLast().print(identity); msg.destroy(); } } client.send(String.format("request #%d", ++requestNbr), 0); } ctx.destroy(); } } //This is our server task. //It uses the multithreaded server model to deal requests out to a pool //of workers and route replies back to clients. One worker can handle //one request at a time but one client can talk to multiple workers at //once. private static class server_task implements Runnable { public void run() { ZContext ctx = new ZContext(); // Frontend socket talks to clients over TCP Socket frontend = ctx.createSocket(ZMQ.ROUTER); frontend.bind("tcp://*:5570"); // Backend socket talks to workers over inproc Socket backend = ctx.createSocket(ZMQ.DEALER); backend.bind("inproc://backend"); // Launch pool of worker threads, precise number is not critical for (int threadNbr = 0; threadNbr < 5; threadNbr++) new Thread(new server_worker(ctx)).start(); // Connect backend to frontend via a proxy ZMQ.proxy(frontend, backend, null); ctx.destroy(); } } //Each worker task works on one request at a time and sends a random number //of replies back, with random delays between replies: private static class server_worker implements Runnable { private ZContext ctx; public server_worker(ZContext ctx) { this.ctx = ctx; } public void run() { Socket worker = ctx.createSocket(ZMQ.DEALER); worker.connect("inproc://backend"); while (!Thread.currentThread().isInterrupted()) { // The DEALER socket gives us the address envelope and message ZMsg msg = ZMsg.recvMsg(worker); ZFrame address = msg.pop(); ZFrame content = msg.pop(); assert (content != null); msg.destroy(); // Send 0..4 replies back int replies = rand.nextInt(5); for (int reply = 0; reply < replies; reply++) { // Sleep for some fraction of a second try { Thread.sleep(rand.nextInt(1000) + 1); } catch (InterruptedException e) { } address.send(worker, ZFrame.REUSE + ZFrame.MORE); content.send(worker, ZFrame.REUSE); } address.destroy(); content.destroy(); } ctx.destroy(); } } //The main thread simply starts several clients, and a server, and then //waits for the server to finish. public static void main(String[] args) throws Exception { ZContext ctx = new ZContext(); new Thread(new client_task()).start(); new Thread(new client_task()).start(); new Thread(new client_task()).start(); new Thread(new server_task()).start(); // Run for 5 seconds then quit Thread.sleep(5 * 1000); ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/bstar.java000066400000000000000000000300331255150477200205650ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZLoop; import org.zeromq.ZLoop.IZLoopHandler; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; // bstar class - Binary Star reactor public class bstar { // States we can be in at any point in time enum State { STATE_PRIMARY, // Primary, waiting for peer to connect STATE_BACKUP, // Backup, waiting for peer to connect STATE_ACTIVE, // Active - accepting connections STATE_PASSIVE // Passive - not accepting connections } // Events, which start with the states our peer can be in enum Event { PEER_PRIMARY, // HA peer is pending primary PEER_BACKUP, // HA peer is pending backup PEER_ACTIVE, // HA peer is active PEER_PASSIVE, // HA peer is passive CLIENT_REQUEST // Client makes request } private ZContext ctx; // Our private context private ZLoop loop; // Reactor loop private Socket statepub; // State publisher private Socket statesub; // State subscriber private State state; // Current state private Event event; // Current event private long peerExpiry; // When peer is considered 'dead' private ZLoop.IZLoopHandler voterFn; // Voting socket handler private Object voterArg; // Arguments for voting handler private ZLoop.IZLoopHandler activeFn; // Call when become active private Object activeArg; // Arguments for handler private ZLoop.IZLoopHandler passiveFn; // Call when become passive private Object passiveArg; // Arguments for handler // The finite-state machine is the same as in the proof-of-concept server. // To understand this reactor in detail, first read the ZLoop class. // .skip // We send state information this often // If peer doesn't respond in two heartbeats, it is 'dead' private final static int BSTAR_HEARTBEAT = 1000; // In msecs // Binary Star finite state machine (applies event to state) // Returns false if there was an exception, true if event was valid. private boolean execute() { boolean rc = true; // Primary server is waiting for peer to connect // Accepts CLIENT_REQUEST events in this state if (state == State.STATE_PRIMARY) { if (event == Event.PEER_BACKUP) { System.out.printf ("I: connected to backup (passive), ready active\n"); state = State.STATE_ACTIVE; if (activeFn != null) activeFn.handle(loop, null, activeArg); } else if (event == Event.PEER_ACTIVE) { System.out.printf ("I: connected to backup (active), ready passive\n"); state = State.STATE_PASSIVE; if (passiveFn != null) passiveFn.handle(loop, null, passiveArg); } else if (event == Event.CLIENT_REQUEST) { // Allow client requests to turn us into the active if we've // waited sufficiently long to believe the backup is not // currently acting as active (i.e., after a failover) assert (peerExpiry > 0); if (System.currentTimeMillis() >= peerExpiry) { System.out.printf ("I: request from client, ready as active\n"); state = State.STATE_ACTIVE; if (activeFn != null) activeFn.handle(loop, null, activeArg); } else // Don't respond to clients yet - it's possible we're // performing a failback and the backup is currently active rc = false; } } else if (state == State.STATE_BACKUP) { if (event == Event.PEER_ACTIVE) { System.out.printf ("I: connected to primary (active), ready passive\n"); state = State.STATE_PASSIVE; if (passiveFn != null) passiveFn.handle(loop, null, passiveArg); } else // Reject client connections when acting as backup if (event == Event.CLIENT_REQUEST) rc = false; } else // .split active and passive states // These are the ACTIVE and PASSIVE states: if (state == State.STATE_ACTIVE) { if (event == Event.PEER_ACTIVE) { // Two actives would mean split-brain System.out.printf ("E: fatal error - dual actives, aborting\n"); rc = false; } } else // Server is passive // CLIENT_REQUEST events can trigger failover if peer looks dead if (state == State.STATE_PASSIVE) { if (event == Event.PEER_PRIMARY) { // Peer is restarting - become active, peer will go passive System.out.printf ("I: primary (passive) is restarting, ready active\n"); state = State.STATE_ACTIVE; } else if (event == Event.PEER_BACKUP) { // Peer is restarting - become active, peer will go passive System.out.printf ("I: backup (passive) is restarting, ready active\n"); state = State.STATE_ACTIVE; } else if (event == Event.PEER_PASSIVE) { // Two passives would mean cluster would be non-responsive System.out.printf ("E: fatal error - dual passives, aborting\n"); rc = false; } else if (event == Event.CLIENT_REQUEST) { // Peer becomes active if timeout has passed // It's the client request that triggers the failover assert (peerExpiry > 0); if (System.currentTimeMillis () >= peerExpiry) { // If peer is dead, switch to the active state System.out.printf ("I: failover successful, ready active\n"); state = State.STATE_ACTIVE; } else // If peer is alive, reject connections rc = false; // Call state change handler if necessary if (state == State.STATE_ACTIVE && activeFn != null) activeFn.handle(loop, null, activeArg); } } return rc; } private void updatePeerExpiry() { peerExpiry = System.currentTimeMillis() + 2 * BSTAR_HEARTBEAT; } // Reactor event handlers... // Publish our state to peer private static IZLoopHandler SendState = new IZLoopHandler () { @Override public int handle(ZLoop loop, PollItem item, Object arg) { bstar self = (bstar) arg; self.statepub.send(String.format("%d", self.state.ordinal())); return 0; } }; // Receive state from peer, execute finite state machine private static IZLoopHandler RecvState = new IZLoopHandler () { @Override public int handle(ZLoop loop, PollItem item, Object arg) { bstar self = (bstar) arg; String state = item.getSocket().recvStr(); if (state != null) { self.event = Event.values()[Integer.parseInt(state)]; self.updatePeerExpiry(); } return self.execute() ? 0 : -1; } }; // Application wants to speak to us, see if it's possible private static IZLoopHandler VoterReady = new IZLoopHandler () { @Override public int handle(ZLoop loop, PollItem item, Object arg) { bstar self = (bstar) arg; // If server can accept input now, call appl handler self.event = Event.CLIENT_REQUEST; if (self.execute()) self.voterFn.handle(loop, item, self.voterArg); else { // Destroy waiting message, no-one to read it ZMsg msg = ZMsg.recvMsg(item.getSocket()); msg.destroy(); } return 0; } }; // .until // .split constructor // This is the constructor for our {{bstar}} class. We have to tell it // whether we're primary or backup server, as well as our local and // remote endpoints to bind and connect to: public bstar(boolean primary, String local, String remote) { // Initialize the Binary Star ctx = new ZContext(); loop = new ZLoop(); state = primary? State.STATE_PRIMARY: State.STATE_BACKUP; // Create publisher for state going to peer statepub = ctx.createSocket(ZMQ.PUB); statepub.bind(local); // Create subscriber for state coming from peer statesub = ctx.createSocket(ZMQ.SUB); statesub.subscribe(ZMQ.SUBSCRIPTION_ALL); statesub.connect(remote); // Set-up basic reactor events loop.addTimer(BSTAR_HEARTBEAT, 0, SendState, this); PollItem poller = new PollItem(statesub, ZMQ.Poller.POLLIN); loop.addPoller(poller, RecvState, this); } // .split destructor // The destructor shuts down the bstar reactor: public void destroy() { loop.destroy(); ctx.destroy(); } // .split zloop method // This method returns the underlying zloop reactor, so we can add // additional timers and readers: public ZLoop zloop() { return loop; } // .split voter method // This method registers a client voter socket. Messages received // on this socket provide the CLIENT_REQUEST events for the Binary Star // FSM and are passed to the provided application handler. We require // exactly one voter per {{bstar}} instance: public int voter(String endpoint, int type, IZLoopHandler handler, Object arg) { // Hold actual handler+arg so we can call this later Socket socket = ctx.createSocket(type); socket.bind(endpoint); voterFn = handler; voterArg = arg; PollItem poller = new PollItem(socket, ZMQ.Poller.POLLIN); return loop.addPoller(poller, VoterReady, this); } // .split register state-change handlers // Register handlers to be called each time there's a state change: public void newActive(IZLoopHandler handler, Object arg) { activeFn = handler; activeArg = arg; } public void newPassive(IZLoopHandler handler, Object arg) { passiveFn = handler; passiveArg = arg; } // .split enable/disable tracing // Enable/disable verbose tracing, for debugging: public void setVerbose(boolean verbose) { loop.verbose(verbose); } // .split start the reactor // Finally, start the configured reactor. It will end if any handler // returns -1 to the reactor, or if the process receives Interrupt public int start() { assert (voterFn != null); updatePeerExpiry(); return loop.start(); } } jeromq-0.3.5/src/test/java/guide/bstarcli.java000066400000000000000000000075531255150477200212700ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; // Binary Star client proof-of-concept implementation. This client does no // real work; it just demonstrates the Binary Star failover model. public class bstarcli { private static final long REQUEST_TIMEOUT = 1000; // msecs private static final long SETTLE_DELAY = 2000; // Before failing over public static void main(String[] argv) throws Exception { ZContext ctx = new ZContext(); String[] server = { "tcp://localhost:5001", "tcp://localhost:5002" }; int serverNbr = 0; System.out.printf ("I: connecting to server at %s...\n", server [serverNbr]); Socket client = ctx.createSocket(ZMQ.REQ); client.connect(server[serverNbr]); int sequence = 0; while (!Thread.currentThread().isInterrupted()) { // We send a request, then we work to get a reply String request = String.format("%d", ++sequence); client.send(request); boolean expectReply = true; while (expectReply) { // Poll socket for a reply, with timeout PollItem items [] = { new PollItem(client, ZMQ.Poller.POLLIN) }; int rc = ZMQ.poll(items, 1, REQUEST_TIMEOUT); if (rc == -1) break; // Interrupted // .split main body of client // We use a Lazy Pirate strategy in the client. If there's no // reply within our timeout, we close the socket and try again. // In Binary Star, it's the client vote that decides which // server is primary; the client must therefore try to connect // to each server in turn: if (items[0].isReadable()) { // We got a reply from the server, must match getSequence String reply = client.recvStr(); if (Integer.parseInt(reply) == sequence) { System.out.printf ("I: server replied OK (%s)\n", reply); expectReply = false; Thread.sleep(1000); // One request per second } else System.out.printf ("E: bad reply from server: %s\n", reply); } else { System.out.printf ("W: no response from server, failing over\n"); // Old socket is confused; close it and open a new one ctx.destroySocket(client); serverNbr = (serverNbr + 1) % 2; Thread.sleep(SETTLE_DELAY); System.out.printf("I: connecting to server at %s...\n", server[serverNbr]); client = ctx.createSocket(ZMQ.REQ); client.connect(server[serverNbr]); // Send request again, on new socket client.send(request); } } } ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/bstarsrv.java000066400000000000000000000224251255150477200213260ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; // Binary Star server proof-of-concept implementation. This server does no // real work; it just demonstrates the Binary Star failover model. public class bstarsrv { // States we can be in at any point in time enum State { STATE_PRIMARY, // Primary, waiting for peer to connect STATE_BACKUP, // Backup, waiting for peer to connect STATE_ACTIVE, // Active - accepting connections STATE_PASSIVE // Passive - not accepting connections } // Events, which start with the states our peer can be in enum Event { PEER_PRIMARY, // HA peer is pending primary PEER_BACKUP, // HA peer is pending backup PEER_ACTIVE, // HA peer is active PEER_PASSIVE, // HA peer is passive CLIENT_REQUEST // Client makes request } // Our finite state machine private State state; // Current state private Event event; // Current event private long peerExpiry; // When peer is considered 'dead' // We send state information this often // If peer doesn't respond in two heartbeats, it is 'dead' private final static long HEARTBEAT = 1000; // In msecs // .split Binary Star state machine // The heart of the Binary Star design is its finite-state machine (FSM). // The FSM runs one event at a time. We apply an event to the current state, // which checks if the event is accepted, and if so, sets a new state: private boolean stateMachine() { boolean exception = false; // These are the PRIMARY and BACKUP states; we're waiting to become // ACTIVE or PASSIVE depending on events we get from our peer: if (state == State.STATE_PRIMARY) { if (event == Event.PEER_BACKUP) { System.out.printf ("I: connected to backup (passive), ready active\n"); state = State.STATE_ACTIVE; } else if (event == Event.PEER_ACTIVE) { System.out.printf ("I: connected to backup (active), ready passive\n"); state = State.STATE_PASSIVE; } // Accept client connections } else if (state == State.STATE_BACKUP) { if (event == Event.PEER_ACTIVE) { System.out.printf ("I: connected to primary (active), ready passive\n"); state = State.STATE_PASSIVE; } else // Reject client connections when acting as backup if (event == Event.CLIENT_REQUEST) exception = true; } else // .split active and passive states // These are the ACTIVE and PASSIVE states: if (state == State.STATE_ACTIVE) { if (event == Event.PEER_ACTIVE) { // Two actives would mean split-brain System.out.printf ("E: fatal error - dual actives, aborting\n"); exception = true; } } else // Server is passive // CLIENT_REQUEST events can trigger failover if peer looks dead if (state == State.STATE_PASSIVE) { if (event == Event.PEER_PRIMARY) { // Peer is restarting - become active, peer will go passive System.out.printf ("I: primary (passive) is restarting, ready active\n"); state = State.STATE_ACTIVE; } else if (event == Event.PEER_BACKUP) { // Peer is restarting - become active, peer will go passive System.out.printf ("I: backup (passive) is restarting, ready active\n"); state = State.STATE_ACTIVE; } else if (event == Event.PEER_PASSIVE) { // Two passives would mean cluster would be non-responsive System.out.printf ("E: fatal error - dual passives, aborting\n"); exception = true; } else if (event == Event.CLIENT_REQUEST) { // Peer becomes active if timeout has passed // It's the client request that triggers the failover assert (peerExpiry > 0); if (System.currentTimeMillis () >= peerExpiry) { // If peer is dead, switch to the active state System.out.printf ("I: failover successful, ready active\n"); state = State.STATE_ACTIVE; } else // If peer is alive, reject connections exception = true; } } return exception; } // .split main task // This is our main task. First we bind/connect our sockets with our // peer and make sure we will get state messages correctly. We use // three sockets; one to publish state, one to subscribe to state, and // one for client requests/replies: public static void main(String[] argv) { // Arguments can be either of: // -p primary server, at tcp://localhost:5001 // -b backup server, at tcp://localhost:5002 ZContext ctx = new ZContext(); Socket statepub = ctx.createSocket(ZMQ.PUB); Socket statesub = ctx.createSocket(ZMQ.SUB); statesub.subscribe(ZMQ.SUBSCRIPTION_ALL); Socket frontend = ctx.createSocket(ZMQ.ROUTER); bstarsrv fsm = new bstarsrv(); if (argv.length == 1 && argv[0].equals("-p")) { System.out.printf("I: Primary active, waiting for backup (passive)\n"); frontend.bind("tcp://*:5001"); statepub.bind("tcp://*:5003"); statesub.connect("tcp://localhost:5004"); fsm.state = State.STATE_PRIMARY; } else if (argv.length == 1 && argv[0].equals("-b")) { System.out.printf("I: Backup passive, waiting for primary (active)\n"); frontend.bind("tcp://*:5002"); statepub.bind("tcp://*:5004"); statesub.connect("tcp://localhost:5003"); fsm.state = State.STATE_BACKUP; } else { System.out.printf("Usage: bstarsrv { -p | -b }\n"); ctx.destroy(); System.exit(0); } // .split handling socket input // We now process events on our two input sockets, and process these // events one at a time via our finite-state machine. Our "work" for // a client request is simply to echo it back: // Set timer for next outgoing state message long sendStateAt = System.currentTimeMillis() + HEARTBEAT; while (!Thread.currentThread().isInterrupted()) { PollItem[] items = { new PollItem(frontend, ZMQ.Poller.POLLIN), new PollItem(statesub, ZMQ.Poller.POLLIN), }; int timeLeft = (int) ((sendStateAt - System.currentTimeMillis())); if (timeLeft < 0) timeLeft = 0; int rc = ZMQ.poll(items, 2, timeLeft); if (rc == -1) break; // Context has been shut down if (items[0].isReadable()) { // Have a client request ZMsg msg = ZMsg.recvMsg(frontend); fsm.event = Event.CLIENT_REQUEST; if (fsm.stateMachine() == false) // Answer client by echoing request back msg.send(frontend); else msg.destroy(); } if (items[1].isReadable()) { // Have state from our peer, execute as event String message = statesub.recvStr(); fsm.event = Event.values()[Integer.parseInt(message)]; if (fsm.stateMachine()) break; // Error, so exit fsm.peerExpiry = System.currentTimeMillis() + 2 * HEARTBEAT; } // If we timed out, send state to peer if (System.currentTimeMillis() >= sendStateAt) { statepub.send(String.valueOf(fsm.state.ordinal())); sendStateAt = System.currentTimeMillis() + HEARTBEAT; } } if (Thread.currentThread().isInterrupted()) System.out.printf ("W: interrupted\n"); // Shutdown sockets and context ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/bstarsrv2.java000066400000000000000000000044321255150477200214060ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZLoop; import org.zeromq.ZLoop.IZLoopHandler; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; // Binary Star server, using bstar reactor public class bstarsrv2 { private static IZLoopHandler Echo = new IZLoopHandler() { @Override public int handle(ZLoop loop, PollItem item, Object arg) { ZMsg msg = ZMsg.recvMsg(item.getSocket()); msg.send(item.getSocket()); return 0; } }; public static void main(String[] argv) { // Arguments can be either of: // -p primary server, at tcp://localhost:5001 // -b backup server, at tcp://localhost:5002 bstar bs = null; if (argv.length == 1 && argv[0].equals("-p")) { System.out.printf("I: Primary active, waiting for backup (passive)\n"); bs = new bstar(true, "tcp://*:5003", "tcp://localhost:5004"); bs.voter ("tcp://*:5001", ZMQ.ROUTER, Echo, null); } else if (argv.length == 1 && argv[0].equals("-b")) { System.out.printf("I: Backup passive, waiting for primary (active)\n"); bs = new bstar(false, "tcp://*:5004", "tcp://localhost:5003"); bs.voter ("tcp://*:5002", ZMQ.ROUTER, Echo, null); } else { System.out.printf("Usage: bstarsrv { -p | -b }\n"); System.exit(0); } bs.start(); bs.destroy(); } } jeromq-0.3.5/src/test/java/guide/clone.java000066400000000000000000000325551255150477200205650ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Poller; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; import org.zeromq.ZThread; import org.zeromq.ZThread.IAttachedRunnable; import java.util.HashMap; import java.util.Map; public class clone { private ZContext ctx; // Our context wrapper private Socket pipe; // Pipe through to clone agent // .split constructor and destructor // Here are the constructor and destructor for the clone class. Note that // we create a context specifically for the pipe that connects our // frontend to the backend agent: public clone() { ctx = new ZContext(); pipe = ZThread.fork(ctx, new CloneAgent()); } public void destroy() { ctx.destroy(); } // .split subtree method // Specify subtree for snapshot and updates, which we must do before // connecting to a server as the subtree specification is sent as the // first command to the server. Sends a [SUBTREE][subtree] command to // the agent: public void subtree(String subtree) { ZMsg msg = new ZMsg(); msg.add("SUBTREE"); msg.add(subtree); msg.send(pipe); } // .split connect method // Connect to a new server endpoint. We can connect to at most two // servers. Sends [CONNECT][endpoint][service] to the agent: public void connect(String address, String service) { ZMsg msg = new ZMsg(); msg.add("CONNECT"); msg.add(address); msg.add(service); msg.send(pipe); } // .split set method // Set a new value in the shared hashmap. Sends a [SET][key][value][ttl] // command through to the agent which does the actual work: public void set(String key, String value, int ttl) { ZMsg msg = new ZMsg(); msg.add("SET"); msg.add(key); msg.add(value); msg.add(String.format("%d", ttl)); msg.send(pipe); } // .split get method // Look up value in distributed hash table. Sends [GET][key] to the agent and // waits for a value response. If there is no value available, will eventually // return NULL: public String get(String key) { ZMsg msg = new ZMsg(); msg.add("GET"); msg.add(key); msg.send(pipe); ZMsg reply = ZMsg.recvMsg(pipe); if (reply != null) { String value = reply.popString(); reply.destroy(); return value; } return null; } // .split working with servers // The backend agent manages a set of servers, which we implement using // our simple class model: private static class Server { private String address; // Server address private int port; // Server port private Socket snapshot; // Snapshot socket private Socket subscriber; // Incoming updates private long expiry; // When server expires private int requests; // How many snapshot requests made? protected Server(ZContext ctx, String address, int port, String subtree) { System.out.printf("I: adding server %s:%d...\n", address, port); this.address = address; this.port = port; snapshot = ctx.createSocket(ZMQ.DEALER); snapshot.connect(String.format("%s:%d", address, port)); subscriber = ctx.createSocket(ZMQ.SUB); subscriber.connect(String.format("%s:%d", address, port + 1)); subscriber.subscribe(subtree.getBytes(ZMQ.CHARSET)); } protected void destroy() { } } // .split backend agent class // Here is the implementation of the backend agent itself: // Number of servers to which we will talk to private final static int SERVER_MAX = 2; // Server considered dead if silent for this long private final static int SERVER_TTL = 5000; // msecs // States we can be in private final static int STATE_INITIAL = 0; // Before asking server for state private final static int STATE_SYNCING = 1; // Getting state from server private final static int STATE_ACTIVE = 2; // Getting new updates from server private static class Agent { private ZContext ctx; // Context wrapper private Socket pipe; // Pipe back to application private Map kvmap; // Actual key/value table private String subtree; // Subtree specification, if any private Server[] server; private int nbrServers; // 0 to SERVER_MAX private int state; // Current state private int curServer; // If active, server 0 or 1 private long sequence; // Last kvmsg processed private Socket publisher; // Outgoing updates protected Agent (ZContext ctx, Socket pipe) { this.ctx = ctx; this.pipe = pipe; kvmap = new HashMap(); subtree = ""; state = STATE_INITIAL; publisher = ctx.createSocket(ZMQ.PUB); server = new Server[SERVER_MAX]; } protected void destroy() { for (int serverNbr = 0; serverNbr < nbrServers; serverNbr++) server[serverNbr].destroy(); } // .split handling a control message // Here we handle the different control messages from the frontend; // SUBTREE, CONNECT, SET, and GET: private boolean controlMessage() { ZMsg msg = ZMsg.recvMsg(pipe); String command = msg.popString(); if (command == null) return false; // Interrupted if (command.equals("SUBTREE")) { subtree = msg.popString(); } else if (command.equals("CONNECT")) { String address = msg.popString(); String service = msg.popString(); if (nbrServers < SERVER_MAX) { server [nbrServers++] = new Server( ctx, address, Integer.parseInt(service), subtree); // We broadcast updates to all known servers publisher.connect(String.format("%s:%d", address, Integer.parseInt(service) + 2)); } else System.out.printf("E: too many servers (max. %d)\n", SERVER_MAX); } else // .split set and get commands // When we set a property, we push the new key-value pair onto // all our connected servers: if (command.equals("SET")) { String key = msg.popString(); String value = msg.popString(); String ttl = msg.popString(); kvmap.put(key, value); // Send key-value pair on to server kvmsg kvmsg = new kvmsg(0); kvmsg.setKey(key); kvmsg.setUUID(); kvmsg.fmtBody("%s", value); kvmsg.setProp("ttl", ttl); kvmsg.send(publisher); kvmsg.destroy(); } else if (command.equals("GET")) { String key = msg.popString(); String value = kvmap.get(key); if (value != null) pipe.send(value); else pipe.send(""); } msg.destroy(); return true; } } private static class CloneAgent implements IAttachedRunnable { @Override public void run(Object[] args, ZContext ctx, Socket pipe) { Agent self = new Agent(ctx, pipe); while (!Thread.currentThread().isInterrupted()) { PollItem[] pollItems = { new PollItem(pipe, Poller.POLLIN), null }; long pollTimer = -1; int pollSize = 2; Server server = self.server[self.curServer]; switch (self.state) { case STATE_INITIAL: // In this state we ask the server for a snapshot, // if we have a server to talk to... if (self.nbrServers > 0) { System.out.printf("I: waiting for server at %s:%d...\n", server.address, server.port); if (server.requests < 2) { server.snapshot.sendMore("ICANHAZ?"); server.snapshot.send(self.subtree); server.requests++; } server.expiry = System.currentTimeMillis() + SERVER_TTL; self.state = STATE_SYNCING; pollItems[1] = new PollItem(server.snapshot, Poller.POLLIN); } else pollSize = 1; break; case STATE_SYNCING: // In this state we read from snapshot and we expect // the server to respond, else we fail over. pollItems[1] = new PollItem(server.snapshot, Poller.POLLIN); break; case STATE_ACTIVE: // In this state we read from subscriber and we expect // the server to give hugz, else we fail over. pollItems[1] = new PollItem(server.subscriber, Poller.POLLIN); break; } if (server != null) { pollTimer = server.expiry - System.currentTimeMillis(); if (pollTimer < 0) pollTimer = 0; } // .split client poll loop // We're ready to process incoming messages; if nothing at all // comes from our server within the timeout, that means the // server is dead: int rc = ZMQ.poll(pollItems, pollSize, pollTimer); if (rc == -1) break; // Context has been shut down if (pollItems[0].isReadable()) { if (!self.controlMessage()) break; // Interrupted } else if (pollItems[1].isReadable()) { kvmsg msg = kvmsg.recv(pollItems[1].getSocket()); if (msg == null) break; // Interrupted // Anything from server resets its expiry time server.expiry = System.currentTimeMillis() + SERVER_TTL; if (self.state == STATE_SYNCING) { // Store in snapshot until we're finished server.requests = 0; if (msg.getKey().equals("KTHXBAI")) { self.sequence = msg.getSequence(); self.state = STATE_ACTIVE; System.out.printf("I: received from %s:%d snapshot=%d\n", server.address, server.port, self.sequence); msg.destroy(); } } else if (self.state == STATE_ACTIVE) { // Discard out-of-sequence updates, incl. hugz if (msg.getSequence() > self.sequence) { self.sequence = msg.getSequence(); System.out.printf("I: received from %s:%d update=%d\n", server.address, server.port, self.sequence); } else msg.destroy(); } } else { // Server has died, failover to next System.out.printf("I: server at %s:%d didn't give hugz\n", server.address, server.port); self.curServer = (self.curServer + 1) % self.nbrServers; self.state = STATE_INITIAL; } } self.destroy(); } } } jeromq-0.3.5/src/test/java/guide/clonecli1.java000066400000000000000000000033551255150477200213320ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Socket; /** * Clone client model 1 * @author Danish Shrestha * */ public class clonecli1 { private static Map kvMap = new HashMap(); private static AtomicLong sequence = new AtomicLong(); public void run() { ZContext ctx = new ZContext(); Socket subscriber = ctx.createSocket(ZMQ.SUB); subscriber.connect("tcp://localhost:5556"); subscriber.subscribe(ZMQ.SUBSCRIPTION_ALL); while (true) { kvsimple kvMsg = kvsimple.recv(subscriber); if (kvMsg == null) break; clonecli1.kvMap.put(kvMsg.getKey(), kvMsg); System.out.println("receiving " + kvMsg); sequence.incrementAndGet(); } ctx.destroy(); } public static void main(String[] args) { new clonecli1().run(); } } jeromq-0.3.5/src/test/java/guide/clonecli2.java000066400000000000000000000046471255150477200213400ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; /** * Clone client Model Two * * @author Danish Shrestha * */ public class clonecli2 { private static Map kvMap = new HashMap(); public void run() { Context ctx = ZMQ.context(1); Socket snapshot = ctx.socket(ZMQ.DEALER); snapshot.connect("tcp://localhost:5556"); Socket subscriber = ctx.socket(ZMQ.SUB); subscriber.connect("tcp://localhost:5557"); subscriber.subscribe(ZMQ.SUBSCRIPTION_ALL); // get state snapshot snapshot.send("ICANHAZ?".getBytes(ZMQ.CHARSET), 0); long sequence = 0; while (true) { kvsimple kvMsg = kvsimple.recv(snapshot); if (kvMsg == null) break; sequence = kvMsg.getSequence(); if ("KTHXBAI".equalsIgnoreCase(kvMsg.getKey())) { System.out.println("Received snapshot = " + kvMsg.getSequence()); break; // done } System.out.println("receiving " + kvMsg.getSequence()); clonecli2.kvMap.put(kvMsg.getKey(), kvMsg); } // now apply pending updates, discard out-of-getSequence messages while (true) { kvsimple kvMsg = kvsimple.recv(subscriber); if (kvMsg == null) break; if (kvMsg.getSequence() > sequence) { sequence = kvMsg.getSequence(); System.out.println("receiving " + sequence); clonecli2.kvMap.put(kvMsg.getKey(), kvMsg); } } } public static void main(String[] args) { new clonecli2().run(); } } jeromq-0.3.5/src/test/java/guide/clonecli3.java000066400000000000000000000065641255150477200213410ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import java.util.Random; import java.util.concurrent.atomic.AtomicLong; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Poller; import org.zeromq.ZMQ.Socket; /** * Clone client Model Three * @author Danish Shrestha * */ public class clonecli3 { private static Map kvMap = new HashMap(); public void run() { ZContext ctx = new ZContext(); Socket snapshot = ctx.createSocket(ZMQ.DEALER); snapshot.connect("tcp://localhost:5556"); Socket subscriber = ctx.createSocket(ZMQ.SUB); subscriber.connect("tcp://localhost:5557"); subscriber.subscribe(ZMQ.SUBSCRIPTION_ALL); Socket push = ctx.createSocket(ZMQ.PUSH); push.connect("tcp://localhost:5558"); // get state snapshot long sequence = 0; snapshot.send("ICANHAZ?".getBytes(ZMQ.CHARSET), 0); while (true) { kvsimple kvMsg = kvsimple.recv(snapshot); if (kvMsg == null) break; // Interrupted sequence = kvMsg.getSequence(); if ("KTHXBAI".equalsIgnoreCase(kvMsg.getKey())) { System.out.println("Received snapshot = " + kvMsg.getSequence()); break; // done } System.out.println("receiving " + kvMsg.getSequence()); clonecli3.kvMap.put(kvMsg.getKey(), kvMsg); } Poller poller = new ZMQ.Poller(1); poller.register(subscriber); Random random = new Random(); // now apply pending updates, discard out-of-getSequence messages long alarm = System.currentTimeMillis() + 5000; while (true) { int rc = poller.poll(Math.max(0, alarm - System.currentTimeMillis())); if (rc == -1) break; // Context has been shut down if (poller.pollin(0)) { kvsimple kvMsg = kvsimple.recv(subscriber); if (kvMsg == null) break; // Interrupted if (kvMsg.getSequence() > sequence) { sequence = kvMsg.getSequence(); System.out.println("receiving " + sequence); clonecli3.kvMap.put(kvMsg.getKey(), kvMsg); } } if (System.currentTimeMillis() >= alarm) { int key = random.nextInt(10000); int body = random.nextInt(1000000); ByteBuffer b = ByteBuffer.allocate(4); b.asIntBuffer().put(body); kvsimple kvUpdateMsg = new kvsimple(key + "", 0, b.array()); kvUpdateMsg.send(push); alarm = System.currentTimeMillis() + 1000; } } ctx.destroy(); } public static void main(String[] args) { new clonecli3().run(); } } jeromq-0.3.5/src/test/java/guide/clonecli4.java000066400000000000000000000070201255150477200213260ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Poller; import org.zeromq.ZMQ.Socket; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import java.util.Random; import java.util.concurrent.atomic.AtomicLong; /** * Clone client Model Four * */ public class clonecli4 { // This client is identical to clonecli3 except for where we // handles subtrees. private final static String SUBTREE = "/client/"; private static Map kvMap = new HashMap(); public void run() { ZContext ctx = new ZContext(); Socket snapshot = ctx.createSocket(ZMQ.DEALER); snapshot.connect("tcp://localhost:5556"); Socket subscriber = ctx.createSocket(ZMQ.SUB); subscriber.connect("tcp://localhost:5557"); subscriber.subscribe(SUBTREE.getBytes(ZMQ.CHARSET)); Socket push = ctx.createSocket(ZMQ.PUSH); push.connect("tcp://localhost:5558"); // get state snapshot snapshot.sendMore("ICANHAZ?"); snapshot.send(SUBTREE); long sequence = 0; while (true) { kvsimple kvMsg = kvsimple.recv(snapshot); if (kvMsg == null) break; // Interrupted sequence = kvMsg.getSequence(); if ("KTHXBAI".equalsIgnoreCase(kvMsg.getKey())) { System.out.println("Received snapshot = " + kvMsg.getSequence()); break; // done } System.out.println("receiving " + kvMsg.getSequence()); clonecli4.kvMap.put(kvMsg.getKey(), kvMsg); } Poller poller = new Poller(1); poller.register(subscriber); Random random = new Random(); // now apply pending updates, discard out-of-getSequence messages long alarm = System.currentTimeMillis() + 5000; while (true) { int rc = poller.poll(Math.max(0, alarm - System.currentTimeMillis())); if (rc == -1) break; // Context has been shut down if (poller.pollin(0)) { kvsimple kvMsg = kvsimple.recv(subscriber); if (kvMsg == null) break; // Interrupted if (kvMsg.getSequence() > sequence) { sequence = kvMsg.getSequence(); System.out.println("receiving " + sequence); clonecli4.kvMap.put(kvMsg.getKey(), kvMsg); } } if (System.currentTimeMillis() >= alarm) { String key = String.format("%s%d", SUBTREE, random.nextInt(10000)); int body = random.nextInt(1000000); ByteBuffer b = ByteBuffer.allocate(4); b.asIntBuffer().put(body); kvsimple kvUpdateMsg = new kvsimple(key, 0, b.array()); kvUpdateMsg.send(push); alarm = System.currentTimeMillis() + 1000; } } ctx.destroy(); } public static void main(String[] args) { new clonecli4().run(); } } jeromq-0.3.5/src/test/java/guide/clonecli5.java000066400000000000000000000070261255150477200213350ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Poller; import org.zeromq.ZMQ.Socket; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import java.util.Random; /** * Clone client Model Five * */ public class clonecli5 { // This client is identical to clonecli3 except for where we // handles subtrees. private final static String SUBTREE = "/client/"; public void run() { ZContext ctx = new ZContext(); Socket snapshot = ctx.createSocket(ZMQ.DEALER); snapshot.connect("tcp://localhost:5556"); Socket subscriber = ctx.createSocket(ZMQ.SUB); subscriber.connect("tcp://localhost:5557"); subscriber.subscribe(SUBTREE.getBytes(ZMQ.CHARSET)); Socket publisher = ctx.createSocket(ZMQ.PUSH); publisher.connect("tcp://localhost:5558"); Map kvMap = new HashMap(); // get state snapshot snapshot.sendMore("ICANHAZ?"); snapshot.send(SUBTREE); long sequence = 0; while (true) { kvmsg kvMsg = kvmsg.recv(snapshot); if (kvMsg == null) break; // Interrupted sequence = kvMsg.getSequence(); if ("KTHXBAI".equalsIgnoreCase(kvMsg.getKey())) { System.out.println("Received snapshot = " + kvMsg.getSequence()); kvMsg.destroy(); break; // done } System.out.println("receiving " + kvMsg.getSequence()); kvMsg.store(kvMap); } Poller poller = new Poller(1); poller.register(subscriber); Random random = new Random(); // now apply pending updates, discard out-of-getSequence messages long alarm = System.currentTimeMillis() + 5000; while (true) { int rc = poller.poll(Math.max(0, alarm - System.currentTimeMillis())); if (rc == -1) break; // Context has been shut down if (poller.pollin(0)) { kvmsg kvMsg = kvmsg.recv(subscriber); if (kvMsg == null) break; // Interrupted if (kvMsg.getSequence() > sequence) { sequence = kvMsg.getSequence(); System.out.println("receiving " + sequence); kvMsg.store(kvMap); } else kvMsg.destroy(); } if (System.currentTimeMillis() >= alarm) { kvmsg kvMsg = new kvmsg(0); kvMsg.fmtKey("%s%d", SUBTREE, random.nextInt(10000)); kvMsg.fmtBody("%d", random.nextInt(1000000)); kvMsg.setProp("ttl", "%d", random.nextInt(30)); kvMsg.send(publisher); kvMsg.destroy(); alarm = System.currentTimeMillis() + 1000; } } ctx.destroy(); } public static void main(String[] args) { new clonecli5().run(); } } jeromq-0.3.5/src/test/java/guide/clonecli6.java000066400000000000000000000037341255150477200213400ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Socket; import java.util.HashMap; import java.util.Map; import java.util.Random; import java.util.concurrent.atomic.AtomicLong; /** * Clone client model 6 */ public class clonecli6 { private final static String SUBTREE = "/client/"; public void run() { // Create distributed hash instance clone clone = new clone(); Random rand = new Random(System.nanoTime()); // Specify configuration clone.subtree(SUBTREE); clone.connect("tcp://localhost", "5556"); clone.connect("tcp://localhost", "5566"); // Set random tuples into the distributed hash while (!Thread.currentThread().isInterrupted()) { // Set random value, check it was stored String key = String.format("%s%d", SUBTREE, rand.nextInt(10000)); String value= String.format("%d", rand.nextInt(1000000)); clone.set(key, value, rand.nextInt(30)); try { Thread.sleep(1000); } catch (InterruptedException e) { } } clone.destroy(); } public static void main(String[] args) { new clonecli6().run(); } } jeromq-0.3.5/src/test/java/guide/clonesrv1.java000066400000000000000000000035031255150477200213700ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.nio.ByteBuffer; import java.util.Random; import java.util.concurrent.atomic.AtomicLong; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; /** * * Clone server model 1 * @author Danish Shrestha * */ public class clonesrv1 { private static AtomicLong sequence = new AtomicLong(); public void run() { Context ctx = ZMQ.context(1); Socket publisher = ctx.socket(ZMQ.PUB); publisher.bind("tcp://*:5556"); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } Random random = new Random(); while (true) { long currentSequenceNumber = sequence.incrementAndGet(); int key = random.nextInt(10000); int body = random.nextInt(1000000); ByteBuffer b = ByteBuffer.allocate(4); b.asIntBuffer().put(body); kvsimple kvMsg = new kvsimple(key + "", currentSequenceNumber, b.array()); kvMsg.send(publisher); System.out.println("sending " + kvMsg); } } public static void main(String[] args) { new clonesrv1().run(); } } jeromq-0.3.5/src/test/java/guide/clonesrv2.java000066400000000000000000000107751255150477200214020ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.nio.ByteBuffer; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Random; import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicLong; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Poller; import org.zeromq.ZMQ.Socket; import org.zeromq.ZThread; import org.zeromq.ZThread.IAttachedRunnable; /** * Clone server Model Two * * @author Danish Shrestha * */ public class clonesrv2 { public void run() { ZContext ctx = new ZContext(); Socket publisher = ctx.createSocket(ZMQ.PUB); publisher.bind("tcp://*:5557"); Socket updates = ZThread.fork(ctx, new StateManager()); Random random = new Random(); long sequence = 0; while (!Thread.currentThread().isInterrupted()) { long currentSequenceNumber = ++sequence; int key = random.nextInt(10000); int body = random.nextInt(1000000); ByteBuffer b = ByteBuffer.allocate(4); b.asIntBuffer().put(body); kvsimple kvMsg = new kvsimple(key + "", currentSequenceNumber, b.array()); kvMsg.send(publisher); kvMsg.send(updates); // send a message to State Manager thead. try { Thread.sleep(1000); } catch (InterruptedException e) { } } System.out.printf(" Interrupted\n%d messages out\n", sequence); ctx.destroy(); } public static class StateManager implements IAttachedRunnable { private static Map kvMap = new LinkedHashMap(); @Override public void run(Object[] args, ZContext ctx, Socket pipe) { pipe.send("READY"); // optional Socket snapshot = ctx.createSocket(ZMQ.ROUTER); snapshot.bind("tcp://*:5556"); Poller poller = new ZMQ.Poller(2); poller.register(pipe, ZMQ.Poller.POLLIN); poller.register(snapshot, ZMQ.Poller.POLLIN); long stateSequence = 0; while (!Thread.currentThread().isInterrupted()) { if (poller.poll() < 0) break; // Context has been shut down // apply state updates from main thread if (poller.pollin(0)) { kvsimple kvMsg = kvsimple.recv(pipe); if (kvMsg == null) break; StateManager.kvMap.put(kvMsg.getKey(), kvMsg); stateSequence = kvMsg.getSequence(); } // execute state snapshot request if (poller.pollin(1)) { byte[] identity = snapshot.recv(0); if (identity == null) break; String request = new String(snapshot.recv(0), ZMQ.CHARSET); if (!request.equals("ICANHAZ?")) { System.out.println("E: bad request, aborting"); break; } Iterator> iter = kvMap.entrySet().iterator(); while (iter.hasNext()) { Entry entry = iter.next(); kvsimple msg = entry.getValue(); System.out.println("Sending message " + entry.getValue().getSequence()); this.sendMessage(msg, identity, snapshot); } // now send end message with getSequence number System.out.println("Sending state snapshot = " + stateSequence); snapshot.send(identity, ZMQ.SNDMORE); kvsimple message = new kvsimple("KTHXBAI", stateSequence, ZMQ.MESSAGE_SEPARATOR); message.send(snapshot); } } } private void sendMessage(kvsimple msg, byte[] identity, Socket snapshot) { snapshot.send(identity, ZMQ.SNDMORE); msg.send(snapshot); } } public static void main(String[] args) { new clonesrv2().run(); } } jeromq-0.3.5/src/test/java/guide/clonesrv3.java000066400000000000000000000074751255150477200214060ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Poller; import org.zeromq.ZMQ.Socket; /** * Clone server Model Three * @author Danish Shrestha * */ public class clonesrv3 { private static Map kvMap = new LinkedHashMap(); public void run() { ZContext ctx = new ZContext(); Socket snapshot = ctx.createSocket(ZMQ.ROUTER); snapshot.bind("tcp://*:5556"); Socket publisher = ctx.createSocket(ZMQ.PUB); publisher.bind("tcp://*:5557"); Socket collector = ctx.createSocket(ZMQ.PULL); collector.bind("tcp://*:5558"); Poller poller = new Poller(2); poller.register(collector, Poller.POLLIN); poller.register(snapshot, Poller.POLLIN); long sequence = 0; while (!Thread.currentThread().isInterrupted()) { if (poller.poll(1000) < 0) break; // Context has been shut down // apply state updates from main thread if (poller.pollin(0)) { kvsimple kvMsg = kvsimple.recv(collector); if (kvMsg == null) // Interrupted break; kvMsg.setSequence(++sequence); kvMsg.send(publisher); clonesrv3.kvMap.put(kvMsg.getKey(), kvMsg); System.out.printf("I: publishing update %5d\n", sequence); } // execute state snapshot request if (poller.pollin(1)) { byte[] identity = snapshot.recv(0); if (identity == null) break; // Interrupted String request = snapshot.recvStr(); if (!request.equals("ICANHAZ?")) { System.out.println("E: bad request, aborting"); break; } Iterator> iter = kvMap.entrySet().iterator(); while (iter.hasNext()) { Entry entry = iter.next(); kvsimple msg = entry.getValue(); System.out.println("Sending message " + entry.getValue().getSequence()); this.sendMessage(msg, identity, snapshot); } // now send end message with getSequence number System.out.println("Sending state snapshot = " + sequence); snapshot.send(identity, ZMQ.SNDMORE); kvsimple message = new kvsimple("KTHXBAI", sequence, ZMQ.SUBSCRIPTION_ALL); message.send(snapshot); } } System.out.printf (" Interrupted\n%d messages handled\n", sequence); ctx.destroy(); } private void sendMessage(kvsimple msg, byte[] identity, Socket snapshot) { snapshot.send(identity, ZMQ.SNDMORE); msg.send(snapshot); } public static void main(String[] args) { new clonesrv3().run(); } } jeromq-0.3.5/src/test/java/guide/clonesrv4.java000066400000000000000000000077311255150477200214020ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Poller; import org.zeromq.ZMQ.Socket; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; /** * Clone server Model Four */ public class clonesrv4 { private static Map kvMap = new LinkedHashMap(); public void run() { ZContext ctx = new ZContext(); Socket snapshot = ctx.createSocket(ZMQ.ROUTER); snapshot.bind("tcp://*:5556"); Socket publisher = ctx.createSocket(ZMQ.PUB); publisher.bind("tcp://*:5557"); Socket collector = ctx.createSocket(ZMQ.PULL); collector.bind("tcp://*:5558"); Poller poller = new Poller(2); poller.register(collector, Poller.POLLIN); poller.register(snapshot, Poller.POLLIN); long sequence = 0; while (!Thread.currentThread().isInterrupted()) { if (poller.poll(1000) < 0) break; // Context has been shut down // apply state updates from main thread if (poller.pollin(0)) { kvsimple kvMsg = kvsimple.recv(collector); if (kvMsg == null) // Interrupted break; kvMsg.setSequence(++sequence); kvMsg.send(publisher); clonesrv4.kvMap.put(kvMsg.getKey(), kvMsg); System.out.printf("I: publishing update %5d\n", sequence); } // execute state snapshot request if (poller.pollin(1)) { byte[] identity = snapshot.recv(0); if (identity == null) break; // Interrupted // .until // Request is in second frame of message String request = snapshot.recvStr(); if (!request.equals("ICANHAZ?")) { System.out.println("E: bad request, aborting"); break; } String subtree = snapshot.recvStr(); Iterator> iter = kvMap.entrySet().iterator(); while (iter.hasNext()) { Entry entry = iter.next(); kvsimple msg = entry.getValue(); System.out.println("Sending message " + entry.getValue().getSequence()); this.sendMessage(msg, identity, subtree, snapshot); } // now send end message with getSequence number System.out.println("Sending state snapshot = " + sequence); snapshot.send(identity, ZMQ.SNDMORE); kvsimple message = new kvsimple("KTHXBAI", sequence, ZMQ.SUBSCRIPTION_ALL); message.send(snapshot); } } System.out.printf (" Interrupted\n%d messages handled\n", sequence); ctx.destroy(); } private void sendMessage(kvsimple msg, byte[] identity, String subtree, Socket snapshot) { snapshot.send(identity, ZMQ.SNDMORE); snapshot.send(subtree, ZMQ.SNDMORE); msg.send(snapshot); } public static void main(String[] args) { new clonesrv4().run(); } } jeromq-0.3.5/src/test/java/guide/clonesrv5.java000066400000000000000000000154151255150477200214010ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZLoop; import org.zeromq.ZLoop.IZLoopHandler; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; // Clone server - Model Five public class clonesrv5 { private ZContext ctx; // Context wrapper private Map kvmap; // Key-value store private ZLoop loop; // zloop reactor private int port; // Main port we're working on private long sequence; // How many updates we're at private Socket snapshot; // Handle snapshot requests private Socket publisher; // Publish updates to clients private Socket collector; // Collect updates from clients // .split snapshot handler // This is the reactor handler for the snapshot socket; it accepts // just the ICANHAZ? request and replies with a state snapshot ending // with a KTHXBAI message: private static class Snapshots implements IZLoopHandler { @Override public int handle(ZLoop loop, PollItem item, Object arg) { clonesrv5 srv = (clonesrv5) arg; Socket socket = item.getSocket(); byte[] identity = socket.recv(); if (identity != null) { // Request is in second frame of message String request = socket.recvStr(); String subtree = null; if (request.equals("ICANHAZ?")) { subtree = socket.recvStr(); } else System.out.printf("E: bad request, aborting\n"); if (subtree != null) { // Send state socket to client for (Entry entry: srv.kvmap.entrySet()) { sendSingle(entry.getValue(), identity, subtree, socket); } // Now send END message with getSequence number System.out.printf("I: sending shapshot=%d\n", srv.sequence); socket.send(identity, ZMQ.SNDMORE); kvmsg kvmsg = new kvmsg(srv.sequence); kvmsg.setKey("KTHXBAI"); kvmsg.setBody(subtree.getBytes(ZMQ.CHARSET)); kvmsg.send(socket); kvmsg.destroy(); } } return 0; } } // .split collect updates // We store each update with a new getSequence number, and if necessary, a // time-to-live. We publish updates immediately on our publisher socket: private static class Collector implements IZLoopHandler { @Override public int handle(ZLoop loop, PollItem item, Object arg) { clonesrv5 srv = (clonesrv5) arg; Socket socket = item.getSocket(); kvmsg msg = kvmsg.recv(socket); if (msg != null) { msg.setSequence(++srv.sequence); msg.send(srv.publisher); int ttl = Integer.parseInt(msg.getProp("ttl")); if (ttl > 0) msg.setProp("ttl", "%d", System.currentTimeMillis() + ttl * 1000); msg.store(srv.kvmap); System.out.printf("I: publishing update=%d\n", srv.sequence); } return 0; } } private static class FlushTTL implements IZLoopHandler { @Override public int handle(ZLoop loop, PollItem item, Object arg) { clonesrv5 srv = (clonesrv5) arg; if (srv.kvmap != null) { for (kvmsg msg: new ArrayList(srv.kvmap.values())) { srv.flushSingle(msg); } } return 0; } } public clonesrv5 () { port = 5556; ctx = new ZContext(); kvmap = new HashMap(); loop = new ZLoop(); loop.verbose(false); // Set up our clone server sockets snapshot = ctx.createSocket(ZMQ.ROUTER); snapshot.bind(String.format("tcp://*:%d", port)); publisher = ctx.createSocket(ZMQ.PUB); publisher.bind(String.format("tcp://*:%d", port + 1)); collector = ctx.createSocket(ZMQ.PULL); collector.bind(String.format("tcp://*:%d", port + 2)); } public void run() { // Register our handlers with reactor PollItem poller = new PollItem(snapshot, ZMQ.Poller.POLLIN); loop.addPoller(poller, new Snapshots(), this); poller = new PollItem(collector, ZMQ.Poller.POLLIN); loop.addPoller(poller, new Collector(), this); loop.addTimer(1000, 0, new FlushTTL(), this); loop.start(); loop.destroy(); ctx.destroy(); } // We call this function for each getKey-value pair in our hash table private static void sendSingle(kvmsg msg, byte[] identity, String subtree, Socket socket) { if (msg.getKey().startsWith(subtree)) { socket.send (identity, // Choose recipient ZMQ.SNDMORE); msg.send(socket); } } // .split flush ephemeral values // At regular intervals, we flush ephemeral values that have expired. This // could be slow on very large data sets: // If getKey-value pair has expired, delete it and publish the // fact to listening clients. private void flushSingle(kvmsg msg) { long ttl = Long.parseLong(msg.getProp("ttl")); if (ttl > 0 && System.currentTimeMillis() >= ttl) { msg.setSequence(++sequence); msg.setBody(ZMQ.MESSAGE_SEPARATOR); msg.send(publisher); msg.store(kvmap); System.out.printf("I: publishing delete=%d\n", sequence); } } public static void main(String[] args) { clonesrv5 srv = new clonesrv5(); srv.run(); } } jeromq-0.3.5/src/test/java/guide/clonesrv6.java000066400000000000000000000357141255150477200214060ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZLoop; import org.zeromq.ZLoop.IZLoopHandler; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; // Clone server - Model Six public class clonesrv6 { private ZContext ctx; // Context wrapper private Map kvmap; // Key-value store private bstar bStar; // Bstar reactor core private long sequence; // How many updates we're at private int port; // Main port we're working on private int peer; // Main port of our peer private Socket publisher; // Publish updates and hugz private Socket collector; // Collect updates from clients private Socket subscriber; // Get updates from peer private List pending; // Pending updates from clients private boolean primary; // TRUE if we're primary private boolean active; // TRUE if we're active private boolean passive; // TRUE if we're passive private static class Snapshots implements IZLoopHandler { @Override public int handle(ZLoop loop, PollItem item, Object arg) { clonesrv6 srv = (clonesrv6) arg; Socket socket = item.getSocket(); byte[] identity = socket.recv(); if (identity != null) { // Request is in second frame of message String request = socket.recvStr(); String subtree = null; if (request.equals("ICANHAZ?")) { subtree = socket.recvStr(); } else System.out.printf("E: bad request, aborting\n"); if (subtree != null) { // Send state socket to client for (Entry entry: srv.kvmap.entrySet()) { sendSingle(entry.getValue(), identity, subtree, socket); } // Now send END message with getSequence number System.out.printf("I: sending shapshot=%d\n", srv.sequence); socket.send(identity, ZMQ.SNDMORE); kvmsg kvmsg = new kvmsg(srv.sequence); kvmsg.setKey("KTHXBAI"); kvmsg.setBody(subtree.getBytes(ZMQ.CHARSET)); kvmsg.send(socket); kvmsg.destroy(); } } return 0; } } private static class Collector implements IZLoopHandler { @Override public int handle(ZLoop loop, PollItem item, Object arg) { clonesrv6 srv = (clonesrv6) arg; Socket socket = item.getSocket(); kvmsg msg = kvmsg.recv(socket); if (msg != null) { if(srv.active){ msg.setSequence(++srv.sequence); msg.send(srv.publisher); int ttl = Integer.parseInt(msg.getProp("ttl")); if (ttl > 0) msg.setProp("ttl", "%d", System.currentTimeMillis() + ttl * 1000); msg.store(srv.kvmap); System.out.printf("I: publishing update=%d\n", srv.sequence); } else { // If we already got message from active, drop it, else // hold on pending list if (srv.wasPending(msg)) msg.destroy(); else srv.pending.add(msg); } } return 0; } } // .split heartbeating // We send a HUGZ message once a second to all subscribers so that they // can detect if our server dies. They'll then switch over to the backup // server, which will become active: private static class SendHugz implements IZLoopHandler { @Override public int handle(ZLoop loop, PollItem item, Object arg) { clonesrv6 srv = (clonesrv6) arg; kvmsg msg = new kvmsg(srv.sequence); msg.setKey("HUGZ"); msg.setBody(ZMQ.MESSAGE_SEPARATOR); msg.send(srv.publisher); msg.destroy(); return 0; } } private static class FlushTTL implements IZLoopHandler { @Override public int handle(ZLoop loop, PollItem item, Object arg) { clonesrv6 srv = (clonesrv6) arg; if (srv.kvmap != null) { for (kvmsg msg: new ArrayList(srv.kvmap.values())) { srv.flushSingle(msg); } } return 0; } } // .split handling state changes // When we switch from passive to active, we apply our pending list so that // our kvmap is up-to-date. When we switch to passive, we wipe our kvmap // and grab a new snapshot from the active server: private static class NewActive implements IZLoopHandler { @Override public int handle(ZLoop loop, PollItem item, Object arg) { clonesrv6 srv = (clonesrv6) arg; srv.active = true; srv.passive = false; // Stop subscribing to updates PollItem poller = new PollItem(srv.subscriber, ZMQ.Poller.POLLIN); srv.bStar.zloop().removePoller(poller); // Apply pending list to own hash table for (kvmsg msg: srv.pending) { msg.setSequence(++srv.sequence); msg.send(srv.publisher); msg.store(srv.kvmap); System.out.printf("I: publishing pending=%d\n", srv.sequence); } return 0; } } private static class NewPassive implements IZLoopHandler { @Override public int handle(ZLoop loop, PollItem item, Object arg) { clonesrv6 srv = (clonesrv6) arg; if (srv.kvmap != null) { for (kvmsg msg: srv.kvmap.values()) msg.destroy(); } srv.active = false; srv.passive = true; // Start subscribing to updates PollItem poller = new PollItem(srv.subscriber, ZMQ.Poller.POLLIN); srv.bStar.zloop().addPoller(poller, new Subscriber(), srv); return 0; } } // .split subscriber handler // When we get an update, we create a new kvmap if necessary, and then // add our update to our kvmap. We're always passive in this case: private static class Subscriber implements IZLoopHandler { @Override public int handle(ZLoop loop, PollItem item, Object arg) { clonesrv6 srv = (clonesrv6) arg; Socket socket = item.getSocket(); // Get state snapshot if necessary if (srv.kvmap == null) { srv.kvmap = new HashMap(); Socket snapshot = srv.ctx.createSocket(ZMQ.DEALER); snapshot.connect(String.format("tcp://localhost:%d", srv.peer)); System.out.printf("I: asking for snapshot from: tcp://localhost:%d\n", srv.peer); snapshot.sendMore("ICANHAZ?"); snapshot.send(""); // blank subtree to get all while (true) { kvmsg msg = kvmsg.recv(snapshot); if (msg == null) break; // Interrupted if (msg.getKey().equals("KTHXBAI")) { srv.sequence = msg.getSequence(); msg.destroy(); break; // Done } msg.store(srv.kvmap); } System.out.printf("I: received snapshot=%d\n",srv.sequence); srv.ctx.destroySocket(snapshot); } // Find and remove update off pending list kvmsg msg = kvmsg.recv(item.getSocket()); if (msg == null) return 0; if (!msg.getKey().equals("HUGZ")) { if (!srv.wasPending(msg)) { // If active update came before client update, flip it // around, store active update (with sequence) on pending // list and use to clear client update when it comes later srv.pending.add(msg.dup()); } // If update is more recent than our kvmap, apply it if (msg.getSequence() > srv.sequence) { srv.sequence = msg.getSequence(); msg.store(srv.kvmap); System.out.printf("I: received update=%d\n",srv.sequence); } } msg.destroy(); return 0; } } public clonesrv6(boolean primary) { if (primary) { bStar = new bstar(true, "tcp://*:5003", "tcp://localhost:5004"); bStar.voter("tcp://*:5556", ZMQ.ROUTER, new Snapshots(), this); port = 5556; peer = 5566; this.primary = true; } else { bStar = new bstar(false, "tcp://*:5004", "tcp://localhost:5003"); bStar.voter("tcp://*:5566", ZMQ.ROUTER, new Snapshots(), this); port = 5566; peer = 5556; this.primary = false; } // Primary server will become first active if (primary) kvmap = new HashMap(); ctx = new ZContext(); pending = new ArrayList(); bStar.setVerbose(true); // Set up our clone server sockets publisher = ctx.createSocket(ZMQ.PUB); collector = ctx.createSocket(ZMQ.SUB); collector.subscribe(ZMQ.SUBSCRIPTION_ALL); publisher.bind(String.format("tcp://*:%d", port + 1)); collector.bind(String.format("tcp://*:%d", port+2)); // Set up our own clone client interface to peer subscriber = ctx.createSocket(ZMQ.SUB); subscriber.subscribe(ZMQ.SUBSCRIPTION_ALL); subscriber.connect(String.format("tcp://localhost:%d", peer + 1)); } // .split main task body // After we've setup our sockets, we register our binary star // event handlers, and then start the bstar reactor. This finishes // when the user presses Ctrl-C or when the process receives a SIGINT // interrupt: public void run() { // Register state change handlers bStar.newActive(new NewActive(), this); bStar.newPassive(new NewPassive(), this); // Register our other handlers with the bstar reactor PollItem poller = new PollItem(collector, ZMQ.Poller.POLLIN); bStar.zloop().addPoller(poller, new Collector(), this); bStar.zloop().addTimer(1000, 0, new FlushTTL(), this); bStar.zloop().addTimer(1000, 0, new SendHugz(), this); // Start the bstar reactor bStar.start(); // Interrupted, so shut down for (kvmsg value: pending) value.destroy(); bStar.destroy(); for (kvmsg value: kvmap.values()) value.destroy(); ctx.destroy(); } // Send one state snapshot key-value pair to a socket // Hash item data is our kvmsg object, ready to send private static void sendSingle(kvmsg msg, byte[] identity, String subtree, Socket socket) { if (msg.getKey().startsWith(subtree)) { socket.send (identity, // Choose recipient ZMQ.SNDMORE); msg.send(socket); } } // The collector is more complex than in the clonesrv5 example because the // way it processes updates depends on whether we're active or passive. // The active applies them immediately to its kvmap, whereas the passive // queues them as pending: // If message was already on pending list, remove it and return TRUE, // else return FALSE. boolean wasPending (kvmsg msg) { Iterator it = pending.iterator(); while (it.hasNext()) { if(java.util.Arrays.equals(msg.UUID(), it.next().UUID())){ it.remove(); return true; } } return false; } // We purge ephemeral values using exactly the same code as in // the previous clonesrv5 example. // .skip // If key-value pair has expired, delete it and publish the // fact to listening clients. private void flushSingle(kvmsg msg) { long ttl = Long.parseLong(msg.getProp("ttl")); if (ttl > 0 && System.currentTimeMillis() >= ttl) { msg.setSequence(++sequence); msg.setBody(ZMQ.MESSAGE_SEPARATOR); msg.send(publisher); msg.store(kvmap); System.out.printf("I: publishing delete=%d\n", sequence); } } // .split main task setup // The main task parses the command line to decide whether to start // as a primary or backup server. We're using the Binary Star pattern // for reliability. This interconnects the two servers so they can // agree on which one is primary and which one is backup. To allow the // two servers to run on the same box, we use different ports for // primary and backup. Ports 5003/5004 are used to interconnect the // servers. Ports 5556/5566 are used to receive voting events (snapshot // requests in the clone pattern). Ports 5557/5567 are used by the // publisher, and ports 5558/5568 are used by the collector: public static void main(String[] args) { clonesrv6 srv = null; if (args.length == 1 && "-p".equals(args[0])) { srv = new clonesrv6(true); } else if (args.length == 1 && "-b".equals(args[0])) { srv = new clonesrv6(false); } else { System.out.printf("Usage: clonesrv4 { -p | -b }\n"); System.exit(0); } srv.run(); } } jeromq-0.3.5/src/test/java/guide/espresso.java000066400000000000000000000105461255150477200213240ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Socket; import org.zeromq.ZThread; import org.zeromq.ZThread.IAttachedRunnable; import java.util.Random; // Espresso Pattern // This shows how to capture data using a pub-sub proxy public class espresso { // The subscriber thread requests messages starting with // A and B, then reads and counts incoming messages. private static class Subscriber implements IAttachedRunnable { @Override public void run(Object[] args, ZContext ctx, Socket pipe) { // Subscribe to "A" and "B" Socket subscriber = ctx.createSocket(ZMQ.SUB); subscriber.connect("tcp://localhost:6001"); subscriber.subscribe("A".getBytes(ZMQ.CHARSET)); subscriber.subscribe("B".getBytes(ZMQ.CHARSET)); int count = 0; while (count < 5) { String string = subscriber.recvStr(); if (string == null) break; // Interrupted count++; } ctx.destroySocket(subscriber); } } // .split publisher thread // The publisher sends random messages starting with A-J: private static class Publisher implements IAttachedRunnable { @Override public void run(Object[] args, ZContext ctx, Socket pipe) { Socket publisher = ctx.createSocket(ZMQ.PUB); publisher.bind("tcp://*:6000"); Random rand = new Random(System.currentTimeMillis()); while (!Thread.currentThread().isInterrupted()) { String string = String.format("%c-%05d", 'A' + rand.nextInt(10), rand.nextInt(100000)); if (!publisher.send(string)) break; // Interrupted try { Thread.sleep(100); // Wait for 1/10th second } catch (InterruptedException e) { } } ctx.destroySocket(publisher); } } // .split listener thread // The listener receives all messages flowing through the proxy, on its // pipe. In CZMQ, the pipe is a pair of ZMQ_PAIR sockets that connect // attached child threads. In other languages your mileage may vary: private static class Listener implements IAttachedRunnable { @Override public void run(Object[] args, ZContext ctx, Socket pipe) { // Print everything that arrives on pipe while (true) { ZFrame frame = ZFrame.recvFrame(pipe); if (frame == null) break; // Interrupted frame.print(null); frame.destroy(); } } } // .split main thread // The main task starts the subscriber and publisher, and then sets // itself up as a listening proxy. The listener runs as a child thread: public static void main(String[] argv) { // Start child threads ZContext ctx = new ZContext(); ZThread.fork(ctx, new Publisher()); ZThread.fork(ctx, new Subscriber()); Socket subscriber = ctx.createSocket(ZMQ.XSUB); subscriber.connect("tcp://localhost:6000"); Socket publisher = ctx.createSocket(ZMQ.XPUB); publisher.bind("tcp://*:6001"); Socket listener = ZThread.fork(ctx, new Listener()); ZMQ.proxy (subscriber, publisher, listener); System.out.println(" interrupted"); // Tell attached threads to exit ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/flcliapi.java000066400000000000000000000273161255150477200212470ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; import org.zeromq.ZThread; import org.zeromq.ZThread.IAttachedRunnable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; // flcliapi class - Freelance Pattern agent class // Implements the Freelance Protocol at http://rfc.zeromq.org/spec:10 public class flcliapi { // If not a single service replies within this time, give up private static final int GLOBAL_TIMEOUT = 2500; // PING interval for servers we think are alive private static final int PING_INTERVAL = 2000; // msecs // Server considered dead if silent for this long private static final int SERVER_TTL = 6000; // msecs // .split API structure // This API works in two halves, a common pattern for APIs that need to // run in the background. One half is an frontend object our application // creates and works with; the other half is a backend "agent" that runs // in a background thread. The frontend talks to the backend over an // inproc pipe socket: // Structure of our frontend class private ZContext ctx; // Our context wrapper private Socket pipe; // Pipe through to flcliapi agent public flcliapi() { ctx = new ZContext(); FreelanceAgent agent = new FreelanceAgent(); pipe = ZThread.fork(ctx, agent); } public void destroy() { ctx.destroy(); } // .split connect method // To implement the connect method, the frontend object sends a multipart // message to the backend agent. The first part is a string "CONNECT", and // the second part is the endpoint. It waits 100msec for the connection to // come up, which isn't pretty, but saves us from sending all requests to a // single server, at startup time: public void connect(String endpoint) { ZMsg msg = new ZMsg(); msg.add("CONNECT"); msg.add(endpoint); msg.send(pipe); try { Thread.sleep(100); // Allow connection to come up } catch (InterruptedException e) { } } // .split request method // To implement the request method, the frontend object sends a message // to the backend, specifying a command "REQUEST" and the request message: public ZMsg request(ZMsg request) { request.push("REQUEST"); request.send(pipe); ZMsg reply = ZMsg.recvMsg(pipe); if (reply != null) { String status = reply.popString(); if (status.equals("FAILED")) reply.destroy(); } return reply; } // .split backend agent // Here we see the backend agent. It runs as an attached thread, talking // to its parent over a pipe socket. It is a fairly complex piece of work // so we'll break it down into pieces. First, the agent manages a set of // servers, using our familiar class approach: // Simple class for one server we talk to private static class Server { private String endpoint; // Server identity/endpoint private boolean alive; // 1 if known to be alive private long pingAt; // Next ping at this time private long expires; // Expires at this time protected Server(String endpoint) { this.endpoint = endpoint; alive = false; pingAt = System.currentTimeMillis() + PING_INTERVAL; expires = System.currentTimeMillis() + SERVER_TTL; } protected void destroy() { } private void ping(Socket socket) { if (System.currentTimeMillis() >= pingAt) { ZMsg ping = new ZMsg(); ping.add(endpoint); ping.add("PING"); ping.send(socket); pingAt = System.currentTimeMillis() + PING_INTERVAL; } } private long tickless(long tickless) { if (tickless > pingAt) return pingAt; return -1; } } // .split backend agent class // We build the agent as a class that's capable of processing messages // coming in from its various sockets: // Simple class for one background agent private static class Agent { private ZContext ctx; // Own context private Socket pipe; // Socket to talk back to application private Socket router; // Socket to talk to servers private Map servers; // Servers we've connected to private List actives; // Servers we know are alive private int sequence; // Number of requests ever sent private ZMsg request; // Current request if any private ZMsg reply; // Current reply if any private long expires; // Timeout for request/reply protected Agent(ZContext ctx, Socket pipe) { this.ctx = ctx; this.pipe = pipe; router = ctx.createSocket(ZMQ.ROUTER); servers = new HashMap(); actives = new ArrayList(); } protected void destroy() { for(Server server: servers.values()) server.destroy(); } // .split control messages // This method processes one message from our frontend class // (it's going to be CONNECT or REQUEST): // Callback when we remove server from agent 'servers' hash table private void controlMessage() { ZMsg msg = ZMsg.recvMsg(pipe); String command = msg.popString(); if (command.equals("CONNECT")) { String endpoint = msg.popString(); System.out.printf("I: connecting to %s...\n", endpoint); router.connect(endpoint); Server server = new Server(endpoint); servers.put(endpoint, server); actives.add(server); server.pingAt = System.currentTimeMillis() + PING_INTERVAL; server.expires = System.currentTimeMillis() + SERVER_TTL; } else if (command.equals("REQUEST")) { assert (request == null); // Strict request-reply cycle // Prefix request with getSequence number and empty envelope String sequenceText = String.format("%d", ++sequence); msg.push(sequenceText); // Take ownership of request message request = msg; msg = null; // Request expires after global timeout expires = System.currentTimeMillis() + GLOBAL_TIMEOUT; } if (msg != null) msg.destroy(); } // .split router messages // This method processes one message from a connected // server: private void routerMessage() { ZMsg reply = ZMsg.recvMsg(router); // Frame 0 is server that replied String endpoint = reply.popString(); Server server = servers.get(endpoint); assert (server != null); if (!server.alive) { actives.add(server); server.alive = true; } server.pingAt = System.currentTimeMillis() + PING_INTERVAL; server.expires = System.currentTimeMillis() + SERVER_TTL; // Frame 1 may be getSequence number for reply String sequenceStr = reply.popString(); if (Integer.parseInt(sequenceStr) == sequence) { reply.push("OK"); reply.send(pipe); request.destroy(); request = null; } else reply.destroy(); } } // .split backend agent implementation // Finally, here's the agent task itself, which polls its two sockets // and processes incoming messages: static private class FreelanceAgent implements IAttachedRunnable { @Override public void run(Object[] args, ZContext ctx, Socket pipe) { Agent agent = new Agent(ctx, pipe); PollItem[] items = { new PollItem(agent.pipe, ZMQ.Poller.POLLIN), new PollItem(agent.router, ZMQ.Poller.POLLIN) }; while (!Thread.currentThread().isInterrupted()) { // Calculate tickless timer, up to 1 hour long tickless = System.currentTimeMillis() + 1000 * 3600; if (agent.request != null && tickless > agent.expires) tickless = agent.expires; for (Server server: agent.servers.values()) { long newTickless = server.tickless(tickless); if (newTickless > 0) tickless = newTickless; } int rc = ZMQ.poll(items, (tickless - System.currentTimeMillis())); if (rc == -1) break; // Context has been shut down if (items[0].isReadable()) agent.controlMessage(); if (items[1].isReadable()) agent.routerMessage(); // If we're processing a request, dispatch to next server if (agent.request != null) { if (System.currentTimeMillis() >= agent.expires) { // Request expired, kill it agent.pipe.send("FAILED"); agent.request.destroy(); agent.request = null; } else { // Find server to talk to, remove any expired ones while (!agent.actives.isEmpty()) { Server server = agent.actives.get(0); if (System.currentTimeMillis() >= server.expires) { agent.actives.remove(0); server.alive = false; } else { ZMsg request = agent.request.duplicate(); request.push(server.endpoint); request.send(agent.router); break; } } } } // Disconnect and delete any expired servers // Send heartbeats to idle servers if needed for (Server server: agent.servers.values()) server.ping(agent.router); } agent.destroy(); } } } jeromq-0.3.5/src/test/java/guide/flclient1.java000066400000000000000000000067241255150477200213450ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; // Freelance client - Model 1 // Uses REQ socket to query one or more services public class flclient1 { private static final int REQUEST_TIMEOUT = 1000; private static final int MAX_RETRIES = 3; // Before we abandon private static ZMsg tryRequest (ZContext ctx, String endpoint, ZMsg request) { System.out.printf("I: trying echo service at %s...\n", endpoint); Socket client = ctx.createSocket(ZMQ.REQ); client.connect(endpoint); // Send request, wait safely for reply ZMsg msg = request.duplicate(); msg.send(client); PollItem[] items = { new PollItem(client, ZMQ.Poller.POLLIN) }; ZMQ.poll(items, REQUEST_TIMEOUT); ZMsg reply = null; if (items[0].isReadable()) reply = ZMsg.recvMsg(client); // Close socket in any case, we're done with it now ctx.destroySocket(client); return reply; } // .split client task // The client uses a Lazy Pirate strategy if it only has one server to talk // to. If it has two or more servers to talk to, it will try each server just // once: public static void main (String[] argv) { ZContext ctx = new ZContext(); ZMsg request = new ZMsg(); request.add("Hello world"); ZMsg reply = null; int endpoints = argv.length; if (endpoints == 0) System.out.printf ("I: syntax: flclient1 ...\n"); else if (endpoints == 1) { // For one endpoint, we retry N times int retries; for (retries = 0; retries < MAX_RETRIES; retries++) { String endpoint = argv [0]; reply = tryRequest(ctx, endpoint, request); if (reply != null) break; // Successful System.out.printf("W: no response from %s, retrying...\n", endpoint); } } else { // For multiple endpoints, try each at most once int endpointNbr; for (endpointNbr = 0; endpointNbr < endpoints; endpointNbr++) { String endpoint = argv[endpointNbr]; reply = tryRequest (ctx, endpoint, request); if (reply != null) break; // Successful System.out.printf ("W: no response from %s\n", endpoint); } } if (reply != null) { System.out.printf ("Service is running OK\n"); reply.destroy(); } request.destroy();; ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/flclient2.java000066400000000000000000000105531255150477200213410ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; // Freelance client - Model 2 // Uses DEALER socket to blast one or more services public class flclient2 { // If not a single service replies within this time, give up private static final int GLOBAL_TIMEOUT = 2500; // .split class implementation // Here is the {{flclient}} class implementation. Each instance has a // context, a DEALER socket it uses to talk to the servers, a counter // of how many servers it's connected to, and a request getSequence number: private ZContext ctx; // Our context wrapper private Socket socket; // DEALER socket talking to servers private int servers; // How many servers we have connected to private int sequence; // Number of requests ever sent public flclient2() { ctx = new ZContext(); socket = ctx.createSocket(ZMQ.DEALER); } public void destroy() { ctx.destroy(); } private void connect(String endpoint) { socket.connect(endpoint); servers++; } private ZMsg request(ZMsg request) { // Prefix request with getSequence number and empty envelope String sequenceText = String.format("%d", ++sequence); request.push(sequenceText); request.push(""); // Blast the request to all connected servers int server; for (server = 0; server < servers; server++) { ZMsg msg = request.duplicate(); msg.send(socket); } // Wait for a matching reply to arrive from anywhere // Since we can poll several times, calculate each one ZMsg reply = null; long endtime = System.currentTimeMillis() + GLOBAL_TIMEOUT; while (System.currentTimeMillis() < endtime) { PollItem[] items = { new PollItem(socket, ZMQ.Poller.POLLIN) }; ZMQ.poll(items, endtime - System.currentTimeMillis()); if (items[0].isReadable()) { // Reply is [empty][getSequence][OK] reply = ZMsg.recvMsg(socket); assert (reply.size() == 3); reply.pop(); String sequenceStr = reply.popString(); int sequenceNbr = Integer.parseInt(sequenceStr); if (sequenceNbr == sequence) break; reply.destroy(); } } request.destroy(); return reply; } public static void main (String[] argv) { if (argv.length == 0) { System.out.printf ("I: syntax: flclient2 ...\n"); System.exit(0); } // Create new freelance client object flclient2 client = new flclient2(); // Connect to each endpoint int argn; for (argn = 0; argn < argv.length; argn++) client.connect(argv[argn]); // Send a bunch of name resolution 'requests', measure time int requests = 10000; long start = System.currentTimeMillis(); while (requests-- > 0) { ZMsg request = new ZMsg(); request.add("random name"); ZMsg reply = client.request(request); if (reply == null) { System.out.printf("E: name service not available, aborting\n"); break; } reply.destroy(); } System.out.printf ("Average round trip cost: %d usec\n", (int) (System.currentTimeMillis() - start) / 10); client.destroy(); } } jeromq-0.3.5/src/test/java/guide/flclient3.java000066400000000000000000000037461255150477200213500ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; // Freelance client - Model 3 // Uses flcliapi class to encapsulate Freelance pattern public class flclient3 { public static void main (String[] argv) { // Create new freelance client object flcliapi client = new flcliapi(); // Connect to several endpoints client.connect("tcp://localhost:5555"); client.connect("tcp://localhost:5556"); client.connect("tcp://localhost:5557"); // Send a bunch of name resolution 'requests', measure time int requests = 10000; long start = System.currentTimeMillis(); while (requests-- > 0) { ZMsg request = new ZMsg(); request.add("random name"); ZMsg reply = client.request(request); if (reply == null) { System.out.printf("E: name service not available, aborting\n"); break; } reply.destroy(); } System.out.printf("Average round trip cost: %d usec\n", (int) (System.currentTimeMillis() - start) / 10); client.destroy(); } } jeromq-0.3.5/src/test/java/guide/flserver1.java000066400000000000000000000032041255150477200213630ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; // Freelance server - Model 1 // Trivial echo service public class flserver1 { public static void main(String[] args) { if (args.length < 1) { System.out.printf("I: syntax: flserver1 \n"); System.exit(0); } ZContext ctx = new ZContext(); Socket server = ctx.createSocket(ZMQ.REP); server.bind(args[0]); System.out.printf ("I: echo service is ready at %s\n", args[0]); while (true) { ZMsg msg = ZMsg.recvMsg(server); if (msg == null) break; // Interrupted msg.send(server); } if (Thread.currentThread().isInterrupted()) System.out.printf ("W: interrupted\n"); ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/flserver2.java000066400000000000000000000037341255150477200213740ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; // Freelance server - Model 2 // Does some work, replies OK, with message sequencing public class flserver2 { public static void main(String[] args) { if (args.length < 1) { System.out.printf("I: syntax: flserver2 \n"); System.exit(0); } ZContext ctx = new ZContext(); Socket server = ctx.createSocket(ZMQ.REP); server.bind(args[0]); System.out.printf ("I: echo service is ready at %s\n", args[0]); while (true) { ZMsg request = ZMsg.recvMsg(server); if (request == null) break; // Interrupted // Fail nastily if run against wrong client assert (request.size() == 2); ZFrame identity = request.pop(); request.destroy(); ZMsg reply = new ZMsg(); reply.add(identity); reply.add("OK"); reply.send(server); } if (Thread.currentThread().isInterrupted()) System.out.printf ("W: interrupted\n"); ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/flserver3.java000066400000000000000000000051011255150477200213630ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; // Freelance server - Model 3 // Uses an ROUTER/ROUTER socket but just one thread public class flserver3 { public static void main(String[] args) { boolean verbose = (args.length > 0 && args[0].equals("-v")); ZContext ctx = new ZContext(); // Prepare server socket with predictable identity String bindEndpoint = "tcp://*:5555"; String connectEndpoint = "tcp://localhost:5555"; Socket server = ctx.createSocket(ZMQ.ROUTER); server.setIdentity(connectEndpoint.getBytes(ZMQ.CHARSET)); server.bind(bindEndpoint); System.out.printf ("I: service is ready at %s\n", bindEndpoint); while (!Thread.currentThread().isInterrupted()) { ZMsg request = ZMsg.recvMsg(server); if (verbose && request != null) request.dump(System.out); if (request == null) break; // Interrupted // Frame 0: identity of client // Frame 1: PING, or client control frame // Frame 2: request body ZFrame identity = request.pop(); ZFrame control = request.pop(); ZMsg reply = new ZMsg(); if (control.equals(new ZFrame("PING"))) reply.add("PONG"); else { reply.add(control); reply.add("OK"); } request.destroy(); reply.push(identity); if (verbose && reply != null) reply.dump(System.out); reply.send(server); } if (Thread.currentThread().isInterrupted()) System.out.printf ("W: interrupted\n"); ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/hwclient.java000066400000000000000000000032531255150477200212730ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; // // Hello World client in Java // Connects REQ socket to tcp://localhost:5555 // Sends "Hello" to server, expects "World" back // import org.zeromq.ZMQ; public class hwclient{ public static void main (String[] args){ ZMQ.Context context = ZMQ.context(1); // Socket to talk to server System.out.println("Connecting to hello world server"); ZMQ.Socket socket = context.socket(ZMQ.REQ); socket.connect ("tcp://localhost:5555"); for(int requestNbr = 0; requestNbr != 10; requestNbr++) { String request = "Hello" ; System.out.println("Sending Hello " + requestNbr ); socket.send(request.getBytes (ZMQ.CHARSET), 0); byte[] reply = socket.recv(0); System.out.println("Received " + new String (reply, ZMQ.CHARSET) + " " + requestNbr); } socket.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/hwserver.java000066400000000000000000000032361255150477200213240ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; // // Hello World server in Java // Binds REP socket to tcp://*:5555 // Expects "Hello" from client, replies with "World" // import org.zeromq.ZMQ; public class hwserver{ public static void main (String[] args) throws Exception{ ZMQ.Context context = ZMQ.context(1); // Socket to talk to clients ZMQ.Socket socket = context.socket(ZMQ.REP); socket.bind ("tcp://*:5555"); while (!Thread.currentThread ().isInterrupted ()) { byte[] reply = socket.recv(0); System.out.println("Received " + ": [" + new String(reply, ZMQ.CHARSET) + "]"); // Create a "Hello" message. String request = "world" ; // Send the message socket.send(request.getBytes (ZMQ.CHARSET), 0); Thread.sleep(1000); // Do some 'work' } socket.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/identity.java000066400000000000000000000034711255150477200213110ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; /** * Demonstrate identities as used by the request-reply pattern. */ public class identity { public static void main (String[] args) throws InterruptedException { Context context = ZMQ.context(1); Socket sink = context.socket(ZMQ.ROUTER); sink.bind("inproc://example"); // First allow 0MQ to set the identity, [00] + random 4byte Socket anonymous = context.socket(ZMQ.REQ); anonymous.connect("inproc://example"); anonymous.send ("ROUTER uses a generated UUID",0); ZHelper.dump (sink); // Then set the identity ourself Socket identified = context.socket(ZMQ.REQ); identified.setIdentity("Hello".getBytes (ZMQ.CHARSET)); identified.connect ("inproc://example"); identified.send("ROUTER socket uses REQ's socket identity", 0); ZHelper.dump (sink); sink.close (); anonymous.close (); identified.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/interrupt.java000066400000000000000000000037671255150477200215240ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; /* * * Interrupt in Java * Shows how to handle Ctrl-C */ import org.zeromq.ZMQ; import org.zeromq.ZMQException; public class interrupt { public static void main (String[] args) { // Prepare our context and socket final ZMQ.Context context = ZMQ.context(1); final Thread zmqThread = new Thread() { @Override public void run() { ZMQ.Socket socket = context.socket(ZMQ.REP); socket.bind("tcp://*:5555"); while (!Thread.currentThread().isInterrupted()) { try { socket.recv (0); } catch (ZMQException e) { if (e.getErrorCode () == ZMQ.Error.ETERM.getCode ()) { break; } } } socket.close(); } }; Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { System.out.println("W: interrupt received, killing server..."); context.term(); try { zmqThread.interrupt(); zmqThread.join(); } catch (InterruptedException e) { } } }); zmqThread.start(); } } jeromq-0.3.5/src/test/java/guide/kvmsg.java000066400000000000000000000304421255150477200206050ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Socket; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.UUID; public class kvmsg { // Keys are short strings private static final int KVMSG_KEY_MAX = 255; // Message is formatted on wire as 4 frames: // frame 0: getKey (0MQ string) // frame 1: getSequence (8 bytes, network order) // frame 2: uuid (blob, 16 bytes) // frame 3: properties (0MQ string) // frame 4: body (blob) private static final int FRAME_KEY = 0; private static final int FRAME_SEQ = 1; private static final int FRAME_UUID = 2; private static final int FRAME_PROPS = 3; private static final int FRAME_BODY = 4; private static final int KVMSG_FRAMES = 5; // Presence indicators for each frame private boolean[] present = new boolean[KVMSG_FRAMES]; // Corresponding 0MQ message frames, if any private byte[][] frame = new byte[KVMSG_FRAMES][]; // Key, copied into safe string private String key; // List of properties, as name=value strings private Properties props; private int props_size; // .split property encoding // These two helpers serialize a list of properties to and from a // message frame: private void encodeProps() { ByteBuffer msg = ByteBuffer.allocate(props_size); for (Entry o: props.entrySet()) { String prop = o.getKey().toString() + "=" + o.getValue().toString() + "\n"; msg.put(prop.getBytes(ZMQ.CHARSET)); } present[FRAME_PROPS] = true; frame[FRAME_PROPS] = msg.array(); } private void decodeProps() { byte[] msg = frame[FRAME_PROPS]; props_size = msg.length; props.clear(); if (msg.length == 0) return; System.out.println("" + msg.length + " :" + new String(msg, ZMQ.CHARSET)); for (String prop: new String(msg, ZMQ.CHARSET).split("\n")) { String[] split = prop.split("="); props.setProperty(split[0], split[1]); } } // .split constructor and destructor // Here are the constructor and destructor for the class: // Constructor, takes a getSequence number for the new kvmsg instance: public kvmsg(long sequence) { props = new Properties(); setSequence(sequence); } public void destroy() { } // .split recv method // This method reads a getKey-value message from the socket and returns a // new {{kvmsg}} instance: public static kvmsg recv(Socket socket) { // This method is almost unchanged from kvsimple // .skip assert (socket != null); kvmsg self = new kvmsg(0); // Read all frames off the wire, reject if bogus int frameNbr; for (frameNbr = 0; frameNbr < KVMSG_FRAMES; frameNbr++) { //zmq_msg_init (&self->frame [frameNbr]); self.present[frameNbr] = true; if ((self.frame[frameNbr] = socket.recv(0)) == null) { self.destroy(); break; } // Verify multipart framing boolean rcvmore = (frameNbr < KVMSG_FRAMES - 1)? true: false; if (socket.hasReceiveMore() != rcvmore) { self.destroy(); break; } } // .until self.decodeProps(); return self; } // Send getKey-value message to socket; any empty frames are sent as such. public void send(Socket socket) { assert (socket != null); encodeProps(); // The rest of the method is unchanged from kvsimple // .skip int frameNbr; for (frameNbr = 0; frameNbr < KVMSG_FRAMES; frameNbr++) { byte[] copy = ZMQ.MESSAGE_SEPARATOR; if (present[frameNbr]) copy = frame[frameNbr]; socket.send(copy, (frameNbr < KVMSG_FRAMES - 1)? ZMQ.SNDMORE: 0); } } // .until // .split dup method // This method duplicates a {{kvmsg}} instance, returns the new instance: public kvmsg dup() { kvmsg kvmsg = new kvmsg(0); int frameNbr; for (frameNbr = 0; frameNbr < KVMSG_FRAMES; frameNbr++) { if (present[frameNbr]) { kvmsg.frame[frameNbr] = new byte[frame[frameNbr].length]; System.arraycopy(frame[frameNbr], 0, kvmsg.frame[frameNbr], 0, frame[frameNbr].length); kvmsg.present[frameNbr] = true; } } kvmsg.props_size = props_size; kvmsg.props.putAll(props); return kvmsg; } // The getKey, getSequence, body, and size methods are the same as in kvsimple. // .skip // Return getKey from last read message, if any, else NULL public String getKey() { if (present[FRAME_KEY]) { if (key == null) { int size = frame[FRAME_KEY].length; if (size > KVMSG_KEY_MAX) size = KVMSG_KEY_MAX; byte[] buf = new byte[size]; System.arraycopy(frame[FRAME_KEY], 0, buf, 0, size); key = new String(buf, ZMQ.CHARSET); } return key; } else return null; } // Set message getKey as provided public void setKey(String key) { byte[] msg = new byte[key.length()]; System.arraycopy(key.getBytes(ZMQ.CHARSET), 0, msg, 0, key.length()); frame[FRAME_KEY] = msg; present[FRAME_KEY] = true; } // Set message getKey using printf format public void fmtKey(String fmt, Object ... args) { setKey(String.format(fmt, args)); } // Return getSequence nbr from last read message, if any public long getSequence() { if (present[FRAME_SEQ]) { assert (frame[FRAME_SEQ].length == 8); ByteBuffer source = ByteBuffer.wrap(frame[FRAME_SEQ]); return source.getLong(); } else return 0; } // Set message getSequence number public void setSequence(long sequence) { ByteBuffer msg = ByteBuffer.allocate(8); msg.putLong(sequence); present[FRAME_SEQ] = true; frame[FRAME_SEQ] = msg.array(); } // Return body from last read message, if any, else NULL public byte[] body() { if (present[FRAME_BODY]) return frame[FRAME_BODY]; else return null; } // Set message body public void setBody(byte[] body) { byte[] msg = new byte[body.length]; System.arraycopy(body, 0, msg, 0, body.length); frame [FRAME_BODY] = msg; present[FRAME_BODY] = true; } // Set message body using printf format public void fmtBody(String fmt, Object... args) { setBody(String.format(fmt, args).getBytes(ZMQ.CHARSET)); } // Return body size from last read message, if any, else zero public int size() { if (present[FRAME_BODY]) return frame[FRAME_BODY].length; else return 0; } // .until // .split UUID methods // These methods get and set the UUID for the getKey-value message: public byte[] UUID() { if (present[FRAME_UUID]) return frame[FRAME_UUID]; else return null; } // Sets the UUID to a randomly generated value public void setUUID() { byte[] msg = UUID.randomUUID().toString().getBytes(ZMQ.CHARSET); present[FRAME_UUID] = true; frame[FRAME_UUID] = msg; } // .split property methods // These methods get and set a specified message property: // Get message property, return "" if no such property is defined. public String getProp(String name) { return props.getProperty(name, ""); } // Set message property. Property name cannot contain '='. Max length of // value is 255 chars. public void setProp(String name, String fmt, Object ... args) { String value = String.format(fmt, args); Object old = props.setProperty(name, value); if (old != null) props_size -= old.toString().length(); else props_size += name.length() + 2; props_size += value.length(); } // .split store method // This method stores the getKey-value message into a hash map, unless // the getKey and value are both null. It nullifies the {{kvmsg}} reference // so that the object is owned by the hash map, not the caller: public void store(Map hash) { if (size() > 0) { if (present[FRAME_KEY] && present[FRAME_BODY]) { hash.put(getKey(), this); } } else hash.remove(getKey()); } // .split dump method // This method extends the {{kvsimple}} implementation with support for // message properties: public void dump() { int size = size(); byte[] body = body(); System.err.printf("[seq:%d]", getSequence()); System.err.printf("[getKey:%s]", getKey()); // .until System.err.printf("[size:%d] ", size); System.err.printf("["); for (String key: props.stringPropertyNames()) { System.err.printf("%s=%s;", key, props.getProperty(key)); } System.err.printf("]"); // .skip for (int charNbr = 0; charNbr < size; charNbr++) System.err.printf("%02X", body[charNbr]); System.err.printf("\n"); } // .until // .split test method // This method is the same as in {{kvsimple}} with added support // for the uuid and property features of {{kvmsg}}: public void test(boolean verbose) { System.out.printf(" * kvmsg: "); // Prepare our context and sockets ZContext ctx = new ZContext(); Socket output = ctx.createSocket(ZMQ.DEALER); output.bind("ipc://kvmsg_selftest.ipc"); Socket input = ctx.createSocket(ZMQ.DEALER); input.connect("ipc://kvmsg_selftest.ipc"); Map kvmap = new HashMap(); // .until // Test send and receive of simple message kvmsg kvmsg = new kvmsg(1); kvmsg.setKey("getKey"); kvmsg.setUUID(); kvmsg.setBody("body".getBytes(ZMQ.CHARSET)); if (verbose) kvmsg.dump(); kvmsg.send(output); kvmsg.store(kvmap); kvmsg = kvmsg.recv(input); if (verbose) kvmsg.dump(); assert (kvmsg.getKey().equals("getKey")); kvmsg.store(kvmap); // Test send and receive of message with properties kvmsg = new kvmsg(2); kvmsg.setProp("prop1", "value1"); kvmsg.setProp("prop2", "value1"); kvmsg.setProp("prop2", "value2"); kvmsg.setKey("getKey"); kvmsg.setUUID(); kvmsg.setBody("body".getBytes(ZMQ.CHARSET)); assert (kvmsg.getProp("prop2").equals("value2")); if (verbose) kvmsg.dump(); kvmsg.send(output); kvmsg.destroy(); kvmsg = kvmsg.recv(input); if (verbose) kvmsg.dump(); assert (kvmsg.key.equals("getKey")); assert (kvmsg.getProp("prop2").equals("value2")); kvmsg.destroy(); // .skip // Shutdown and destroy all objects ctx.destroy(); System.out.printf("OK\n"); } // .until } jeromq-0.3.5/src/test/java/guide/kvsimple.java000066400000000000000000000061221255150477200213060ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.nio.ByteBuffer; import java.util.Arrays; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Socket; /** * * A simple getKey value message class * @author Danish Shrestha * */ public class kvsimple { private final String key; private long sequence; private final byte[] body; public kvsimple(String key, long sequence, byte[] body) { this.key = key; this.sequence = sequence; this.body = body; // clone if needed } public String getKey() { return key; } public long getSequence() { return sequence; } public void setSequence(long sequence) { this.sequence = sequence; } public byte[] getBody() { return body; } public void send(Socket publisher) { publisher.send(key.getBytes(ZMQ.CHARSET), ZMQ.SNDMORE); ByteBuffer bb = ByteBuffer.allocate(8); bb.asLongBuffer().put(sequence); publisher.send(bb.array(), ZMQ.SNDMORE); publisher.send(body, 0); } public static kvsimple recv(Socket updates) { byte [] data = updates.recv(0); if (data == null || !updates.hasReceiveMore()) return null; String key = new String(data, ZMQ.CHARSET); data = updates.recv(0); if (data == null || !updates.hasReceiveMore()) return null; Long sequence = ByteBuffer.wrap(data).getLong(); byte[] body = updates.recv(0); if (body == null || updates.hasReceiveMore()) return null; return new kvsimple(key, sequence, body); } @Override public String toString() { return "kvsimple [getKey=" + key + ", getSequence=" + sequence + ", body=" + Arrays.toString(body) + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(body); result = prime * result + ((key == null) ? 0 : key.hashCode()); result = prime * result + (int) (sequence ^ (sequence >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; kvsimple other = (kvsimple) obj; if (!Arrays.equals(body, other.body)) return false; if (key == null) { if (other.key != null) return false; } else if (!key.equals(other.key)) return false; if (sequence != other.sequence) return false; return true; } } jeromq-0.3.5/src/test/java/guide/lbbroker.java000066400000000000000000000156131255150477200212630ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.LinkedList; import java.util.Queue; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Poller; import org.zeromq.ZMQ.Socket; public class lbbroker { private static final int NBR_CLIENTS = 10; private static final int NBR_WORKERS = 3; /** * Basic request-reply client using REQ socket */ private static class ClientTask extends Thread { public void run() { Context context = ZMQ.context(1); // Prepare our context and sockets Socket client = context.socket(ZMQ.REQ); ZHelper.setId (client); // Set a printable identity client.connect("ipc://frontend.ipc"); // Send request, get reply client.send("HELLO"); String reply = client.recvStr (); System.out.println("Client: " + reply); client.close(); context.term(); } } /** * While this example runs in a single process, that is just to make * it easier to start and stop the example. Each thread has its own * context and conceptually acts as a separate process. * This is the worker task, using a REQ socket to do load-balancing. */ private static class WorkerTask extends Thread { public void run() { Context context = ZMQ.context(1); // Prepare our context and sockets Socket worker = context.socket(ZMQ.REQ); ZHelper.setId (worker); // Set a printable identity worker.connect("ipc://backend.ipc"); // Tell backend we're ready for work worker.send("READY"); while(!Thread.currentThread ().isInterrupted ()) { String address = worker.recvStr (); String empty = worker.recvStr (); assert (empty.length() == 0); // Get request, send reply String request = worker.recvStr (); System.out.println("Worker: " + request); worker.sendMore (address); worker.sendMore (""); worker.send("OK"); } worker.close (); context.term (); } } /** * This is the main task. It starts the clients and workers, and then * routes requests between the two layers. Workers signal READY when * they start; after that we treat them as ready when they reply with * a response back to a client. The load-balancing data structure is * just a queue of next available workers. */ public static void main (String[] args) { Context context = ZMQ.context(1); // Prepare our context and sockets Socket frontend = context.socket(ZMQ.ROUTER); Socket backend = context.socket(ZMQ.ROUTER); frontend.bind("ipc://frontend.ipc"); backend.bind("ipc://backend.ipc"); int clientNbr; for (clientNbr = 0; clientNbr < NBR_CLIENTS; clientNbr++) new ClientTask().start(); for (int workerNbr = 0; workerNbr < NBR_WORKERS; workerNbr++) new WorkerTask().start(); // Here is the main loop for the least-recently-used queue. It has two // sockets; a frontend for clients and a backend for workers. It polls // the backend in all cases, and polls the frontend only when there are // one or more workers ready. This is a neat way to use 0MQ's own queues // to hold messages we're not ready to process yet. When we get a client // reply, we pop the next available worker, and send the request to it, // including the originating client identity. When a worker replies, we // re-queue that worker, and we forward the reply to the original client, // using the reply envelope. // Queue of available workers Queue workerQueue = new LinkedList(); while (!Thread.currentThread().isInterrupted()) { // Initialize poll set Poller items = new Poller (2); //  Always poll for worker activity on backend items.register(backend, Poller.POLLIN); //  Poll front-end only if we have available workers if(workerQueue.size() > 0) items.register(frontend, Poller.POLLIN); if (items.poll() < 0) break; // Interrupted // Handle worker activity on backend if (items.pollin(0)) { // Queue worker address for LRU routing workerQueue.add (backend.recvStr ()); // Second frame is empty String empty = backend.recvStr (); assert (empty.length() == 0); // Third frame is READY or else a client reply address String clientAddr = backend.recvStr (); // If client reply, send rest back to frontend if (!clientAddr.equals("READY")) { empty = backend.recvStr (); assert (empty.length() == 0); String reply = backend.recvStr (); frontend.sendMore(clientAddr); frontend.sendMore(""); frontend.send(reply); if (--clientNbr == 0) break; } } if (items.pollin(1)) { // Now get next client request, route to LRU worker // Client request is [address][empty][request] String clientAddr = frontend.recvStr (); String empty = frontend.recvStr (); assert (empty.length() == 0); String request = frontend.recvStr (); String workerAddr = workerQueue.poll(); backend.sendMore (workerAddr); backend.sendMore (""); backend.sendMore (clientAddr ); backend.sendMore (""); backend.send (request); } } frontend.close(); backend.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/lbbroker2.java000066400000000000000000000130641255150477200213430ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Poller; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; import org.zeromq.ZThread; import java.util.Arrays; import java.util.LinkedList; import java.util.Queue; /** * Load-balancing broker * Demonstrates use of the high level API */ public class lbbroker2 { private static final int NBR_CLIENTS = 10; private static final int NBR_WORKERS = 3; private static byte[] WORKER_READY = { '\001' }; // Signals worker is ready /** * Basic request-reply client using REQ socket */ private static class ClientTask implements ZThread.IDetachedRunnable { @Override public void run (Object ... args) { ZContext context = new ZContext(); // Prepare our context and sockets Socket client = context.createSocket (ZMQ.REQ); ZHelper.setId (client); // Set a printable identity client.connect("ipc://frontend.ipc"); // Send request, get reply client.send("HELLO"); String reply = client.recvStr (); System.out.println("Client: " + reply); context.destroy (); } } /** * Worker using REQ socket to do load-balancing */ private static class WorkerTask implements ZThread.IDetachedRunnable { @Override public void run (Object ... args) { ZContext context = new ZContext(); // Prepare our context and sockets Socket worker = context.createSocket (ZMQ.REQ); ZHelper.setId (worker); // Set a printable identity worker.connect("ipc://backend.ipc"); // Tell backend we're ready for work ZFrame frame = new ZFrame (WORKER_READY); frame.send (worker, 0); while(true) { ZMsg msg = ZMsg.recvMsg (worker); if (msg == null) break; msg.getLast ().reset ("OK"); msg.send (worker); } context.destroy (); } } /** * This is the main task. This has the identical functionality to * the previous lbbroker example but uses higher level classes to start child threads * to hold the list of workers, and to read and send messages: */ public static void main (String[] args) { ZContext context = new ZContext(); // Prepare our context and sockets Socket frontend = context.createSocket (ZMQ.ROUTER); Socket backend = context.createSocket (ZMQ.ROUTER); frontend.bind("ipc://frontend.ipc"); backend.bind("ipc://backend.ipc"); int clientNbr; for (clientNbr = 0; clientNbr < NBR_CLIENTS; clientNbr++) ZThread.start (new ClientTask ()); for (int workerNbr = 0; workerNbr < NBR_WORKERS; workerNbr++) ZThread.start (new WorkerTask ()); // Queue of available workers Queue workerQueue = new LinkedList (); // Here is the main loop for the load-balancer. It works the same way // as the previous example, but is a lot shorter because ZMsg class gives // us an API that does more with fewer calls: while (!Thread.currentThread().isInterrupted()) { // Initialize poll set Poller items = new Poller (2); //  Always poll for worker activity on backend items.register(backend, Poller.POLLIN); //  Poll front-end only if we have available workers if(workerQueue.size() > 0) items.register(frontend, Poller.POLLIN); if (items.poll() < 0) break; // Interrupted // Handle worker activity on backend if (items.pollin(0)) { ZMsg msg = ZMsg.recvMsg (backend); if (msg == null) break; // Interrupted ZFrame identity = msg.unwrap (); // Queue worker address for LRU routing workerQueue.add (identity); // Forward message to client if it's not a READY ZFrame frame = msg.getFirst (); if (Arrays.equals (frame.getData (), WORKER_READY)) msg.destroy (); else msg.send (frontend); } if (items.pollin(1)) { // Get client request, route to first available worker ZMsg msg = ZMsg.recvMsg (frontend); if (msg != null) { msg.wrap (workerQueue.poll ()); msg.send (backend); } } } context.destroy (); } } jeromq-0.3.5/src/test/java/guide/lbbroker3.java000066400000000000000000000146761255150477200213560ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMsg; import org.zeromq.ZLoop; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; import org.zeromq.ZThread; import java.util.Arrays; import java.util.LinkedList; import java.util.Queue; /** * Load-balancing broker * Demonstrates use of the ZLoop API and reactor style * * The client and worker tasks are identical from the previous example. */ public class lbbroker3 { private static final int NBR_CLIENTS = 10; private static final int NBR_WORKERS = 3; private static byte[] WORKER_READY = { '\001' }; /** * Basic request-reply client using REQ socket */ private static class ClientTask implements ZThread.IDetachedRunnable { @Override public void run (Object ... args) { ZContext context = new ZContext(); // Prepare our context and sockets Socket client = context.createSocket (ZMQ.REQ); ZHelper.setId (client); // Set a printable identity client.connect("ipc://frontend.ipc"); // Send request, get reply client.send("HELLO"); String reply = client.recvStr (); System.out.println("Client: " + reply); context.destroy (); } } /** * Worker using REQ socket to do load-balancing */ private static class WorkerTask implements ZThread.IDetachedRunnable { @Override public void run (Object ... args) { ZContext context = new ZContext(); // Prepare our context and sockets Socket worker = context.createSocket (ZMQ.REQ); ZHelper.setId (worker); // Set a printable identity worker.connect("ipc://backend.ipc"); // Tell backend we're ready for work ZFrame frame = new ZFrame (WORKER_READY); frame.send (worker, 0); while(true) { ZMsg msg = ZMsg.recvMsg (worker); if (msg == null) break; msg.getLast ().reset ("OK"); msg.send (worker); } context.destroy (); } } //Our load-balancer structure, passed to reactor handlers private static class LBBroker { Socket frontend; // Listen to clients Socket backend; // Listen to workers Queue workers; // List of ready workers }; /** * In the reactor design, each time a message arrives on a socket, the * reactor passes it to a handler function. We have two handlers; one * for the frontend, one for the backend: */ private static class FrontendHandler implements ZLoop.IZLoopHandler { @Override public int handle(ZLoop loop, PollItem item, Object arg_) { LBBroker arg = (LBBroker)arg_; ZMsg msg = ZMsg.recvMsg (arg.frontend); if (msg != null) { msg.wrap(arg.workers.poll()); msg.send(arg.backend); // Cancel reader on frontend if we went from 1 to 0 workers if (arg.workers.size() == 0) { loop.removePoller (new PollItem (arg.frontend, 0)); } } return 0; } } private static class BackendHandler implements ZLoop.IZLoopHandler { @Override public int handle(ZLoop loop, PollItem item, Object arg_) { LBBroker arg = (LBBroker)arg_; ZMsg msg = ZMsg.recvMsg(arg.backend); if (msg != null) { ZFrame address = msg.unwrap(); // Queue worker address for load-balancing arg.workers.add(address); // Enable reader on frontend if we went from 0 to 1 workers if (arg.workers.size() == 1) { PollItem newItem = new PollItem (arg.frontend, ZMQ.Poller.POLLIN); loop.addPoller (newItem, frontendHandler, arg); } // Forward message to client if it's not a READY ZFrame frame = msg.getFirst(); if (Arrays.equals (frame.getData(), WORKER_READY)) msg.destroy(); else msg.send(arg.frontend); } return 0; } } private final static FrontendHandler frontendHandler = new FrontendHandler(); private final static BackendHandler backendHandler = new BackendHandler(); /** * And the main task now sets-up child tasks, then starts its reactor. * If you press Ctrl-C, the reactor exits and the main task shuts down. */ public static void main (String[] args) { ZContext context = new ZContext(); LBBroker arg = new LBBroker (); // Prepare our context and sockets arg.frontend = context.createSocket (ZMQ.ROUTER); arg.backend = context.createSocket (ZMQ.ROUTER); arg.frontend.bind("ipc://frontend.ipc"); arg.backend.bind("ipc://backend.ipc"); int clientNbr; for (clientNbr = 0; clientNbr < NBR_CLIENTS; clientNbr++) ZThread.start (new ClientTask ()); for (int workerNbr = 0; workerNbr < NBR_WORKERS; workerNbr++) ZThread.start (new WorkerTask ()); // Queue of available workers arg.workers = new LinkedList (); // Prepare reactor and fire it up ZLoop reactor = new ZLoop (); PollItem item = new PollItem (arg.backend, ZMQ.Poller.POLLIN); reactor.addPoller (item, backendHandler, arg); reactor.start (); context.destroy (); } } jeromq-0.3.5/src/test/java/guide/lpclient.java000066400000000000000000000075131255150477200212730ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Poller; import org.zeromq.ZMQ.Socket; // // Lazy Pirate client // Use zmq_poll to do a safe request-reply // To run, start lpserver and then randomly kill/restart it // public class lpclient { private final static int REQUEST_TIMEOUT = 2500; // msecs, (> 1000!) private final static int REQUEST_RETRIES = 3; // Before we abandon private final static String SERVER_ENDPOINT = "tcp://localhost:5555"; public static void main(String[] argv) { ZContext ctx = new ZContext(); System.out.println("I: connecting to server"); Socket client = ctx.createSocket(ZMQ.REQ); assert (client != null); client.connect(SERVER_ENDPOINT); int sequence = 0; int retriesLeft = REQUEST_RETRIES; while (retriesLeft > 0 && !Thread.currentThread().isInterrupted()) { // We send a request, then we work to get a reply String request = String.format("%d", ++sequence); client.send(request); int expect_reply = 1; while (expect_reply > 0) { // Poll socket for a reply, with timeout PollItem items[] = {new PollItem(client, Poller.POLLIN)}; int rc = ZMQ.poll(items, REQUEST_TIMEOUT); if (rc == -1) break; // Interrupted // Here we process a server reply and exit our loop if the // reply is valid. If we didn't a reply we close the client // socket and resend the request. We try a number of times // before finally abandoning: if (items[0].isReadable()) { // We got a reply from the server, must match getSequence String reply = client.recvStr(); if (reply == null) break; // Interrupted if (Integer.parseInt(reply) == sequence) { System.out.printf("I: server replied OK (%s)\n", reply); retriesLeft = REQUEST_RETRIES; expect_reply = 0; } else System.out.printf("E: malformed reply from server: %s\n", reply); } else if (--retriesLeft == 0) { System.out.println("E: server seems to be offline, abandoning\n"); break; } else { System.out.println("W: no response from server, retrying\n"); // Old socket is confused; close it and open a new one ctx.destroySocket(client); System.out.println("I: reconnecting to server\n"); client = ctx.createSocket(ZMQ.REQ); client.connect(SERVER_ENDPOINT); // Send request again, on new socket client.send(request); } } } ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/lpserver.java000066400000000000000000000040251255150477200213160ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.Random; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; // // Lazy Pirate server // Binds REQ socket to tcp://*:5555 // Like hwserver except: // - echoes request as-is // - randomly runs slowly, or exits to simulate a crash. // public class lpserver { public static void main(String[] argv) throws Exception { Random rand = new Random(System.nanoTime()); Context context = ZMQ.context(1); Socket server = context.socket(ZMQ.REP); server.bind("tcp://*:5555"); int cycles = 0; while (true) { String request = server.recvStr(); cycles++; // Simulate various problems, after a few cycles if (cycles > 3 && rand.nextInt(3) == 0) { System.out.println("I: simulating a crash"); break; } else if (cycles > 3 && rand.nextInt(3) == 0) { System.out.println("I: simulating CPU overload"); Thread.sleep(2000); } System.out.printf("I: normal request (%s)\n", request); Thread.sleep(1000); // Do some heavy work server.send(request); } server.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/lruqueue3.java000066400000000000000000000137371255150477200214200ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.LinkedList; import java.util.Queue; import org.zeromq.ZLoop; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMsg; class ClientThread3 extends Thread { public void run() { ZContext context = new ZContext(); // Prepare our context and sockets Socket client = context.createSocket(ZMQ.REQ); // Initialize random number generator client.connect("ipc://frontend.ipc"); // Send request, get reply while (true) { client.send("HELLO".getBytes(ZMQ.CHARSET), 0); byte[] data = client.recv(0); if (data == null) break; String reply = new String(data, ZMQ.CHARSET); try { Thread.sleep(1000); } catch (InterruptedException e) { } System.out.println(Thread.currentThread().getName() + " Client Sent HELLO"); } context.destroy(); } } class WorkerThread3 extends Thread { public void run() { ZContext context = new ZContext(); // Prepare our context and sockets Socket worker = context.createSocket(ZMQ.REQ); worker.connect("ipc://backend.ipc"); ZFrame frame = new ZFrame(lruqueue3.LRU_READY); // Tell backend we're ready for work frame.send(worker, 0); while (true) { ZMsg msg = ZMsg.recvMsg(worker); if (msg == null) break; msg.getLast().reset("OK".getBytes(ZMQ.CHARSET)); msg.send(worker); System.out.println(Thread.currentThread().getName() + " Worker Sent OK"); } context.destroy(); } } //Our LRU queue structure, passed to reactor handlers class LRUQueueArg { Socket frontend; // Listen to clients Socket backend; // Listen to workers Queue workers; // List of ready workers }; //In the reactor design, each time a message arrives on a socket, the //reactor passes it to a handler function. We have two handlers; one //for the frontend, one for the backend: class FrontendHandler implements ZLoop.IZLoopHandler { @Override public int handle(ZLoop loop, PollItem item, Object arg_) { LRUQueueArg arg = (LRUQueueArg) arg_; ZMsg msg = ZMsg.recvMsg(arg.frontend); if (msg != null) { msg.wrap(arg.workers.poll()); msg.send(arg.backend); // Cancel reader on frontend if we went from 1 to 0 workers if (arg.workers.size() == 0) { PollItem poller = new PollItem(arg.frontend, ZMQ.Poller.POLLIN); loop.removePoller(poller); } } return 0; } } class BackendHandler implements ZLoop.IZLoopHandler { @Override public int handle(ZLoop loop, PollItem item, Object arg_) { LRUQueueArg arg = (LRUQueueArg) arg_; ZMsg msg = ZMsg.recvMsg(arg.backend); if (msg != null) { ZFrame address = msg.unwrap(); // Queue worker address for LRU routing arg.workers.add(address); // Enable reader on frontend if we went from 0 to 1 workers if (arg.workers.size() == 1) { PollItem poller = new PollItem(arg.frontend, ZMQ.Poller.POLLIN); loop.addPoller(poller, lruqueue3.handle_frontend, arg); } // Forward message to client if it's not a READY ZFrame frame = msg.getFirst(); if (new String(frame.getData(), ZMQ.CHARSET).equals(lruqueue3.LRU_READY)) msg.destroy(); else msg.send(arg.frontend); } return 0; } } public class lruqueue3 { public final static String LRU_READY = "\001"; protected final static FrontendHandler handle_frontend = new FrontendHandler(); protected final static BackendHandler handle_backend = new BackendHandler(); public static void main(String[] args) { ZContext context = new ZContext(); LRUQueueArg arg = new LRUQueueArg(); // Prepare our context and sockets Socket frontend = context.createSocket(ZMQ.ROUTER); Socket backend = context.createSocket(ZMQ.ROUTER); arg.frontend = frontend; arg.backend = backend; frontend.bind("ipc://frontend.ipc"); backend.bind("ipc://backend.ipc"); int client_nbr; for (client_nbr = 0; client_nbr < 10; client_nbr++) new ClientThread3().start(); int worker_nbr; for (worker_nbr = 0; worker_nbr < 3; worker_nbr++) new WorkerThread3().start(); // Queue of available workers arg.workers = new LinkedList(); // Prepare reactor and fire it up ZLoop reactor = new ZLoop(); reactor.verbose(true); PollItem poller = new PollItem(arg.backend, ZMQ.Poller.POLLIN); reactor.addPoller(poller, handle_backend, arg); reactor.start(); reactor.destroy(); for (ZFrame frame : arg.workers) { frame.destroy(); } context.destroy(); System.exit(0); } } jeromq-0.3.5/src/test/java/guide/lvcache.java000066400000000000000000000065211255150477200210640ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; import java.util.HashMap; import java.util.Map; // Last value cache // Uses XPUB subscription messages to re-send data public class lvcache { public static void main(String[] args) { ZContext context = new ZContext(); Socket frontend = context.createSocket(ZMQ.SUB); frontend.bind("tcp://*:5557"); Socket backend = context.createSocket(ZMQ.XPUB); backend.bind("tcp://*:5558"); // Subscribe to every single topic from publisher frontend.subscribe(ZMQ.SUBSCRIPTION_ALL); // Store last instance of each topic in a cache Map cache = new HashMap(); // .split main poll loop // We route topic updates from frontend to backend, and // we handle subscriptions by sending whatever we cached, // if anything: while (true) { PollItem[] items = { new PollItem(frontend, ZMQ.Poller.POLLIN), new PollItem(backend, ZMQ.Poller.POLLIN), }; if (ZMQ.poll(items, 1000) == -1) break; // Interrupted // Any new topic data we cache and then forward if (items[0].isReadable()) { String topic = frontend.recvStr(); String current = frontend.recvStr(); if (topic == null) break; cache.put(topic, current); backend.sendMore(topic); backend.send(current); } // .split handle subscriptions // When we get a new subscription, we pull data from the cache: if (items[1].isReadable()) { ZFrame frame = ZFrame.recvFrame(backend); if (frame == null) break; // Event is one byte 0=unsub or 1=sub, followed by topic byte[] event = frame.getData(); if (event [0] == 1) { String topic = new String(event, 1, event.length -1, ZMQ.CHARSET); System.out.printf ("Sending cached topic %s\n", topic); String previous = cache.get(topic); if (previous != null) { backend.sendMore(topic); backend.send(previous); } } frame.destroy(); } } context.destroy(); } } jeromq-0.3.5/src/test/java/guide/mdbroker.java000066400000000000000000000317661255150477200212750ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.ArrayDeque; import java.util.Deque; import java.util.Formatter; import java.util.HashMap; import java.util.Map; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMsg; /** * Majordomo Protocol broker * A minimal implementation of http://rfc.zeromq.org/spec:7 and spec:8 */ public class mdbroker { // We'd normally pull these from config data private static final String INTERNAL_SERVICE_PREFIX = "mmi."; private static final int HEARTBEAT_LIVENESS = 3; // 3-5 is reasonable private static final int HEARTBEAT_INTERVAL = 2500; // msecs private static final int HEARTBEAT_EXPIRY = HEARTBEAT_INTERVAL * HEARTBEAT_LIVENESS; // --------------------------------------------------------------------- /** * This defines a single service. */ private static class Service { public final String name; // Service name Deque requests; // List of client requests Deque waiting; // List of waiting workers public Service(String name) { this.name = name; this.requests = new ArrayDeque(); this.waiting = new ArrayDeque(); } } /** * This defines one worker, idle or active. */ private static class Worker { String identity;// Identity of worker ZFrame address;// Address frame to route to Service service; // Owning service, if known long expiry;// Expires at unless heartbeat public Worker(String identity, ZFrame address) { this.address = address; this.identity = identity; this.expiry = System.currentTimeMillis() + HEARTBEAT_INTERVAL * HEARTBEAT_LIVENESS; } } // --------------------------------------------------------------------- private ZContext ctx;// Our context private ZMQ.Socket socket; // Socket for clients & workers private long heartbeatAt;// When to send HEARTBEAT private Map services;// known services private Map workers;// known workers private Deque waiting;// idle workers private boolean verbose = false;// Print activity to stdout private Formatter log = new Formatter(System.out); // --------------------------------------------------------------------- /** * Main method - create and start new broker. */ public static void main(String[] args) { mdbroker broker = new mdbroker(args.length > 0 && "-v".equals(args[0])); // Can be called multiple times with different endpoints broker.bind("tcp://*:5555"); broker.mediate(); } /** * Initialize broker state. */ public mdbroker(boolean verbose) { this.verbose = verbose; this.services = new HashMap(); this.workers = new HashMap(); this.waiting = new ArrayDeque(); this.heartbeatAt = System.currentTimeMillis() + HEARTBEAT_INTERVAL; this.ctx = new ZContext(); this.socket = ctx.createSocket(ZMQ.ROUTER); } // --------------------------------------------------------------------- /** * Main broker work happens here */ public void mediate() { while (!Thread.currentThread().isInterrupted()) { ZMQ.Poller items = new ZMQ.Poller(1); items.register(socket, ZMQ.Poller.POLLIN); if (items.poll(HEARTBEAT_INTERVAL) == -1) break; // Interrupted if (items.pollin(0)) { ZMsg msg = ZMsg.recvMsg(socket); if (msg == null) break; // Interrupted if (verbose) { log.format("I: received message:\n"); msg.dump(log.out()); } ZFrame sender = msg.pop(); ZFrame empty = msg.pop(); ZFrame header = msg.pop(); if (MDP.C_CLIENT.frameEquals(header)) { processClient(sender, msg); } else if (MDP.W_WORKER.frameEquals(header)) processWorker(sender, msg); else { log.format("E: invalid message:\n"); msg.dump(log.out()); msg.destroy(); } sender.destroy(); empty.destroy(); header.destroy(); } purgeWorkers(); sendHeartbeats(); } destroy(); // interrupted } /** * Disconnect all workers, destroy context. */ private void destroy() { Worker[] deleteList = workers.entrySet().toArray(new Worker[0]); for (Worker worker : deleteList) { deleteWorker(worker, true); } ctx.destroy(); } /** * Process a request coming from a client. */ private void processClient(ZFrame sender, ZMsg msg) { assert (msg.size() >= 2); // Service name + body ZFrame serviceFrame = msg.pop(); // Set reply return address to client sender msg.wrap(sender.duplicate()); if (serviceFrame.toString().startsWith(INTERNAL_SERVICE_PREFIX)) serviceInternal(serviceFrame, msg); else dispatch(requireService(serviceFrame), msg); serviceFrame.destroy(); } /** * Process message sent to us by a worker. */ private void processWorker(ZFrame sender, ZMsg msg) { assert (msg.size() >= 1); // At least, command ZFrame command = msg.pop(); boolean workerReady = workers.containsKey(sender.strhex()); Worker worker = requireWorker(sender); if (MDP.W_READY.frameEquals(command)) { // Not first command in session || Reserved service name if (workerReady || sender.toString().startsWith(INTERNAL_SERVICE_PREFIX)) deleteWorker(worker, true); else { // Attach worker to service and mark as idle ZFrame serviceFrame = msg.pop(); worker.service = requireService(serviceFrame); workerWaiting(worker); serviceFrame.destroy(); } } else if (MDP.W_REPLY.frameEquals(command)) { if (workerReady) { // Remove & save client return envelope and insert the // protocol header and service name, then rewrap envelope. ZFrame client = msg.unwrap(); msg.addFirst(worker.service.name); msg.addFirst(MDP.C_CLIENT.newFrame()); msg.wrap(client); msg.send(socket); workerWaiting(worker); } else { deleteWorker(worker, true); } } else if (MDP.W_HEARTBEAT.frameEquals(command)) { if (workerReady) { worker.expiry = System.currentTimeMillis() + HEARTBEAT_EXPIRY; } else { deleteWorker(worker, true); } } else if (MDP.W_DISCONNECT.frameEquals(command)) deleteWorker(worker, false); else { log.format("E: invalid message:\n"); msg.dump(log.out()); } msg.destroy(); } /** * Deletes worker from all data structures, and destroys worker. */ private void deleteWorker(Worker worker, boolean disconnect) { assert (worker != null); if (disconnect) { sendToWorker(worker, MDP.W_DISCONNECT, null, null); } if (worker.service != null) worker.service.waiting.remove(worker); workers.remove(worker); worker.address.destroy(); } /** * Finds the worker (creates if necessary). */ private Worker requireWorker(ZFrame address) { assert (address != null); String identity = address.strhex(); Worker worker = workers.get(identity); if (worker == null) { worker = new Worker(identity, address.duplicate()); workers.put(identity, worker); if (verbose) log.format("I: registering new worker: %s\n", identity); } return worker; } /** * Locates the service (creates if necessary). */ private Service requireService(ZFrame serviceFrame) { assert (serviceFrame != null); String name = serviceFrame.toString(); Service service = services.get(name); if (service == null) { service = new Service(name); services.put(name, service); } return service; } /** * Bind broker to endpoint, can call this multiple times. We use a single * socket for both clients and workers. */ private void bind(String endpoint) { socket.bind(endpoint); log.format("I: MDP broker/0.1.1 is active at %s\n", endpoint); } /** * Handle internal service according to 8/MMI specification */ private void serviceInternal(ZFrame serviceFrame, ZMsg msg) { String returnCode = "501"; if ("mmi.service".equals(serviceFrame.toString())) { String name = msg.peekLast().toString(); returnCode = services.containsKey(name) ? "200" : "400"; } msg.peekLast().reset(returnCode.getBytes(ZMQ.CHARSET)); // Remove & save client return envelope and insert the // protocol header and service name, then rewrap envelope. ZFrame client = msg.unwrap(); msg.addFirst(serviceFrame.duplicate()); msg.addFirst(MDP.C_CLIENT.newFrame()); msg.wrap(client); msg.send(socket); } /** * Send heartbeats to idle workers if it's time */ public synchronized void sendHeartbeats() { // Send heartbeats to idle workers if it's time if (System.currentTimeMillis() >= heartbeatAt) { for (Worker worker : waiting) { sendToWorker(worker, MDP.W_HEARTBEAT, null, null); } heartbeatAt = System.currentTimeMillis() + HEARTBEAT_INTERVAL; } } /** * Look for & kill expired workers. Workers are oldest to most recent, so we * stop at the first alive worker. */ public synchronized void purgeWorkers() { for (Worker w = waiting.peekFirst(); w != null && w.expiry < System.currentTimeMillis(); w = waiting .peekFirst()) { log.format("I: deleting expired worker: %s\n", w.identity); deleteWorker(waiting.pollFirst(), false); } } /** * This worker is now waiting for work. */ public synchronized void workerWaiting(Worker worker) { // Queue to broker and service waiting lists waiting.addLast(worker); worker.service.waiting.addLast(worker); worker.expiry = System.currentTimeMillis() + HEARTBEAT_EXPIRY; dispatch(worker.service, null); } /** * Dispatch requests to waiting workers as possible */ private void dispatch(Service service, ZMsg msg) { assert (service != null); if (msg != null)// Queue message if any service.requests.offerLast(msg); purgeWorkers(); while (!service.waiting.isEmpty() && !service.requests.isEmpty()) { msg = service.requests.pop(); Worker worker = service.waiting.pop(); waiting.remove(worker); sendToWorker(worker, MDP.W_REQUEST, null, msg); msg.destroy(); } } /** * Send message to worker. If message is provided, sends that message. Does * not destroy the message, this is the caller's job. */ public void sendToWorker(Worker worker, MDP command, String option, ZMsg msgp) { ZMsg msg = msgp == null ? new ZMsg() : msgp.duplicate(); // Stack protocol envelope to start of message if (option != null) msg.addFirst(new ZFrame(option)); msg.addFirst(command.newFrame()); msg.addFirst(MDP.W_WORKER.newFrame()); // Stack routing envelope to start of message msg.wrap(worker.address.duplicate()); if (verbose) { log.format("I: sending %s to worker\n", command); msg.dump(log.out()); } msg.send(socket); } } jeromq-0.3.5/src/test/java/guide/mdcliapi.java000066400000000000000000000102011255150477200212270ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.Formatter; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMsg; /** * Majordomo Protocol Client API, Java version Implements the MDP/Worker spec at * http://rfc.zeromq.org/spec:7. * */ public class mdcliapi { private String broker; private ZContext ctx; private ZMQ.Socket client; private long timeout = 2500; private int retries = 3; private boolean verbose; private Formatter log = new Formatter(System.out); public long getTimeout() { return timeout; } public void setTimeout(long timeout) { this.timeout = timeout; } public int getRetries() { return retries; } public void setRetries(int retries) { this.retries = retries; } public mdcliapi(String broker, boolean verbose) { this.broker = broker; this.verbose = verbose; ctx = new ZContext(); reconnectToBroker(); } /** * Connect or reconnect to broker */ void reconnectToBroker() { if (client != null) { ctx.destroySocket(client); } client = ctx.createSocket(ZMQ.REQ); client.connect(broker); if (verbose) log.format("I: connecting to broker at %s\n", broker); } /** * Send request to broker and get reply by hook or crook Takes ownership of * request message and destroys it when sent. Returns the reply message or * NULL if there was no reply. * * @param service * @param request * @return */ public ZMsg send(String service, ZMsg request) { request.push(new ZFrame(service)); request.push(MDP.C_CLIENT.newFrame()); if (verbose) { log.format("I: send request to '%s' service: \n", service); request.dump(log.out()); } ZMsg reply = null; int retriesLeft = retries; while (retriesLeft > 0 && !Thread.currentThread().isInterrupted()) { request.duplicate().send(client); // Poll socket for a reply, with timeout ZMQ.Poller items = new ZMQ.Poller(1); items.register(client, ZMQ.Poller.POLLIN); if (items.poll(timeout) == -1) break; // Interrupted if (items.pollin(0)) { ZMsg msg = ZMsg.recvMsg(client); if (verbose){ log.format("I: received reply: \n"); msg.dump(log.out()); } // Don't try to handle errors, just assert noisily assert (msg.size() >= 3); ZFrame header = msg.pop(); assert (MDP.C_CLIENT.equals(header.toString())); header.destroy(); ZFrame replyService = msg.pop(); assert (service.equals(replyService.toString())); replyService.destroy(); reply = msg; break; } else { items.unregister(client); if (--retriesLeft == 0) { log.format("W: permanent error, abandoning\n"); break; } log.format("W: no reply, reconnecting\n"); reconnectToBroker(); } } request.destroy(); return reply; } public void destroy() { ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/mdcliapi2.java000066400000000000000000000075711255150477200213310ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.Formatter; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMsg; /** * Majordomo Protocol Client API, asynchronous Java version. Implements the * MDP/Worker spec at http://rfc.zeromq.org/spec:7. */ public class mdcliapi2 { private String broker; private ZContext ctx; private ZMQ.Socket client; private long timeout = 2500; private boolean verbose; private Formatter log = new Formatter(System.out); public long getTimeout() { return timeout; } public void setTimeout(long timeout) { this.timeout = timeout; } public mdcliapi2(String broker, boolean verbose) { this.broker = broker; this.verbose = verbose; ctx = new ZContext(); reconnectToBroker(); } /** * Connect or reconnect to broker */ void reconnectToBroker() { if (client != null) { ctx.destroySocket(client); } client = ctx.createSocket(ZMQ.DEALER); client.connect(broker); if (verbose) log.format("I: connecting to broker at %s...\n", broker); } /** * Returns the reply message or NULL if there was no reply. Does not attempt * to recover from a broker failure, this is not possible without storing * all unanswered requests and resending them all… */ public ZMsg recv() { ZMsg reply = null; // Poll socket for a reply, with timeout ZMQ.Poller items = new ZMQ.Poller(1); items.register(client, ZMQ.Poller.POLLIN); if (items.poll(timeout * 1000) == -1) return null; // Interrupted if (items.pollin(0)) { ZMsg msg = ZMsg.recvMsg(client); if (verbose) { log.format("I: received reply: \n"); msg.dump(log.out()); } // Don't try to handle errors, just assert noisily assert (msg.size() >= 4); ZFrame empty = msg.pop(); assert (empty.getData().length == 0); empty.destroy(); ZFrame header = msg.pop(); assert (MDP.C_CLIENT.equals(header.toString())); header.destroy(); ZFrame replyService = msg.pop(); replyService.destroy(); reply = msg; } return reply; } /** * Send request to broker and get reply by hook or crook Takes ownership of * request message and destroys it when sent. */ public boolean send(String service, ZMsg request) { assert (request != null); // Prefix request with protocol frames // Frame 0: empty (REQ emulation) // Frame 1: "MDPCxy" (six bytes, MDP/Client x.y) // Frame 2: Service name (printable string) request.addFirst(service); request.addFirst(MDP.C_CLIENT.newFrame()); request.addFirst(""); if (verbose) { log.format("I: send request to '%s' service: \n", service); request.dump(log.out()); } return request.send(client); } public void destroy() { ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/mdclient.java000066400000000000000000000030531255150477200212530ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMsg; /** * Majordomo Protocol client example. Uses the mdcli API to hide all MDP aspects */ public class mdclient { public static void main(String[] args) { boolean verbose = (args.length > 0 && "-v".equals(args[0])); mdcliapi clientSession = new mdcliapi("tcp://localhost:5555", verbose); int count; for (count = 0; count < 100000; count++) { ZMsg request = new ZMsg(); request.addString("Hello world"); ZMsg reply = clientSession.send("echo", request); if (reply != null) reply.destroy(); else break; // Interrupt or failure } System.out.printf("%d requests/replies processed\n", count); clientSession.destroy(); } } jeromq-0.3.5/src/test/java/guide/mdclient2.java000066400000000000000000000032411255150477200213340ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMsg; /** * Majordomo Protocol client example, asynchronous. Uses the mdcli API to hide * all MDP aspects */ public class mdclient2 { public static void main(String[] args) { boolean verbose = (args.length > 0 && "-v".equals(args[0])); mdcliapi2 clientSession = new mdcliapi2("tcp://localhost:5555", verbose); int count; for (count = 0; count < 100000; count++) { ZMsg request = new ZMsg(); request.addString("Hello world"); clientSession.send("echo", request); } for (count = 0; count < 100000; count++) { ZMsg reply = clientSession.recv(); if (reply != null) reply.destroy(); else break; // Interrupt or failure } System.out.printf("%d requests/replies processed\n", count); clientSession.destroy(); } } jeromq-0.3.5/src/test/java/guide/mdworker.java000066400000000000000000000027011255150477200213050ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMsg; /** * Majordomo Protocol worker example. Uses the mdwrk API to hide all MDP aspects * */ public class mdworker { /** * @param args */ public static void main(String[] args) { boolean verbose = (args.length > 0 && "-v".equals(args[0])); mdwrkapi workerSession = new mdwrkapi("tcp://localhost:5555", "echo", verbose); ZMsg reply = null; while (!Thread.currentThread().isInterrupted()) { ZMsg request = workerSession.receive(reply); if (request == null) break; //Interrupted reply = request; // Echo is complex :-) } workerSession.destroy(); } } jeromq-0.3.5/src/test/java/guide/mdwrkapi.java000066400000000000000000000156501255150477200213000ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.Formatter; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMsg; /** * Majordomo Protocol Client API, Java version Implements the MDP/Worker spec at * http://rfc.zeromq.org/spec:7. */ public class mdwrkapi { private static final int HEARTBEAT_LIVENESS = 3; // 3-5 is reasonable private String broker; private ZContext ctx; private String service; private ZMQ.Socket worker; // Socket to broker private long heartbeatAt;// When to send HEARTBEAT private int liveness;// How many attempts left private int heartbeat = 2500;// Heartbeat delay, msecs private int reconnect = 2500; // Reconnect delay, msecs // Internal state private boolean expectReply = false; // false only at start private long timeout = 2500; private boolean verbose;// Print activity to stdout private Formatter log = new Formatter(System.out); // Return address, if any private ZFrame replyTo; public mdwrkapi(String broker, String service, boolean verbose) { assert (broker != null); assert (service != null); this.broker = broker; this.service = service; this.verbose = verbose; ctx = new ZContext(); reconnectToBroker(); } /** * Send message to broker If no msg is provided, creates one internally * * @param command * @param option * @param msg */ void sendToBroker(MDP command, String option, ZMsg msg) { msg = msg != null ? msg.duplicate() : new ZMsg(); // Stack protocol envelope to start of message if (option != null) msg.addFirst(new ZFrame(option)); msg.addFirst(command.newFrame()); msg.addFirst(MDP.W_WORKER.newFrame()); msg.addFirst(new ZFrame(ZMQ.MESSAGE_SEPARATOR)); if (verbose) { log.format("I: sending %s to broker\n", command); msg.dump(log.out()); } msg.send(worker); } /** * Connect or reconnect to broker */ void reconnectToBroker() { if (worker != null) { ctx.destroySocket(worker); } worker = ctx.createSocket(ZMQ.DEALER); worker.connect(broker); if (verbose) log.format("I: connecting to broker at %s\n", broker); // Register service with broker sendToBroker(MDP.W_READY, service, null); // If liveness hits zero, queue is considered disconnected liveness = HEARTBEAT_LIVENESS; heartbeatAt = System.currentTimeMillis() + heartbeat; } /** * Send reply, if any, to broker and wait for next request. */ public ZMsg receive(ZMsg reply) { // Format and send the reply if we were provided one assert (reply != null || !expectReply); if (reply != null) { assert (replyTo != null); reply.wrap(replyTo); sendToBroker(MDP.W_REPLY, null, reply); reply.destroy(); } expectReply = true; while (!Thread.currentThread().isInterrupted()) { // Poll socket for a reply, with timeout ZMQ.Poller items = new ZMQ.Poller(1); items.register(worker, ZMQ.Poller.POLLIN); if (items.poll(timeout) == -1) break; // Interrupted if (items.pollin(0)) { ZMsg msg = ZMsg.recvMsg(worker); if (msg == null) break; // Interrupted if (verbose) { log.format("I: received message from broker: \n"); msg.dump(log.out()); } liveness = HEARTBEAT_LIVENESS; // Don't try to handle errors, just assert noisily assert (msg != null && msg.size() >= 3); ZFrame empty = msg.pop(); assert (empty.getData().length == 0); empty.destroy(); ZFrame header = msg.pop(); assert (MDP.W_WORKER.frameEquals(header)); header.destroy(); ZFrame command = msg.pop(); if (MDP.W_REQUEST.frameEquals(command)) { // We should pop and save as many addresses as there are // up to a null part, but for now, just save one replyTo = msg.unwrap(); command.destroy(); return msg; // We have a request to process } else if (MDP.W_HEARTBEAT.frameEquals(command)) { // Do nothing for heartbeats } else if (MDP.W_DISCONNECT.frameEquals(command)) { reconnectToBroker(); } else { log.format("E: invalid input message: \n"); msg.dump(log.out()); } command.destroy(); msg.destroy(); } else if (--liveness == 0) { if (verbose) log.format("W: disconnected from broker - retrying\n"); try { Thread.sleep(reconnect); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // Restore the // interrupted status break; } reconnectToBroker(); } // Send HEARTBEAT if it's time if (System.currentTimeMillis() > heartbeatAt) { sendToBroker(MDP.W_HEARTBEAT, null, null); heartbeatAt = System.currentTimeMillis() + heartbeat; } } if (Thread.currentThread().isInterrupted()) log.format("W: interrupt received, killing worker\n"); return null; } public void destroy() { ctx.destroy(); } // ============== getters and setters ================= public int getHeartbeat() { return heartbeat; } public void setHeartbeat(int heartbeat) { this.heartbeat = heartbeat; } public int getReconnect() { return reconnect; } public void setReconnect(int reconnect) { this.reconnect = reconnect; } } jeromq-0.3.5/src/test/java/guide/mmiecho.java000066400000000000000000000031451255150477200210770ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMsg; /** * MMI echo query example */ public class mmiecho { public static void main(String[] args) { boolean verbose = (args.length > 0 && "-v".equals(args[0])); mdcliapi clientSession = new mdcliapi("tcp://localhost:5555", verbose); ZMsg request = new ZMsg(); // This is the service we want to look up request.addString("echo"); // This is the service we send our request to ZMsg reply = clientSession.send("mmi.service", request); if (reply != null) { String replyCode = reply.getFirst().toString(); System.out.printf("Lookup echo service: %s\n", replyCode); } else { System.out .println("E: no response from broker, make sure it's running"); } clientSession.destroy(); } } jeromq-0.3.5/src/test/java/guide/msgqueue.java000066400000000000000000000030521255150477200213060ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; /** * Simple message queuing broker * Same as request-reply broker but using QUEUE device. */ public class msgqueue{ public static void main (String[] args) { // Prepare our context and sockets Context context = ZMQ.context(1); // Socket facing clients Socket frontend = context.socket(ZMQ.ROUTER); frontend.bind("tcp://*:5559"); // Socket facing services Socket backend = context.socket(ZMQ.DEALER); backend.bind("tcp://*:5560"); // Start the proxy ZMQ.proxy (frontend, backend, null); // We never get here but clean up anyhow frontend.close(); backend.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/mspoller.java000066400000000000000000000040371255150477200213140ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; // // Reading from multiple sockets in Java // This version uses ZMQ.Poller // public class mspoller { public static void main (String[] args) { ZMQ.Context context = ZMQ.context(1); // Connect to task ventilator ZMQ.Socket receiver = context.socket(ZMQ.PULL); receiver.connect("tcp://localhost:5557"); // Connect to weather server ZMQ.Socket subscriber = context.socket(ZMQ.SUB); subscriber.connect("tcp://localhost:5556"); subscriber.subscribe("10001 ".getBytes(ZMQ.CHARSET)); // Initialize poll set ZMQ.Poller items = new ZMQ.Poller (2); items.register(receiver, ZMQ.Poller.POLLIN); items.register(subscriber, ZMQ.Poller.POLLIN); // Process messages from both sockets while (!Thread.currentThread ().isInterrupted ()) { byte[] message; items.poll(); if (items.pollin(0)) { message = receiver.recv(0); System.out.println("Process task"); } if (items.pollin(1)) { message = subscriber.recv(0); System.out.println("Process weather update"); } } receiver.close (); context.term (); } } jeromq-0.3.5/src/test/java/guide/msreader.java000066400000000000000000000041731255150477200212620ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; // // Reading from multiple sockets in Java // This version uses a simple recv loop // public class msreader { public static void main (String[] args) throws Exception { // Prepare our context and sockets ZMQ.Context context = ZMQ.context(1); // Connect to task ventilator ZMQ.Socket receiver = context.socket(ZMQ.PULL); receiver.connect("tcp://localhost:5557"); // Connect to weather server ZMQ.Socket subscriber = context.socket(ZMQ.SUB); subscriber.connect("tcp://localhost:5556"); subscriber.subscribe("10001 ".getBytes(ZMQ.CHARSET)); // Process messages from both sockets // We prioritize traffic from the task ventilator while (!Thread.currentThread ().isInterrupted ()) { // Process any waiting tasks byte[] task; while((task = receiver.recv(ZMQ.DONTWAIT)) != null) { System.out.println("process task"); } // Process any waiting weather updates byte[] update; while ((update = subscriber.recv(ZMQ.DONTWAIT)) != null) { System.out.println("process weather update"); } // No activity, so sleep for 1 msec Thread.sleep(1000); } subscriber.close (); context.term (); } } jeromq-0.3.5/src/test/java/guide/mtrelay.java000066400000000000000000000053721255150477200211370ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; /** * Multithreaded relay */ public class mtrelay{ private static class Step1 extends Thread { private Context context; private Step1 (Context context) { this.context = context; } @Override public void run(){ // Signal downstream to step 2 Socket xmitter = context.socket(ZMQ.PAIR); xmitter.connect("inproc://step2"); System.out.println ("Step 1 ready, signaling step 2"); xmitter.send("READY", 0); xmitter.close (); } } private static class Step2 extends Thread { private Context context; private Step2 (Context context) { this.context = context; } @Override public void run(){ // Bind to inproc: endpoint, then start upstream thread Socket receiver = context.socket(ZMQ.PAIR); receiver.bind("inproc://step2"); Thread step1 = new Step1 (context); step1.start(); // Wait for signal receiver.recv(0); receiver.close (); // Connect to step3 and tell it we're ready Socket xmitter = context.socket(ZMQ.PAIR); xmitter.connect("inproc://step3"); xmitter.send("READY", 0); xmitter.close (); } } public static void main (String[] args) { Context context = ZMQ.context(1); // Bind to inproc: endpoint, then start upstream thread Socket receiver = context.socket(ZMQ.PAIR); receiver.bind("inproc://step3"); // Step 2 relays the signal to step 3 Thread step2 = new Step2 (context); step2.start(); // Wait for signal receiver.recv(0); receiver.close (); System.out.println ("Test successful!"); context.term (); } } jeromq-0.3.5/src/test/java/guide/mtserver.java000066400000000000000000000047051255150477200213300ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; /** * Multi threaded Hello World server */ public class mtserver { private static class Worker extends Thread { private Context context; private Worker (Context context) { this.context = context; } @Override public void run() { ZMQ.Socket socket = context.socket(ZMQ.REP); socket.connect ("inproc://workers"); while (true) { // Wait for next request from client (C string) String request = socket.recvStr (0); System.out.println ( Thread.currentThread().getName() + " Received request: [" + request + "]"); // Do some 'work' try { Thread.sleep (1000); } catch (InterruptedException e) { } // Send reply back to client (C string) socket.send("world", 0); } } } public static void main (String[] args) { Context context = ZMQ.context(1); Socket clients = context.socket(ZMQ.ROUTER); clients.bind ("tcp://*:5555"); Socket workers = context.socket(ZMQ.DEALER); workers.bind ("inproc://workers"); for(int thread_nbr = 0; thread_nbr < 5; thread_nbr++) { Thread worker = new Worker (context); worker.start(); } // Connect work threads to client threads via a queue ZMQ.proxy (clients, workers, null); // We never get here but clean up anyhow clients.close(); workers.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/pathopub.java000066400000000000000000000037431255150477200213040ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Socket; import java.util.Random; // Pathological publisher // Sends out 1,000 topics and then one random update per second public class pathopub { public static void main(String[] args) throws Exception { ZContext context = new ZContext(); Socket publisher = context.createSocket(ZMQ.PUB); if (args.length == 1) publisher.connect(args[0]); else publisher.bind("tcp://*:5556"); // Ensure subscriber connection has time to complete Thread.sleep(1000); // Send out all 1,000 topic messages int topicNbr; for (topicNbr = 0; topicNbr < 1000; topicNbr++) { publisher.send(String.format("%03d", topicNbr), ZMQ.SNDMORE); publisher.send("Save Roger"); } // Send one random update per second Random rand = new Random(System.currentTimeMillis()); while (!Thread.currentThread().isInterrupted()) { Thread.sleep(1000); publisher.send(String.format("%03d", rand.nextInt(1000)), ZMQ.SNDMORE); publisher.send("Off with his head!"); } context.destroy(); } } jeromq-0.3.5/src/test/java/guide/pathosub.java000066400000000000000000000034131255150477200213010ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Socket; import java.util.Random; // Pathological subscriber // Subscribes to one random topic and prints received messages public class pathosub { public static void main(String[] args) { ZContext context = new ZContext(); Socket subscriber = context.createSocket(ZMQ.SUB); if (args.length == 1) subscriber.connect(args[0]); else subscriber.connect("tcp://localhost:5556"); Random rand = new Random(System.currentTimeMillis()); String subscription = String.format("%03d", rand.nextInt(1000)); subscriber.subscribe(subscription.getBytes(ZMQ.CHARSET)); while (true) { String topic = subscriber.recvStr(); if (topic == null) break; String data = subscriber.recvStr(); assert(topic.equals(subscription)); System.out.println(data); } context.destroy(); } } jeromq-0.3.5/src/test/java/guide/peering1.java000066400000000000000000000061231255150477200211670ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.Random; import org.zeromq.ZMQ.Poller; import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; // Broker peering simulation (part 1) // Prototypes the state flow public class peering1 { public static void main(String[] argv) { // First argument is this broker's name // Other arguments are our peers' names // if (argv.length < 1) { System.out.println("syntax: peering1 me {you}\n"); System.exit(-1); } String self = argv[0]; System.out.println(String.format("I: preparing broker at %s\n", self)); Random rand = new Random(System.nanoTime()); ZContext ctx = new ZContext(); // Bind state backend to endpoint Socket statebe = ctx.createSocket(ZMQ.PUB); statebe.bind(String.format("ipc://%s-state.ipc", self)); // Connect statefe to all peers Socket statefe = ctx.createSocket(ZMQ.SUB); statefe.subscribe(ZMQ.SUBSCRIPTION_ALL); int argn; for (argn = 1; argn < argv.length; argn++) { String peer = argv[argn]; System.out.printf("I: connecting to state backend at '%s'\n", peer); statefe.connect(String.format("ipc://%s-state.ipc", peer)); } // The main loop sends out status messages to peers, and collects // status messages back from peers. The zmq_poll timeout defines // our own heartbeat: while (true) { // Poll for activity, or 1 second timeout PollItem items[] = {new PollItem(statefe, Poller.POLLIN)}; int rc = ZMQ.poll(items, 1000); if (rc == -1) break; // Interrupted // Handle incoming status messages if (items[0].isReadable()) { String peer_name = new String(statefe.recv(0), ZMQ.CHARSET); String available = new String(statefe.recv(0), ZMQ.CHARSET); System.out.printf("%s - %s workers free\n", peer_name, available); } else { // Send random values for worker availability statebe.send(self, ZMQ.SNDMORE); statebe.send(String.format("%d", rand.nextInt(10)), 0); } } ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/peering2.java000066400000000000000000000230131255150477200211650ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.io.IOException; import java.util.ArrayList; import java.util.Random; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Poller; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; // Broker peering simulation (part 2) // Prototypes the request-reply flow public class peering2 { private static final int NBR_CLIENTS = 10; private static final int NBR_WORKERS = 3; private static final String WORKER_READY = "\001"; // Signals worker is ready // Our own name; in practice this would be configured per node private static String self; // The client task does a request-reply dialog using a standard // synchronous REQ socket: private static class client_task extends Thread { @Override public void run() { ZContext ctx = new ZContext(); Socket client = ctx.createSocket(ZMQ.REQ); client.connect(String.format("ipc://%s-localfe.ipc", self)); while (true) { // Send request, get reply client.send("HELLO", 0); String reply = client.recvStr(0); if (reply == null) break; // Interrupted System.out.printf("Client: %s\n", reply); try { Thread.sleep(1000); } catch (InterruptedException e) { } } ctx.destroy(); } } // The worker task plugs into the LRU routing dialog using a REQ // socket: private static class worker_task extends Thread { @Override public void run() { ZContext ctx = new ZContext(); Socket worker = ctx.createSocket(ZMQ.REQ); worker.connect(String.format("ipc://%s-localbe.ipc", self)); // Tell broker we're ready for work ZFrame frame = new ZFrame(WORKER_READY); frame.send(worker, 0); while (true) { // Send request, get reply ZMsg msg = ZMsg.recvMsg(worker, 0); if (msg == null) break; // Interrupted msg.getLast().print("Worker: "); msg.getLast().reset("OK"); msg.send(worker); } ctx.destroy(); } } // The main task begins by setting-up its frontend and backend sockets // and then starting its client and worker tasks: public static void main(String[] argv) { // First argument is this broker's name // Other arguments are our peers' names // if (argv.length < 1) { System.out.println("syntax: peering2 me {you}"); System.exit(-1); } self = argv[0]; System.out.printf("I: preparing broker at %s\n", self); Random rand = new Random(System.nanoTime()); ZContext ctx = new ZContext(); // Bind cloud frontend to endpoint Socket cloudfe = ctx.createSocket(ZMQ.ROUTER); cloudfe.setIdentity(self.getBytes(ZMQ.CHARSET)); cloudfe.bind(String.format("ipc://%s-cloud.ipc", self)); // Connect cloud backend to all peers Socket cloudbe = ctx.createSocket(ZMQ.ROUTER); cloudbe.setIdentity(self.getBytes(ZMQ.CHARSET)); int argn; for (argn = 1; argn < argv.length; argn++) { String peer = argv[argn]; System.out.printf("I: connecting to cloud forintend at '%s'\n", peer); cloudbe.connect(String.format("ipc://%s-cloud.ipc", peer)); } // Prepare local frontend and backend Socket localfe = ctx.createSocket(ZMQ.ROUTER); localfe.bind(String.format("ipc://%s-localfe.ipc", self)); Socket localbe = ctx.createSocket(ZMQ.ROUTER); localbe.bind(String.format("ipc://%s-localbe.ipc", self)); // Get user to tell us when we can start System.out.println("Press Enter when all brokers are started: "); try { System.in.read(); } catch (IOException e) { e.printStackTrace(); } // Start local workers int worker_nbr; for (worker_nbr = 0; worker_nbr < NBR_WORKERS; worker_nbr++) new worker_task().start(); // Start local clients int client_nbr; for (client_nbr = 0; client_nbr < NBR_CLIENTS; client_nbr++) new client_task().start(); // Here we handle the request-reply flow. We're using the LRU approach // to poll workers at all times, and clients only when there are one or // more workers available. // Least recently used queue of available workers int capacity = 0; ArrayList workers = new ArrayList(); while (true) { // First, route any waiting replies from workers PollItem backends[] = { new PollItem(localbe, Poller.POLLIN), new PollItem(cloudbe, Poller.POLLIN) }; // If we have no workers anyhow, wait indefinitely int rc = ZMQ.poll(backends, capacity > 0 ? 1000 : -1); if (rc == -1) break; // Interrupted // Handle reply from local worker ZMsg msg = null; if (backends[0].isReadable()) { msg = ZMsg.recvMsg(localbe); if (msg == null) break; // Interrupted ZFrame address = msg.unwrap(); workers.add(address); capacity++; // If it's READY, don't route the message any further ZFrame frame = msg.getFirst(); if (new String(frame.getData(), ZMQ.CHARSET).equals(WORKER_READY)) { msg.destroy(); msg = null; } } // Or handle reply from peer broker else if (backends[1].isReadable()) { msg = ZMsg.recvMsg(cloudbe); if (msg == null) break; // Interrupted // We don't use peer broker address for anything ZFrame address = msg.unwrap(); address.destroy(); } // Route reply to cloud if it's addressed to a broker for (argn = 1; msg != null && argn < argv.length; argn++) { byte[] data = msg.getFirst().getData(); if (argv[argn].equals(new String(data, ZMQ.CHARSET))) { msg.send(cloudfe); msg = null; } } // Route reply to client if we still need to if (msg != null) msg.send(localfe); // Now we route as many client requests as we have worker capacity // for. We may reroute requests from our local frontend, but not from // // the cloud frontend. We reroute randomly now, just to test things // out. In the next version we'll do this properly by calculating // cloud capacity:// while (capacity > 0) { PollItem frontends[] = { new PollItem(localfe, Poller.POLLIN), new PollItem(cloudfe, Poller.POLLIN) }; rc = ZMQ.poll(frontends, 0); assert (rc >= 0); int reroutable = 0; // We'll do peer brokers first, to prevent starvation if (frontends[1].isReadable()) { msg = ZMsg.recvMsg(cloudfe); reroutable = 0; } else if (frontends[0].isReadable()) { msg = ZMsg.recvMsg(localfe); reroutable = 1; } else break; // No work, go back to backends // If reroutable, send to cloud 20% of the time // Here we'd normally use cloud status information // if (reroutable != 0 && argv.length > 1 && rand.nextInt(5) == 0) { // Route to random broker peer int random_peer = rand.nextInt(argv.length - 1) + 1; msg.push(argv[random_peer]); msg.send(cloudbe); } else { ZFrame frame = workers.remove(0); msg.wrap(frame); msg.send(localbe); capacity--; } } } // When we're done, clean up properly while (workers.size() > 0) { ZFrame frame = workers.remove(0); frame.destroy(); } ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/peering3.java000066400000000000000000000317261255150477200212000ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.ArrayList; import java.util.Random; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Poller; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; // Broker peering simulation (part 3) // Prototypes the full flow of status and tasks public class peering3 { private static final int NBR_CLIENTS = 10; private static final int NBR_WORKERS = 5; private static final String WORKER_READY = "\001"; // Signals worker is ready // Our own name; in practice this would be configured per node private static String self; // This is the client task. It issues a burst of requests and then // sleeps for a few seconds. This simulates sporadic activity; when // a number of clients are active at once, the local workers should // be overloaded. The client uses a REQ socket for requests and also // pushes statistics to the monitor socket: private static class client_task extends Thread { @Override public void run() { ZContext ctx = new ZContext(); Socket client = ctx.createSocket(ZMQ.REQ); client.connect(String.format("ipc://%s-localfe.ipc", self)); Socket monitor = ctx.createSocket(ZMQ.PUSH); monitor.connect(String.format("ipc://%s-monitor.ipc", self)); Random rand = new Random(System.nanoTime()); while (true) { try { Thread.sleep(rand.nextInt(5) * 1000); } catch (InterruptedException e1) { } int burst = rand.nextInt(15); while (burst > 0) { String taskId = String.format("%04X", rand.nextInt(10000)); // Send request, get reply client.send(taskId, 0); // Wait max ten seconds for a reply, then complain PollItem pollSet[] = {new PollItem(client, Poller.POLLIN)}; int rc = ZMQ.poll(pollSet, 10 * 1000); if (rc == -1) break; // Interrupted if (pollSet[0].isReadable()) { String reply = client.recvStr(0); if (reply == null) break; // Interrupted // Worker is supposed to answer us with our task id assert (reply.equals(taskId)); monitor.send(String.format("%s", reply), 0); } else { monitor.send( String.format("E: CLIENT EXIT - lost task %s", taskId), 0); ctx.destroy(); return; } burst--; } } } } // This is the worker task, which uses a REQ socket to plug into the LRU // router. It's the same stub worker task you've seen in other examples: private static class worker_task extends Thread { @Override public void run() { Random rand = new Random(System.nanoTime()); ZContext ctx = new ZContext(); Socket worker = ctx.createSocket(ZMQ.REQ); worker.connect(String.format("ipc://%s-localbe.ipc", self)); // Tell broker we're ready for work ZFrame frame = new ZFrame(WORKER_READY); frame.send(worker, 0); while (true) { // Send request, get reply ZMsg msg = ZMsg.recvMsg(worker, 0); if (msg == null) break; // Interrupted // Workers are busy for 0/1 seconds try { Thread.sleep(rand.nextInt(2) * 1000); } catch (InterruptedException e) { } msg.send(worker); } ctx.destroy(); } } // The main task begins by setting-up all its sockets. The local frontend // talks to clients, and our local backend talks to workers. The cloud // frontend talks to peer brokers as if they were clients, and the cloud // backend talks to peer brokers as if they were workers. The state // backend publishes regular state messages, and the state frontend // subscribes to all state backends to collect these messages. Finally, // we use a PULL monitor socket to collect printable messages from tasks: public static void main(String[] argv) { // First argument is this broker's name // Other arguments are our peers' names // if (argv.length < 1) { System.out.println("syntax: peering3 me {you}"); System.exit(-1); } self = argv[0]; System.out.printf("I: preparing broker at %s\n", self); Random rand = new Random(System.nanoTime()); ZContext ctx = new ZContext(); // Prepare local frontend and backend Socket localfe = ctx.createSocket(ZMQ.ROUTER); localfe.bind(String.format("ipc://%s-localfe.ipc", self)); Socket localbe = ctx.createSocket(ZMQ.ROUTER); localbe.bind(String.format("ipc://%s-localbe.ipc", self)); // Bind cloud frontend to endpoint Socket cloudfe = ctx.createSocket(ZMQ.ROUTER); cloudfe.setIdentity(self.getBytes(ZMQ.CHARSET)); cloudfe.bind(String.format("ipc://%s-cloud.ipc", self)); // Connect cloud backend to all peers Socket cloudbe = ctx.createSocket(ZMQ.ROUTER); cloudbe.setIdentity(self.getBytes(ZMQ.CHARSET)); int argn; for (argn = 1; argn < argv.length; argn++) { String peer = argv[argn]; System.out.printf("I: connecting to cloud forintend at '%s'\n", peer); cloudbe.connect(String.format("ipc://%s-cloud.ipc", peer)); } // Bind state backend to endpoint Socket statebe = ctx.createSocket(ZMQ.PUB); statebe.bind(String.format("ipc://%s-state.ipc", self)); // Connect statefe to all peers Socket statefe = ctx.createSocket(ZMQ.SUB); statefe.subscribe(ZMQ.SUBSCRIPTION_ALL); for (argn = 1; argn < argv.length; argn++) { String peer = argv[argn]; System.out.printf("I: connecting to state backend at '%s'\n", peer); statefe.connect(String.format("ipc://%s-state.ipc", peer)); } // Prepare monitor socket Socket monitor = ctx.createSocket(ZMQ.PULL); monitor.bind(String.format("ipc://%s-monitor.ipc", self)); // Start local workers int worker_nbr; for (worker_nbr = 0; worker_nbr < NBR_WORKERS; worker_nbr++) new worker_task().start(); // Start local clients int client_nbr; for (client_nbr = 0; client_nbr < NBR_CLIENTS; client_nbr++) new client_task().start(); // Queue of available workers int localCapacity = 0; int cloudCapacity = 0; ArrayList workers = new ArrayList(); // The main loop has two parts. First we poll workers and our two service // sockets (statefe and monitor), in any case. If we have no ready workers, // there's no point in looking at incoming requests. These can remain on // their internal 0MQ queues: while (true) { // First, route any waiting replies from workers PollItem primary[] = { new PollItem(localbe, Poller.POLLIN), new PollItem(cloudbe, Poller.POLLIN), new PollItem(statefe, Poller.POLLIN), new PollItem(monitor, Poller.POLLIN) }; // If we have no workers anyhow, wait indefinitely int rc = ZMQ.poll(primary, localCapacity > 0 ? 1000 : -1); if (rc == -1) break; // Interrupted // Track if capacity changes during this iteration int previous = localCapacity; // Handle reply from local worker ZMsg msg = null; if (primary[0].isReadable()) { msg = ZMsg.recvMsg(localbe); if (msg == null) break; // Interrupted ZFrame address = msg.unwrap(); workers.add(address); localCapacity++; // If it's READY, don't route the message any further ZFrame frame = msg.getFirst(); if (new String(frame.getData(), ZMQ.CHARSET).equals(WORKER_READY)) { msg.destroy(); msg = null; } } // Or handle reply from peer broker else if (primary[1].isReadable()) { msg = ZMsg.recvMsg(cloudbe); if (msg == null) break; // Interrupted // We don't use peer broker address for anything ZFrame address = msg.unwrap(); address.destroy(); } // Route reply to cloud if it's addressed to a broker for (argn = 1; msg != null && argn < argv.length; argn++) { byte[] data = msg.getFirst().getData(); if (argv[argn].equals(new String(data, ZMQ.CHARSET))) { msg.send(cloudfe); msg = null; } } // Route reply to client if we still need to if (msg != null) msg.send(localfe); // If we have input messages on our statefe or monitor sockets we // can process these immediately: if (primary[2].isReadable()) { String peer = statefe.recvStr(); String status = statefe.recvStr(); cloudCapacity = Integer.parseInt(status); } if (primary[3].isReadable()) { String status = monitor.recvStr(); System.out.println(status); } // Now we route as many client requests as we have worker capacity // for. We may reroute requests from our local frontend, but not from // // the cloud frontend. We reroute randomly now, just to test things // out. In the next version we'll do this properly by calculating // cloud capacity:// while (localCapacity + cloudCapacity > 0) { PollItem secondary[] = { new PollItem(localfe, Poller.POLLIN), new PollItem(cloudfe, Poller.POLLIN) }; if (localCapacity > 0) rc = ZMQ.poll(secondary, 2, 0); else rc = ZMQ.poll(secondary, 1, 0); assert (rc >= 0); if (secondary[0].isReadable()) { msg = ZMsg.recvMsg(localfe); } else if (secondary[1].isReadable()) { msg = ZMsg.recvMsg(cloudfe); } else break; // No work, go back to backends if (localCapacity > 0) { ZFrame frame = workers.remove(0); msg.wrap(frame); msg.send(localbe); localCapacity--; } else { // Route to random broker peer int random_peer = rand.nextInt(argv.length - 1) + 1; msg.push(argv[random_peer]); msg.send(cloudbe); } } // We broadcast capacity messages to other peers; to reduce chatter // we do this only if our capacity changed. if (localCapacity != previous) { // We stick our own address onto the envelope statebe.sendMore(self); // Broadcast new capacity statebe.send(String.format("%d", localCapacity), 0); } } // When we're done, clean up properly while (workers.size() > 0) { ZFrame frame = workers.remove(0); frame.destroy(); } ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/ppqueue.java000066400000000000000000000152431255150477200211440ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.ArrayList; import java.util.Iterator; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; // // Paranoid Pirate queue // public class ppqueue { private final static int HEARTBEAT_LIVENESS = 3; // 3-5 is reasonable private final static int HEARTBEAT_INTERVAL = 1000; // msecs // Paranoid Pirate Protocol constants private final static String PPP_READY = "\001"; // Signals worker is ready private final static String PPP_HEARTBEAT = "\002"; // Signals worker heartbeat // Here we define the worker class; a structure and a set of functions that // as constructor, destructor, and methods on worker objects: private static class Worker { ZFrame address; // Address of worker String identity; // Printable identity long expiry; // Expires at this time protected Worker(ZFrame address) { this.address = address; identity = new String(address.getData(), ZMQ.CHARSET); expiry = System.currentTimeMillis() + HEARTBEAT_INTERVAL * HEARTBEAT_LIVENESS; } // The ready method puts a worker to the end of the ready list: protected void ready(ArrayList workers) { Iterator it = workers.iterator(); while (it.hasNext()) { Worker worker = it.next(); if (identity.equals(worker.identity)) { it.remove(); break; } } workers.add(this); } // The next method returns the next available worker address: protected static ZFrame next(ArrayList workers) { Worker worker = workers.remove(0); assert (worker != null); ZFrame frame = worker.address; return frame; } // The purge method looks for and kills expired workers. We hold workers // from oldest to most recent, so we stop at the first alive worker: protected static void purge(ArrayList workers) { Iterator it = workers.iterator(); while (it.hasNext()) { Worker worker = it.next(); if (System.currentTimeMillis() < worker.expiry) { break; } it.remove(); } } }; // The main task is an LRU queue with heartbeating on workers so we can // detect crashed or blocked worker tasks: public static void main(String[] args) { ZContext ctx = new ZContext (); Socket frontend = ctx.createSocket(ZMQ.ROUTER); Socket backend = ctx.createSocket(ZMQ.ROUTER); frontend.bind( "tcp://*:5555"); // For clients backend.bind( "tcp://*:5556"); // For workers // List of available workers ArrayList workers = new ArrayList (); // Send out heartbeats at regular intervals long heartbeat_at = System.currentTimeMillis() + HEARTBEAT_INTERVAL; while (true) { PollItem items [] = { new PollItem( backend, ZMQ.Poller.POLLIN ), new PollItem( frontend, ZMQ.Poller.POLLIN ) }; // Poll frontend only if we have available workers int rc = ZMQ.poll (items, workers.size() > 0 ? 2:1, HEARTBEAT_INTERVAL ); if (rc == -1) break; // Interrupted // Handle worker activity on backend if (items [0].isReadable()) { // Use worker address for LRU routing ZMsg msg = ZMsg.recvMsg (backend); if (msg == null) break; // Interrupted // Any sign of life from worker means it's ready ZFrame address = msg.unwrap(); Worker worker = new Worker(address); worker.ready(workers); // Validate control message, or return reply to client if (msg.size() == 1) { ZFrame frame = msg.getFirst(); String data = new String(frame.getData(), ZMQ.CHARSET); if (!data.equals(PPP_READY) && !data.equals( PPP_HEARTBEAT)) { System.out.println ("E: invalid message from worker"); msg.dump(System.out); } msg.destroy(); } else msg.send(frontend); } if (items [1].isReadable()) { // Now get next client request, route to next worker ZMsg msg = ZMsg.recvMsg (frontend); if (msg == null) break; // Interrupted msg.push(Worker.next(workers)); msg.send( backend); } // We handle heartbeating after any socket activity. First we send // heartbeats to any idle workers if it's time. Then we purge any // dead workers: if (System.currentTimeMillis() >= heartbeat_at) { for (Worker worker: workers) { worker.address.send(backend, ZFrame.REUSE + ZFrame.MORE); ZFrame frame = new ZFrame (PPP_HEARTBEAT); frame.send(backend, 0); } heartbeat_at = System.currentTimeMillis() + HEARTBEAT_INTERVAL; } Worker.purge (workers); } // When we're done, clean up properly while ( workers.size() > 0) { Worker worker = workers.remove(0); } workers.clear(); ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/ppworker.java000066400000000000000000000153411255150477200213300ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.Random; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; // // Paranoid Pirate worker // public class ppworker { private final static int HEARTBEAT_LIVENESS = 3; // 3-5 is reasonable private final static int HEARTBEAT_INTERVAL = 1000; // msecs private final static int INTERVAL_INIT = 1000; // Initial reconnect private final static int INTERVAL_MAX = 32000; // After exponential backoff // Paranoid Pirate Protocol constants private final static String PPP_READY = "\001"; // Signals worker is ready private final static String PPP_HEARTBEAT = "\002"; // Signals worker heartbeat // Helper function that returns a new configured socket // connected to the Paranoid Pirate queue private static Socket worker_socket(ZContext ctx) { Socket worker = ctx.createSocket(ZMQ.DEALER); worker.connect("tcp://localhost:5556"); // Tell queue we're ready for work System.out.println("I: worker ready\n"); ZFrame frame = new ZFrame(PPP_READY); frame.send(worker, 0); return worker; } // We have a single task, which implements the worker side of the // Paranoid Pirate Protocol (PPP). The interesting parts here are // the heartbeating, which lets the worker detect if the queue has // died, and vice-versa: public static void main(String[] args) { ZContext ctx = new ZContext(); Socket worker = worker_socket(ctx); // If liveness hits zero, queue is considered disconnected int liveness = HEARTBEAT_LIVENESS; int interval = INTERVAL_INIT; // Send out heartbeats at regular intervals long heartbeat_at = System.currentTimeMillis() + HEARTBEAT_INTERVAL; Random rand = new Random(System.nanoTime()); int cycles = 0; while (true) { PollItem items[] = {new PollItem(worker, ZMQ.Poller.POLLIN)}; int rc = ZMQ.poll(items, HEARTBEAT_INTERVAL); if (rc == -1) break; // Interrupted if (items[0].isReadable()) { // Get message // - 3-part envelope + content -> request // - 1-part HEARTBEAT -> heartbeat ZMsg msg = ZMsg.recvMsg(worker); if (msg == null) break; // Interrupted // To test the robustness of the queue implementation we // // simulate various typical problems, such as the worker // crashing, or running very slowly. We do this after a few // cycles so that the architecture can get up and running // first: if (msg.size() == 3) { cycles++; if (cycles > 3 && rand.nextInt(5) == 0) { System.out.println("I: simulating a crash\n"); msg.destroy(); msg = null; break; } else if (cycles > 3 && rand.nextInt(5) == 0) { System.out.println("I: simulating CPU overload\n"); try { Thread.sleep(3000); } catch (InterruptedException e) { break; } } System.out.println("I: normal reply\n"); msg.send(worker); liveness = HEARTBEAT_LIVENESS; try { Thread.sleep(1000); } catch (InterruptedException e) { break; } // Do some heavy work } else // When we get a heartbeat message from the queue, it means the // queue was (recently) alive, so reset our liveness indicator: if (msg.size() == 1) { ZFrame frame = msg.getFirst(); if (PPP_HEARTBEAT.equals(new String(frame.getData(), ZMQ.CHARSET))) liveness = HEARTBEAT_LIVENESS; else { System.out.println("E: invalid message\n"); msg.dump(System.out); } msg.destroy(); } else { System.out.println("E: invalid message\n"); msg.dump(System.out); } interval = INTERVAL_INIT; } else // If the queue hasn't sent us heartbeats in a while, destroy the // socket and reconnect. This is the simplest most brutal way of // discarding any messages we might have sent in the meantime:// if (--liveness == 0) { System.out.println("W: heartbeat failure, can't reach queue\n"); System.out.printf("W: reconnecting in %sd msec\n", interval); try { Thread.sleep(interval); } catch (InterruptedException e) { e.printStackTrace(); } if (interval < INTERVAL_MAX) interval *= 2; ctx.destroySocket(worker); worker = worker_socket(ctx); liveness = HEARTBEAT_LIVENESS; } // Send heartbeat to queue if it's time if (System.currentTimeMillis() > heartbeat_at) { heartbeat_at = System.currentTimeMillis() + HEARTBEAT_INTERVAL; System.out.println("I: worker heartbeat\n"); ZFrame frame = new ZFrame(PPP_HEARTBEAT); frame.send(worker, 0); } } ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/psenvpub.java000066400000000000000000000030321255150477200213130ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; /** * Pubsub envelope publisher */ public class psenvpub { public static void main (String[] args) throws Exception { // Prepare our context and publisher Context context = ZMQ.context(1); Socket publisher = context.socket(ZMQ.PUB); publisher.bind("tcp://*:5563"); while (!Thread.currentThread ().isInterrupted ()) { // Write two messages, each with an envelope and content publisher.sendMore ("A"); publisher.send ("We don't want to see this"); publisher.sendMore ("B"); publisher.send("We would like to see this"); } publisher.close (); context.term (); } } jeromq-0.3.5/src/test/java/guide/psenvsub.java000066400000000000000000000031031255150477200213150ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; /** * Pubsub envelope subscriber */ public class psenvsub { public static void main (String[] args) { // Prepare our context and subscriber Context context = ZMQ.context(1); Socket subscriber = context.socket(ZMQ.SUB); subscriber.connect("tcp://localhost:5563"); subscriber.subscribe("B".getBytes(ZMQ.CHARSET)); while (!Thread.currentThread ().isInterrupted ()) { // Read envelope with address String address = subscriber.recvStr (); // Read message contents String contents = subscriber.recvStr (); System.out.println(address + " : " + contents); } subscriber.close (); context.term (); } } jeromq-0.3.5/src/test/java/guide/rrbroker.java000066400000000000000000000052711255150477200213100ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Poller; import org.zeromq.ZMQ.Socket; /** * Simple request-reply broker * */ public class rrbroker{ public static void main (String[] args) { // Prepare our context and sockets Context context = ZMQ.context(1); Socket frontend = context.socket(ZMQ.ROUTER); Socket backend = context.socket(ZMQ.DEALER); frontend.bind("tcp://*:5559"); backend.bind("tcp://*:5560"); System.out.println("launch and connect broker."); // Initialize poll set Poller items = new Poller (2); items.register(frontend, Poller.POLLIN); items.register(backend, Poller.POLLIN); boolean more = false; byte[] message; // Switch messages between sockets while (!Thread.currentThread().isInterrupted()) { // poll and memorize multipart detection items.poll(); if (items.pollin(0)) { while (true) { // receive message message = frontend.recv(0); more = frontend.hasReceiveMore(); // Broker it backend.send(message, more ? ZMQ.SNDMORE : 0); if(!more){ break; } } } if (items.pollin(1)) { while (true) { // receive message message = backend.recv(0); more = backend.hasReceiveMore(); // Broker it frontend.send(message, more ? ZMQ.SNDMORE : 0); if(!more){ break; } } } } // We never get here but clean up anyhow frontend.close(); backend.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/rrclient.java000066400000000000000000000032211255150477200212730ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; /** * Hello World client * Connects REQ socket to tcp://localhost:5559 * Sends "Hello" to server, expects "World" back */ public class rrclient{ public static void main (String[] args) { Context context = ZMQ.context(1); // Socket to talk to server Socket requester = context.socket(ZMQ.REQ); requester.connect("tcp://localhost:5559"); System.out.println("launch and connect client."); for (int request_nbr = 0; request_nbr < 10; request_nbr++) { requester.send("Hello", 0); String reply = requester.recvStr (0); System.out.println("Received reply " + request_nbr + " [" + reply + "]"); } // We never get here but clean up anyhow requester.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/rrworker.java000066400000000000000000000033271255150477200213350ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; // Hello World worker // Connects REP socket to tcp://*:5560 // Expects "Hello" from client, replies with "World" public class rrworker { public static void main (String[] args) throws Exception { Context context = ZMQ.context (1); // Socket to talk to server Socket responder = context.socket (ZMQ.REP); responder.connect ("tcp://localhost:5560"); while (!Thread.currentThread ().isInterrupted ()) { // Wait for next request from client String string = responder.recvStr (0); System.out.printf ("Received request: [%s]\n", string); // Do some 'work' Thread.sleep (1000); // Send reply back to client responder.send ("World"); } // We never get here but clean up anyhow responder.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/rtdealer.java000066400000000000000000000071401255150477200212570ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; import java.util.Random; /** * ROUTER-TO-REQ example */ public class rtdealer { private static Random rand = new Random(); private static final int NBR_WORKERS = 10; private static class Worker extends Thread { @Override public void run() { Context context = ZMQ.context(1); Socket worker = context.socket(ZMQ.DEALER); ZHelper.setId (worker); // Set a printable identity worker.connect("tcp://localhost:5671"); int total = 0; while (true) { // Tell the broker we're ready for work worker.sendMore (""); worker.send ("Hi Boss"); // Get workload from broker, until finished worker.recvStr (); // Envelope delimiter String workload = worker.recvStr (); boolean finished = workload.equals ("Fired!"); if (finished) { System.out.printf ("Completed: %d tasks\n", total); break; } total++; // Do some random work try { Thread.sleep (rand.nextInt (500) + 1); } catch (InterruptedException e) { } } worker.close(); context.term(); } } /** * While this example runs in a single process, that is just to make * it easier to start and stop the example. Each thread has its own * context and conceptually acts as a separate process. */ public static void main (String[] args) throws Exception { Context context = ZMQ.context(1); Socket broker = context.socket(ZMQ.ROUTER); broker.bind("tcp://*:5671"); for (int workerNbr = 0; workerNbr < NBR_WORKERS; workerNbr++) { Thread worker = new Worker (); worker.start (); } // Run for five seconds and then tell workers to end long endTime = System.currentTimeMillis () + 5000; int workersFired = 0; while (true) { // Next message gives us least recently used worker String identity = broker.recvStr (); broker.sendMore (identity); broker.recv (0); // Envelope delimiter broker.recv (0); // Response from worker broker.sendMore (""); // Encourage workers until it's time to fire them if (System.currentTimeMillis () < endTime) broker.send ("Work harder"); else { broker.send ("Fired!"); if (++workersFired == NBR_WORKERS) break; } } broker.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/rtmama.java000066400000000000000000000060251255150477200207370ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; // //Custom routing Router to Mama (ROUTER to REQ) // public class rtmama { private static final int NBR_WORKERS =10; public static class Worker implements Runnable { private final byte[] END = "END".getBytes(ZMQ.CHARSET); public void run() { ZMQ.Context context = ZMQ.context(1); ZMQ.Socket worker = context.socket(ZMQ.REQ); // worker.setIdentity(); will set a random id automatically worker.connect("ipc://routing.ipc"); int total = 0; while (true) { worker.send("ready", 0); byte[] workerload = worker.recv(0); if (new String(workerload, ZMQ.CHARSET).equals("END")) { System.out.println( String.format( "Processs %d tasks.", total ) ); break; } total += 1; } worker.close(); context.term(); } } public static void main(String[] args) { ZMQ.Context context = ZMQ.context(1); ZMQ.Socket client = context.socket(ZMQ.ROUTER); client.bind("ipc://routing.ipc"); for (int i = 0 ; i != NBR_WORKERS; i++) { new Thread(new Worker()).start(); } for (int i = 0 ; i != NBR_WORKERS; i++) { // LRU worker is next waiting in queue byte[] address = client.recv(0); byte[] empty = client.recv(0); byte[] ready = client.recv(0); client.send(address, ZMQ.SNDMORE); client.send("", ZMQ.SNDMORE); client.send("This is the workload", 0); } for (int i = 0 ; i != NBR_WORKERS; i++) { // LRU worker is next waiting in queue byte[] address = client.recv(0); byte[] empty = client.recv(0); byte[] ready = client.recv(0); client.send(address, ZMQ.SNDMORE); client.send("", ZMQ.SNDMORE); client.send("END", 0); } // Now ask mamas to shut down and report their results client.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/rtpapa.java000066400000000000000000000044321255150477200207450ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; // //Custom routing Router to Papa (ROUTER to REP) // import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; public class rtpapa { // We will do this all in one thread to emphasize the getSequence // of events public static void main(String[] args) { Context context = ZMQ.context(1); Socket client = context.socket(ZMQ.ROUTER); client.bind("ipc://routing.ipc"); Socket worker = context.socket(ZMQ.REP); worker.setIdentity("A".getBytes(ZMQ.CHARSET)); worker.connect("ipc://routing.ipc"); // Wait for the worker to connect so that when we send a message // with routing envelope, it will actually match the worker try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // Send papa address, address stack, empty part, and request client.send("A", ZMQ.SNDMORE); client.send("address 3", ZMQ.SNDMORE); client.send("address 2", ZMQ.SNDMORE); client.send("address 1", ZMQ.SNDMORE); client.send("", ZMQ.SNDMORE); client.send("This is the workload", 0); // Worker should get just the workload ZHelper.dump(worker); // We don't play with envelopes in the worker worker.send("This is the reply", 0); // Now dump what we got off the ROUTER socket ZHelper.dump(client); client.close(); worker.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/rtreq.java000066400000000000000000000067741255150477200206260ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; import java.util.Random; /** * ROUTER-TO-REQ example */ public class rtreq { private static Random rand = new Random(); private static final int NBR_WORKERS = 10; private static class Worker extends Thread { @Override public void run() { Context context = ZMQ.context(1); Socket worker = context.socket(ZMQ.REQ); ZHelper.setId (worker); // Set a printable identity worker.connect("tcp://localhost:5671"); int total = 0; while (true) { // Tell the broker we're ready for work worker.send ("Hi Boss"); // Get workload from broker, until finished String workload = worker.recvStr (); boolean finished = workload.equals ("Fired!"); if (finished) { System.out.printf ("Completed: %d tasks\n", total); break; } total++; // Do some random work try { Thread.sleep (rand.nextInt (500) + 1); } catch (InterruptedException e) { } } worker.close(); context.term(); } } /** * While this example runs in a single process, that is just to make * it easier to start and stop the example. Each thread has its own * context and conceptually acts as a separate process. */ public static void main (String[] args) throws Exception { Context context = ZMQ.context(1); Socket broker = context.socket(ZMQ.ROUTER); broker.bind("tcp://*:5671"); for (int workerNbr = 0; workerNbr < NBR_WORKERS; workerNbr++) { Thread worker = new Worker (); worker.start (); } // Run for five seconds and then tell workers to end long endTime = System.currentTimeMillis () + 5000; int workersFired = 0; while (true) { // Next message gives us least recently used worker String identity = broker.recvStr (); broker.sendMore (identity); broker.recvStr (); // Envelope delimiter broker.recvStr (); // Response from worker broker.sendMore (""); // Encourage workers until it's time to fire them if (System.currentTimeMillis () < endTime) broker.send ("Work harder"); else { broker.send ("Fired!"); if (++workersFired == NBR_WORKERS) break; } } broker.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/spqueue.java000066400000000000000000000065151255150477200211510ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.ArrayList; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Poller; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; // // Simple Pirate queue // This is identical to load-balancing pattern, with no reliability mechanisms // at all. It depends on the client for recovery. Runs forever. // public class spqueue { private final static String WORKER_READY = "\001"; // Signals worker is ready public static void main(String[] args) { ZContext ctx = new ZContext(); Socket frontend = ctx.createSocket(ZMQ.ROUTER); Socket backend = ctx.createSocket(ZMQ.ROUTER); frontend.bind("tcp://*:5555"); // For clients backend.bind("tcp://*:5556"); // For workers // Queue of available workers ArrayList workers = new ArrayList(); // The body of this example is exactly the same as lruqueue2. while (true) { PollItem items[] = { new PollItem(backend, Poller.POLLIN), new PollItem(frontend, Poller.POLLIN) }; int rc = ZMQ.poll(items, workers.size() > 0 ? 2 : 1, -1); // Poll frontend only if we have available workers if (rc == -1) break; // Interrupted // Handle worker activity on backend if (items[0].isReadable()) { // Use worker address for LRU routing ZMsg msg = ZMsg.recvMsg(backend); if (msg == null) break; // Interrupted ZFrame address = msg.unwrap(); workers.add(address); // Forward message to client if it's not a READY ZFrame frame = msg.getFirst(); if (new String(frame.getData(), ZMQ.CHARSET).equals(WORKER_READY)) msg.destroy(); else msg.send(frontend); } if (items[1].isReadable()) { // Get client request, route to first available worker ZMsg msg = ZMsg.recvMsg(frontend); if (msg != null) { msg.wrap(workers.remove(0)); msg.send(backend); } } } // When we're done, clean up properly while (workers.size() > 0) { ZFrame frame = workers.remove(0); frame.destroy(); } workers.clear(); ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/spworker.java000066400000000000000000000051531255150477200213330ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.Random; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; // // Simple Pirate worker // Connects REQ socket to tcp://*:5556 // Implements worker part of load-balancing queueing // public class spworker { private final static String WORKER_READY = "\001"; // Signals worker is ready public static void main(String[] args) throws Exception { ZContext ctx = new ZContext(); Socket worker = ctx.createSocket(ZMQ.REQ); // Set random identity to make tracing easier Random rand = new Random(System.nanoTime()); String identity = String.format("%04X-%04X", rand.nextInt(0x10000), rand.nextInt(0x10000)); worker.setIdentity(identity.getBytes(ZMQ.CHARSET)); worker.connect("tcp://localhost:5556"); // Tell broker we're ready for work System.out.printf("I: (%s) worker ready\n", identity); ZFrame frame = new ZFrame(WORKER_READY); frame.send(worker, 0); int cycles = 0; while (true) { ZMsg msg = ZMsg.recvMsg(worker); if (msg == null) break; // Interrupted // Simulate various problems, after a few cycles cycles++; if (cycles > 3 && rand.nextInt(5) == 0) { System.out.printf("I: (%s) simulating a crash\n", identity); msg.destroy(); break; } else if (cycles > 3 && rand.nextInt(5) == 0) { System.out.printf("I: (%s) simulating CPU overload\n", identity); Thread.sleep(3000); } System.out.printf("I: (%s) normal reply\n", identity); Thread.sleep(1000); // Do some heavy work msg.send(worker); } ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/suisnail.java000066400000000000000000000076561255150477200213200ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; // Suicidal Snail import org.zeromq.ZContext; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Socket; import org.zeromq.ZThread; import org.zeromq.ZThread.IAttachedRunnable; import java.util.Random; public class suisnail { private static final long MAX_ALLOWED_DELAY = 1000; // msecs private static Random rand = new Random(System.currentTimeMillis()); // This is our subscriber. It connects to the publisher and subscribes // to everything. It sleeps for a short time between messages to // simulate doing too much work. If a message is more than one second // late, it croaks. private static class Subscriber implements IAttachedRunnable { @Override public void run(Object[] args, ZContext ctx, Socket pipe) { // Subscribe to everything Socket subscriber = ctx.createSocket(ZMQ.SUB); subscriber.subscribe(ZMQ.SUBSCRIPTION_ALL); subscriber.connect("tcp://localhost:5556"); // Get and process messages while (true) { String string = subscriber.recvStr(); System.out.printf("%s\n", string); long clock = Long.parseLong(string); // Suicide snail logic if (System.currentTimeMillis() - clock > MAX_ALLOWED_DELAY) { System.err.println("E: subscriber cannot keep up, aborting"); break; } // Work for 1 msec plus some random additional time try { Thread.sleep(1000 + rand.nextInt(2000)); } catch (InterruptedException e) { break; } } pipe.send("gone and died"); } } // .split publisher task // This is our publisher task. It publishes a time-stamped message to its // PUB socket every millisecond: private static class Publisher implements IAttachedRunnable { @Override public void run(Object[] args, ZContext ctx, Socket pipe) { // Prepare publisher Socket publisher = ctx.createSocket(ZMQ.PUB); publisher.bind("tcp://*:5556"); while (true) { // Send current clock (msecs) to subscribers String string = String.format("%d", System.currentTimeMillis()); publisher.send(string); String signal = pipe.recvStr(ZMQ.DONTWAIT); if (signal != null) { break; } try { Thread.sleep(1); } catch (InterruptedException e) { } } } } // .split main task // The main task simply starts a client and a server, and then // waits for the client to signal that it has died: public static void main (String[] args) throws Exception { ZContext ctx = new ZContext(); Socket pubpipe = ZThread.fork(ctx, new Publisher()); Socket subpipe = ZThread.fork(ctx, new Subscriber()); subpipe.recvStr(); pubpipe.send("break"); Thread.sleep(100); ctx.destroy(); } } jeromq-0.3.5/src/test/java/guide/syncpub.java000066400000000000000000000044371255150477200211460ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; /** * Synchronized publisher. */ public class syncpub{ /** * We wait for 10 subscribers */ protected static int SUBSCRIBERS_EXPECTED = 10; public static void main (String[] args) { Context context = ZMQ.context(1); // Socket to talk to clients Socket publisher = context.socket(ZMQ.PUB); publisher.setLinger(5000); // In 0MQ 3.x pub socket could drop messages if sub can follow the generation of pub messages publisher.setSndHWM(0); publisher.bind("tcp://*:5561"); // Socket to receive signals Socket syncservice = context.socket(ZMQ.REP); syncservice.bind("tcp://*:5562"); System.out.println("Waiting subscribers"); // Get synchronization from subscribers int subscribers = 0; while (subscribers < SUBSCRIBERS_EXPECTED) { // - wait for synchronization request syncservice.recv(0); // - send synchronization reply syncservice.send("", 0); subscribers++; } // Now broadcast exactly 1M updates followed by END System.out.println ("Broadcasting messages"); int update_nbr; for (update_nbr = 0; update_nbr < 1000000; update_nbr++){ publisher.send("Rhubarb", 0); } publisher.send("END", 0); // clean up publisher.close(); syncservice.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/syncsub.java000066400000000000000000000036701255150477200211470ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; /** * Synchronized subscriber. */ public class syncsub{ public static void main (String[] args) { Context context = ZMQ.context(1); // First, connect our subscriber socket Socket subscriber = context.socket(ZMQ.SUB); subscriber.connect("tcp://localhost:5561"); subscriber.subscribe(ZMQ.SUBSCRIPTION_ALL); // Second, synchronize with publisher Socket syncclient = context.socket(ZMQ.REQ); syncclient.connect("tcp://localhost:5562"); // - send a synchronization request syncclient.send(ZMQ.MESSAGE_SEPARATOR, 0); // - wait for synchronization reply syncclient.recv(0); // Third, get our updates and report how many we got int update_nbr = 0; while (true) { String string = subscriber.recvStr(0); if (string.equals("END")) { break; } update_nbr++; } System.out.println("Received " + update_nbr + " updates."); subscriber.close(); syncclient.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/tasksink.java000066400000000000000000000040131255150477200213000ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; // // Task sink in Java // Binds PULL socket to tcp://localhost:5558 // Collects results from workers via that socket // public class tasksink { public static void main (String[] args) throws Exception { // Prepare our context and socket ZMQ.Context context = ZMQ.context(1); ZMQ.Socket receiver = context.socket(ZMQ.PULL); receiver.bind("tcp://*:5558"); // Wait for start of batch String string = new String(receiver.recv(0), ZMQ.CHARSET); // Start our clock now long tstart = System.currentTimeMillis(); // Process 100 confirmations int task_nbr; int total_msec = 0; // Total calculated cost in msecs for (task_nbr = 0; task_nbr < 100; task_nbr++) { string = new String(receiver.recv(0), ZMQ.CHARSET).trim(); if ((task_nbr / 10) * 10 == task_nbr) { System.out.print(":"); } else { System.out.print("."); } } // Calculate and report duration of batch long tend = System.currentTimeMillis(); System.out.println("\nTotal elapsed time: " + (tend - tstart) + " msec"); receiver.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/tasksink2.java000066400000000000000000000043221255150477200213650ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; /** * Task sink - design 2 * Adds pub-sub flow to send kill signal to workers */ public class tasksink2 { public static void main (String[] args) throws Exception { // Prepare our context and socket ZMQ.Context context = ZMQ.context(1); ZMQ.Socket receiver = context.socket(ZMQ.PULL); receiver.bind("tcp://*:5558"); // Socket for worker control ZMQ.Socket controller = context.socket(ZMQ.PUB); controller.bind("tcp://*:5559"); // Wait for start of batch receiver.recv(0); // Start our clock now long tstart = System.currentTimeMillis(); // Process 100 confirmations int task_nbr; for (task_nbr = 0; task_nbr < 100; task_nbr++) { receiver.recv(0); if ((task_nbr / 10) * 10 == task_nbr) { System.out.print(":"); } else { System.out.print("."); } System.out.flush(); } // Calculate and report duration of batch long tend = System.currentTimeMillis(); System.out.println("Total elapsed time: " + (tend - tstart) + " msec"); // Send the kill signal to the workers controller.send("KILL", 0); // Give it some time to deliver Thread.sleep(1); receiver.close(); controller.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/taskvent.java000066400000000000000000000046041255150477200213160ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.Random; import org.zeromq.ZMQ; // // Task ventilator in Java // Binds PUSH socket to tcp://localhost:5557 // Sends batch of tasks to workers via that socket // public class taskvent { public static void main (String[] args) throws Exception { ZMQ.Context context = ZMQ.context(1); // Socket to send messages on ZMQ.Socket sender = context.socket(ZMQ.PUSH); sender.bind("tcp://*:5557"); // Socket to send messages on ZMQ.Socket sink = context.socket(ZMQ.PUSH); sink.connect("tcp://localhost:5558"); System.out.println("Press Enter when the workers are ready: "); System.in.read(); System.out.println("Sending tasks to workers\n"); // The first message is "0" and signals start of batch sink.send("0", 0); // Initialize random number generator Random srandom = new Random(System.currentTimeMillis()); // Send 100 tasks int task_nbr; int total_msec = 0; // Total expected cost in msecs for (task_nbr = 0; task_nbr < 100; task_nbr++) { int workload; // Random workload from 1 to 100msecs workload = srandom.nextInt(100) + 1; total_msec += workload; System.out.print(workload + "."); String string = String.format("%d", workload); sender.send(string, 0); } System.out.println("Total expected cost: " + total_msec + " msec"); Thread.sleep(1000); // Give 0MQ time to deliver sink.close(); sender.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/taskwork.java000066400000000000000000000040021255150477200213140ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; // // Task worker in Java // Connects PULL socket to tcp://localhost:5557 // Collects workloads from ventilator via that socket // Connects PUSH socket to tcp://localhost:5558 // Sends results to sink via that socket // public class taskwork { public static void main (String[] args) throws Exception { ZMQ.Context context = ZMQ.context(1); // Socket to receive messages on ZMQ.Socket receiver = context.socket(ZMQ.PULL); receiver.connect("tcp://localhost:5557"); // Socket to send messages to ZMQ.Socket sender = context.socket(ZMQ.PUSH); sender.connect("tcp://localhost:5558"); // Process tasks forever while (!Thread.currentThread ().isInterrupted ()) { String string = new String(receiver.recv(0), ZMQ.CHARSET).trim(); long msec = Long.parseLong(string); // Simple progress indicator for the viewer System.out.flush(); System.out.print(string + '.'); // Do the work Thread.sleep(msec); // Send results to sink sender.send(ZMQ.MESSAGE_SEPARATOR, 0); } sender.close(); receiver.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/taskwork2.java000066400000000000000000000045561255150477200214140ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; /** * Task worker - design 2 * Adds pub-sub flow to receive and respond to kill signal */ public class taskwork2 { public static void main (String[] args) throws InterruptedException { ZMQ.Context context = ZMQ.context(1); ZMQ.Socket receiver = context.socket(ZMQ.PULL); receiver.connect("tcp://localhost:5557"); ZMQ.Socket sender = context.socket(ZMQ.PUSH); sender.connect("tcp://localhost:5558"); ZMQ.Socket controller = context.socket(ZMQ.SUB); controller.connect("tcp://localhost:5559"); controller.subscribe(ZMQ.SUBSCRIPTION_ALL); ZMQ.Poller items = new ZMQ.Poller (2); items.register(receiver, ZMQ.Poller.POLLIN); items.register(controller, ZMQ.Poller.POLLIN); while (true) { items.poll(); if (items.pollin(0)) { String message = receiver.recvStr (0); long nsec = Long.parseLong(message); // Simple progress indicator for the viewer System.out.print(message + '.'); System.out.flush(); // Do the work Thread.sleep(nsec); // Send results to sink sender.send("", 0); } // Any waiting controller command acts as 'KILL' if (items.pollin(1)) { break; // Exit loop } } // Finished receiver.close(); sender.close(); controller.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/ticlient.java000066400000000000000000000064451255150477200212770ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; // Titanic client example // Implements client side of http://rfc.zeromq.org/spec:9 // Calls a TSP service // Returns response if successful (status code 200 OK), else NULL // import org.zeromq.ZFrame; import org.zeromq.ZMsg; public class ticlient { static ZMsg serviceCall (mdcliapi session, String service, ZMsg request) { ZMsg reply = session.send(service, request); if (reply != null) { ZFrame status = reply.pop(); if (status.streq("200")) { status.destroy(); return reply; } else if (status.streq("400")) { System.out.println("E: client fatal error, aborting"); } else if (status.streq("500")) { System.out.println("E: server fatal error, aborting"); } reply.destroy(); } return null; // Didn't succeed; don't care why not } public static void main (String[] args) throws Exception { boolean verbose = (args.length > 0 && args[0].equals("-v")); mdcliapi session = new mdcliapi("tcp://localhost:5555", verbose); // 1. Send 'echo' request to Titanic ZMsg request = new ZMsg(); request.add("echo"); request.add("Hello world"); ZMsg reply = serviceCall( session, "titanic.request", request); ZFrame uuid = null; if (reply != null) { uuid = reply.pop(); reply.destroy(); uuid.print("I: request UUID "); } // 2. Wait until we get a reply while (!Thread.currentThread().isInterrupted()) { Thread.sleep(100); request = new ZMsg(); request.add(uuid.duplicate()); reply = serviceCall( session, "titanic.reply", request); if (reply != null) { String replyString = reply.getLast().toString(); System.out.printf ("Reply: %s\n", replyString); reply.destroy(); // 3. Close request request = new ZMsg(); request.add(uuid.duplicate()); reply = serviceCall(session, "titanic.close", request); reply.destroy(); break; } else { System.out.println("I: no reply yet, trying again..."); Thread.sleep (5000); // Try again in 5 seconds } } uuid.destroy(); session.destroy(); } } jeromq-0.3.5/src/test/java/guide/titanic.java000066400000000000000000000323501255150477200211110ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; import org.zeromq.ZThread; import org.zeromq.ZThread.IAttachedRunnable; import org.zeromq.ZThread.IDetachedRunnable; import java.io.BufferedWriter; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.RandomAccessFile; import java.util.UUID; public class titanic { // Return a new UUID as a printable character string // Caller must free returned string when finished with it static String generateUUID() { return UUID.randomUUID().toString(); } private static final String TITANIC_DIR = ".titanic"; // Returns freshly allocated request filename for given UUID private static String requestFilename(String uuid) { String filename = String.format("%s/%s.req", TITANIC_DIR, uuid); return filename; } // Returns freshly allocated reply filename for given UUID private static String replyFilename(String uuid) { String filename = String.format("%s/%s.rep", TITANIC_DIR, uuid); return filename; } // .split Titanic request service // The {{titanic.request}} task waits for requests to this service. It writes // each request to disk and returns a UUID to the client. The client picks // up the reply asynchronously using the {{titanic.reply}} service: static class TitanicRequest implements IAttachedRunnable { @Override public void run(Object[] args, ZContext ctx, Socket pipe) { mdwrkapi worker = new mdwrkapi( "tcp://localhost:5555", "titanic.request", false); ZMsg reply = null; while (true) { // Send reply if it's not null // And then get next request from broker ZMsg request = worker.receive(reply); if (request == null) break; // Interrupted, exit // Ensure message directory exists new File(TITANIC_DIR).mkdirs(); // Generate UUID and save message to disk String uuid = generateUUID(); String filename = requestFilename(uuid); DataOutputStream file = null; try { file = new DataOutputStream(new FileOutputStream(filename)); ZMsg.save(request, file); } catch (IOException e) { e.printStackTrace(); } finally { try { if (file != null) file.close(); } catch (IOException e) { } } request.destroy(); // Send UUID through to message queue reply = new ZMsg(); reply.add(uuid); reply.send(pipe); // Now send UUID back to client // Done by the mdwrk_recv() at the top of the loop reply = new ZMsg(); reply.add("200"); reply.add(uuid); } worker.destroy(); } } // .split Titanic reply service // The {{titanic.reply}} task checks if there's a reply for the specified // request (by UUID), and returns a 200 (OK), 300 (Pending), or 400 // (Unknown) accordingly: static class TitanicReply implements IDetachedRunnable { @Override public void run(Object[] args) { mdwrkapi worker = new mdwrkapi( "tcp://localhost:5555", "titanic.reply", false); ZMsg reply = null; while (true) { ZMsg request = worker.receive(reply); if (request == null) break; // Interrupted, exit String uuid = request.popString(); String reqFilename = requestFilename(uuid); String repFilename = replyFilename(uuid); if (new File(repFilename).exists()) { DataInputStream file = null; try { file = new DataInputStream(new FileInputStream(repFilename)); reply = ZMsg.load(file); reply.push("200"); } catch (IOException e) { e.printStackTrace(); } finally { try { if (file != null) file.close(); } catch (IOException e) { } } } else { reply = new ZMsg(); if (new File(reqFilename).exists()) reply.push("300"); //Pending else reply.push("400"); //Unknown } request.destroy(); } worker.destroy(); } } // .split Titanic close task // The {{titanic.close}} task removes any waiting replies for the request // (specified by UUID). It's idempotent, so it is safe to call more than // once in a row: static class TitanicClose implements IDetachedRunnable { @Override public void run(Object[] args) { mdwrkapi worker = new mdwrkapi( "tcp://localhost:5555", "titanic.close", false); ZMsg reply = null; while (true) { ZMsg request = worker.receive(reply); if (request == null) break; // Interrupted, exit String uuid = request.popString(); String req_filename = requestFilename(uuid); String rep_filename = replyFilename(uuid); new File(rep_filename).delete(); new File(req_filename).delete(); request.destroy(); reply = new ZMsg(); reply.add("200"); } worker.destroy(); } } // .split worker task // This is the main thread for the Titanic worker. It starts three child // threads; for the request, reply, and close services. It then dispatches // requests to workers using a simple brute force disk queue. It receives // request UUIDs from the {{titanic.request}} service, saves these to a disk // file, and then throws each request at MDP workers until it gets a // response. public static void main(String[] args) { boolean verbose = (args.length > 0 && "-v".equals(args[0])); ZContext ctx = new ZContext(); Socket requestPipe = ZThread.fork(ctx, new TitanicRequest()); ZThread.start(new TitanicReply()); ZThread.start(new TitanicClose()); // Main dispatcher loop while (true) { // We'll dispatch once per second, if there's no activity PollItem items [] = { new PollItem(requestPipe, ZMQ.Poller.POLLIN) }; int rc = ZMQ.poll(items, 1, 1000); if (rc == -1) break; // Interrupted if (items [0].isReadable()) { // Ensure message directory exists new File(TITANIC_DIR).mkdirs(); // Append UUID to queue, prefixed with '-' for pending ZMsg msg = ZMsg.recvMsg(requestPipe); if (msg == null) break; // Interrupted String uuid = msg.popString(); BufferedWriter wfile = null; try { wfile = new BufferedWriter(new FileWriter(TITANIC_DIR + "/queue", true)); wfile.write("-" + uuid + "\n"); } catch (IOException e) { e.printStackTrace(); break; } finally { try { if (wfile != null) wfile.close(); } catch (IOException e) { } } msg.destroy(); } // Brute force dispatcher byte[] entry = new byte[37]; //"?........:....:....:....:............:"; RandomAccessFile file = null; try { file = new RandomAccessFile(TITANIC_DIR + "/queue", "rw"); while (file.read(entry) > 0) { // UUID is prefixed with '-' if still waiting if (entry[0] == '-') { if (verbose) System.out.printf("I: processing request %s\n", new String(entry, 1, entry.length -1, ZMQ.CHARSET)); if (serviceSuccess(new String(entry, 1, entry.length -1, ZMQ.CHARSET))) { // Mark queue entry as processed file.seek(file.getFilePointer() - 37); file.writeBytes("+"); file.seek(file.getFilePointer() + 36); } } // Skip end of line, LF or CRLF if (file.readByte() == '\r') file.readByte(); if (Thread.currentThread().isInterrupted()) break; } } catch (FileNotFoundException e) { } catch (IOException e) { e.printStackTrace(); } finally { if (file != null) { try { file.close(); } catch (IOException e) { } } } } } // .split try to call a service // Here, we first check if the requested MDP service is defined or not, // using a MMI lookup to the Majordomo broker. If the service exists, // we send a request and wait for a reply using the conventional MDP // client API. This is not meant to be fast, just very simple: static boolean serviceSuccess(String uuid) { // Load request message, service will be first frame String filename = requestFilename(uuid); // If the client already closed request, treat as successful if (!new File(filename).exists()) return true; DataInputStream file = null; ZMsg request; try { file = new DataInputStream(new FileInputStream(filename)); request = ZMsg.load(file); } catch (IOException e) { e.printStackTrace(); return true; } finally { try { if (file != null) file.close(); } catch (IOException e) { } } ZFrame service = request.pop(); String serviceName = service.toString(); // Create MDP client session with short timeout mdcliapi client = new mdcliapi("tcp://localhost:5555", false); client.setTimeout(1000); // 1 sec client.setRetries(1); // only 1 retry // Use MMI protocol to check if service is available ZMsg mmiRequest = new ZMsg(); mmiRequest.add(service); ZMsg mmiReply = client.send("mmi.service", mmiRequest); boolean serviceOK = (mmiReply != null && mmiReply.getFirst().toString().equals("200")); mmiReply.destroy(); boolean result = false; if (serviceOK) { ZMsg reply = client.send(serviceName, request); if (reply != null) { filename = replyFilename(uuid); DataOutputStream ofile = null; try { ofile = new DataOutputStream(new FileOutputStream(filename)); ZMsg.save(reply, ofile); } catch (IOException e) { e.printStackTrace(); return true; } finally { try { if (file != null) file.close(); } catch (IOException e) { } } result = true; } reply.destroy();; } else request.destroy(); client.destroy(); return result; } } jeromq-0.3.5/src/test/java/guide/tripping.java000066400000000000000000000130411255150477200213060ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZContext; import org.zeromq.ZFrame; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMsg; /** * Round-trip demonstrator. Broker, Worker and Client are mocked as separate * threads. */ public class tripping { static class Broker implements Runnable { @Override public void run() { ZContext ctx = new ZContext(); Socket frontend = ctx.createSocket(ZMQ.ROUTER); Socket backend = ctx.createSocket(ZMQ.ROUTER); frontend.setHWM (0); backend.setHWM (0); frontend.bind("tcp://*:5555"); backend.bind("tcp://*:5556"); while (!Thread.currentThread().isInterrupted()) { ZMQ.Poller items = new ZMQ.Poller(2); items.register(frontend, ZMQ.Poller.POLLIN); items.register(backend, ZMQ.Poller.POLLIN); if (items.poll() == -1) break; // Interrupted if (items.pollin(0)) { ZMsg msg = ZMsg.recvMsg(frontend); if (msg == null) break; // Interrupted ZFrame address = msg.pop(); address.destroy(); msg.addFirst(new ZFrame("W")); msg.send(backend); } if (items.pollin(1)) { ZMsg msg = ZMsg.recvMsg(backend); if (msg == null) break; // Interrupted ZFrame address = msg.pop(); address.destroy(); msg.addFirst(new ZFrame("C")); msg.send(frontend); } } ctx.destroy(); } } static class Worker implements Runnable { @Override public void run() { ZContext ctx = new ZContext(); Socket worker = ctx.createSocket(ZMQ.DEALER); worker.setHWM (0); worker.setIdentity("W".getBytes(ZMQ.CHARSET)); worker.connect("tcp://localhost:5556"); while (!Thread.currentThread().isInterrupted()) { ZMsg msg = ZMsg.recvMsg(worker); msg.send(worker); } ctx.destroy(); } } static class Client implements Runnable { private static int SAMPLE_SIZE = 10000; @Override public void run() { ZContext ctx = new ZContext(); Socket client = ctx.createSocket(ZMQ.DEALER); client.setHWM (0); client.setIdentity("C".getBytes(ZMQ.CHARSET)); client.connect("tcp://localhost:5555"); System.out.println("Setting up test"); try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } int requests; long start; System.out.println("Synchronous round-trip test"); start = System.currentTimeMillis(); for (requests = 0; requests < SAMPLE_SIZE; requests++) { ZMsg req = new ZMsg(); req.addString("hello"); req.send(client); ZMsg.recvMsg(client).destroy(); } System.out.printf(" %d calls/second\n", (1000 * SAMPLE_SIZE) / (System.currentTimeMillis() - start)); System.out.println("Asynchronous round-trip test"); start = System.currentTimeMillis(); for (requests = 0; requests < SAMPLE_SIZE; requests++) { ZMsg req = new ZMsg(); req.addString("hello"); req.send(client); } for (requests = 0; requests < SAMPLE_SIZE && !Thread.currentThread().isInterrupted(); requests++) { ZMsg.recvMsg(client).destroy(); } System.out.printf(" %d calls/second\n", (1000 * SAMPLE_SIZE) / (System.currentTimeMillis() - start)); ctx.destroy(); } } public static void main(String[] args) { if (args.length==1) Client.SAMPLE_SIZE = Integer.parseInt(args[0]); Thread brokerThread = new Thread(new Broker()); Thread workerThread = new Thread(new Worker()); Thread clientThread = new Thread(new Client()); brokerThread.setDaemon(true); workerThread.setDaemon(true); brokerThread.start(); workerThread.start(); clientThread.start(); try { clientThread.join(); workerThread.interrupt(); brokerThread.interrupt(); Thread.sleep(200);// give them some time } catch (InterruptedException e) { } } } jeromq-0.3.5/src/test/java/guide/version.java000066400000000000000000000020521255150477200211370ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; // Report 0MQ version public class version { public static void main (String[] args) { System.out.println(String.format("Version string: %s, Version int: %d", ZMQ.getVersionString(), ZMQ.getFullVersion())); } } jeromq-0.3.5/src/test/java/guide/wuclient.java000066400000000000000000000043641255150477200213140ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.StringTokenizer; import org.zeromq.ZMQ; // // Weather update client in Java // Connects SUB socket to tcp://localhost:5556 // Collects weather updates and finds avg temp in zipcode // public class wuclient { public static void main (String[] args) { ZMQ.Context context = ZMQ.context(1); // Socket to talk to server System.out.println("Collecting updates from weather server"); ZMQ.Socket subscriber = context.socket(ZMQ.SUB); subscriber.connect("tcp://localhost:5556"); // Subscribe to zipcode, default is NYC, 10001 String filter = (args.length > 0) ? args[0] : "10001 "; subscriber.subscribe(filter.getBytes(ZMQ.CHARSET)); // Process 100 updates int update_nbr; long total_temp = 0; for (update_nbr = 0; update_nbr < 100; update_nbr++) { // Use trim to remove the tailing '0' character String string = subscriber.recvStr(0).trim(); StringTokenizer sscanf = new StringTokenizer(string, " "); int zipcode = Integer.valueOf(sscanf.nextToken()); int temperature = Integer.valueOf(sscanf.nextToken()); int relhumidity = Integer.valueOf(sscanf.nextToken()); total_temp += temperature; } System.out.println("Average temperature for zipcode '" + filter + "' was " + (int) (total_temp / update_nbr)); subscriber.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/wuproxy.java000066400000000000000000000031421255150477200212100ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; /** * Weather proxy device. */ public class wuproxy{ public static void main (String[] args) { // Prepare our context and sockets Context context = ZMQ.context(1); // This is where the weather server sits Socket frontend = context.socket(ZMQ.SUB); frontend.connect("tcp://192.168.55.210:5556"); // This is our public endpoint for subscribers Socket backend = context.socket(ZMQ.PUB); backend.bind("tcp://10.1.1.0:8100"); // Subscribe on everything frontend.subscribe(ZMQ.SUBSCRIPTION_ALL); // Run the proxy until the user interrupts us ZMQ.proxy (frontend, backend, null); frontend.close(); backend.close(); context.term(); } } jeromq-0.3.5/src/test/java/guide/wuserver.java000066400000000000000000000036441255150477200213440ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package guide; import java.util.Random; import org.zeromq.ZMQ; // // Weather update server in Java // Binds PUB socket to tcp://*:5556 // Publishes random weather updates // public class wuserver { public static void main (String[] args) throws Exception { // Prepare our context and publisher ZMQ.Context context = ZMQ.context(1); ZMQ.Socket publisher = context.socket(ZMQ.PUB); publisher.bind("tcp://*:5556"); publisher.bind("ipc://weather"); // Initialize random number generator Random srandom = new Random(System.currentTimeMillis()); while (!Thread.currentThread ().isInterrupted ()) { // Get values that will fool the boss int zipcode, temperature, relhumidity; zipcode = 10000 + srandom.nextInt(10000) ; temperature = srandom.nextInt(215) - 80 + 1; relhumidity = srandom.nextInt(50) + 10 + 1; // Send message to all subscribers String update = String.format("%05d %d %d", zipcode, temperature, relhumidity); publisher.send(update, 0); } publisher.close (); context.term (); } } jeromq-0.3.5/src/test/java/org/000077500000000000000000000000001255150477200163025ustar00rootroot00000000000000jeromq-0.3.5/src/test/java/org/zeromq/000077500000000000000000000000001255150477200176175ustar00rootroot00000000000000jeromq-0.3.5/src/test/java/org/zeromq/TestProxy.java000066400000000000000000000101731255150477200224450ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; import org.junit.Test; import static org.junit.Assert.assertNotNull; public class TestProxy { static class Client extends Thread { private Socket s = null; private String name = null; public Client(Context ctx, String name) { s = ctx.socket(ZMQ.REQ); this.name = name; s.setIdentity(name.getBytes(ZMQ.CHARSET)); } @Override public void run() { s.connect("tcp://127.0.0.1:6660"); s.send("hello", 0); String msg = s.recvStr(0); s.send("world", 0); msg = s.recvStr(0); s.close(); } } static class Dealer extends Thread { private Socket s = null; private String name = null; public Dealer(Context ctx, String name) { s = ctx.socket(ZMQ.DEALER); this.name = name; s.setIdentity(name.getBytes(ZMQ.CHARSET)); } @Override public void run() { System.out.println("Start dealer " + name); s.connect("tcp://127.0.0.1:6661"); int count = 0; while (count < 2) { String msg = s.recvStr(0); if (msg == null) { throw new RuntimeException(); } String identity = msg; System.out.println(name + " received client identity " + identity); msg = s.recvStr(0); if (msg == null) { throw new RuntimeException(); } System.out.println(name + " received bottom " + msg); msg = s.recvStr(0); if (msg == null) { throw new RuntimeException(); } String data = msg; System.out.println(name + " received data " + msg + " " + data); s.send(identity, ZMQ.SNDMORE); s.send((byte[]) null, ZMQ.SNDMORE); String response = "OK " + data; s.send(response, 0); count++; } s.close(); System.out.println("Stop dealer " + name); } } static class Main extends Thread { Context ctx; Main(Context ctx) { this.ctx = ctx; } @Override public void run() { Socket frontend = ctx.socket(ZMQ.ROUTER); assertNotNull(frontend); frontend.bind("tcp://127.0.0.1:6660"); Socket backend = ctx.socket(ZMQ.DEALER); assertNotNull(backend); backend.bind("tcp://127.0.0.1:6661"); ZMQ.proxy(frontend, backend, null); frontend.close(); backend.close(); assert true; } } @Test public void testProxy() throws Exception { Context ctx = ZMQ.context(1); assert (ctx != null); Main mt = new Main(ctx); mt.start(); new Dealer(ctx, "AA").start(); new Dealer(ctx, "BB").start(); Thread.sleep(1000); Thread c1 = new Client(ctx, "X"); c1.start(); Thread c2 = new Client(ctx, "Y"); c2.start(); c1.join(); c2.join(); ctx.term(); } } jeromq-0.3.5/src/test/java/org/zeromq/TestReqRouterThreadedTcp.java000066400000000000000000000125771255150477200253760ustar00rootroot00000000000000package org.zeromq; /* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.junit.Assert.assertThat; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; import org.zeromq.ZMQ.Socket; /** * Tests a REQ-ROUTER dialog with several methods, * each component being on a separate thread. * @author fred * */ public class TestReqRouterThreadedTcp { private static final long REQUEST_TIMEOUT = 1000; // msecs /** * A very simple server for one reply only. * @author fred * */ private class Server extends Thread { private final int port; /** * Creates a new server. * @param port the port to which to connect. */ public Server(int port) { this.port = port; } @Override public void run() { ZContext ctx = new ZContext(); ZMQ.Socket server = ctx.createSocket(ZMQ.ROUTER); server.bind("tcp://localhost:" + port); ZMsg msg = ZMsg.recvMsg(server); // only one echo message for this server msg.send(server); msg.destroy(); // Clean up. ctx.destroySocket(server); ctx.close(); } } private class Client extends Thread { private final int port; final AtomicBoolean finished = new AtomicBoolean(); /** * Creates a new client. * @param port the port to which to connect. */ public Client(int port) { this.port = port; } @Override public void run() { ZContext ctx = new ZContext(); ZMQ.Socket client = ctx.createSocket(ZMQ.REQ); client.connect("tcp://localhost:" + port); client.send("DATA"); inBetween(client); String reply = client.recvStr(); assertThat(reply, notNullValue()); assertThat(reply, is("DATA")); // Clean up. ctx.destroySocket(client); ctx.close(); finished.set(true); } /** * Called between the request-reply cycle. * @param client the socket participating to the cycle of request-reply */ protected void inBetween(Socket client) { // to be overriden } } private class ClientPoll extends Client { public ClientPoll(int port) { super(port); } // same results // @Override // protected void inBetween(Socket client) { // // Poll socket for a reply, with timeout // PollItem items[] = { new PollItem(client, ZMQ.Poller.POLLIN) }; // int rc = ZMQ.poll(items, 1, REQUEST_TIMEOUT); // assertThat(rc, is(1)); // boolean readable = items[0].isReadable(); // assertThat(readable, is(true)); // } /** * Here we use a poller to check for readability of the message. * This should activate the prefetching mechanism. */ @Override protected void inBetween(Socket client) { // Poll socket for a reply, with timeout ZMQ.Poller poller = new ZMQ.Poller(1); poller.register(client, ZMQ.Poller.POLLIN); int rc = poller.poll(REQUEST_TIMEOUT); assertThat(rc, is(1)); boolean readable = poller.pollin(0); assertThat(readable, is(true)); // now a message should have been prefetched } } /** * Test dialog directly. * @throws Exception if something bad occurs. */ @Test public void testReqRouterTcp() throws Exception { int port = 5962; Server server = new Server(port); server.start(); Client client = new Client(port); client.start(); server.join(); client.join(); boolean finished = client.finished.get(); assertThat(finished, is(true)); } /** * Test dialog with a polling access in between request-reply. * This should activate the prefetching mechanism. * @throws Exception if something bad occurs. */ @Test public void testReqRouterTcpPoll() throws Exception { int port = 5963; Server server = new Server(port); server.start(); ClientPoll client = new ClientPoll(port); client.start(); server.join(); client.join(); boolean finished = client.finished.get(); assertThat(finished, is(true)); } } jeromq-0.3.5/src/test/java/org/zeromq/TestZActor.java000066400000000000000000000112171255150477200225260ustar00rootroot00000000000000package org.zeromq; import java.util.Arrays; import java.util.List; import java.util.UUID; import org.junit.Assert; import org.junit.Test; import org.zeromq.ZActor.Actor; import org.zeromq.ZMQ.Socket; import zmq.ZError; public class TestZActor { private class MiniActor extends ZActor.SimpleActor { } @Test public void testMinimalistic() { Actor acting = new ZActor.SimpleActor() { @Override public List createSockets(ZContext ctx, Object[] args) { assert ("TEST".equals(args[0])); return Arrays.asList(ctx.createSocket(ZMQ.PUB)); } @Override public boolean backstage(Socket pipe, ZPoller poller, int events) { String string = pipe.recvStr(); if ("HELLO".equals(string)) { pipe.send("WORLD"); return false; } return true; } }; ZActor actor = new ZActor(acting, "LOCK", Arrays.asList("TEST").toArray()); Socket pipe = actor.pipe(); boolean rc = pipe.send("HELLO"); Assert.assertTrue("Unable to send a message through pipe", rc); ZMsg msg = actor.recv(); String world = msg.popString(); Assert.assertEquals("No matching response from actor", "WORLD", world); msg = actor.recv(); Assert.assertNull("Able te receive a message from a locked actor", msg); rc = actor.sign(); Assert.assertFalse("Locked actor is still here", rc); rc = actor.send("whatever"); Assert.assertFalse("Able to send a message to a locked actor", rc); try { rc = pipe.send("boom ?!"); Assert.assertTrue("actor pipe was closed pretty fast", rc); } catch (ZMQException e) { int errno = e.getErrorCode(); Assert.assertEquals("Expected exception has the wrong code", ZError.ETERM, errno); } System.out.println("."); } @Test public void testRecreateAgent() { MiniActor acting = new MiniActor() { private int counter = 0; @Override public List createSockets(ZContext ctx, Object[] args) { ++counter; System.out.print(".Acting Ready for a hello world."); assert ("TEST".equals(args[0])); return super.createSockets(ctx, args); } @Override public boolean backstage(Socket pipe, ZPoller poller, int events) { String string = pipe.recvStr(); if ("HELLO".equals(string)) { System.out.print("Hi! "); pipe.send("WORLD", ZMQ.SNDMORE); pipe.send(Integer.toString(counter)); return false; } return true; } public boolean destroyed(Socket pipe, ZPoller poller) { if (counter == 2) { System.out.print(".Acting Finished."); return false; } // recreate a new agent return true; } }; ZActor actor = new ZActor(acting, UUID.randomUUID().toString(), Arrays.asList("TEST").toArray()); ZAgent agent = actor.agent(); agent = actor; agent = actor.agent(); Socket pipe = agent.pipe(); boolean rc = pipe.send("HELLO"); assert (rc); ZMsg msg = actor.recv(); String world = msg.popString(); String counter = msg.popString(); assert ("WORLD".equals(world)); assert ("1".equals(counter)); rc = actor.send("HELLO"); assert (rc); msg = agent.recv(); world = msg.popString(); counter = msg.popString(); assert (msg != null); assert ("WORLD".equals(world)); assert ("2".equals(counter)); msg = agent.recv(); Assert.assertNull("Able te receive a message from a locked actor", msg); rc = agent.sign(); Assert.assertFalse("Locked actor is still here", rc); rc = agent.send("whatever"); Assert.assertFalse("Able to send a message to a locked actor", rc); try { rc = pipe.send("boom ?!"); Assert.assertTrue("actor pipe was closed pretty fast", rc); } catch (ZMQException e) { int errno = e.getErrorCode(); Assert.assertEquals("Expected exception has the wrong code", ZError.ETERM, errno); } System.out.println(); } } jeromq-0.3.5/src/test/java/org/zeromq/TestZContext.java000066400000000000000000000031331255150477200231000ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import org.junit.Assert; import org.junit.Test; import org.zeromq.ZMQ.Socket; public class TestZContext { @Test public void testZContext() { ZContext ctx = new ZContext(); Socket s1 = ctx.createSocket(ZMQ.PAIR); Socket s2 = ctx.createSocket(ZMQ.XREQ); Socket s3 = ctx.createSocket(ZMQ.REQ); Socket s4 = ctx.createSocket(ZMQ.REP); Socket s5 = ctx.createSocket(ZMQ.PUB); Socket s6 = ctx.createSocket(ZMQ.SUB); ctx.close(); Assert.assertEquals(0, ctx.getSockets().size()); } @Test public void testZContextSocketCloseBeforeContextClose() { ZContext ctx = new ZContext(); Socket s1 = ctx.createSocket(ZMQ.PUSH); Socket s2 = ctx.createSocket(ZMQ.PULL); s1.close(); s2.close(); ctx.close(); } } jeromq-0.3.5/src/test/java/org/zeromq/TestZLoop.java000066400000000000000000000176241255150477200223770ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import org.junit.After; import org.junit.Assert; import org.zeromq.ZMQ.Poller; import org.zeromq.ZMQ.Socket; import org.zeromq.ZMQ.PollItem; import org.junit.Test; import org.junit.Before; public class TestZLoop { private String received; private ZContext ctx; private Socket input; private Socket output; @Before public void setUp() { ctx = new ZContext(); assert (ctx != null); output = ctx.createSocket(ZMQ.PAIR); assert (output != null); output.bind("inproc://zloop.test"); input = ctx.createSocket(ZMQ.PAIR); assert (input != null); input.connect("inproc://zloop.test"); received = "FAILED"; } @After public void tearDown() { ctx.destroy(); } @Test public void testZLoop() { int rc = 0; ZLoop loop = new ZLoop(); assert (loop != null); ZLoop.IZLoopHandler timerEvent = new ZLoop.IZLoopHandler() { @Override public int handle(ZLoop loop, PollItem item, Object arg) { ((Socket) arg).send("PING", 0); return 0; } }; ZLoop.IZLoopHandler socketEvent = new ZLoop.IZLoopHandler() { @Override public int handle(ZLoop loop, PollItem item, Object arg) { received = ((Socket) arg).recvStr(0); // Just end the reactor return -1; } }; // After 10 msecs, send a ping message to output loop.addTimer(10, 1, timerEvent, input); // When we get the ping message, end the reactor PollItem pollInput = new PollItem(output, Poller.POLLIN); rc = loop.addPoller(pollInput, socketEvent, output); Assert.assertEquals(0, rc); loop.start(); loop.removePoller(pollInput); Assert.assertEquals("PING", received); } @Test public void testZLoopAddTimerFromTimer() { int rc = 0; ZLoop loop = new ZLoop(); assert (loop != null); ZLoop.IZLoopHandler timerEvent = new ZLoop.IZLoopHandler() { @Override public int handle(ZLoop loop, PollItem item, Object arg) { final long now = System.currentTimeMillis(); ZLoop.IZLoopHandler timerEvent2 = new ZLoop.IZLoopHandler() { @Override public int handle(ZLoop loop, PollItem item, Object arg) { final long now2 = System.currentTimeMillis(); assert (now2 >= now + 10); ((Socket) arg).send("PING", 0); return 0; } }; loop.addTimer(10, 1, timerEvent2, arg); return 0; } }; ZLoop.IZLoopHandler socketEvent = new ZLoop.IZLoopHandler() { @Override public int handle(ZLoop loop, PollItem item, Object arg) { received = ((Socket) arg).recvStr(0); // Just end the reactor return -1; } }; // After 10 msecs, fire a timer that registers // another timer that sends the ping message loop.addTimer(10, 1, timerEvent, input); // When we get the ping message, end the reactor PollItem pollInput = new PollItem(output, Poller.POLLIN); rc = loop.addPoller(pollInput, socketEvent, output); Assert.assertEquals(0, rc); loop.start(); loop.removePoller(pollInput); Assert.assertEquals("PING", received); } @Test(timeout = 1000) public void testZLoopAddTimerFromSocketHandler() { int rc = 0; ZLoop loop = new ZLoop(); assert (loop != null); ZLoop.IZLoopHandler timerEvent = new ZLoop.IZLoopHandler() { @Override public int handle(ZLoop loop, PollItem item, Object arg) { ((Socket) arg).send("PING", 0); return 0; } }; ZLoop.IZLoopHandler socketEvent = new ZLoop.IZLoopHandler() { @Override public int handle(ZLoop loop, PollItem item, Object arg) { final long now = System.currentTimeMillis(); ZLoop.IZLoopHandler timerEvent2 = new ZLoop.IZLoopHandler() { @Override public int handle(ZLoop loop, PollItem item, Object arg) { final long now2 = System.currentTimeMillis(); Assert.assertTrue(now2 >= now + 10); received = ((Socket) arg).recvStr(0); // Just end the reactor return -1; } }; // After 10 msec fire a timer that ends the reactor loop.addTimer(10, 1, timerEvent2, arg); return 0; } }; // Fire a timer that sends the ping message loop.addTimer(0, 1, timerEvent, input); // When we get the ping message, end the reactor PollItem pollInput = new PollItem(output, Poller.POLLIN); rc = loop.addPoller(pollInput, socketEvent, output); Assert.assertEquals(0, rc); loop.start(); loop.removePoller(pollInput); Assert.assertEquals("PING", received); } @Test(timeout = 1000) public void testZLoopEndReactorFromTimer() { int rc = 0; ZLoop loop = new ZLoop(); assert (loop != null); ZLoop.IZLoopHandler timerEvent = new ZLoop.IZLoopHandler() { @Override public int handle(ZLoop loop, PollItem item, Object arg) { ((Socket) arg).send("PING", 0); return 0; } }; ZLoop.IZLoopHandler socketEvent = new ZLoop.IZLoopHandler() { @Override public int handle(ZLoop loop, PollItem item, Object arg) { // After 10 msecs, fire an event that ends the reactor ZLoop.IZLoopHandler shutdownEvent = new ZLoop.IZLoopHandler() { @Override public int handle(ZLoop loop, PollItem item, Object arg) { received = ((Socket) arg).recvStr(0); // Just end the reactor return -1; } }; loop.addTimer(10, 1, shutdownEvent, arg); return 0; } }; // Fire event that sends a ping message to output loop.addTimer(0, 1, timerEvent, input); // When we get the ping message, end the reactor PollItem pollInput = new PollItem(output, Poller.POLLIN); rc = loop.addPoller(pollInput, socketEvent, output); Assert.assertEquals(0, rc); loop.start(); loop.removePoller(pollInput); Assert.assertEquals("PING", received); } } jeromq-0.3.5/src/test/java/org/zeromq/TestZMQ.java000066400000000000000000000340431255150477200217750ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.CharacterCodingException; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import org.junit.Test; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; public class TestZMQ { static class Client extends Thread { private Socket s = null; public Client(Context ctx) { s = ctx.socket(ZMQ.PULL); } @Override public void run() { System.out.println("Start client thread "); s.connect("tcp://127.0.0.1:6669"); s.recv(0); s.close(); System.out.println("Stop client thread "); } } @Test public void testPollerPollout() throws Exception { ZMQ.Context context = ZMQ.context(1); Client client = new Client(context); // Socket to send messages to ZMQ.Socket sender = context.socket(ZMQ.PUSH); sender.bind("tcp://127.0.0.1:6669"); ZMQ.Poller outItems; outItems = context.poller(); outItems.register(sender, ZMQ.Poller.POLLOUT); while (!Thread.currentThread().isInterrupted()) { outItems.poll(1000); if (outItems.pollout(0)) { sender.send("OK", 0); System.out.println("ok"); break; } else { System.out.println("not writable"); client.start(); } } client.join(); sender.close(); context.term(); } @Test public void testByteBufferSend() throws InterruptedException { ZMQ.Context context = ZMQ.context(1); ByteBuffer bb = ByteBuffer.allocate(4).order(ByteOrder.nativeOrder()); ZMQ.Socket push = null; ZMQ.Socket pull = null; try { push = context.socket(ZMQ.PUSH); pull = context.socket(ZMQ.PULL); pull.bind("tcp://*:12344"); push.connect("tcp://localhost:12344"); bb.put("PING".getBytes(ZMQ.CHARSET)); bb.flip(); push.sendByteBuffer(bb, 0); String actual = new String(pull.recv(), ZMQ.CHARSET); assertEquals("PING", actual); } finally { try { push.close(); } catch (Exception ignore) { } try { pull.close(); } catch (Exception ignore) { } try { context.term(); } catch (Exception ignore) { } } } @Test public void testByteBufferRecv() throws InterruptedException, CharacterCodingException { ZMQ.Context context = ZMQ.context(1); ByteBuffer bb = ByteBuffer.allocate(6).order(ByteOrder.nativeOrder()); ZMQ.Socket push = null; ZMQ.Socket pull = null; try { push = context.socket(ZMQ.PUSH); pull = context.socket(ZMQ.PULL); pull.bind("tcp://*:12345"); push.connect("tcp://localhost:12345"); push.send("PING".getBytes(ZMQ.CHARSET), 0); pull.recvByteBuffer(bb, 0); bb.flip(); byte[] b = new byte[bb.remaining()]; bb.duplicate().get(b); assertEquals("PING", new String(b, ZMQ.CHARSET)); } finally { try { push.close(); } catch (Exception ignore) { ignore.printStackTrace(); } try { pull.close(); } catch (Exception ignore) { ignore.printStackTrace(); } try { context.term(); } catch (Exception ignore) { ignore.printStackTrace(); } } } @Test(expected = ZMQException.class) public void testBindSameAddress() { ZMQ.Context context = ZMQ.context(1); ZMQ.Socket socket1 = context.socket(ZMQ.REQ); ZMQ.Socket socket2 = context.socket(ZMQ.REQ); socket1.bind("tcp://*:12346"); try { socket2.bind("tcp://*:12346"); fail("Exception not thrown"); } catch (ZMQException e) { assertEquals(e.getErrorCode(), ZMQ.Error.EADDRINUSE.getCode()); throw e; } finally { socket1.close(); socket2.close(); context.term(); } } @Test(expected = ZMQException.class) public void testBindInprocSameAddress() { ZMQ.Context context = ZMQ.context(1); ZMQ.Socket socket1 = context.socket(ZMQ.REQ); ZMQ.Socket socket2 = context.socket(ZMQ.REQ); socket1.bind("inproc://address.already.in.use"); try { socket2.bind("inproc://address.already.in.use"); fail("Exception not thrown"); } catch (ZMQException e) { assertEquals(e.getErrorCode(), ZMQ.Error.EADDRINUSE.getCode()); throw e; } finally { socket1.close(); socket2.close(); context.term(); } } @Test public void testEventConnected() { Context context = ZMQ.context(1); ZMQ.Event event; Socket helper = context.socket(ZMQ.REQ); int port = helper.bindToRandomPort("tcp://127.0.0.1"); Socket socket = context.socket(ZMQ.REP); Socket monitor = context.socket(ZMQ.PAIR); monitor.setReceiveTimeOut(100); assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_CONNECTED)); monitor.connect("inproc://monitor.socket"); socket.connect("tcp://127.0.0.1:" + port); event = ZMQ.Event.recv(monitor); assertNotNull("No event was received", event); assertEquals(ZMQ.EVENT_CONNECTED, event.getEvent()); helper.close(); socket.close(); monitor.close(); context.term(); } @Test public void testEventConnectDelayed() { Context context = ZMQ.context(1); ZMQ.Event event; Socket socket = context.socket(ZMQ.REP); Socket monitor = context.socket(ZMQ.PAIR); monitor.setReceiveTimeOut(100); assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_CONNECT_DELAYED)); monitor.connect("inproc://monitor.socket"); socket.connect("tcp://127.0.0.1:6751"); event = ZMQ.Event.recv(monitor); assertNotNull("No event was received", event); assertEquals(ZMQ.EVENT_CONNECT_DELAYED, event.getEvent()); socket.close(); monitor.close(); context.term(); } @Test public void testEventConnectRetried() { Context context = ZMQ.context(1); ZMQ.Event event; Socket socket = context.socket(ZMQ.REP); Socket monitor = context.socket(ZMQ.PAIR); monitor.setReceiveTimeOut(100); assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_CONNECT_RETRIED)); monitor.connect("inproc://monitor.socket"); socket.connect("tcp://127.0.0.1:6752"); event = ZMQ.Event.recv(monitor); assertNotNull("No event was received", event); assertEquals(ZMQ.EVENT_CONNECT_RETRIED, event.getEvent()); socket.close(); monitor.close(); context.term(); } @Test public void testEventListening() { Context context = ZMQ.context(1); ZMQ.Event event; Socket socket = context.socket(ZMQ.REP); Socket monitor = context.socket(ZMQ.PAIR); monitor.setReceiveTimeOut(100); assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_LISTENING)); monitor.connect("inproc://monitor.socket"); socket.bindToRandomPort("tcp://127.0.0.1"); event = ZMQ.Event.recv(monitor); assertNotNull("No event was received", event); assertEquals(ZMQ.EVENT_LISTENING, event.getEvent()); socket.close(); monitor.close(); context.term(); } @Test public void testEventBindFailed() { Context context = ZMQ.context(1); ZMQ.Event event; Socket helper = context.socket(ZMQ.REP); int port = helper.bindToRandomPort("tcp://127.0.0.1"); Socket socket = context.socket(ZMQ.REP); Socket monitor = context.socket(ZMQ.PAIR); monitor.setReceiveTimeOut(100); assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_BIND_FAILED)); monitor.connect("inproc://monitor.socket"); try { socket.bind("tcp://127.0.0.1:" + port); } catch (ZMQException ex) { } event = ZMQ.Event.recv(monitor); assertNotNull("No event was received", event); assertEquals(ZMQ.EVENT_BIND_FAILED, event.getEvent()); helper.close(); socket.close(); monitor.close(); context.term(); } @Test public void testEventAccepted() { Context context = ZMQ.context(1); ZMQ.Event event; Socket socket = context.socket(ZMQ.REP); Socket monitor = context.socket(ZMQ.PAIR); Socket helper = context.socket(ZMQ.REQ); monitor.setReceiveTimeOut(100); assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_ACCEPTED)); monitor.connect("inproc://monitor.socket"); int port = socket.bindToRandomPort("tcp://127.0.0.1"); helper.connect("tcp://127.0.0.1:" + port); event = ZMQ.Event.recv(monitor); assertNotNull("No event was received", event); assertEquals(ZMQ.EVENT_ACCEPTED, event.getEvent()); helper.close(); socket.close(); monitor.close(); context.term(); } @Test public void testEventClosed() { Context context = ZMQ.context(1); ZMQ.Event event; Socket socket = context.socket(ZMQ.REP); Socket monitor = context.socket(ZMQ.PAIR); monitor.setReceiveTimeOut(100); socket.bindToRandomPort("tcp://127.0.0.1"); assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_CLOSED)); monitor.connect("inproc://monitor.socket"); socket.close(); event = ZMQ.Event.recv(monitor); assertNotNull("No event was received", event); assertEquals(ZMQ.EVENT_CLOSED, event.getEvent()); monitor.close(); context.term(); } @Test public void testEventDisconnected() { Context context = ZMQ.context(1); ZMQ.Event event; Socket socket = context.socket(ZMQ.REP); Socket monitor = context.socket(ZMQ.PAIR); Socket helper = context.socket(ZMQ.REQ); monitor.setReceiveTimeOut(100); int port = socket.bindToRandomPort("tcp://127.0.0.1"); helper.connect("tcp://127.0.0.1:" + port); assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_DISCONNECTED)); monitor.connect("inproc://monitor.socket"); helper.close(); event = ZMQ.Event.recv(monitor); assertNotNull("No event was received", event); assertEquals(ZMQ.EVENT_DISCONNECTED, event.getEvent()); socket.close(); monitor.close(); context.term(); } @Test public void testEventMonitorStopped() { Context context = ZMQ.context(1); ZMQ.Event event; Socket socket = context.socket(ZMQ.REP); Socket monitor = context.socket(ZMQ.PAIR); monitor.setReceiveTimeOut(100); assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_MONITOR_STOPPED)); monitor.connect("inproc://monitor.socket"); socket.monitor(null, 0); event = ZMQ.Event.recv(monitor); assertNotNull("No event was received", event); assertEquals(ZMQ.EVENT_MONITOR_STOPPED, event.getEvent()); socket.close(); monitor.close(); context.term(); } @Test public void testSocketUnbind() { Context context = ZMQ.context(1); Socket push = context.socket(ZMQ.PUSH); Socket pull = context.socket(ZMQ.PULL); pull.setReceiveTimeOut(50); int port = pull.bindToRandomPort("tcp://127.0.0.1"); push.connect("tcp://127.0.0.1:" + port); byte[] data = "ABC".getBytes(); push.send(data); assertArrayEquals(data, pull.recv()); pull.unbind("tcp://127.0.0.1:" + port); push.send(data); assertNull(pull.recv()); push.close(); pull.close(); context.term(); } @Test public void testContextBlocky() { Context ctx = ZMQ.context(1); Socket router = ctx.socket(ZMQ.ROUTER); long rc = router.getLinger(); assertEquals(-1, rc); router.close(); ctx.setBlocky(false); router = ctx.socket(ZMQ.ROUTER); rc = router.getLinger(); assertEquals(0, rc); router.close(); ctx.term(); } @Test(timeout = 1000) public void testSocketDoubleClose() { Context ctx = ZMQ.context(1); Socket socket = ctx.socket(ZMQ.PUSH); socket.close(); socket.close(); } } jeromq-0.3.5/src/test/java/org/zeromq/TestZPoller.java000066400000000000000000000040201255150477200227050ustar00rootroot00000000000000package org.zeromq; import java.io.IOException; import java.nio.channels.SelectableChannel; import org.junit.Assert; import org.junit.Test; import org.zeromq.ZMQ.Socket; import org.zeromq.ZPoller.EventsHandler; public class TestZPoller { @Test public void testUseNull() throws IOException { ZContext ctx = null; //new ZContext(); ZPoller poller = new ZPoller(new ZStar.VerySimpleSelectorCreator().create()); SelectableChannel channel = null; Socket socket = null; //ctx.createSocket(ZMQ.SUB); boolean rc = false; rc = poller.register(socket, ZPoller.IN); Assert.assertFalse("Registering a null socket was successful", rc); rc = poller.register(channel, ZPoller.OUT); Assert.assertFalse("Registering a null channel was successful", rc); int events = poller.poll(10); Assert.assertEquals("reading event on without sockets", 0, events); rc = poller.isReadable(socket); Assert.assertFalse("checking read event on a null socket was successful", rc); rc = poller.writable(socket); Assert.assertFalse("checking write event on a null socket was successful", rc); rc = poller.readable(channel); Assert.assertFalse("checking read event on a null channel was successful", rc); rc = poller.isWritable(channel); Assert.assertFalse("checking write event on a null channel was successful", rc); EventsHandler global = null; poller.setGlobalHandler(global); EventsHandler handler = null; rc = poller.register(socket, handler, ZPoller.ERR); Assert.assertFalse("Register with handler on a null socket was successful", rc); rc = poller.register(channel, ZPoller.ERR); Assert.assertFalse("Register with handler on a null channel was successful", rc); events = poller.poll(10); Assert.assertEquals("reading event with events handlers without sockets", 0, events); poller.close(); System.out.println(); } } jeromq-0.3.5/src/test/java/org/zeromq/TestZProxy.java000066400000000000000000000074271255150477200226070ustar00rootroot00000000000000package org.zeromq; import java.util.Arrays; import org.junit.Assert; import org.junit.Test; import org.zeromq.ZMQ.Socket; public class TestZProxy { @Test public void testAllOptions() { final ZProxy.Proxy provider = new ZProxy.Proxy.SimpleProxy() { public Socket create(ZContext ctx, ZProxy.Plug place, Object[] extraArgs) { Socket socket = null; if (place == ZProxy.Plug.FRONT) { socket = ctx.createSocket(ZMQ.ROUTER); } if (place == ZProxy.Plug.BACK) { socket = ctx.createSocket(ZMQ.DEALER); } return socket; } public void configure(Socket socket, ZProxy.Plug place, Object[] extrArgs) { if (place == ZProxy.Plug.FRONT) { socket.bind("tcp://127.0.0.1:6660"); } if (place == ZProxy.Plug.BACK) { socket.bind("tcp://127.0.0.1:6661"); } if (place == ZProxy.Plug.CAPTURE && socket != null) { socket.bind("tcp://127.0.0.1:4263"); } } @Override public boolean restart(ZMsg cfg, Socket socket, ZProxy.Plug place, Object[] extraArgs) { if (place == ZProxy.Plug.FRONT) { socket.unbind("tcp://127.0.0.1:6660"); socket.bind("tcp://127.0.0.1:6660"); } if (place == ZProxy.Plug.BACK) { socket.unbind("tcp://127.0.0.1:6661"); socket.bind("tcp://127.0.0.1:6661"); } if (place == ZProxy.Plug.CAPTURE && socket != null) { socket.unbind("tcp://127.0.0.1:4263"); socket.bind("tcp://127.0.0.1:5347"); } return false; } @Override public boolean configure(Socket pipe, ZMsg cfg, Socket frontend, Socket backend, Socket capture, Object[] args) { assert (cfg.popString().equals("TEST-CONFIG")); ZMsg msg = new ZMsg(); msg.add("TODO"); msg.send(pipe); return true; } @Override public boolean custom(Socket pipe, String cmd, Socket frontend, Socket backend, Socket capture, Object[] args) { // TODO test custom commands return super.custom(pipe, cmd, frontend, backend, capture, args); } }; ZProxy proxy = ZProxy.newProxy(null, "ProxyOne", provider, "ABRACADABRA", Arrays.asList("TEST")); final boolean async = false; final boolean sync = true; String status = null; status = proxy.status(async); Assert.assertEquals("async status before any operation is not good!", ZProxy.ALIVE, status); status = proxy.start(async); Assert.assertEquals("Start async status is not good!", ZProxy.STOPPED, status); status = proxy.pause(async); Assert.assertEquals("Pause async status is not good!", ZProxy.STARTED, status); status = proxy.stop(async); Assert.assertEquals("Stop async status is not good!", ZProxy.PAUSED, status); status = proxy.status(async); Assert.assertEquals("async status is not good!", ZProxy.STOPPED, status); ZMsg msg = new ZMsg(); msg.add("TEST-CONFIG"); ZMsg recvd = proxy.configure(msg); Assert.assertEquals("TODO", recvd.popString()); System.out.println("Received config"); proxy.exit(async); // rc = pipe.send("boom ?!"); // assert (!rc); System.out.println(); } } jeromq-0.3.5/src/test/java/org/zeromq/TestZStar.java000066400000000000000000000055721255150477200223760ustar00rootroot00000000000000package org.zeromq; import java.nio.channels.Selector; import java.util.Arrays; import java.util.concurrent.TimeUnit; import org.junit.Assert; import org.junit.Test; import org.zeromq.ZMQ.Socket; import org.zeromq.ZStar.Fortune; public class TestZStar { private final class BlackHole implements ZStar.Fortune { @Override public String premiere(Socket mic, Object[] args) { return "Test " + Arrays.toString(args); } @Override public ZStar.Star create(ZContext ctx, Socket pipe, Selector sel, int count, ZStar.Star previous, Object[] args) { return new NoNo(); } @Override public boolean interview(Socket mic) { System.out.print("Fortune is not here anymore ..."); // tell that star is not here anymore return true; } @Override public void party(ZContext ctx) { // do nothing System.out.print(" Cleaning the remains.. "); } } private final class NoNo implements ZStar.Star { @Override public void prepare() { // do nothing } @Override public int breathe() { return -1; } @Override public boolean act(int events) { return false; } @Override public boolean entract() { return false; } @Override public boolean renews() { return false; } } @Test public void testNoStar() { System.out.print("No star: "); ZStar.Fortune fortune = new BlackHole(); ZStar.Entourage entourage = new ZStar.Entourage() { @Override public void breakaleg(ZContext ctx, Fortune fortune, Socket phone, Object[] bags) { // Crepi il lupo! } @Override public void party(ZContext ctx) { // right now there are some random closing issues ZStar.party(30, TimeUnit.MILLISECONDS); // waited a bit here seems to arrange that. // no user penalty cost, the show is over. } }; ZStar star = new ZStar(fortune, "motdelafin", Arrays.asList("TEST", entourage).toArray()); ZMsg msg = star.recv(); Assert.assertNull("Able to receive a message from a black hole", msg); boolean rc = star.sign(); Assert.assertFalse("Able to detect the presence of a black hole", rc); rc = star.send("whatever"); Assert.assertFalse("Able to send a command to a black hole", rc); // don't try it // rc = star.pipe().send("boom ?!"); // star.retire(); System.out.println("."); } } jeromq-0.3.5/src/test/java/org/zeromq/TestZThread.java000066400000000000000000000041451255150477200226670ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import org.zeromq.ZMQ.Socket; import org.junit.Assert; import org.junit.Test; public class TestZThread { @Test public void testDetached() { ZThread.IDetachedRunnable detached = new ZThread.IDetachedRunnable() { @Override public void run(Object[] args) { ZContext ctx = new ZContext(); assert (ctx != null); Socket push = ctx.createSocket(ZMQ.PUSH); assert (push != null); ctx.destroy(); } }; ZThread.start(detached); } @Test public void testFork() { ZContext ctx = new ZContext(); ZThread.IAttachedRunnable attached = new ZThread.IAttachedRunnable() { @Override public void run(Object[] args, ZContext ctx, Socket pipe) { // Create a socket to check it'll be automatically deleted ctx.createSocket(ZMQ.PUSH); pipe.recvStr(); pipe.send("pong"); } }; Socket pipe = ZThread.fork(ctx, attached); assert (pipe != null); pipe.send("ping"); String pong = pipe.recvStr(); Assert.assertEquals(pong, "pong"); // Everything should be cleanly closed now ctx.destroy(); } } jeromq-0.3.5/src/test/java/org/zeromq/ZBeaconTest.java000066400000000000000000000033721255150477200226500ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import java.net.InetAddress; import org.junit.Test; import org.zeromq.ZBeacon.Listener; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; public class ZBeaconTest { @Test public void test() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); byte[] beacon = new byte[] { 'H', 'Y', 'D', 'R', 'A', 0x01, 0x12, 0x34 }; byte[] prefix = new byte[] { 'H', 'Y', 'D', 'R', 'A', 0x01 }; ZBeacon zbeacon = new ZBeacon("255.255.255.255", 5670, beacon, false); zbeacon.setPrefix(prefix); zbeacon.setListener(new Listener() { @Override public void onBeacon(InetAddress sender, byte[] beacon) { latch.countDown(); } }); zbeacon.start(); latch.await(20, TimeUnit.SECONDS); assertEquals(latch.getCount(), 0); zbeacon.stop(); } } jeromq-0.3.5/src/test/java/org/zeromq/ZMsgTest.java000066400000000000000000000037601255150477200222100ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package org.zeromq; import org.junit.Assert; import org.junit.Test; /** * Created by hartmann on 3/21/14. */ public class ZMsgTest { @Test public void testRecvFrame() throws Exception { ZMQ.Context ctx = ZMQ.context(0); ZMQ.Socket socket = ctx.socket(ZMQ.PULL); ZFrame f = ZFrame.recvFrame(socket, ZMQ.NOBLOCK); Assert.assertNull(f); socket.close(); ctx.close(); } @Test public void testRecvMsg() throws Exception { ZMQ.Context ctx = ZMQ.context(0); ZMQ.Socket socket = ctx.socket(ZMQ.PULL); ZMsg msg = ZMsg.recvMsg(socket, ZMQ.NOBLOCK); Assert.assertNull(msg); socket.close(); ctx.close(); } @Test public void testRecvNullByteMsg() throws Exception { ZMQ.Context ctx = ZMQ.context(0); ZMQ.Socket sender = ctx.socket(ZMQ.PUSH); ZMQ.Socket receiver = ctx.socket(ZMQ.PULL); receiver.bind("inproc://" + this.hashCode()); sender.connect("inproc://" + this.hashCode()); sender.send(new byte[0]); ZMsg msg = ZMsg.recvMsg(receiver, ZMQ.NOBLOCK); Assert.assertNotNull(msg); sender.close(); receiver.close(); ctx.close(); } } jeromq-0.3.5/src/test/java/perf/000077500000000000000000000000001255150477200164475ustar00rootroot00000000000000jeromq-0.3.5/src/test/java/perf/InprocLat.java000066400000000000000000000103521255150477200212060ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package perf; import zmq.Ctx; import zmq.Msg; import zmq.SocketBase; import zmq.ZMQ; public class InprocLat { private InprocLat() { } static class Worker implements Runnable { private Ctx ctx; private int roundtripCount; Worker(Ctx ctx, int roundtripCount) { this.ctx = ctx; this.roundtripCount = roundtripCount; } @Override public void run() { SocketBase s = ZMQ.socket(ctx, ZMQ.ZMQ_REP); if (s == null) { printf("error in socket: %s\n"); exit(1); } boolean rc = ZMQ.connect(s, "inproc://lat_test"); if (!rc) { printf("error in connect: %s\n"); exit(1); } Msg msg; for (int i = 0; i != roundtripCount; i++) { msg = ZMQ.recvMsg(s, 0); if (msg == null) { printf("error in recvmsg: %s\n"); exit(1); } int r = ZMQ.sendMsg(s, msg, 0); if (r < 0) { printf("error in sendmsg: %s\n"); exit(1); } } ZMQ.close(s); } private void exit(int i) { // TODO Auto-generated method stub } } public static void main(String[] argv) throws Exception { if (argv.length != 2) { printf("usage: inproc_lat \n"); return; } int messageSize = atoi(argv [0]); int roundtripCount = atoi(argv [1]); Ctx ctx = ZMQ.init(1); if (ctx == null) { printf("error in init:"); return; } SocketBase s = ZMQ.socket(ctx, ZMQ.ZMQ_REQ); if (s == null) { printf("error in socket: "); return; } boolean rc = ZMQ.bind(s, "inproc://lat_test"); if (!rc) { printf("error in bind: "); return; } Thread localThread = new Thread(new Worker(ctx, roundtripCount)); localThread.start(); Msg smsg = ZMQ.msgInitWithSize(messageSize); printf("message size: %d [B]\n", (int) messageSize); printf("roundtrip count: %d\n", (int) roundtripCount); long watch = ZMQ.startStopwatch(); for (int i = 0; i != roundtripCount; i++) { int r = ZMQ.sendMsg(s, smsg, 0); if (r < 0) { printf("error in sendmsg: %s\n"); return; } Msg msg = ZMQ.recvMsg(s, 0); if (msg == null) { printf("error in recvmsg: %s\n"); return; } if (ZMQ.msgSize(msg) != messageSize) { printf("message of incorrect size received\n"); return; } } long elapsed = ZMQ.stopStopwatch(watch); double latency = (double) elapsed / (roundtripCount * 2); localThread.join(); printf("average latency: %.3f [us]\n", (double) latency); ZMQ.close(s); ZMQ.term(ctx); } private static int atoi(String string) { return Integer.parseInt(string); } private static void printf(String string) { System.out.println(string); } private static void printf(String string, Object ... args) { System.out.println(String.format(string, args)); } } jeromq-0.3.5/src/test/java/perf/LocalLat.java000066400000000000000000000054311255150477200210100ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package perf; import zmq.Ctx; import zmq.Msg; import zmq.SocketBase; import zmq.ZMQ; public class LocalLat { private LocalLat() { } public static void main(String[] args) { String bindTo; int roundtripCount; int messageSize; Ctx ctx; SocketBase s; boolean rc; int n; int i; Msg msg; if (args.length != 3) { printf("usage: local_lat " + "\n"); return; } bindTo = args [0]; messageSize = atoi(args [1]); roundtripCount = atoi(args [2]); ctx = ZMQ.init(1); if (ctx == null) { printf("error in init: %s\n"); return; } s = ZMQ.socket(ctx, ZMQ.ZMQ_REP); if (s == null) { printf("error in socket: %s\n", ZMQ.strerror(s.errno())); return; } rc = ZMQ.bind(s, bindTo); if (!rc) { printf("error in bind: %s\n", ZMQ.strerror(s.errno())); return; } for (i = 0; i != roundtripCount; i++) { msg = ZMQ.recvMsg(s, 0); if (msg == null) { printf("error in recvmsg: %s\n", ZMQ.strerror(s.errno())); return; } if (ZMQ.msgSize(msg) != messageSize) { printf("message of incorrect size received\n"); return; } n = ZMQ.sendMsg(s, msg, 0); if (n < 0) { printf("error in sendmsg: %s\n", ZMQ.strerror(s.errno())); return; } } ZMQ.sleep(1000); ZMQ.close(s); ZMQ.term(ctx); } private static int atoi(String string) { return Integer.parseInt(string); } private static void printf(String string) { System.out.println(string); } private static void printf(String string, Object ... args) { System.out.println(String.format(string, args)); } } jeromq-0.3.5/src/test/java/perf/LocalThr.java000066400000000000000000000070711255150477200210270ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package perf; import zmq.Ctx; import zmq.Msg; import zmq.SocketBase; import zmq.ZMQ; public class LocalThr { private LocalThr() { } public static void main(String[] argv) { String bindTo; long messageCount; int messageSize; Ctx ctx; SocketBase s; boolean rc; long i; Msg msg; long watch; long elapsed; long throughput; double megabits; if (argv.length != 3) { printf("usage: local_thr \n"); return; } bindTo = argv [0]; messageSize = atoi(argv [1]); messageCount = atol(argv [2]); ctx = ZMQ.init(1); if (ctx == null) { printf("error in init"); return; } s = ZMQ.socket(ctx, ZMQ.ZMQ_PULL); if (s == null) { printf("error in socket"); } // Add your socket options here. // For example ZMQ_RATE, ZMQ_RECOVERY_IVL and ZMQ_MCAST_LOOP for PGM. rc = ZMQ.bind(s, bindTo); if (!rc) { printf("error in bind: %s\n"); return; } msg = ZMQ.recvMsg(s, 0); if (msg == null) { printf("error in recvmsg: %s\n"); return; } watch = ZMQ.startStopwatch(); for (i = 0; i != messageCount - 1; i++) { msg = ZMQ.recvMsg(s, 0); if (msg == null) { printf("error in recvmsg: %s\n"); return; } if (ZMQ.msgSize(msg) != messageSize) { printf("message of incorrect size received " + ZMQ.msgSize(msg)); return; } } elapsed = ZMQ.stopStopwatch(watch); if (elapsed == 0) { elapsed = 1; } throughput = (long) ((double) messageCount / (double) elapsed * 1000000L); megabits = (double) (throughput * messageSize * 8) / 1000000; printf("message elapsed: %.3f \n", (double) elapsed / 1000000L); printf("message size: %d [B]\n", (int) messageSize); printf("message count: %d\n", (int) messageCount); printf("mean throughput: %d [msg/s]\n", (int) throughput); printf("mean throughput: %.3f [Mb/s]\n", (double) megabits); ZMQ.close(s); ZMQ.term(ctx); } private static void printf(String str, Object ... args) { // TODO Auto-generated method stub System.out.println(String.format(str, args)); } private static int atoi(String string) { return Integer.valueOf(string); } private static long atol(String string) { return Long.valueOf(string); } private static void printf(String string) { System.out.println(string); } } jeromq-0.3.5/src/test/java/perf/RemoteThr.java000066400000000000000000000050651255150477200212310ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package perf; import zmq.Ctx; import zmq.Msg; import zmq.SocketBase; import zmq.ZMQ; public class RemoteThr { private RemoteThr() { } public static void main(String[] argv) { String connectTo; long messageCount; int messageSize; Ctx ctx; SocketBase s; boolean rc; long i; Msg msg; if (argv.length != 3) { printf("usage: remote_thr \n"); return; } connectTo = argv[0]; messageSize = atoi(argv[1]); messageCount = atol(argv[2]); ctx = ZMQ.init(1); if (ctx == null) { printf("error in init"); return; } s = ZMQ.socket(ctx, ZMQ.ZMQ_PUSH); if (s == null) { printf("error in socket"); } // Add your socket options here. // For example ZMQ_RATE, ZMQ_RECOVERY_IVL and ZMQ_MCAST_LOOP for PGM. rc = ZMQ.connect(s, connectTo); if (!rc) { printf("error in connect: %s\n"); return; } for (i = 0; i != messageCount; i++) { msg = ZMQ.msgInitWithSize(messageSize); if (msg == null) { printf("error in msg_init: %s\n"); return; } int n = ZMQ.sendMsg(s, msg, 0); if (n < 0) { printf("error in sendmsg: %s\n"); return; } } ZMQ.close(s); ZMQ.term(ctx); } private static int atoi(String string) { return Integer.valueOf(string); } private static long atol(String string) { return Long.valueOf(string); } private static void printf(String string) { System.out.println(string); } } jeromq-0.3.5/src/test/java/zmq/000077500000000000000000000000001255150477200163225ustar00rootroot00000000000000jeromq-0.3.5/src/test/java/zmq/Helper.java000066400000000000000000000144651255150477200204160ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; public class Helper { public static AtomicInteger counter = new AtomicInteger(2); private Helper() { } public static class DummyCtx extends Ctx { } public static class DummySocketChannel implements WritableByteChannel { private int bufsize; private byte[] buf; public DummySocketChannel() { this(64); } public DummySocketChannel(int bufsize) { this.bufsize = bufsize; buf = new byte[bufsize]; } public byte[] data() { return buf; } @Override public void close() throws IOException { } @Override public boolean isOpen() { return true; } @Override public int write(ByteBuffer src) throws IOException { int remaining = src.remaining(); if (remaining > bufsize) { src.get(buf); return bufsize; } src.get(buf, 0, remaining); return remaining; } } public static DummyCtx ctx = new DummyCtx(); public static class DummyIOThread extends IOThread { public DummyIOThread() { super(ctx, 2); } } public static class DummySocket extends SocketBase { public DummySocket() { super(ctx, counter.get(), counter.get()); counter.incrementAndGet(); } @Override protected void xattachPipe(Pipe pipe, boolean icanhasall) { } @Override protected void xpipeTerminated(Pipe pipe) { } } public static class DummySession extends SessionBase { public List out = new ArrayList(); public DummySession() { this(new DummyIOThread(), false, new DummySocket(), new Options(), new Address("tcp", "localhost:9090", false)); } public DummySession(IOThread ioThread, boolean connect, SocketBase socket, Options options, Address addr) { super(ioThread, connect, socket, options, addr); } @Override public int pushMsg(Msg msg) { System.out.println("session.write " + msg); out.add(msg); return 0; } @Override public Msg pullMsg() { System.out.println("session.read " + out); if (out.size() == 0) { return null; } Msg msg = out.remove(0); return msg; } } public static void bounce(SocketBase sb, SocketBase sc) { byte[] content = "12345678ABCDEFGH12345678abcdefgh".getBytes(ZMQ.CHARSET); // Send the message. int rc = ZMQ.send(sc, content, 32, ZMQ.ZMQ_SNDMORE); assert (rc == 32); rc = ZMQ.send(sc, content, 32, 0); assertThat(rc, is(32)); // Bounce the message back. Msg msg; msg = ZMQ.recv(sb, 0); assert (msg.size() == 32); long rcvmore = ZMQ.getSocketOption(sb, ZMQ.ZMQ_RCVMORE); assert (rcvmore == 1); msg = ZMQ.recv(sb, 0); assert (rc == 32); rcvmore = ZMQ.getSocketOption(sb, ZMQ.ZMQ_RCVMORE); assert (rcvmore == 0); rc = ZMQ.send(sb, new Msg(msg), ZMQ.ZMQ_SNDMORE); assert (rc == 32); rc = ZMQ.send(sb, new Msg(msg), 0); assert (rc == 32); // Receive the bounced message. msg = ZMQ.recv(sc, 0); assert (rc == 32); rcvmore = ZMQ.getSocketOption(sc, ZMQ.ZMQ_RCVMORE); assertThat(rcvmore , is(1L)); msg = ZMQ.recv(sc, 0); assert (rc == 32); rcvmore = ZMQ.getSocketOption(sc, ZMQ.ZMQ_RCVMORE); assertThat(rcvmore , is(0L)); // Check whether the message is still the same. //assert (memcmp (buf2, content, 32) == 0); } public static void send(Socket sa, String data) throws IOException { byte[] content = data.getBytes(ZMQ.CHARSET); byte[] length = String.format("%04d", content.length).getBytes(ZMQ.CHARSET); byte[] buf = new byte[1024]; int reslen; int rc; // Bounce the message back. InputStream in = sa.getInputStream(); OutputStream out = sa.getOutputStream(); out.write(length); out.write(content); System.out.println("sent " + data.length() + " " + data); int toRead = 4; // 4 + greeting_size int read = 0; while (toRead > 0) { rc = in.read(buf, read, toRead); read += rc; toRead -= rc; System.out.println("read " + rc + " total_read " + read + " toRead " + toRead); } System.out.println(String.format("%02x %02x %02x %02x", buf[0], buf[1], buf[2], buf[3])); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } reslen = Integer.valueOf(new String(buf, 0, 4, ZMQ.CHARSET)); in.read(buf, 0, reslen); System.out.println("recv " + reslen + " " + new String(buf, 0, reslen, ZMQ.CHARSET)); } } jeromq-0.3.5/src/test/java/zmq/TcpAddressTest.java000066400000000000000000000023471255150477200220670ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import java.net.InetSocketAddress; import static org.junit.Assert.assertEquals; public class TcpAddressTest { @Test public void parsesIpv6Address() { String addressString = "2000::a1"; int port = 9999; TcpAddress address = new TcpAddress("[" + addressString + "]:" + port); InetSocketAddress expected = new InetSocketAddress(addressString, port); assertEquals(expected, address.address()); } } jeromq-0.3.5/src/test/java/zmq/TestAddress.java000066400000000000000000000031261255150477200214140ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.hamcrest.CoreMatchers.is; public class TestAddress { @Test public void testToNotResolvedToString() { Address addr = new Address("tcp", "google.com:90", false); String saddr = addr.toString(); assertThat(saddr, is("tcp://google.com:90")); } @Test public void testResolvedToString() { Address addr = new Address("tcp", "google.com:90", false); addr.resolve(); String resolved = addr.toString(); assertTrue(resolved.matches("tcp://\\d+\\.\\d+\\.\\d+\\.\\d+:90")); } @Test(expected = IllegalArgumentException.class) public void testInvaid() { new Address("tcp", "ggglocalhostxxx:90", false).resolve(); } } jeromq-0.3.5/src/test/java/zmq/TestBlob.java000066400000000000000000000024231255150477200207040ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.util.HashMap; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestBlob { @Test public void testBlobMap() { HashMap map = new HashMap(); Blob b = Blob.createBlob("a".getBytes(ZMQ.CHARSET), false); map.put(b, "aa"); assertThat(map.remove(b), notNullValue()); assertThat(map.size(), is(0)); } } jeromq-0.3.5/src/test/java/zmq/TestConnectDelay.java000066400000000000000000000157131255150477200224040ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertEquals; public class TestConnectDelay { @Test public void testConnectDelay1() throws Exception { // TEST 1. // First we're going to attempt to send messages to two // pipes, one connected, the other not. We should see // the PUSH load balancing to both pipes, and hence half // of the messages getting queued, as connect() creates a // pipe immediately. Ctx context = ZMQ.createContext(); assert (context != null); SocketBase to = ZMQ.socket(context, ZMQ.ZMQ_PULL); assert (to != null); int val = 0; ZMQ.setSocketOption(to, ZMQ.ZMQ_LINGER, val); boolean rc = ZMQ.bind(to, "tcp://*:7555"); assert (rc); // Create a socket pushing to two endpoints - only 1 message should arrive. SocketBase from = ZMQ.socket(context, ZMQ.ZMQ_PUSH); assert (from != null); val = 0; ZMQ.setSocketOption(from, ZMQ.ZMQ_LINGER, val); rc = ZMQ.connect(from, "tcp://localhost:7556"); assert (rc); rc = ZMQ.connect(from, "tcp://localhost:7555"); assert (rc); for (int i = 0; i < 10; ++i) { String message = "message "; message += ('0' + i); int sent = ZMQ.send(from, message, 0); assert (sent >= 0); } // We now consume from the connected pipe // - we should see just 5 int timeout = 1000; ZMQ.setSocketOption(to, ZMQ.ZMQ_RCVTIMEO, timeout); int seen = 0; for (int i = 0; i < 10; ++i) { Msg msg = ZMQ.recv(to, 0); if (msg == null) { break; } seen++; } assertEquals(seen, 5); ZMQ.close(from); ZMQ.close(to); ZMQ.term(context); } @Test public void testConnectDelay2() throws Exception { // TEST 2 // This time we will do the same thing, connect two pipes, // one of which will succeed in connecting to a bound // receiver, the other of which will fail. However, we will // also set the delay attach on connect flag, which should // cause the pipe attachment to be delayed until the connection // succeeds. Ctx context = ZMQ.createContext(); SocketBase to = ZMQ.socket(context, ZMQ.ZMQ_PULL); assert (to != null); boolean rc = ZMQ.bind(to, "tcp://*:7560"); assert (rc); int val = 0; ZMQ.setSocketOption(to, ZMQ.ZMQ_LINGER, val); assert (rc); // Create a socket pushing to two endpoints - all messages should arrive. SocketBase from = ZMQ.socket(context, ZMQ.ZMQ_PUSH); assert (from != null); val = 0; ZMQ.setSocketOption(from, ZMQ.ZMQ_LINGER, val); // Set the key flag val = 1; ZMQ.setSocketOption(from, ZMQ.ZMQ_DELAY_ATTACH_ON_CONNECT, val); // Connect to the invalid socket rc = ZMQ.connect(from, "tcp://localhost:7561"); assert (rc); // Connect to the valid socket rc = ZMQ.connect(from, "tcp://localhost:7560"); assert (rc); for (int i = 0; i < 10; ++i) { String message = "message "; message += ('0' + i); int sent = ZMQ.send(from, message, 0); assert (sent >= 0); } int timeout = 1000; ZMQ.setSocketOption(to, ZMQ.ZMQ_RCVTIMEO, timeout); int seen = 0; for (int i = 0; i < 10; ++i) { Msg msg = ZMQ.recv(to, 0); if (msg == null) { break; } seen++; } assertEquals(seen, 10); ZMQ.close(from); ZMQ.close(to); ZMQ.term(context); } @Test public void testConnectDelay3() throws Exception { // TEST 3 // This time we want to validate that the same blocking behaviour // occurs with an existing connection that is broken. We will send // messages to a connected pipe, disconnect and verify the messages // block. Then we reconnect and verify messages flow again. Ctx context = ZMQ.createContext(); SocketBase backend = ZMQ.socket(context, ZMQ.ZMQ_DEALER); assert (backend != null); SocketBase frontend = ZMQ.socket(context, ZMQ.ZMQ_DEALER); assert (frontend != null); int val = 0; ZMQ.setSocketOption(backend, ZMQ.ZMQ_LINGER, val); val = 0; ZMQ.setSocketOption(frontend, ZMQ.ZMQ_LINGER, val); // Frontend connects to backend using DELAY_ATTACH_ON_CONNECT val = 1; ZMQ.setSocketOption(frontend, ZMQ.ZMQ_DELAY_ATTACH_ON_CONNECT, val); boolean rc = ZMQ.bind(backend, "tcp://*:7760"); assert (rc); rc = ZMQ.connect(frontend, "tcp://localhost:7760"); assert (rc); // Ping backend to frontend so we know when the connection is up int sent = ZMQ.send(backend, "Hello", 0); assertEquals(5, sent); Msg msg = ZMQ.recv(frontend, 0); assertEquals(5, msg.size()); // Send message from frontend to backend sent = ZMQ.send(frontend, "Hello", ZMQ.ZMQ_DONTWAIT); assertEquals(5, sent); ZMQ.close(backend); // Give time to process disconnect // There's no way to do this except with a sleep Thread.sleep(1000); // Send a message, should fail sent = ZMQ.send(frontend, "Hello", ZMQ.ZMQ_DONTWAIT); assertEquals(-1, sent); // Recreate backend socket backend = ZMQ.socket(context, ZMQ.ZMQ_DEALER); val = 0; ZMQ.setSocketOption(backend, ZMQ.ZMQ_LINGER, val); rc = ZMQ.bind(backend, "tcp://*:7760"); assert (rc); // Ping backend to frontend so we know when the connection is up sent = ZMQ.send(backend, "Hello", 0); assertEquals(5, sent); msg = ZMQ.recv(frontend, 0); assertEquals(5, msg.size()); // After the reconnect, should succeed sent = ZMQ.send(frontend, "Hello", ZMQ.ZMQ_DONTWAIT); assertEquals(5, sent); ZMQ.close(backend); ZMQ.close(frontend); ZMQ.term(context); } } jeromq-0.3.5/src/test/java/zmq/TestConnectResolve.java000066400000000000000000000033171255150477200227620ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestConnectResolve { @Test public void testConnectResolve() { System.out.println("test_connect_resolve running...\n"); Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); // Create pair of socket, each with high watermark of 2. Thus the total // buffer space should be 4 messages. SocketBase sock = ZMQ.socket(ctx, ZMQ.ZMQ_PUB); assertThat(sock, notNullValue()); boolean brc = ZMQ.connect(sock, "tcp://localhost:1234"); assertThat(brc, is(true)); /* try { brc = ZMQ.connect (sock, "tcp://foobar123xyz:1234"); assertTrue(false); } catch (IllegalArgumentException e) { } */ ZMQ.close(sock); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestDecoder.java000066400000000000000000000127741255150477200214050ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.nio.ByteBuffer; import org.junit.Before; import org.junit.Test; import zmq.Helper.DummySession; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; public class TestDecoder { DecoderBase decoder; Helper.DummySession session; @Before public void setUp() { session = new DummySession(); decoder = new Decoder(64, 256); decoder.setMsgSink(session); } // as if it read data from socket private int readShortMessage(ByteBuffer buf) { buf.put((byte) 6); buf.put((byte) 0); // flag buf.put("hello".getBytes(ZMQ.CHARSET)); return buf.position(); } // as if it read data from socket private int readLongMessage1(ByteBuffer buf) { buf.put((byte) 201); buf.put((byte) 0); // flag for (int i = 0; i < 6; i++) { buf.put("0123456789".getBytes(ZMQ.CHARSET)); } buf.put("01".getBytes(ZMQ.CHARSET)); return buf.position(); } private int readLongMessage2(ByteBuffer buf) { buf.put("23456789".getBytes(ZMQ.CHARSET)); for (int i = 0; i < 13; i++) { buf.put("0123456789".getBytes(ZMQ.CHARSET)); } return buf.position(); } @Test public void testReader() { ByteBuffer in = decoder.getBuffer(); int insize = readShortMessage(in); assertThat(insize, is(7)); in.flip(); int process = decoder.processBuffer(in, insize); assertThat(process, is(7)); } @Test public void testReaderLong() { ByteBuffer in = decoder.getBuffer(); int insize = readLongMessage1(in); assertThat(insize, is(64)); in.flip(); int process = decoder.processBuffer(in, insize); assertThat(process, is(64)); in = decoder.getBuffer(); assertThat(in.capacity(), is(200)); assertThat(in.position(), is(62)); insize = readLongMessage2(in); assertThat(insize, is(200)); process = decoder.processBuffer(in, 138); assertThat(process, is(138)); assertThat(in.array()[199], is((byte) '9')); } @Test public void testReaderMultipleMsg() { ByteBuffer in = decoder.getBuffer(); int insize = readShortMessage(in); assertThat(insize, is(7)); readShortMessage(in); in.flip(); int processed = decoder.processBuffer(in, 14); assertThat(processed, is(14)); assertThat(in.position(), is(14)); assertThat(session.out.size(), is(2)); } static class CustomDecoder extends DecoderBase { private static final int READ_HEADER = 0; private static final int READ_BODY = 1; byte[] header = new byte[10]; Msg msg; int size = -1; IMsgSink sink; public CustomDecoder(int bufsize, long maxmsgsize) { super(bufsize); nextStep(header, 10, READ_HEADER); } @Override protected boolean next() { switch (state()) { case READ_HEADER: return readHeader(); case READ_BODY: return readBody(); } return false; } private boolean readHeader() { assertThat(new String(header, 0, 6, ZMQ.CHARSET), is("HEADER")); ByteBuffer b = ByteBuffer.wrap(header, 6, 4); size = b.getInt(); msg = new Msg(size); nextStep(msg, READ_BODY); return true; } private boolean readBody() { sink.pushMsg(msg); nextStep(header, 10, READ_HEADER); return true; } @Override public boolean stalled() { return state() == READ_BODY; } @Override public void setMsgSink(IMsgSink msgSink) { sink = msgSink; } } @Test public void testCustomDecoder() { CustomDecoder cdecoder = new CustomDecoder(32, 64); cdecoder.setMsgSink(session); ByteBuffer in = cdecoder.getBuffer(); int insize = readHeader(in); assertThat(insize, is(10)); readBody(in); in.flip(); int processed = cdecoder.processBuffer(in, 30); assertThat(processed, is(30)); assertThat(cdecoder.size, is(20)); assertThat(session.out.size(), is(1)); } private void readBody(ByteBuffer in) { in.put("1234567890".getBytes(ZMQ.CHARSET)); in.put("1234567890".getBytes(ZMQ.CHARSET)); } private int readHeader(ByteBuffer in) { in.put("HEADER".getBytes(ZMQ.CHARSET)); in.putInt(20); return in.position(); } } jeromq-0.3.5/src/test/java/zmq/TestDisconnectInproc.java000066400000000000000000000077431255150477200233040ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; public class TestDisconnectInproc { @Test public void testDisconnectInproc() throws Exception { int publicationsReceived = 0; boolean isSubscribed = false; Ctx context = ZMQ.createContext(); SocketBase pubSocket = ZMQ.socket(context, ZMQ.ZMQ_XPUB); SocketBase subSocket = ZMQ.socket(context, ZMQ.ZMQ_SUB); ZMQ.setSocketOption(subSocket, ZMQ.ZMQ_SUBSCRIBE, "foo".getBytes()); ZMQ.bind(pubSocket, "inproc://someInProcDescriptor"); int more; int iteration = 0; while (true) { PollItem[] items = { new PollItem(subSocket, ZMQ.ZMQ_POLLIN), // read publications new PollItem(pubSocket, ZMQ.ZMQ_POLLIN) // read subscriptions }; ZMQ.poll(items, 2, 500); if (items[1].isReadable()) { while (true) { Msg msg = ZMQ.recv(pubSocket, 0); int msgSize = msg.size(); byte[] buffer = msg.data(); if (buffer[0] == 0) { assertTrue(isSubscribed); System.out.printf("unsubscribing from '%s'\n", new String(buffer, 1, msgSize - 1)); isSubscribed = false; } else { assert (!isSubscribed); System.out.printf("subscribing on '%s'\n", new String(buffer, 1, msgSize - 1)); isSubscribed = true; } more = ZMQ.getSocketOption(pubSocket, ZMQ.ZMQ_RCVMORE); if (more == 0) { break; // Last message part } } } if (items[0].isReadable()) { while (true) { Msg msg = ZMQ.recv(subSocket, 0); int msgSize = msg.size(); byte[] buffer = msg.data(); System.out.printf("received on subscriber '%s'\n", new String(buffer, 0, msgSize)); more = ZMQ.getSocketOption(subSocket, ZMQ.ZMQ_RCVMORE); if (more == 0) { publicationsReceived++; break; // Last message part } } } if (iteration == 1) { ZMQ.connect(subSocket, "inproc://someInProcDescriptor"); } if (iteration == 4) { ZMQ.disconnect(subSocket, "inproc://someInProcDescriptor"); } if (iteration == 10) { break; } Msg channelEnvlp = new Msg("foo".getBytes(ZMQ.CHARSET)); ZMQ.sendMsg(pubSocket, channelEnvlp, ZMQ.ZMQ_SNDMORE); Msg message = new Msg("this is foo!".getBytes(ZMQ.CHARSET)); ZMQ.sendMsg(pubSocket, message, 0); iteration++; } assertEquals(3, publicationsReceived); assertTrue(!isSubscribed); ZMQ.close(pubSocket); ZMQ.close(subSocket); ZMQ.term(context); } } jeromq-0.3.5/src/test/java/zmq/TestEncoder.java000066400000000000000000000122111255150477200214010ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.io.IOException; import java.nio.ByteBuffer; import org.junit.Before; import org.junit.Test; import zmq.Helper.DummySession; import zmq.Helper.DummySocketChannel; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; public class TestEncoder { EncoderBase encoder; Helper.DummySession session; DummySocketChannel sock; @Before public void setUp() { session = new DummySession(); encoder = new Encoder(64); encoder.setMsgSource(session); sock = new DummySocketChannel(); } // as if it read data from socket private Msg readShortMessage() { Msg msg = new Msg("hello".getBytes(ZMQ.CHARSET)); return msg; } // as if it read data from socket private Msg readLongMessage1() { Msg msg = new Msg(200); for (int i = 0; i < 20; i++) { msg.put("0123456789".getBytes(ZMQ.CHARSET)); } return msg; } @Test public void testReader() { Msg msg = readShortMessage(); session.pushMsg(msg); Transfer out = encoder.getData(null); int outsize = out.remaining(); assertThat(outsize, is(7)); int written = write(out); assertThat(written, is(7)); int remaning = out.remaining(); assertThat(remaning, is(0)); } private int write(Transfer out) { try { return out.transferTo(sock); } catch (IOException e) { e.printStackTrace(); return -1; } } @Test public void testReaderLong() { Msg msg = readLongMessage1(); session.pushMsg(msg); Transfer out = encoder.getData(null); int insize = out.remaining(); assertThat(insize, is(64)); int written = write(out); assertThat(written, is(64)); out = encoder.getData(null); int remaning = out.remaining(); assertThat(remaning, is(138)); written = write(out); assertThat(written, is(64)); remaning = out.remaining(); assertThat(remaning, is(74)); written = write(out); assertThat(written, is(64)); remaning = out.remaining(); assertThat(remaning, is(10)); written = write(out); assertThat(written, is(10)); remaning = out.remaining(); assertThat(remaning, is(0)); } static class CustomEncoder extends EncoderBase { public static final boolean RAW_ENCODER = true; private static final int read_header = 0; private static final int read_body = 1; ByteBuffer header = ByteBuffer.allocate(10); Msg msg; int size = -1; IMsgSource source; public CustomEncoder(int bufsize) { super(bufsize); nextStep(null, read_body, true); } @Override protected boolean next() { switch (state()) { case read_header: return readHeader(); case read_body: return readBody(); } return false; } private boolean readHeader() { nextStep(msg.data(), msg.size(), read_body, !msg.hasMore()); return true; } private boolean readBody() { msg = source.pullMsg(); if (msg == null) { return false; } header.clear(); header.put("HEADER".getBytes(ZMQ.CHARSET)); header.putInt(msg.size()); header.flip(); nextStep(header.array(), 10, read_header, !msg.hasMore()); return true; } @Override public void setMsgSource(IMsgSource msgSource) { source = msgSource; } } @Test public void testCustomDecoder() { CustomEncoder cencoder = new CustomEncoder(32); cencoder.setMsgSource(session); Msg msg = new Msg("12345678901234567890".getBytes(ZMQ.CHARSET)); session.pushMsg(msg); Transfer out = cencoder.getData(null); write(out); byte[] data = sock.data(); assertThat(new String(data, 0, 6, ZMQ.CHARSET), is("HEADER")); assertThat((int) data[9], is(20)); assertThat(new String(data, 10, 20, ZMQ.CHARSET), is("12345678901234567890")); } } jeromq-0.3.5/src/test/java/zmq/TestHwm.java000066400000000000000000000051421255150477200205620ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestHwm { @Test public void testHwm() { Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); int rc = 0; boolean brc = false; // Create pair of socket, each with high watermark of 2. Thus the total // buffer space should be 4 messages. SocketBase sb = ZMQ.socket(ctx, ZMQ.ZMQ_PULL); assertThat(sb, notNullValue()); int hwm = 2; ZMQ.setSocketOption(sb, ZMQ.ZMQ_RCVHWM, hwm); brc = ZMQ.bind(sb, "inproc://a"); assertThat(brc, is(true)); SocketBase sc = ZMQ.socket(ctx, ZMQ.ZMQ_PUSH); assertThat(sc, notNullValue()); ZMQ.setSocketOption(sc, ZMQ.ZMQ_SNDHWM, hwm); brc = ZMQ.connect(sc, "inproc://a"); assertThat(brc, is(true)); // Try to send 10 messages. Only 4 should succeed. for (int i = 0; i < 10; i++) { rc = ZMQ.send(sc, null, 0, ZMQ.ZMQ_DONTWAIT); if (i < 4) { assertThat(rc, is(0)); } else { assertThat(rc, is(-1)); } } Msg m; // There should be now 4 messages pending, consume them. for (int i = 0; i != 4; i++) { m = ZMQ.recv(sb, 0); assertThat(m, notNullValue()); assertThat(m.size(), is(0)); } // Now it should be possible to send one more. rc = ZMQ.send(sc, null, 0, 0); assertThat(rc, is(0)); // Consume the remaining message. m = ZMQ.recv(sb, 0); assertThat(rc, notNullValue()); assertThat(m.size(), is(0)); ZMQ.close(sc); ZMQ.close(sb); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestInvalidRep.java000066400000000000000000000057321255150477200220710ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestInvalidRep { // Create REQ/ROUTER wiring. @Test public void testInvalidRep() { Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); SocketBase routerSocket = ZMQ.socket(ctx, ZMQ.ZMQ_ROUTER); assertThat(routerSocket, notNullValue()); SocketBase reqSocket = ZMQ.socket(ctx, ZMQ.ZMQ_REQ); assertThat(reqSocket, notNullValue()); int linger = 0; int rc; ZMQ.setSocketOption(routerSocket, ZMQ.ZMQ_LINGER, linger); ZMQ.setSocketOption(reqSocket, ZMQ.ZMQ_LINGER, linger); boolean brc = ZMQ.bind(routerSocket, "inproc://hi"); assertThat(brc, is(true)); brc = ZMQ.connect(reqSocket, "inproc://hi"); assertThat(brc, is(true)); // Initial request. rc = ZMQ.send(reqSocket, "r", 0); assertThat(rc, is(1)); // Receive the request. Msg addr; Msg bottom; Msg body; addr = ZMQ.recv(routerSocket, 0); int addrSize = addr.size(); System.out.println("addrSize: " + addr.size()); assertThat(addr.size() > 0, is(true)); bottom = ZMQ.recv(routerSocket, 0); assertThat(bottom.size(), is(0)); body = ZMQ.recv(routerSocket, 0); assertThat(body.size(), is(1)); assertThat(body.data()[0], is((byte) 'r')); // Send invalid reply. rc = ZMQ.send(routerSocket, addr, 0); assertThat(rc, is(addrSize)); // Send valid reply. rc = ZMQ.send(routerSocket, addr, ZMQ.ZMQ_SNDMORE); assertThat(rc, is(addrSize)); rc = ZMQ.send(routerSocket, bottom, ZMQ.ZMQ_SNDMORE); assertThat(rc, is(0)); rc = ZMQ.send(routerSocket, "b", 0); assertThat(rc, is(1)); // Check whether we've got the valid reply. body = ZMQ.recv(reqSocket, 0); assertThat(body.size(), is(1)); assertThat(body.data()[0] , is((byte) 'b')); // Tear down the wiring. ZMQ.close(routerSocket); ZMQ.close(reqSocket); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestLastEndpoint.java000066400000000000000000000032651255150477200224370ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestLastEndpoint { static void bindAndVerify(SocketBase s, String endpoint) { boolean brc = ZMQ.bind(s, endpoint); assertThat(brc, is(true)); String stest = (String) ZMQ.getSocketOptionExt(s, ZMQ.ZMQ_LAST_ENDPOINT); assertThat(stest, is(endpoint)); } @Test public void testLastEndpoint() { // Create the infrastructure Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); SocketBase sb = ZMQ.socket(ctx, ZMQ.ZMQ_ROUTER); assertThat(sb, notNullValue()); bindAndVerify(sb, "tcp://127.0.0.1:5560"); bindAndVerify(sb, "tcp://127.0.0.1:5561"); bindAndVerify(sb, "ipc:///tmp/testep"); sb.close(); ctx.terminate(); } } jeromq-0.3.5/src/test/java/zmq/TestMonitor.java000066400000000000000000000141461255150477200214620ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestMonitor { static class SocketMonitor extends Thread { private Ctx ctx; private int events; private String monitorAddr; public SocketMonitor(Ctx ctx, String monitorAddr) { this.ctx = ctx; this.monitorAddr = monitorAddr; events = 0; } @Override public void run() { SocketBase s = ZMQ.socket(ctx, ZMQ.ZMQ_PAIR); boolean rc = s.connect(monitorAddr); assertThat(rc, is(true)); // Only some of the exceptional events could fire while (true) { ZMQ.Event event = ZMQ.Event.read(s); if (event == null && s.errno() == ZError.ETERM) { break; } assertThat(event, notNullValue()); switch (event.event) { // listener specific case ZMQ.ZMQ_EVENT_LISTENING: events |= ZMQ.ZMQ_EVENT_LISTENING; break; case ZMQ.ZMQ_EVENT_ACCEPTED: events |= ZMQ.ZMQ_EVENT_ACCEPTED; break; // connecter specific case ZMQ.ZMQ_EVENT_CONNECTED: events |= ZMQ.ZMQ_EVENT_CONNECTED; break; case ZMQ.ZMQ_EVENT_CONNECT_DELAYED: events |= ZMQ.ZMQ_EVENT_CONNECT_DELAYED; break; // generic - either end of the socket case ZMQ.ZMQ_EVENT_CLOSE_FAILED: events |= ZMQ.ZMQ_EVENT_CLOSE_FAILED; break; case ZMQ.ZMQ_EVENT_CLOSED: events |= ZMQ.ZMQ_EVENT_CLOSED; break; case ZMQ.ZMQ_EVENT_DISCONNECTED: events |= ZMQ.ZMQ_EVENT_DISCONNECTED; break; default: // out of band / unexpected event assertTrue("Unkown Event " + event.event, true); } } s.close(); } } @Test public void testMonitor() throws Exception { String addr = "tcp://127.0.0.1:5590"; SocketMonitor [] threads = new SocketMonitor [3]; // Create the infrastructure Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); // set socket monitor SocketBase rep = ZMQ.socket(ctx, ZMQ.ZMQ_REP); assertThat(rep, notNullValue()); try { ZMQ.monitorSocket(rep, addr, 0); assertTrue(false); } catch (IllegalArgumentException e) { } // REP socket monitor, all events boolean rc = ZMQ.monitorSocket(rep, "inproc://monitor.rep", ZMQ.ZMQ_EVENT_ALL); assertThat(rc, is(true)); threads [0] = new SocketMonitor(ctx, "inproc://monitor.rep"); threads [0].start(); rc = ZMQ.bind(rep, addr); assertThat(rc, is(true)); SocketBase req = ZMQ.socket(ctx, ZMQ.ZMQ_REQ); assertThat(req, notNullValue()); // REQ socket monitor, all events rc = ZMQ.monitorSocket(req, "inproc://monitor.req", ZMQ.ZMQ_EVENT_ALL); assertThat(rc, is(true)); threads [1] = new SocketMonitor(ctx, "inproc://monitor.req"); threads [1].start(); rc = ZMQ.connect(req, addr); assertThat(rc, is(true)); // 2nd REQ socket SocketBase req2 = ZMQ.socket(ctx, ZMQ.ZMQ_REQ); assertThat(req2, notNullValue()); // 2nd REQ socket monitor, connected event only rc = ZMQ.monitorSocket(req2, "inproc://monitor.req2", ZMQ.ZMQ_EVENT_CONNECTED); assertThat(rc, is(true)); threads [2] = new SocketMonitor(ctx, "inproc://monitor.req2"); threads [2].start(); rc = ZMQ.connect(req2, addr); assertThat(rc, is(true)); Helper.bounce(rep, req); // Allow a window for socket events as connect can be async ZMQ.sleep(1); // Close the REP socket ZMQ.close(rep); // Allow some time for detecting error states ZMQ.sleep(1); // Close the REQ socket ZMQ.close(req); // Close the 2nd REQ socket ZMQ.close(req2); // Allow for closed or disconnected events to bubble up ZMQ.sleep(1); ZMQ.term(ctx); // Expected REP socket events // We expect to at least observe these events assertTrue((threads[0].events & ZMQ.ZMQ_EVENT_LISTENING) > 0); assertTrue((threads[0].events & ZMQ.ZMQ_EVENT_ACCEPTED) > 0); assertTrue((threads[0].events & ZMQ.ZMQ_EVENT_CLOSED) > 0); // Expected REQ socket events assertTrue((threads[1].events & ZMQ.ZMQ_EVENT_CONNECTED) > 0); assertTrue((threads[1].events & ZMQ.ZMQ_EVENT_DISCONNECTED) > 0); assertTrue((threads[1].events & ZMQ.ZMQ_EVENT_CLOSED) > 0); // Expected 2nd REQ socket events assertTrue((threads[2].events & ZMQ.ZMQ_EVENT_CONNECTED) > 0); assertTrue((threads[2].events & ZMQ.ZMQ_EVENT_CLOSED) == 0); threads[0].join(); threads[1].join(); threads[2].join(); } } jeromq-0.3.5/src/test/java/zmq/TestMsg.java000066400000000000000000000030131255150477200205500ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import java.nio.ByteBuffer; public class TestMsg { @Test(expected = IllegalArgumentException.class) public void shouldThrowForNullByteBuffer() { new Msg((ByteBuffer) null); } @Test(expected = IllegalArgumentException.class) public void shouldThrowForBufferWithWrongPosition() { ByteBuffer buffer = ByteBuffer.allocate(10); buffer.putChar('a'); buffer.putChar('b'); buffer.putChar('c'); new Msg(buffer); } @Test public void shouldWorkForFlippedBuffers() { ByteBuffer buffer = ByteBuffer.allocate(10); buffer.putChar('a'); buffer.putChar('b'); buffer.putChar('c'); buffer.flip(); new Msg(buffer); } } jeromq-0.3.5/src/test/java/zmq/TestMsgFlags.java000066400000000000000000000045201255150477200215310ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestMsgFlags { // Create REQ/ROUTER wiring. @Test public void testMsgFlags() { Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); SocketBase sb = ZMQ.socket(ctx, ZMQ.ZMQ_ROUTER); assertThat(sb, notNullValue()); boolean brc = ZMQ.bind(sb, "inproc://a"); assertThat(brc, is(true)); SocketBase sc = ZMQ.socket(ctx, ZMQ.ZMQ_DEALER); assertThat(sc, notNullValue()); brc = ZMQ.connect(sc, "inproc://a"); assertThat(brc, is(true)); int rc; // Send 2-part message. rc = ZMQ.send(sc, "A", ZMQ.ZMQ_SNDMORE); assertThat(rc, is(1)); rc = ZMQ.send(sc, "B", 0); assertThat(rc, is(1)); // Identity comes first. Msg msg = ZMQ.recvMsg(sb, 0); int more = ZMQ.getMessageOption(msg, ZMQ.ZMQ_MORE); assertThat(more, is(1)); // Then the first part of the message body. msg = ZMQ.recvMsg(sb, 0); assertThat(rc, is(1)); more = ZMQ.getMessageOption(msg, ZMQ.ZMQ_MORE); assertThat(more, is(1)); // And finally, the second part of the message body. msg = ZMQ.recvMsg(sb, 0); assertThat(rc, is(1)); more = ZMQ.getMessageOption(msg, ZMQ.ZMQ_MORE); assertThat(more, is(0)); // Tear down the wiring. ZMQ.close(sb); ZMQ.close(sc); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestPairInproc.java000066400000000000000000000031371255150477200220770ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestPairInproc { // Create REQ/ROUTER wiring. @Test public void testPairInproc() { Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); SocketBase sb = ZMQ.socket(ctx, ZMQ.ZMQ_PAIR); assertThat(sb, notNullValue()); boolean brc = ZMQ.bind(sb, "inproc://a"); assertThat(brc , is(true)); SocketBase sc = ZMQ.socket(ctx, ZMQ.ZMQ_PAIR); assertThat(sc, notNullValue()); brc = ZMQ.connect(sc, "inproc://a"); assertThat(brc , is(true)); Helper.bounce(sb, sc); // Tear down the wiring. ZMQ.close(sb); ZMQ.close(sc); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestPairIpc.java000066400000000000000000000031451255150477200213570ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestPairIpc { // Create REQ/ROUTER wiring. @Test public void testPairIpc() { Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); SocketBase sb = ZMQ.socket(ctx, ZMQ.ZMQ_PAIR); assertThat(sb, notNullValue()); boolean brc = ZMQ.bind(sb, "ipc:///tmp/tester"); assertThat(brc, is(true)); SocketBase sc = ZMQ.socket(ctx, ZMQ.ZMQ_PAIR); assertThat(sc, notNullValue()); brc = ZMQ.connect(sc, "ipc:///tmp/tester"); assertThat(brc, is(true)); Helper.bounce(sb, sc); // Tear down the wiring. ZMQ.close(sb); ZMQ.close(sc); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestPairTcp.java000066400000000000000000000031541255150477200213720ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestPairTcp { // Create REQ/ROUTER wiring. @Test public void testPairTpc() { Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); SocketBase sb = ZMQ.socket(ctx, ZMQ.ZMQ_PAIR); assertThat(sb, notNullValue()); boolean brc = ZMQ.bind(sb, "tcp://127.0.0.1:6570"); assertThat(brc, is(true)); SocketBase sc = ZMQ.socket(ctx, ZMQ.ZMQ_PAIR); assertThat(sc, notNullValue()); brc = ZMQ.connect(sc, "tcp://127.0.0.1:6570"); assertThat(brc, is(true)); Helper.bounce(sb, sc); // Tear down the wiring. ZMQ.close(sb); ZMQ.close(sc); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestProxyTcp.java000066400000000000000000000205701255150477200216210ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.io.IOException; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.channels.Selector; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestProxyTcp { static class Client extends Thread { public Client() { } @Override public void run() { System.out.println("Start client thread"); try { Socket s = new Socket("127.0.0.1", 6560); Helper.send(s, "hellow"); Helper.send(s, "1234567890abcdefghizklmnopqrstuvwxyz"); Helper.send(s, "end"); Helper.send(s, "end"); s.close(); } catch (IOException e) { e.printStackTrace(); } System.out.println("Stop client thread"); } } static class Dealer extends Thread { private final SocketBase s; private final String name; public Dealer(Ctx ctx, String name) { this.s = ZMQ.socket(ctx, ZMQ.ZMQ_DEALER); this.name = name; } @Override public void run() { System.out.println("Start dealer " + name); ZMQ.connect(s, "tcp://127.0.0.1:6561"); int i = 0; while (true) { Msg msg = s.recv(0); if (msg == null) { throw new RuntimeException("hello"); } System.out.println("REP recieved " + msg); String data = new String(msg.data(), 0, msg.size(), ZMQ.CHARSET); Msg response = null; if ((i % 3) == 2) { response = new Msg(msg.size() + 3); response.put("OK ".getBytes(ZMQ.CHARSET)) .put(msg.data()); } else { response = new Msg(msg.data()); } s.send(response, (i % 3) == 2 ? 0 : ZMQ.ZMQ_SNDMORE); i++; if (data.equals("end")) { break; } } s.close(); System.out.println("Stop dealer " + name); } } static class ProxyDecoder extends DecoderBase { private static final int READ_HEADER = 0; private static final int READ_BODY = 1; byte [] header = new byte [4]; Msg msg; int size = -1; boolean identitySent = false; Msg bottom; IMsgSink msgSink; public ProxyDecoder(int bufsize, long maxmsgsize) { super(bufsize); nextStep(header, 4, READ_HEADER); bottom = new Msg(); bottom.setFlags(Msg.MORE); } @Override protected boolean next() { switch (state()) { case READ_HEADER: return readHeader(); case READ_BODY: return readBody(); } return false; } private boolean readHeader() { size = Integer.parseInt(new String(header, ZMQ.CHARSET)); System.out.println("Received " + size); msg = new Msg(size); nextStep(msg, READ_BODY); return true; } private boolean readBody() { if (msgSink == null) { return false; } System.out.println("Received body " + new String(msg.data(), ZMQ.CHARSET)); if (!identitySent) { Msg identity = new Msg(); msgSink.pushMsg(identity); identitySent = true; } msgSink.pushMsg(bottom); msgSink.pushMsg(msg); nextStep(header, 4, READ_HEADER); return true; } @Override public boolean stalled() { return state() == READ_BODY; } @Override public void setMsgSink(IMsgSink msgSink) { this.msgSink = msgSink; } } static class ProxyEncoder extends EncoderBase { public static final boolean RAW_ENCODER = true; private static final int WRITE_HEADER = 0; private static final int WRITE_BODY = 1; ByteBuffer header = ByteBuffer.allocate(4); Msg msg; int size = -1; boolean messageReady; boolean identityRecieved; IMsgSource msgSource; public ProxyEncoder(int bufsize) { super(bufsize); nextStep(null, WRITE_HEADER, true); messageReady = false; identityRecieved = false; } @Override protected boolean next() { switch (state()) { case WRITE_HEADER: return writeHeader(); case WRITE_BODY: return writeBody(); } return false; } private boolean writeBody() { System.out.println("writer body "); nextStep(msg, WRITE_HEADER, !msg.hasMore()); return true; } private boolean writeHeader() { if (msgSource == null) { return false; } msg = msgSource.pullMsg(); if (msg == null) { return false; } if (!identityRecieved) { identityRecieved = true; nextStep(header.array(), msg.size() < 255 ? 2 : 10, WRITE_BODY, false); return true; } else if (!messageReady) { messageReady = true; msg = msgSource.pullMsg(); if (msg == null) { return false; } } messageReady = false; System.out.println("write header " + msg.size()); header.clear(); header.put(String.format("%04d", msg.size()).getBytes(ZMQ.CHARSET)); header.flip(); nextStep(header.array(), 4, WRITE_BODY, false); return true; } @Override public void setMsgSource(IMsgSource msgSource) { this.msgSource = msgSource; } } static class Main extends Thread { private Ctx ctx; private Selector selector; Main(Ctx ctx) { this.ctx = ctx; } @Override public void run() { boolean rc; SocketBase sa = ZMQ.socket(ctx, ZMQ.ZMQ_ROUTER); assertThat(sa, notNullValue()); sa.setSocketOpt(ZMQ.ZMQ_DECODER, ProxyDecoder.class); sa.setSocketOpt(ZMQ.ZMQ_ENCODER, ProxyEncoder.class); rc = ZMQ.bind(sa, "tcp://127.0.0.1:6560"); assertThat(rc, is(true)); SocketBase sb = ZMQ.socket(ctx, ZMQ.ZMQ_DEALER); assertThat(sb, notNullValue()); rc = ZMQ.bind(sb, "tcp://127.0.0.1:6561"); assertThat(rc, is(true)); ZMQ.proxy(sa, sb, null); ZMQ.close(sa); ZMQ.close(sb); } } @Test public void testProxyTcp() throws Exception { Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); Main mt = new Main(ctx); mt.start(); new Dealer(ctx, "A").start(); new Dealer(ctx, "B").start(); Thread.sleep(1000); Thread client = new Client(); client.start(); client.join(); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestPubsubTcp.java000066400000000000000000000036611255150477200217420ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestPubsubTcp { @Test public void testPubsubTcp() throws Exception { Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); SocketBase sb = ZMQ.socket(ctx, ZMQ.ZMQ_PUB); assertThat(sb, notNullValue()); boolean rc = ZMQ.bind(sb, "tcp://127.0.0.1:7660"); assertThat(rc, is(true)); SocketBase sc = ZMQ.socket(ctx, ZMQ.ZMQ_SUB); assertThat(sc, notNullValue()); sc.setSocketOpt(ZMQ.ZMQ_SUBSCRIBE, "topic"); rc = ZMQ.connect(sc, "tcp://127.0.0.1:7660"); assertThat(rc, is(true)); ZMQ.sleep(2); sb.send(new Msg("topic abc".getBytes(ZMQ.CHARSET)), 0); sb.send(new Msg("topix defg".getBytes(ZMQ.CHARSET)), 0); sb.send(new Msg("topic defgh".getBytes(ZMQ.CHARSET)), 0); Msg msg = sc.recv(0); assertThat(msg.size(), is(9)); msg = sc.recv(0); assertThat(msg.size(), is(11)); ZMQ.close(sc); ZMQ.close(sb); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestReqrepDevice.java000066400000000000000000000105531255150477200224070ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestReqrepDevice { // Create REQ/ROUTER wiring. @Test public void testReprepDevice() { boolean brc; Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); // Create a req/rep device. SocketBase dealer = ZMQ.socket(ctx, ZMQ.ZMQ_DEALER); assertThat(dealer, notNullValue()); brc = ZMQ.bind(dealer, "tcp://127.0.0.1:5580"); assertThat(brc , is(true)); SocketBase router = ZMQ.socket(ctx, ZMQ.ZMQ_ROUTER); assertThat(router, notNullValue()); brc = ZMQ.bind(router, "tcp://127.0.0.1:5581"); assertThat(brc , is(true)); // Create a worker. SocketBase rep = ZMQ.socket(ctx, ZMQ.ZMQ_REP); assertThat(rep, notNullValue()); brc = ZMQ.connect(rep, "tcp://127.0.0.1:5580"); assertThat(brc , is(true)); SocketBase req = ZMQ.socket(ctx, ZMQ.ZMQ_REQ); assertThat(req, notNullValue()); brc = ZMQ.connect(req, "tcp://127.0.0.1:5581"); assertThat(brc, is(true)); // Send a request. int rc; Msg msg; String buff; long rcvmore; rc = ZMQ.send(req, "ABC", ZMQ.ZMQ_SNDMORE); assertThat(rc, is(3)); rc = ZMQ.send(req, "DEFG", 0); assertThat(rc, is(4)); // Pass the request through the device. for (int i = 0; i != 4; i++) { msg = ZMQ.recvMsg(router, 0); assertThat(msg, notNullValue()); rcvmore = ZMQ.getSocketOption(router, ZMQ.ZMQ_RCVMORE); rc = ZMQ.sendMsg(dealer, msg, rcvmore > 0 ? ZMQ.ZMQ_SNDMORE : 0); assertThat(rc >= 0, is(true)); } // Receive the request. msg = ZMQ.recv(rep, 0); assertThat(msg.size() , is(3)); buff = new String(msg.data(), ZMQ.CHARSET); assertThat(buff , is("ABC")); rcvmore = ZMQ.getSocketOption(rep, ZMQ.ZMQ_RCVMORE); assertThat(rcvmore > 0, is(true)); msg = ZMQ.recv(rep, 0); assertThat(msg.size(), is(4)); buff = new String(msg.data(), ZMQ.CHARSET); assertThat(buff, is("DEFG")); rcvmore = ZMQ.getSocketOption(rep, ZMQ.ZMQ_RCVMORE); assertThat(rcvmore, is(0L)); // Send the reply. rc = ZMQ.send(rep, "GHIJKL", ZMQ.ZMQ_SNDMORE); assertThat(rc, is(6)); rc = ZMQ.send(rep, "MN", 0); assertThat(rc , is(2)); // Pass the reply through the device. for (int i = 0; i != 4; i++) { msg = ZMQ.recvMsg(dealer, 0); assertThat(msg, notNullValue()); rcvmore = ZMQ.getSocketOption(dealer, ZMQ.ZMQ_RCVMORE); rc = ZMQ.sendMsg(router, msg, rcvmore > 0 ? ZMQ.ZMQ_SNDMORE : 0); assertThat(rc >= 0, is(true)); } // Receive the reply. msg = ZMQ.recv(req, 0); assertThat(msg.size(), is(6)); buff = new String(msg.data(), ZMQ.CHARSET); assertThat(buff, is("GHIJKL")); rcvmore = ZMQ.getSocketOption(req, ZMQ.ZMQ_RCVMORE); assertThat(rcvmore > 0, is(true)); msg = ZMQ.recv(req, 0); assertThat(msg.size(), is(2)); buff = new String(msg.data(), ZMQ.CHARSET); assertThat(buff, is("MN")); rcvmore = ZMQ.getSocketOption(req, ZMQ.ZMQ_RCVMORE); assertThat(rcvmore, is(0L)); // Clean up. ZMQ.close(req); ZMQ.close(rep); ZMQ.close(router); ZMQ.close(dealer); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestReqrepInproc.java000066400000000000000000000031411255150477200224350ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestReqrepInproc { // Create REQ/ROUTER wiring. @Test public void testReqrepInproc() { Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); SocketBase sb = ZMQ.socket(ctx, ZMQ.ZMQ_REP); assertThat(sb, notNullValue()); boolean brc = ZMQ.bind(sb, "inproc://a"); assertThat(brc , is(true)); SocketBase sc = ZMQ.socket(ctx, ZMQ.ZMQ_REQ); assertThat(sc, notNullValue()); brc = ZMQ.connect(sc, "inproc://a"); assertThat(brc , is(true)); Helper.bounce(sb, sc); // Tear down the wiring. ZMQ.close(sb); ZMQ.close(sc); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestReqrepIpc.java000066400000000000000000000031101255150477200217120ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestReqrepIpc { @Test public void testReqrepIpc() { Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); SocketBase sb = ZMQ.socket(ctx, ZMQ.ZMQ_REP); assertThat(sb, notNullValue()); boolean brc = ZMQ.bind(sb, "ipc:///tmp/tester2"); assertThat(brc , is(true)); SocketBase sc = ZMQ.socket(ctx, ZMQ.ZMQ_REQ); assertThat(sc, notNullValue()); brc = ZMQ.connect(sc, "ipc:///tmp/tester2"); assertThat(brc , is(true)); Helper.bounce(sb, sc); // Tear down the wiring. ZMQ.close(sb); ZMQ.close(sc); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestReqrepTcp.java000066400000000000000000000030661255150477200217370ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestReqrepTcp { @Test public void testReqrepTcp() throws Exception { Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); SocketBase sb = ZMQ.socket(ctx, ZMQ.ZMQ_REP); assertThat(sb, notNullValue()); boolean rc = ZMQ.bind(sb, "tcp://127.0.0.1:7560"); assertThat(rc, is(true)); SocketBase sc = ZMQ.socket(ctx, ZMQ.ZMQ_REQ); assertThat(sc, notNullValue()); rc = ZMQ.connect(sc, "tcp://127.0.0.1:7560"); assertThat(rc, is(true)); Helper.bounce(sb, sc); ZMQ.close(sc); ZMQ.close(sb); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestRouterHandover.java000066400000000000000000000070411255150477200227760ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertThat; public class TestRouterHandover { @Test public void testRouterHandover() throws Exception { int rc; boolean brc; Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); SocketBase router = ZMQ.socket(ctx, ZMQ.ZMQ_ROUTER); brc = ZMQ.bind(router, "tcp://127.0.0.1:15561"); assertThat(brc , is(true)); // Enable the handover flag ZMQ.setSocketOption(router, ZMQ.ZMQ_ROUTER_HANDOVER, 1); assertThat(router, notNullValue()); // Create dealer called "X" and connect it to our router SocketBase dealerOne = ZMQ.socket(ctx, ZMQ.ZMQ_DEALER); assertThat(dealerOne, notNullValue()); ZMQ.setSocketOption(dealerOne, ZMQ.ZMQ_IDENTITY, "X"); brc = ZMQ.connect(dealerOne, "tcp://127.0.0.1:15561"); assertThat(brc, is(true)); // Get message from dealer to know when connection is ready rc = ZMQ.send(dealerOne, "Hello", 0); assertThat(rc, is(5)); Msg msg = ZMQ.recv(router, 0); assertThat(msg.size() , is(1)); assertThat(new String(msg.data()) , is("X")); msg = ZMQ.recv(router, 0); assertThat(msg.size(), is(5)); // Now create a second dealer that uses the same identity SocketBase dealerTwo = ZMQ.socket(ctx, ZMQ.ZMQ_DEALER); assertThat(dealerTwo, notNullValue()); ZMQ.setSocketOption(dealerTwo, ZMQ.ZMQ_IDENTITY, "X"); brc = ZMQ.connect(dealerTwo, "tcp://127.0.0.1:15561"); assertThat(brc, is(true)); // Get message from dealer to know when connection is ready rc = ZMQ.send(dealerTwo, "Hello", 0); assertThat(rc, is(5)); msg = ZMQ.recv(router, 0); assertThat(msg.size() , is(1)); assertThat(new String(msg.data()) , is("X")); msg = ZMQ.recv(router, 0); assertThat(msg.size(), is(5)); // Send a message to 'X' identity. This should be delivered // to the second dealer, instead of the first because of the handover. rc = ZMQ.send(router, "X", ZMQ.ZMQ_SNDMORE); assertThat(rc, is(1)); rc = ZMQ.send(router, "Hello", 0); assertThat(rc, is(5)); // Ensure that the first dealer doesn't receive the message // but the second one does msg = ZMQ.recv(dealerOne, ZMQ.ZMQ_DONTWAIT); assertThat(msg, nullValue()); msg = ZMQ.recv(dealerTwo, 0); assertThat(msg.size(), is(5)); // Clean up. ZMQ.close(router); ZMQ.close(dealerOne); ZMQ.close(dealerTwo); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestRouterMandatory.java000066400000000000000000000057451255150477200231770ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestRouterMandatory { @Test public void testRouterMandatory() throws Exception { int rc; boolean brc; Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); SocketBase sa = ZMQ.socket(ctx, ZMQ.ZMQ_ROUTER); ZMQ.setSocketOption(sa, ZMQ.ZMQ_SNDHWM, 1); assertThat(sa, notNullValue()); brc = ZMQ.bind(sa, "tcp://127.0.0.1:15560"); assertThat(brc , is(true)); // Sending a message to an unknown peer with the default setting rc = ZMQ.send(sa, "UNKNOWN", ZMQ.ZMQ_SNDMORE); assertThat(rc, is(7)); rc = ZMQ.send(sa, "DATA", 0); assertThat(rc, is(4)); int mandatory = 1; // Set mandatory routing on socket ZMQ.setSocketOption(sa, ZMQ.ZMQ_ROUTER_MANDATORY, mandatory); // Send a message and check that it fails rc = ZMQ.send(sa, "UNKNOWN", ZMQ.ZMQ_SNDMORE | ZMQ.ZMQ_DONTWAIT); assertThat(rc, is(-1)); assertThat(sa.errno(), is(ZError.EHOSTUNREACH)); // Create a valid socket SocketBase sb = ZMQ.socket(ctx, ZMQ.ZMQ_DEALER); assertThat(sb, notNullValue()); ZMQ.setSocketOption(sb, ZMQ.ZMQ_RCVHWM, 1); ZMQ.setSocketOption(sb, ZMQ.ZMQ_IDENTITY, "X"); brc = ZMQ.connect(sb, "tcp://127.0.0.1:15560"); // wait until connect Thread.sleep(1000); // make it full and check that it fails rc = ZMQ.send(sa, "X", ZMQ.ZMQ_SNDMORE); assertThat(rc, is(1)); rc = ZMQ.send(sa, "DATA1", 0); assertThat(rc, is(5)); rc = ZMQ.send(sa, "X", ZMQ.ZMQ_SNDMORE | ZMQ.ZMQ_DONTWAIT); if (rc == 1) { // the first frame has been sent rc = ZMQ.send(sa, "DATA2", 0); assertThat(rc, is(5)); // send more rc = ZMQ.send(sa, "X", ZMQ.ZMQ_SNDMORE | ZMQ.ZMQ_DONTWAIT); } assertThat(rc, is(-1)); assertThat(sa.errno(), is(ZError.EAGAIN)); // Clean up. ZMQ.close(sa); ZMQ.close(sb); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestShutdownStress.java000066400000000000000000000044411255150477200230470ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestShutdownStress { private static final int THREAD_COUNT = 100; class Worker implements Runnable { SocketBase s; Worker(SocketBase s) { this.s = s; } @Override public void run() { boolean rc = ZMQ.connect(s, "tcp://127.0.0.1:5560"); assertThat(rc, is(true)); // Start closing the socket while the connecting process is underway. ZMQ.close(s); } } @Test public void testShutdownStress() throws Exception { Thread[] threads = new Thread[THREAD_COUNT]; for (int j = 0; j != 10; j++) { Ctx ctx = ZMQ.init(7); assertThat(ctx, notNullValue()); SocketBase s1 = ZMQ.socket(ctx, ZMQ.ZMQ_PUB); assertThat(s1, notNullValue()); boolean rc = ZMQ.bind(s1, "tcp://127.0.0.1:7570"); assertThat(rc, is(true)); for (int i = 0; i != THREAD_COUNT; i++) { SocketBase s2 = ZMQ.socket(ctx, ZMQ.ZMQ_SUB); assert (s2 != null); threads[i] = new Thread(new Worker(s2)); threads[i].start(); } for (int i = 0; i != THREAD_COUNT; i++) { threads[i].join(); } ZMQ.close(s1); ZMQ.term(ctx); } } } jeromq-0.3.5/src/test/java/zmq/TestSubForward.java000066400000000000000000000050151255150477200221040ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.notNullValue; public class TestSubForward { // Create REQ/ROUTER wiring. @Test public void testSubForward() { Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); SocketBase xpub = ZMQ.socket(ctx, ZMQ.ZMQ_XPUB); assertThat(xpub, notNullValue()); boolean rc = ZMQ.bind(xpub, "tcp://127.0.0.1:5570"); SocketBase xsub = ZMQ.socket(ctx, ZMQ.ZMQ_XSUB); assertThat(xsub, notNullValue()); rc = ZMQ.bind(xsub, "tcp://127.0.0.1:5571"); assertThat(rc, is(true)); SocketBase pub = ZMQ.socket(ctx, ZMQ.ZMQ_PUB); assertThat(pub, notNullValue()); rc = ZMQ.connect(pub, "tcp://127.0.0.1:5571"); assertThat(rc, is(true)); SocketBase sub = ZMQ.socket(ctx, ZMQ.ZMQ_SUB); assertThat(sub, notNullValue()); rc = ZMQ.connect(sub, "tcp://127.0.0.1:5570"); assertThat(rc, is(true)); ZMQ.setSocketOption(sub, ZMQ.ZMQ_SUBSCRIBE, ""); Msg msg = ZMQ.recv(xpub, 0); assertThat(msg, notNullValue()); int n = ZMQ.send(xsub, msg, 0); assertThat(n, not(0)); ZMQ.sleep(1); n = ZMQ.send(pub, null, 0, 0); assertThat(n, is(0)); msg = ZMQ.recv(xsub, 0); assertThat(msg, notNullValue()); n = ZMQ.send(xpub, msg, 0); assertThat(n, is(0)); msg = ZMQ.recv(sub, 0); assertThat(msg, notNullValue()); // Tear down the wiring. ZMQ.close(xpub); ZMQ.close(xsub); ZMQ.close(pub); ZMQ.close(sub); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestTermEndpoint.java000066400000000000000000000063471255150477200224470ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; public class TestTermEndpoint { @Test public void testTermEndpoint() throws Exception { String ep = "tcp://127.0.0.1:7590"; Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); SocketBase push = ZMQ.socket(ctx, ZMQ.ZMQ_PUSH); assertThat(push, notNullValue()); boolean rc = ZMQ.bind(push, ep); assertThat(rc, is(true)); SocketBase pull = ZMQ.socket(ctx, ZMQ.ZMQ_PULL); assertThat(pull, notNullValue()); rc = ZMQ.connect(pull, ep); assertThat(rc, is(true)); // Pass one message through to ensure the connection is established. int r = ZMQ.send(push, "ABC", 0); assertThat(r, is(3)); Msg msg = ZMQ.recv(pull, 0); assertThat(msg.size(), is(3)); // Unbind the lisnening endpoint rc = ZMQ.unbind(push, ep); assertThat(rc, is(true)); // Let events some time ZMQ.sleep(1); // Check that sending would block (there's no outbound connection). r = ZMQ.send(push, "ABC", ZMQ.ZMQ_DONTWAIT); assertThat(r, is(-1)); // Clean up. ZMQ.close(pull); ZMQ.close(push); ZMQ.term(ctx); // Now the other way round. System.out.println("disconnect endpoint test running..."); ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); push = ZMQ.socket(ctx, ZMQ.ZMQ_PUSH); assertThat(push, notNullValue()); rc = ZMQ.bind(push, ep); assertThat(rc, is(true)); pull = ZMQ.socket(ctx, ZMQ.ZMQ_PULL); assertThat(pull, notNullValue()); rc = ZMQ.connect(pull, ep); assertThat(rc, is(true)); // Pass one message through to ensure the connection is established. r = ZMQ.send(push, "ABC", 0); assertThat(r, is(3)); msg = ZMQ.recv(pull, 0); assertThat(msg.size(), is(3)); // Disconnect the bound endpoint rc = ZMQ.disconnect(push, ep); assertThat(rc, is(true)); // Let events some time ZMQ.sleep(1); // Check that sending would block (there's no outbound connection). r = ZMQ.send(push, "ABC", ZMQ.ZMQ_DONTWAIT); assertThat(r, is(-1)); // Clean up. ZMQ.close(pull); ZMQ.close(push); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestTimeo.java000066400000000000000000000067071255150477200211140ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.CoreMatchers.notNullValue; public class TestTimeo { class Worker implements Runnable { Ctx ctx; Worker(Ctx ctx) { this.ctx = ctx; } @Override public void run() { ZMQ.sleep(1); SocketBase sc = ZMQ.socket(ctx, ZMQ.ZMQ_PUSH); assertThat(sc, notNullValue()); boolean rc = ZMQ.connect(sc, "inproc://timeout_test"); assertThat(rc, is(true)); ZMQ.sleep(1); ZMQ.close(sc); } } @Test public void testTimeo() throws Exception { Ctx ctx = ZMQ.init(1); assertThat(ctx, notNullValue()); SocketBase sb = ZMQ.socket(ctx, ZMQ.ZMQ_PULL); assertThat(sb, notNullValue()); boolean rc = ZMQ.bind(sb, "inproc://timeout_test"); assertThat(rc, is(true)); // Check whether non-blocking recv returns immediately. Msg msg = ZMQ.recv(sb, ZMQ.ZMQ_DONTWAIT); assertThat(msg, nullValue()); // Check whether recv timeout is honoured. int timeout = 500; ZMQ.setSocketOption(sb, ZMQ.ZMQ_RCVTIMEO, timeout); long watch = ZMQ.startStopwatch(); msg = ZMQ.recv(sb, 0); assertThat(msg , nullValue()); long elapsed = ZMQ.stopStopwatch(watch); assertThat(elapsed > 440000 && elapsed < 550000, is(true)); // Check whether connection during the wait doesn't distort the timeout. timeout = 2000; ZMQ.setSocketOption(sb, ZMQ.ZMQ_RCVTIMEO, timeout); Thread thread = new Thread(new Worker(ctx)); thread.start(); watch = ZMQ.startStopwatch(); msg = ZMQ.recv(sb, 0); assertThat(msg , nullValue()); elapsed = ZMQ.stopStopwatch(watch); assertThat(elapsed > 1900000 && elapsed < 2100000, is(true)); thread.join(); // Check that timeouts don't break normal message transfer. SocketBase sc = ZMQ.socket(ctx, ZMQ.ZMQ_PUSH); assertThat(sc, notNullValue()); ZMQ.setSocketOption(sb, ZMQ.ZMQ_RCVTIMEO, timeout); ZMQ.setSocketOption(sb, ZMQ.ZMQ_SNDTIMEO, timeout); rc = ZMQ.connect(sc, "inproc://timeout_test"); assertThat(rc, is(true)); Msg smsg = new Msg("12345678ABCDEFGH12345678abcdefgh".getBytes(ZMQ.CHARSET)); int r = ZMQ.send(sc, smsg, 0); assertThat(r, is(32)); msg = ZMQ.recv(sb, 0); assertThat(msg.size(), is(32)); ZMQ.close(sc); ZMQ.close(sb); ZMQ.term(ctx); } } jeromq-0.3.5/src/test/java/zmq/TestUtils.java000066400000000000000000000052521255150477200211310ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import java.util.ArrayList; import java.util.List; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; public class TestUtils { @Test public void testRealloc() { Integer[] src = new Integer[] {1, 3, 5}; Integer[] dest = Utils.realloc(Integer.class, src, 3, true); assertThat(src.length, is(3)); assertThat(src, is(dest)); dest = Utils.realloc(Integer.class, src, 5, true); assertThat(dest.length, is(5)); assertThat(dest[0], is(1)); assertThat(dest[1], is(3)); assertThat(dest[2], is(5)); assertThat(dest[4], nullValue()); dest = Utils.realloc(Integer.class, src, 6, false); assertThat(dest.length, is(6)); assertThat(dest[0], nullValue()); assertThat(dest[1], nullValue()); assertThat(dest[2], nullValue()); assertThat(dest[3], is(1)); assertThat(dest[4], is(3)); assertThat(dest[5], is(5)); src = new Integer[] {1, 3, 5, 7, 9, 11}; dest = Utils.realloc(Integer.class, src, 4, false); assertThat(dest.length, is(4)); assertThat(dest[0], is(1)); assertThat(dest[1], is(3)); assertThat(dest[2], is(5)); assertThat(dest[3], is(7)); dest = Utils.realloc(Integer.class, src, 3, true); assertThat(dest.length, is(3)); assertThat(dest[0], is(7)); assertThat(dest[1], is(9)); assertThat(dest[2], is(11)); } @Test public void testSwap() { List data = new ArrayList(); data.add(1); data.add(3); data.add(5); data.add(7); Utils.swap(data, 1, 3); assertThat(data.get(1), is(7)); assertThat(data.get(3), is(3)); Utils.swap(data, 2, 2); assertThat(data.get(2), is(5)); } } jeromq-0.3.5/src/test/java/zmq/TestYQueue.java000066400000000000000000000033461255150477200212500ustar00rootroot00000000000000/* Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file This file is part of 0MQ. 0MQ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 0MQ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package zmq; import org.junit.Test; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.is; public class TestYQueue { @Test public void testReuse() { // yqueue has a first empty entry YQueue p = new YQueue(3); Msg m1 = new Msg(1); Msg m2 = new Msg(2); Msg m3 = new Msg(3); Msg m4 = new Msg(4); Msg m5 = new Msg(5); Msg m6 = new Msg(6); Msg m7 = new Msg(7); m7.put("1234567".getBytes(ZMQ.CHARSET)); p.push(m1); assertThat(p.backPos(), is(1)); p.push(m2); // might allocated new chunk p.push(m3); assertThat(p.backPos(), is(3)); assertThat(p.frontPos(), is(0)); p.pop(); p.pop(); p.pop(); // offer the old chunk assertThat(p.frontPos(), is(3)); p.push(m4); p.push(m5); // might reuse the old chunk p.push(m6); assertThat(p.backPos(), is(0)); } }