├── .gitignore ├── .travis.yml ├── AUTHORS ├── CHANGELOG.md ├── COPYING ├── COPYING.LESSER ├── README.md ├── bin └── update-gh-page.sh ├── debs ├── jzmq_2.1.0-1_amd64.deb ├── jzmq_2.1.1-1_amd64.deb ├── jzmq_2.1.2-1_amd64.deb └── jzmq_2.1.3-1_amd64.deb ├── pom.xml └── src ├── main └── java │ └── org │ └── zeromq │ ├── ContextFactory.java │ ├── Patterns.java │ ├── Sockets.java │ ├── api │ ├── Backgroundable.java │ ├── BeaconListener.java │ ├── BeaconReactor.java │ ├── BinaryStarReactor.java │ ├── Bindable.java │ ├── Broadcastable.java │ ├── CloneClient.java │ ├── CloneServer.java │ ├── Connectable.java │ ├── Context.java │ ├── DeviceType.java │ ├── LoopAdapter.java │ ├── LoopHandler.java │ ├── Message.java │ ├── MessageFlag.java │ ├── PollAdapter.java │ ├── PollListener.java │ ├── Pollable.java │ ├── Poller.java │ ├── PollerType.java │ ├── Reactor.java │ ├── Receiver.java │ ├── Routable.java │ ├── RoutedMessage.java │ ├── Sender.java │ ├── Socket.java │ ├── SocketSpec.java │ ├── SocketType.java │ ├── Subscribable.java │ ├── TransportType.java │ ├── TypedReceiver.java │ ├── TypedSender.java │ ├── UdpBeacon.java │ └── exception │ │ ├── ContextTerminatedException.java │ │ ├── InvalidSocketException.java │ │ ├── ZMQExceptions.java │ │ └── ZMQRuntimeException.java │ └── jzmq │ ├── ManagedContext.java │ ├── ManagedSocket.java │ ├── UdpSocket.java │ ├── beacon │ ├── BeaconReactorBuilder.java │ └── BeaconReactorImpl.java │ ├── bstar │ ├── BinaryStarClient.java │ ├── BinaryStarReactorBuilder.java │ ├── BinaryStarReactorImpl.java │ └── BinaryStarSocketBuilder.java │ ├── clone │ ├── CloneClientAgent.java │ ├── CloneClientBuilder.java │ ├── CloneClientImpl.java │ ├── CloneMessage.java │ ├── CloneServerBuilder.java │ └── CloneServerImpl.java │ ├── device │ └── DeviceBuilder.java │ ├── examples │ ├── PublishSubscribe.java │ ├── PushPull.java │ └── RequestReply.java │ ├── poll │ ├── PollableImpl.java │ ├── PollerBuilder.java │ └── PollerImpl.java │ ├── reactor │ ├── PollItem.java │ ├── ReactorBuilder.java │ ├── ReactorImpl.java │ └── ReactorTimer.java │ └── sockets │ ├── DealerSocketBuilder.java │ ├── PairSocketBuilder.java │ ├── PubSocketBuilder.java │ ├── PullSocketBuilder.java │ ├── PushSocketBuilder.java │ ├── RepSocketBuilder.java │ ├── ReqSocketBuilder.java │ ├── RouterSocketBuilder.java │ ├── SocketBuilder.java │ ├── SubSocketBuilder.java │ ├── XPubSocketBuilder.java │ └── XSubSocketBuilder.java └── test ├── java ├── guide │ ├── GuideHelper.java │ ├── asyncsrv.java │ ├── hwclient.java │ ├── hwserver.java │ ├── identity.java │ ├── lbbroker.java │ ├── lbbroker2.java │ ├── msgqueue.java │ ├── mspoller.java │ ├── msreader.java │ ├── mtrelay.java │ ├── mtserver.java │ ├── psenvpub.java │ ├── psenvsub.java │ ├── rrbroker.java │ ├── rrclient.java │ ├── rrworker.java │ ├── rtdealer.java │ ├── rtreq.java │ ├── syncpub.java │ ├── syncsub.java │ ├── tasksink.java │ ├── tasksink2.java │ ├── taskvent.java │ ├── taskwork.java │ ├── taskwork2.java │ ├── version.java │ ├── wuclient.java │ ├── wuproxy.java │ └── wuserver.java └── org │ └── zeromq │ ├── api │ ├── BeaconReactorTest.java │ ├── BinaryStarReactorTest.java │ ├── CloneServerTest.java │ ├── DealerRepTest.java │ ├── DeviceBuilderTest.java │ ├── ForkTest.java │ ├── MessageTest.java │ ├── PollerTest.java │ ├── ProxyTest.java │ ├── PubSubTest.java │ ├── PushPullTest.java │ ├── QueueTest.java │ ├── ReactorTest.java │ ├── ReqRepTest.java │ ├── RoutedMessageTest.java │ ├── RouterDealerTest.java │ ├── RouterTest.java │ ├── SocketBuilderTest.java │ ├── SocketTest.java │ └── SocketsTest.java │ └── client │ ├── BackupStar.java │ ├── CloneClientMain.java │ ├── CloneServerMain.java │ └── PrimaryStar.java └── resources └── logback.xml /.gitignore: -------------------------------------------------------------------------------- 1 | \#* 2 | *.class 3 | *.jar 4 | .classpath 5 | .project 6 | .settings 7 | target/ 8 | .idea 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | before_install: 2 | - sudo apt-get update -y 3 | 4 | language: java 5 | 6 | script: mvn test 7 | 8 | jdk: 9 | - oraclejdk8 10 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Contributors 2 | ============ 3 | John Watson 4 | Stephen Riesenberg -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v0.2.0 4 | 5 | * [#44](https://github.com/zeromq/jzmq-api/pull/44): Fix deprecation warnings 6 | * [#43](https://github.com/zeromq/jzmq-api/pull/43): Flip ByteBuffer when building a new frame [bug fix] 7 | * [#41](https://github.com/zeromq/jzmq-api/pull/41): Upgrade pom 8 | * Upgraded to jeromq 0.5.1 9 | * Upgraded plugins 10 | * Removed oss-parent 11 | * [#39](https://github.com/zeromq/jzmq-api/pull/39): Upgrade to jeromq 0.4.3 12 | 13 | ## v0.1.0 14 | 15 | * [#37](https://github.com/zeromq/jzmq-api/pull/37): Improvements for large byte values in FrameBuilder 16 | * Add error checking for large byte/string values 17 | * Allow unsigned byte values 18 | * [#36](https://github.com/zeromq/jzmq-api/pull/36): Consistency improvements to Message 19 | * Removed Message.Frame.wrap() in favor of Message.Frame.of() 20 | * [#34](https://github.com/zeromq/jzmq-api/pull/34): Fixes and enhancements 21 | * Added putBytes and getBytes methods 22 | * Fixed bug in FrameBuilder's checkCapacity method 23 | * Added additional methods to Message, Frame, and FrameBuilder to support code generation (e.g. zproto) 24 | * Fixed ReactorBuilder's start/run methods 25 | * [#32](https://github.com/zeromq/jzmq-api/pull/32): Added Clone Pattern implementation 26 | * Added Clone pattern support … 27 | * Fixed bug in FrameBuilder when growing buffer dynamically 28 | * Cleaned up asserts 29 | * Added multiple subscription support 30 | * [#30](https://github.com/zeromq/jzmq-api/pull/30): Fixes and improvements 31 | * Fixed shutdown bug in no-context API 32 | * Removed Object varargs in various API interfaces for more idiomatic Java 33 | * Removed unnecessary public visibility modifier in various interface declarations 34 | * Added additional javadoc to various objects and API interfaces 35 | * Usability improvements to Message 36 | * Lowered visibility of internal API method in ManagedContext (never released-experimental) 37 | * Converted handlers (singleton instance fields) in reactors to nested classes for readability 38 | * Changed BinaryStarClient to forward additional replies 39 | * Fixed terminate bug in Reactor when running on jeromq 40 | * Fixed NPE in BinaryStarClient on shutdown 41 | * Upgraded to jeromq 0.3.6 for build stability 42 | * [#29](https://github.com/zeromq/jzmq-api/pull/29): Multiple code improvements 43 | * [#28](https://github.com/zeromq/jzmq-api/pull/28): Added no-context API 44 | * [#26](https://github.com/zeromq/jzmq-api/pull/26): Added new convenience methods to Message 45 | * [#25](https://github.com/zeromq/jzmq-api/pull/25): Added unregister method to Poller 46 | * [#22](https://github.com/zeromq/jzmq-api/pull/22): Added LoopAdapter class 47 | * [#19](https://github.com/zeromq/jzmq-api/pull/19): Changes to Message.Frame 48 | * Changed Frame to use ByteBuffer instead of byte array 49 | * Added various `Frame.put*` methods 50 | * [#14](https://github.com/zeromq/jzmq-api/pull/15): Added support for Clone Pattern 51 | * Added terminate method to Context with implementation to asynchronously terminate (attempting to easily abort pollers) 52 | * Added event-driven Reactor 53 | * Added Binary Star Reactor 54 | * Added subscribeAll method to SubSocketBuilder 55 | * Added BeaconReactor 56 | * Changed PollListener API to accept Pollable 57 | * Added BinaryStarClient background agent and socket builder 58 | * Various improvements and test fixes 59 | * [#13](https://github.com/zeromq/jzmq-api/pull/14): Added support for simple queue device 60 | * [#12](https://github.com/zeromq/jzmq-api/pull/12): Changes to support jzmq / jeromq maven profiles 61 | * Added two maven profiles to pom.xml, jzmq and jeromq 62 | * Switched to snapshot builds of jzmq and jeromq until next release, as these changes depend on recent changes made to both libraries 63 | * Changes to accommodate building against both jzmq and jeromq 64 | * [#11](https://github.com/zeromq/jzmq-api/pull/11): Upgraded to Java 7 65 | * [#10](https://github.com/zeromq/jzmq-api/pull/10): Improvements to Poller and Backgroundable 66 | * Made Poller an interface and moved to api package 67 | * Added methods to Poller for enable/disable (somewhat analogous to register/unregister) 68 | * Fixed re-indexing pollables bug 69 | * Added support for managing background threads other than PAIR sockets 70 | * Added method to Backgroundable for shutdown, called by ManagedContext 71 | * Added shadow method to Context for multi-threaded shutdown/cleanup 72 | * [#9](https://github.com/zeromq/jzmq-api/pull/9): Additional enhancements to exception handling 73 | * Messages return null when encoutering errors 74 | * Poller throws higher level exceptions 75 | * Enhanced/refactored Poller 76 | * [#8](https://github.com/zeromq/jzmq-api/pull/8): Advanced exception handling 77 | * Added new exceptions (ZMQRuntimeException, InvalidSocketException, ContextTerminatedException) all extending from ZMQException 78 | * Added utility to wrap exceptions from jzmq 79 | * Added exception handling logic to wrap exceptions 80 | * [#7](https://github.com/zeromq/jzmq-api/pull/7): API improvements 81 | * New Context.fork method inspired by ZThread.fork 82 | * New interface: Backgroundable 83 | * Additional URLs for connect methods 84 | * [#5](https://github.com/zeromq/jzmq-api/pull/5): Improvements to Message API 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jzmq-api 2 | 3 | [![Build Status](https://travis-ci.org/zeromq/jzmq-api.png)](https://travis-ci.org/zeromq/jzmq-api) 4 | 5 | A Java ØMQ API for abstracting the various implementations of ZeroMQ Message Transport Protocol. 6 | 7 | ## Warning 8 | 9 | The API is still in it's infancy and will be subject to much change. 10 | 11 | ## Installation 12 | 13 | This library supports using both jzmq and JeroMQ via profiles. The default is JeroMQ. 14 | 15 | Before you can begin using this library with jzmq, you need to have the zmq and jzmq shared libraries in either: 16 | * `/usr/lib` 17 | * `/usr/local/lib`. 18 | 19 | ## Getting Started 20 | 21 | The latest [javadocs](http://zeromq.github.com/jzmq-api/javadocs/). 22 | 23 | Be sure to read the [wiki](https://github.com/zeromq/jzmq-api/wiki). 24 | 25 | ### Ubuntu 12.04 Precise 26 | 27 | This is currently how I go about setting up my environment. 28 | 29 | ```bash 30 | # This installs v3.2.2 of libzmq 31 | sudo add-apt-repository ppa:chris-lea/zeromq 32 | sudo apt-get update 33 | sudo apt-get install libzmq-dev libpgm-dev 34 | 35 | cd /tmp 36 | wget https://raw.github.com/zeromq/jzmq-api/master/debs/jzmq_2.1.0-1_amd64.deb 37 | sudo dpkg -i jzmq_2.1.0-1_amd64.deb 38 | ``` 39 | Add the following dependency to your `pom.xml` file: 40 | 41 | ```xml 42 | 43 | org.zeromq 44 | jzmq-api 45 | 0.1.0-SNAPSHOT 46 | 47 | ``` 48 | ```xml 49 | 50 | 51 | sonatype-nexus-snapshots 52 | https://oss.sonatype.org/content/repositories/snapshots 53 | 54 | 55 | ``` 56 | ## Eclipse 57 | 58 | ```bash 59 | mvn eclipse:eclipse -DdownloadSources=true -DdownloadJavadocs=true 60 | ``` 61 | ## Usage 62 | 63 | ## Contribution Process 64 | 65 | This project uses the [C4 process](http://rfc.zeromq.org/spec:16) for all code changes. 66 | 67 | ## License 68 | 69 | Copyright © 2013 Trevor Bernard 70 | 71 | Copyright other contributors as noted in the AUTHORS file. 72 | 73 | This 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. 74 | -------------------------------------------------------------------------------- /bin/update-gh-page.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | git checkout gh-pages 4 | rm -r javadocs 5 | cp -r target/apidocs javadocs 6 | git add -u javadocs 7 | git add javadocs 8 | git commit -m "Updating javadocs" 9 | git push origin gh-pages 10 | git checkout master 11 | -------------------------------------------------------------------------------- /debs/jzmq_2.1.0-1_amd64.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeromq/jzmq-api/366f9ab92f2079012576fd8d00e8f0253a344f89/debs/jzmq_2.1.0-1_amd64.deb -------------------------------------------------------------------------------- /debs/jzmq_2.1.1-1_amd64.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeromq/jzmq-api/366f9ab92f2079012576fd8d00e8f0253a344f89/debs/jzmq_2.1.1-1_amd64.deb -------------------------------------------------------------------------------- /debs/jzmq_2.1.2-1_amd64.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeromq/jzmq-api/366f9ab92f2079012576fd8d00e8f0253a344f89/debs/jzmq_2.1.2-1_amd64.deb -------------------------------------------------------------------------------- /debs/jzmq_2.1.3-1_amd64.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeromq/jzmq-api/366f9ab92f2079012576fd8d00e8f0253a344f89/debs/jzmq_2.1.3-1_amd64.deb -------------------------------------------------------------------------------- /src/main/java/org/zeromq/ContextFactory.java: -------------------------------------------------------------------------------- 1 | package org.zeromq; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.zeromq.api.Context; 6 | import org.zeromq.jzmq.ManagedContext; 7 | 8 | /** 9 | * Factory containing utility methods for managing instances of a ØMQ Context. 10 | */ 11 | public class ContextFactory { 12 | 13 | /** Default io threads, to be customized by the application, or set via property. */ 14 | public static int DEFAULT_IO_THREADS = Integer.parseInt( 15 | System.getProperty("zmq.default.io.threads", "1")); 16 | 17 | private static final Logger log = LoggerFactory.getLogger(ContextFactory.class); 18 | 19 | /** 20 | * Protected constructor. 21 | */ 22 | private ContextFactory() { 23 | } 24 | 25 | /** 26 | * Create a new ØMQ Context. 27 | * 28 | * @param ioThreads The number of background I/O threads to use 29 | * @return A new ØMQ Context 30 | */ 31 | public static Context createContext(int ioThreads) { 32 | if (ioThreads < 0) { 33 | throw new IllegalArgumentException("ioThreads must be positive"); 34 | } 35 | return new ManagedContext(ZMQ.context(ioThreads)); 36 | } 37 | 38 | /** 39 | * Retrieve the singleton instance of a ØMQ Context. 40 | * 41 | * @return A singleton ØMQ Context 42 | */ 43 | public static Context context() { 44 | return ContextHolder.INSTANCE; 45 | } 46 | 47 | /** 48 | * Lazily initialized singleton. 49 | */ 50 | private static class ContextHolder { 51 | private static Context INSTANCE = createContext(DEFAULT_IO_THREADS); 52 | static { 53 | Runtime.getRuntime().addShutdownHook(new Thread() { 54 | @Override 55 | public void run() { 56 | log.debug("closing singleton context..."); 57 | INSTANCE.terminate(); 58 | INSTANCE.close(); 59 | } 60 | }); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/Patterns.java: -------------------------------------------------------------------------------- 1 | package org.zeromq; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.zeromq.api.BinaryStarReactor; 6 | import org.zeromq.api.CloneClient; 7 | import org.zeromq.api.CloneServer; 8 | import org.zeromq.api.Socket; 9 | import org.zeromq.jzmq.beacon.BeaconReactorBuilder; 10 | import org.zeromq.jzmq.bstar.BinaryStarReactorBuilder; 11 | import org.zeromq.jzmq.bstar.BinaryStarSocketBuilder; 12 | import org.zeromq.jzmq.clone.CloneClientBuilder; 13 | import org.zeromq.jzmq.clone.CloneServerBuilder; 14 | 15 | /** 16 | * Class containing utility methods for creating objects for different patterns 17 | * without using a ØMQ Context directly. 18 | */ 19 | public class Patterns { 20 | private static final Logger log = LoggerFactory.getLogger(Patterns.class); 21 | 22 | /** 23 | * Protected constructor. 24 | */ 25 | private Patterns() { 26 | } 27 | 28 | /** 29 | * Create a new BinaryStarReactor, which will create one half of an HA-pair 30 | * with event-driven polling of a client Socket. 31 | * 32 | * @return A builder for constructing a BinaryStarReactor 33 | */ 34 | public static BinaryStarReactorBuilder buildBinaryStarReactor() { 35 | return ContextFactory.context().buildBinaryStarReactor(); 36 | } 37 | 38 | /** 39 | * Create a ØMQ Socket, backed by a background agent that is connecting 40 | * to a BinaryStarReactor HA-pair. 41 | * 42 | * @return A builder for constructing connecting a BinaryStarReactor client Socket 43 | */ 44 | public static BinaryStarSocketBuilder buildBinaryStarSocket() { 45 | return ContextFactory.context().buildBinaryStarSocket(); 46 | } 47 | 48 | /** 49 | * Create a ØMQ DEALER Socket, backed by a background agent that is connected 50 | * to a BinaryStarReactor HA-pair. 51 | * 52 | * @param primaryUrl The primary server's url to connect to 53 | * @param backupUrl The backup server's url to connect to 54 | * @return A new Socket connected to an HA-pair 55 | */ 56 | public static Socket newBinaryStarSocket(String primaryUrl, String backupUrl) { 57 | return buildBinaryStarSocket().connect(primaryUrl, backupUrl); 58 | } 59 | 60 | /** 61 | * Create a new CloneServer, which will create one half of an HA-pair 62 | * for distributing key/value data to clients. 63 | * 64 | * @return A builder for constructing a CloneServer 65 | */ 66 | public static CloneServerBuilder buildCloneServer() { 67 | return ContextFactory.context().buildCloneServer(); 68 | } 69 | 70 | /** 71 | * Create a new CloneServer, which will create one half of an HA-pair 72 | * for distributing key/value data to clients. 73 | * 74 | * @param mode The server mode (e.g. PRIMARY, BACKUP) 75 | * @param primaryAddress The primary server's url to connect to (if mode is BACKUP) 76 | * @param backupAddress The backup server's url to connect to (if mode is PRIMARY) 77 | * @return A new CloneServer 78 | */ 79 | public static CloneServer newCloneServer(BinaryStarReactor.Mode mode, String primaryAddress, String backupAddress) { 80 | CloneServer cloneServer = buildCloneServer() 81 | .withMode(mode) 82 | .withPrimaryAddress(primaryAddress) 83 | .withBackupAddress(backupAddress) 84 | .withPrimaryPort(5556) 85 | .withBackupPort(5566) 86 | .withPrimaryBinaryStarPort(5003) 87 | .withBackupBinaryStarPort(5004) 88 | .build(); 89 | cloneServer.start(); 90 | Runtime.getRuntime().addShutdownHook(new CloneServerShutdownHook(cloneServer)); 91 | 92 | return cloneServer; 93 | } 94 | 95 | /** 96 | * Create a new CloneClient, connected to an HA-pair, for publishing key/value data 97 | * to anonymous peers. 98 | * 99 | * @return A builder for constructing a CloneClient 100 | */ 101 | public static CloneClientBuilder buildCloneClient() { 102 | return ContextFactory.context().buildCloneClient(); 103 | } 104 | 105 | /** 106 | * Create a new CloneClient, connected to an HA-pair, for publishing key/value data 107 | * to anonymous peers. 108 | * 109 | * @param primaryAddress The primary server's url to connect to 110 | * @param backupAddress The backup server's url to connect to 111 | * @param subtree The prefix (subtree) to subscribe to 112 | * @return A new CloneClient 113 | */ 114 | public static CloneClient newCloneClient(String primaryAddress, String backupAddress, String subtree) { 115 | return buildCloneClient() 116 | .withPrimaryAddress(primaryAddress) 117 | .withBackupAddress(backupAddress) 118 | .withPrimaryPort(5556) 119 | .withBackupPort(5566) 120 | .withSubtree(subtree) 121 | .build(); 122 | } 123 | 124 | /** 125 | * Create a new BeaconReactor, which will send and receive UDP beacons 126 | * on a broadcast address, with event-driven handling of received beacons. 127 | * 128 | * @return A builder for constructing a BeaconReactor 129 | */ 130 | public static BeaconReactorBuilder buildBeaconReactor() { 131 | return ContextFactory.context().buildBeaconReactor(); 132 | } 133 | 134 | private static class CloneServerShutdownHook extends Thread { 135 | private CloneServer cloneServer; 136 | 137 | public CloneServerShutdownHook(CloneServer cloneServer) { 138 | this.cloneServer = cloneServer; 139 | } 140 | 141 | @Override 142 | public void run() { 143 | log.info("Stopping CloneServer..."); 144 | cloneServer.stop(); 145 | log.info("CloneServer stopped"); 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/Backgroundable.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | /** 4 | * Capable of running in a background thread. 5 | */ 6 | public interface Backgroundable { 7 | /** 8 | * Run a background thread communicating over the given socket. 9 | * 10 | * @param context The parent context 11 | * @param socket The socket used for communication 12 | */ 13 | void run(Context context, Socket socket); 14 | 15 | /** 16 | * Called just prior to the socket being closed. 17 | */ 18 | void onClose(); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/BeaconListener.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import java.net.InetAddress; 4 | 5 | /** 6 | * Listener to handle beacon events sent via UDP. 7 | */ 8 | public interface BeaconListener { 9 | /** 10 | * Handle a validated beacon event. 11 | * 12 | * @param sender The sender of the beacon 13 | * @param beacon The beacon, containing connection information 14 | */ 15 | void onBeacon(InetAddress sender, UdpBeacon beacon); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/BeaconReactor.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | /** 4 | * An event-driven reactor for discovery beacons. 5 | */ 6 | public interface BeaconReactor { 7 | /** 8 | * Start the underlying Reactor. 9 | */ 10 | void start(); 11 | 12 | /** 13 | * Stop the underlying Reactor. 14 | */ 15 | void stop(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/BinaryStarReactor.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | /** 4 | * Reactor implementing the Binary Star pattern, used to construct HA-pairs 5 | * that can forward messages to an application in an event-driven manner. 6 | */ 7 | public interface BinaryStarReactor { 8 | /** 9 | * We send state information this often. If peer doesn't respond in two heartbeats, it is 'dead'. 10 | */ 11 | long BSTAR_HEARTBEAT = 1000; 12 | 13 | /** 14 | * Startup modes. 15 | */ 16 | enum Mode { 17 | /** 18 | * Primary node. 19 | */ 20 | PRIMARY, 21 | /** 22 | * Backup node. 23 | */ 24 | BACKUP 25 | } 26 | 27 | /** 28 | * States we can be in at any point in time. 29 | */ 30 | enum State { 31 | /** 32 | * Primary, waiting for peer to connect. 33 | */ 34 | PRIMARY_CONNECTING, 35 | /** 36 | * Backup, waiting for peer to connect. 37 | */ 38 | BACKUP_CONNECTING, 39 | /** 40 | * Active - accepting connections. 41 | */ 42 | ACTIVE, 43 | /** 44 | * Passive - Not accepting connections. 45 | */ 46 | PASSIVE 47 | } 48 | 49 | /** 50 | * Events, which start with the states our peer can be in. 51 | */ 52 | enum Event { 53 | /** 54 | * HA peer is pending primary. 55 | */ 56 | PEER_PRIMARY, 57 | /** 58 | * HA peer is pending backup. 59 | */ 60 | PEER_BACKUP, 61 | /** 62 | * HA peer is active. 63 | */ 64 | PEER_ACTIVE, 65 | /** 66 | * HA peer is passive. 67 | */ 68 | PEER_PASSIVE, 69 | /** 70 | * Client makes request. 71 | */ 72 | CLIENT_REQUEST 73 | } 74 | 75 | /** 76 | * Start the underlying Reactor. 77 | */ 78 | void start(); 79 | 80 | /** 81 | * Stop the underlying Reactor. 82 | */ 83 | void stop(); 84 | 85 | /** 86 | * Register a client voter socket. Only one socket can be registered. 87 | * 88 | * @param socket The client socket 89 | */ 90 | void registerVoterSocket(Socket socket); 91 | 92 | /** 93 | * Register a voter handler to be called each time the application receives a message. 94 | * 95 | * @param handler The handler for client events 96 | */ 97 | void setVoterHandler(LoopHandler handler); 98 | 99 | /** 100 | * Register a handler to be called each time there's a state change. 101 | * 102 | * @param handler The handler for state change events 103 | */ 104 | void setActiveHandler(LoopHandler handler); 105 | 106 | /** 107 | * Register a handler to be called each time there's a state change. 108 | * 109 | * @param handler The handler for state change events 110 | */ 111 | void setPassiveHandler(LoopHandler handler); 112 | 113 | /** 114 | * Get the underlying {@link Reactor}. 115 | * 116 | * @return The underlying Reactor 117 | */ 118 | Reactor getReactor(); 119 | 120 | /** 121 | * Set the heartbeat interval used to detect peer outage. 122 | * 123 | * @param heartbeatInterval The heartbeat interval, in milliseconds 124 | */ 125 | void setHeartbeatInterval(long heartbeatInterval); 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/Bindable.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | /** 4 | * Used to create sockets capable of binding to local endpoints. 5 | */ 6 | public interface Bindable { 7 | /** 8 | * Bind to a url. 9 | * 10 | * @param url the url to bind to 11 | * @return the socket 12 | */ 13 | Socket bind(String url); 14 | 15 | /** 16 | * Bind to a url. 17 | * 18 | * @param url the url to bind to 19 | * @param additionalUrls additional urls to bind to 20 | * @return the socket 21 | */ 22 | Socket bind(String url, String... additionalUrls); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/Broadcastable.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | public interface Broadcastable { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/CloneClient.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * An API client implementing the CHP (Clustered Hashmap Protocol), which will 7 | * communicate via an agent (background thread) with a pair of stateful servers 8 | * using the Binary Star Pattern. 9 | */ 10 | public interface CloneClient { 11 | /** 12 | * Specify subtree for snapshot and updates. 13 | *

14 | * Note: We must do this before connecting to a server as the subtree 15 | * specification is sent as the first command to the server. 16 | * 17 | * @param subtree The prefix (subtree) to subscribe to 18 | */ 19 | void subscribe(String subtree); 20 | 21 | /** 22 | * Connect to a new server endpoint. We can connect to at most two servers. 23 | * 24 | * @param address The address of the server to connect to 25 | * @param port The port on the server to connect to 26 | */ 27 | void connect(String address, int port); 28 | 29 | /** 30 | * Set a new value in the shared hashmap, with no ttl. 31 | * 32 | * @param key The key associated with the new value 33 | * @param value The new value to set in the shared hashmap 34 | */ 35 | void set(String key, String value); 36 | 37 | /** 38 | * Set a new value in the shared hashmap. 39 | * 40 | * @param key The key associated with the new value 41 | * @param value The new value to set in the shared hashmap 42 | * @param ttl The time-to-live for the given value, in seconds 43 | */ 44 | void set(String key, String value, long ttl); 45 | 46 | /** 47 | * Look up the value in the shared hashmap. 48 | * 49 | * @param key The key to look up 50 | * @return The value associated with the given key, or null 51 | */ 52 | String get(String key); 53 | 54 | /** 55 | * Look up all values in the shared hashmap. 56 | * 57 | * @return The entire map 58 | */ 59 | Map getAll(); 60 | 61 | /** 62 | * Destroy this client. 63 | */ 64 | void close(); 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/CloneServer.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | /** 4 | * A service interface for a server implementing CHP (Clustered Hashmap Protocol). 5 | */ 6 | public interface CloneServer { 7 | /** 8 | * Start the underlying Reactor. 9 | */ 10 | void start(); 11 | 12 | /** 13 | * Stop the underlying Reactor. 14 | */ 15 | void stop(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/Connectable.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | /** 4 | * Used to create sockets capable of connecting to remote endpoints. 5 | */ 6 | public interface Connectable { 7 | /** 8 | * Connect to a url. 9 | * 10 | * @param url the url to connect to 11 | * @return the socket 12 | */ 13 | Socket connect(String url); 14 | 15 | /** 16 | * Connect to a url. 17 | * 18 | * @param url the url to connect to 19 | * @param additionalUrls additional urls to connect to 20 | * @return the socket 21 | */ 22 | Socket connect(String url, String... additionalUrls); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/DeviceType.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | /** 4 | * Values for Device types 5 | */ 6 | public enum DeviceType { 7 | /** 8 | * ZMQ_STREAMER collects tasks from a set of pushers and forwards these to a set of pullers. You will generally use 9 | * this to bridge networks. Messages are fair-queued from pushers and load-balanced to pullers. 10 | */ 11 | STREAMER(1), 12 | /** 13 | * ZMQ_FORWARDER collects messages from a set of publishers and forwards these to a set of subscribers. You will 14 | * generally use this to bridge networks, e.g. read on TCP unicast and forward on multicast. 15 | */ 16 | FORWARDER(2), 17 | /** 18 | * ZMQ_QUEUE creates a shared queue that collects requests from a set of clients, and distributes these fairly among 19 | * a set of services. Requests are fair-queued from frontend connections and load-balanced between backend 20 | * connections. Replies automatically return to the client that made the original request. 21 | */ 22 | QUEUE(3); 23 | 24 | private final int type; 25 | 26 | DeviceType(int type) { 27 | this.type = type; 28 | } 29 | 30 | /** 31 | * Device type connects a frontend socket to a backend socket. 32 | * 33 | * @return device type 34 | */ 35 | public int getType() { 36 | return type; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/LoopAdapter.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import java.nio.channels.SelectableChannel; 4 | 5 | /** 6 | * An abstract class for implementing a {@link LoopHandler}. 7 | */ 8 | public class LoopAdapter implements LoopHandler { 9 | @Override 10 | public void execute(Reactor reactor, Pollable pollable) { 11 | execute(reactor, pollable.getSocket()); 12 | execute(reactor, pollable.getChannel()); 13 | } 14 | 15 | protected void execute(Reactor reactor, Socket socket) { 16 | } 17 | 18 | protected void execute(Reactor reactor, SelectableChannel channel) { 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/LoopHandler.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | /** 4 | * Callback from within an event-driven reactor. 5 | */ 6 | public interface LoopHandler { 7 | /** 8 | * Execute a loop operation. 9 | * 10 | * @param reactor The Reactor 11 | * @param pollable The Pollable containing the socket or channel 12 | */ 13 | void execute(Reactor reactor, Pollable pollable); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/MessageFlag.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | /** 4 | * Send and Receive flags 5 | */ 6 | public enum MessageFlag { 7 | 8 | /** 9 | * Specifies no flags. 10 | */ 11 | NONE(0), 12 | /** 13 | * Specifies that the operation should be performed in non-blocking mode. 14 | */ 15 | DONT_WAIT(1), 16 | /** 17 | * Specifies that the message being sent is a multi-part message, and that further message parts are to follow. 18 | */ 19 | SEND_MORE(2); 20 | 21 | private final int flag; 22 | 23 | private MessageFlag(int flag) { 24 | this.flag = flag; 25 | } 26 | 27 | /** 28 | * Send and receive flag constant 29 | * 30 | * @return flag 31 | */ 32 | public int getFlag() { 33 | return flag; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/PollAdapter.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import java.nio.channels.SelectableChannel; 4 | 5 | /** 6 | * An abstract class for implementing a {@link PollListener}. 7 | */ 8 | public class PollAdapter implements PollListener { 9 | @Override 10 | public void handleIn(Pollable pollable) { 11 | handleIn(pollable.getSocket()); 12 | handleIn(pollable.getChannel()); 13 | } 14 | 15 | @Override 16 | public void handleOut(Pollable pollable) { 17 | handleOut(pollable.getSocket()); 18 | handleOut(pollable.getChannel()); 19 | } 20 | 21 | @Override 22 | public void handleError(Pollable pollable) { 23 | handleError(pollable.getSocket()); 24 | handleError(pollable.getChannel()); 25 | } 26 | 27 | protected void handleIn(Socket socket) { 28 | } 29 | 30 | protected void handleOut(Socket socket) { 31 | } 32 | 33 | protected void handleError(Socket socket) { 34 | } 35 | 36 | protected void handleIn(SelectableChannel channel) { 37 | } 38 | 39 | protected void handleOut(SelectableChannel channel) { 40 | } 41 | 42 | protected void handleError(SelectableChannel channel) { 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/PollListener.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | /** 4 | * A listener of a Poller. 5 | */ 6 | public interface PollListener { 7 | /** 8 | * Callback to handle incoming messages. 9 | * 10 | * @param pollable The pollable 11 | */ 12 | void handleIn(Pollable pollable); 13 | 14 | /** 15 | * Callback to handle outgoing messages. 16 | * 17 | * @param pollable The pollable 18 | */ 19 | void handleOut(Pollable pollable); 20 | 21 | /** 22 | * Callback to handle errors. 23 | * 24 | * @param pollable The pollable 25 | */ 26 | void handleError(Pollable pollable); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/Pollable.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import java.nio.channels.SelectableChannel; 4 | import java.util.EnumSet; 5 | 6 | /** 7 | * An item in a poll set. 8 | */ 9 | public interface Pollable { 10 | /** 11 | * Get the socket (if any) for this poll item. 12 | * 13 | * @return The socket, or null if this is a SelectableChannel Pollable 14 | */ 15 | Socket getSocket(); 16 | 17 | /** 18 | * Get the SelectableChannel (if any) for this poll item. 19 | * 20 | * @return The channel, or null if this is a Socket Pollable 21 | */ 22 | SelectableChannel getChannel(); 23 | 24 | /** 25 | * Get the options used for this poll item 26 | * 27 | * @return The options used for this Pollable 28 | */ 29 | EnumSet getOptions(); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/Poller.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import java.nio.channels.SelectableChannel; 4 | 5 | /** 6 | * Poller for polling sockets and receiving callbacks for events. 7 | */ 8 | public interface Poller { 9 | 10 | /** 11 | * Poll a socket indefinitely. 12 | */ 13 | void poll(); 14 | 15 | /** 16 | * Poll a socket for a given amount of time. 17 | * 18 | * @param timeoutMillis The number of milliseconds to wait before returning 19 | */ 20 | void poll(long timeoutMillis); 21 | 22 | /** 23 | * Enable a socket in the poller after it has been disabled. 24 | * 25 | * @param socket The socket registered with the poller to be enabled 26 | * @return The new index of the socket in the poller, for reference 27 | */ 28 | int enable(Socket socket); 29 | 30 | /** 31 | * Disable a socket in the poller, preventing it from waking up the thread 32 | * when messages are received on it. 33 | * 34 | * @param socket The socket registered with the poller to be disabled 35 | * @return true if the socket was disabled, false otherwise 36 | */ 37 | boolean disable(Socket socket); 38 | 39 | /** 40 | * Enable a channel in the poller after it has been disabled. 41 | * 42 | * @param channel The channel registered with the poller to be enabled 43 | * @return The new index of the socket in the poller, for reference 44 | */ 45 | int enable(SelectableChannel channel); 46 | 47 | /** 48 | * Disable a channel in the poller, preventing it from waking up the thread 49 | * when messages are received on it. 50 | * 51 | * @param channel The channel registered with the poller to be disabled 52 | * @return true if the socket was disabled, false otherwise 53 | */ 54 | boolean disable(SelectableChannel channel); 55 | 56 | /** 57 | * Register a new poll item. 58 | * 59 | * @param pollable The pollable containing the socket and polling options 60 | * @param listener The listener that handles events for the given pollable 61 | * @return The new index of the socket in the poller, for reference 62 | */ 63 | int register(Pollable pollable, PollListener listener); 64 | 65 | /** 66 | * Unregister a socket from the poller. 67 | * 68 | * @param socket The socket registered with the poller to be unregistered 69 | * @return true if the socket was unregistered, false otherwise 70 | */ 71 | boolean unregister(Socket socket); 72 | 73 | /** 74 | * Unregister a channel from the poller. 75 | * 76 | * @param channel The channel registered with the poller to be unregistered 77 | * @return true if the socket was disabled, false otherwise 78 | */ 79 | boolean unregister(SelectableChannel channel); 80 | 81 | } -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/PollerType.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | /** 4 | * Enumeration of poller types. 5 | */ 6 | public enum PollerType { 7 | POLL_IN(1), POLL_OUT(2), POLL_ERROR(4); 8 | 9 | private final int type; 10 | 11 | PollerType(int type) { 12 | this.type = type; 13 | } 14 | 15 | /** 16 | * The integer representation of this poller type. 17 | * 18 | * @return The integer representation of this poller type 19 | */ 20 | public int getType() { 21 | return type; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/Reactor.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | /** 4 | * An event-driven reactor. 5 | */ 6 | public interface Reactor { 7 | /** 8 | * Start the reactor. 9 | */ 10 | void start(); 11 | 12 | /** 13 | * Stop the reactor. 14 | */ 15 | void stop(); 16 | 17 | /** 18 | * Add a new Pollable to this Reactor. 19 | *

20 | * This method is not thread-safe, and should only be done from inside the 21 | * LoopHandler when invoked by the Reactor on its own thread. 22 | * 23 | * @param pollable The Pollable with the socket to poll 24 | * @param handler The loop handler 25 | */ 26 | void addPollable(Pollable pollable, LoopHandler handler); 27 | 28 | /** 29 | * Add a new ReactorTimer to this Reactor. 30 | *

31 | * This method is not thread-safe, and should only be done from inside the 32 | * LoopHandler when invoked by the Reactor on its own thread. 33 | * 34 | * @param initialDelay The initial delay, in milliseconds 35 | * @param numIterations The number of iterations, after which this timer stop 36 | * @param handler The loop handler 37 | */ 38 | void addTimer(long initialDelay, int numIterations, LoopHandler handler); 39 | 40 | /** 41 | * Cancel an existing Pollable or ReactorTimer and remove the corresponding 42 | * LoopHandler from executing. 43 | *

44 | * This method is not thread-safe, and should only be done from inside the 45 | * LoopHandler when invoked by the Reactor on its own thread. 46 | * 47 | * @param handler The loop handler 48 | */ 49 | void cancel(LoopHandler handler); 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/Receiver.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | /** 6 | * Socket capable of receiving message parts. 7 | */ 8 | public interface Receiver { 9 | /** 10 | * Receive a message part from a socket. 11 | * 12 | * @return The message bytes 13 | */ 14 | byte[] receive(); 15 | 16 | /** 17 | * Receive a message part from a socket. 18 | * 19 | * @param flag Flag controlling behavior of the receive operation 20 | * @return The message bytes 21 | */ 22 | byte[] receive(MessageFlag flag); 23 | 24 | /** 25 | * Receive a message part from a socket. 26 | * 27 | * @param buf The byte buffer 28 | * @param offset The buffer offset 29 | * @param len The buffer length 30 | * @param flag Flag controlling behavior of the receive operation 31 | * @return The number of bytes read, -1 on error 32 | */ 33 | int receive(byte[] buf, int offset, int len, MessageFlag flag); 34 | 35 | /** 36 | * Receive a message part from a socket into a byte buffer. 37 | * 38 | * @param buf The byte buffer 39 | * @param flag Flag controlling behavior of the receive operation 40 | * @return The number of bytes read, -1 on error 41 | */ 42 | int receiveByteBuffer(ByteBuffer buf, MessageFlag flag); 43 | 44 | /** 45 | * This receiver has more of a multi-part message waiting for receipt. 46 | * 47 | * @return true if there is more data, false otherwise 48 | */ 49 | boolean hasMoreToReceive(); 50 | 51 | /** 52 | * Receive the full message (all frames) from the socket. 53 | * 54 | * @return The full message (all frames) from the socket. 55 | */ 56 | Message receiveMessage(); 57 | 58 | /** 59 | * Receive the full message (all frames) from the socket. 60 | * 61 | * @param flag Flag controlling behavior of the receive operation 62 | * @return The full message (all frames) from the socket. 63 | */ 64 | Message receiveMessage(MessageFlag flag); 65 | 66 | /** 67 | * Receive a routed message (all frames) from the socket. 68 | * 69 | * @return The full message (all frames) from the socket, assuming it has been through a Router socket, and has 70 | * routing frames associated with it. 71 | */ 72 | RoutedMessage receiveRoutedMessage(); 73 | 74 | /** 75 | * Receive a routed message (all frames) from the socket. 76 | * 77 | * @param flag Flag controlling behavior of the receive operation 78 | * @return The full message (all frames) from the socket, assuming it has been through a Router socket, and has 79 | * routing frames associated with it. 80 | */ 81 | RoutedMessage receiveRoutedMessage(MessageFlag flag); 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/Routable.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import org.zeromq.jzmq.sockets.SocketBuilder; 4 | 5 | /** 6 | * A socket builder for a router socket. 7 | */ 8 | public interface Routable { 9 | /** 10 | * Set the 'router mandatory' socket option. 11 | * 12 | * @return This builder object 13 | */ 14 | SocketBuilder withRouterMandatory(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/RoutedMessage.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | /** 8 | * Routed message contains route frames and payload frames. 9 | */ 10 | public class RoutedMessage extends Message { 11 | 12 | /** 13 | * Construct an empty message. 14 | */ 15 | public RoutedMessage() { 16 | 17 | } 18 | 19 | /** 20 | * Takes a route with no frames. 21 | * 22 | * @param route The initial route 23 | */ 24 | public RoutedMessage(Route route) { 25 | super(route.getRoutingFrames()); 26 | } 27 | 28 | /** 29 | * Takes routes with no frames. 30 | * 31 | * @param routes An initial list of routes 32 | */ 33 | public RoutedMessage(List routes) { 34 | for (Route route : routes) { 35 | addFrames(route.getRoutingFrames()); 36 | } 37 | } 38 | 39 | /** 40 | * Takes the existing message and adds a route to the beginning of it. 41 | * 42 | * @param route The initial route 43 | * @param message A message containing frames to be added 44 | */ 45 | public RoutedMessage(Route route, Message message) { 46 | this(route); 47 | addFrames(message); 48 | } 49 | 50 | /** 51 | * Takes the existing message and adds routes to the beginning of it. 52 | * 53 | * @param routes An initial list of routes 54 | * @param message A message containing frames to be added 55 | */ 56 | public RoutedMessage(List routes, Message message) { 57 | this(routes); 58 | addFrames(message); 59 | } 60 | 61 | /** 62 | * Get the message portion of the routed message, which is the frames after 63 | * all routing frames. 64 | * 65 | * @return The message payload 66 | */ 67 | public Message getPayload() { 68 | List frames = getFrames(); 69 | //each route is 2 frames, so get everything after the routing frames. 70 | return new Message(frames.subList(getRoutes().size() * 2, frames.size())); 71 | } 72 | 73 | public List getRoutes() { 74 | List results = new ArrayList(); 75 | List frames = getFrames(); 76 | for (int i = 0; i < frames.size(); i++) { 77 | Frame address = frames.get(i); 78 | if (frames.size() > i + 1) { 79 | Frame blank = frames.get(++i); 80 | if (blank.isBlank()) { 81 | results.add(new Route(address.getData())); 82 | } else { 83 | break; 84 | } 85 | } else { 86 | break; 87 | } 88 | } 89 | 90 | return results; 91 | } 92 | 93 | /** 94 | * Mutates this Message, to remove the top-most Route, which is then returned. 95 | * 96 | * @return The unwrapped Route 97 | */ 98 | public Route unwrap() { 99 | if (getRoutes().isEmpty()) { 100 | throw new IllegalStateException("Cannot unwrap an unrouted message."); 101 | } 102 | Frame route = super.popFrame(); 103 | super.popFrame(); 104 | 105 | return new Route(route.getData()); 106 | } 107 | 108 | /** 109 | * Represents a route, or address frame, which will be combined with a blank 110 | * frame over the wire. 111 | */ 112 | public static class Route { 113 | public static final Frame BLANK = new Frame(new byte[0]); 114 | 115 | //todo store Frame or bytes? 116 | private final byte[] address; 117 | 118 | public Route(String address) { 119 | this(address.getBytes(Message.CHARSET)); 120 | } 121 | 122 | public Route(byte[] address) { 123 | this.address = address; 124 | } 125 | 126 | public byte[] getAddress() { 127 | return address; 128 | } 129 | 130 | public String getString() { 131 | return new String(address, Message.CHARSET); 132 | } 133 | 134 | public List getRoutingFrames() { 135 | List frames = new ArrayList(2); 136 | frames.add(new Frame(address)); 137 | frames.add(BLANK); 138 | return frames; 139 | } 140 | 141 | @Override 142 | public String toString() { 143 | return "Route{address=" + new String(address, Message.CHARSET) + '}'; 144 | } 145 | 146 | @Override 147 | public boolean equals(Object o) { 148 | if (this == o) return true; 149 | if (o == null || getClass() != o.getClass()) return false; 150 | 151 | Route route = (Route) o; 152 | 153 | if (!Arrays.equals(address, route.address)) return false; 154 | 155 | return true; 156 | } 157 | 158 | @Override 159 | public int hashCode() { 160 | return address != null ? Arrays.hashCode(address) : 0; 161 | } 162 | } 163 | 164 | } -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/Sender.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | /** 6 | * Socket capable of sending message parts. 7 | */ 8 | public interface Sender { 9 | /** 10 | * Send a message part on a socket. 11 | * 12 | * @param buf The message bytes 13 | * @return true if the operation was successful, false otherwise 14 | */ 15 | boolean send(byte[] buf); 16 | 17 | /** 18 | * Send a message part on a socket. 19 | * 20 | * @param buf The message bytes 21 | * @param flag Flag controlling behavior of the send operation 22 | * @return true if the operation was successful, false otherwise 23 | */ 24 | boolean send(byte[] buf, MessageFlag flag); 25 | 26 | /** 27 | * Send a message part on a socket. 28 | * 29 | * @param buf The message bytes 30 | * @param offset The buffer offset 31 | * @param length The buffer length 32 | * @param flag Flag controlling behavior of the send operation 33 | * @return true if the operation was successful, false otherwise 34 | */ 35 | boolean send(byte[] buf, int offset, int length, MessageFlag flag); 36 | 37 | /** 38 | * Send a message part on a socket from a byte buffer. 39 | * 40 | * @param buf The byte buffer 41 | * @param flag Flag controlling behavior of the send operation 42 | * @return true if the operation was successful, false otherwise 43 | */ 44 | boolean sendByteBuffer(ByteBuffer buf, MessageFlag flag); 45 | 46 | /** 47 | * Send the full message (all frames) on the socket. 48 | * 49 | * @param message The full message 50 | * @return true if the operation was successful, false otherwise 51 | */ 52 | boolean send(Message message); 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/Socket.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import java.io.Closeable; 4 | 5 | import org.zeromq.ZMQ; 6 | 7 | /** 8 | * ØMQ sockets provide an abstraction of asynchronous message queues, multiple messaging patterns, message filtering 9 | * (subscriptions), seamless access to multiple transport protocols and more. 10 | */ 11 | public interface Socket extends Sender, Receiver, Closeable { 12 | // This is JZMQ specific. Eventually need to abstract this away. 13 | ZMQ.Socket getZMQSocket(); 14 | 15 | /** 16 | * Retrieve the owning Context for this Socket. 17 | * 18 | * @return The ØMQ Context 19 | */ 20 | Context getContext(); 21 | 22 | /** 23 | * Retrieve the status of this ØMQ Socket. 24 | * 25 | * @return true if the Socket is open, false otherwise 26 | */ 27 | boolean isActive(); 28 | 29 | /** 30 | * Retrieve the type of transport this ØMQ Socket is using. UNIMPLEMENTED! 31 | * 32 | * @return The transport type used by this Socket 33 | */ 34 | TransportType getTransportType(); 35 | 36 | /** 37 | * Close this ØMQ Socket. 38 | */ 39 | void close(); 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/SocketSpec.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | 4 | /** 5 | * ØMQ Socket specification 6 | * 7 | * Socket options for that Socket type 8 | */ 9 | public interface SocketSpec { 10 | public SocketType getSocketType(); 11 | 12 | public TransportType getTransportType(); 13 | 14 | public long getLinger(); 15 | 16 | public long getReceiveHighWatermark(); 17 | 18 | public long getSendHighWatermark(); 19 | 20 | public String getIdentity(); 21 | 22 | public long getSendBufferSize(); 23 | 24 | public long getReceiveBufferSize(); 25 | 26 | public long getMaxMessageSize(); 27 | 28 | public long getReceiveTimeout(); 29 | 30 | public long getSendTimeout(); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/SocketType.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | /** 4 | * Values for Socket types 5 | */ 6 | public enum SocketType { 7 | /** 8 | * A socket of type ZMQ_PAIR can only be connected to a single peer at any one time. No message routing or filtering 9 | * is performed on messages sent over a ZMQ_PAIR socket. 10 | */ 11 | PAIR(org.zeromq.SocketType.PAIR), 12 | /** 13 | * A socket of type ZMQ_PUB is used by a publisher to distribute data. Messages sent are distributed in a fan out 14 | * fashion to all connected peers. 15 | */ 16 | PUB(org.zeromq.SocketType.PUB), 17 | /** 18 | * A socket of type ZMQ_SUB is used by a subscriber to subscribe to data distributed by a publisher. Initially a 19 | * ZMQ_SUB socket is not subscribed to any messages. 20 | */ 21 | SUB(org.zeromq.SocketType.SUB), 22 | /** 23 | * A socket of type ZMQ_REP is used by a service to receive requests from and send replies to a client. This socket 24 | * type allows only an alternating sequence of receive(request) and subsequent send(reply) calls. 25 | */ 26 | REQ(org.zeromq.SocketType.REQ), 27 | /** 28 | * A socket of type ZMQ_REQ is used by a client to send requests to and receive replies from a service. This socket 29 | * type allows only an alternating sequence of send(request) and subsequent receive(reply) calls. 30 | */ 31 | REP(org.zeromq.SocketType.REP), 32 | /** 33 | * A socket of type ZMQ_DEALER is an advanced pattern used for extending request/reply sockets. Each message sent is 34 | * round-robined among all connected peers, and each message received is fair-queued from all connected peers. 35 | */ 36 | DEALER(org.zeromq.SocketType.DEALER), 37 | /** 38 | * A socket of type ZMQ_ROUTER is an advanced socket type used for extending request/reply sockets. When receiving 39 | * messages a ZMQ_ROUTER socket shall prepend a message part containing the identity of the originating peer to the 40 | * message before passing it to the application. 41 | */ 42 | ROUTER(org.zeromq.SocketType.ROUTER), 43 | /** 44 | * A socket of type ZMQ_PULL is used by a pipeline node to receive messages from upstream pipeline nodes. Messages 45 | * are fair-queued from among all connected upstream nodes. 46 | */ 47 | PULL(org.zeromq.SocketType.PULL), 48 | /** 49 | * A socket of type ZMQ_PUSH is used by a pipeline node to send messages to downstream pipeline nodes. Messages are 50 | * round-robined to all connected downstream nodes. 51 | */ 52 | PUSH(org.zeromq.SocketType.PUSH), 53 | /** 54 | * Same as ZMQ_PUB except that you can receive subscriptions from the peers in form of incoming messages. 55 | */ 56 | XPUB(org.zeromq.SocketType.XPUB), 57 | /** 58 | * Same as ZMQ_SUB except that you subscribe by sending subscription messages to the socket. 59 | */ 60 | XSUB(org.zeromq.SocketType.XSUB); 61 | 62 | private final org.zeromq.SocketType type; 63 | 64 | SocketType(org.zeromq.SocketType type) { 65 | this.type = type; 66 | } 67 | 68 | /** 69 | * Socket type which determines the semantics of communication over the socket. 70 | * 71 | * @return socket type 72 | */ 73 | public org.zeromq.SocketType getType() { 74 | return type; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/Subscribable.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import org.zeromq.jzmq.sockets.SubSocketBuilder; 4 | 5 | /** 6 | * A socket builder for a subscriber socket. 7 | */ 8 | public interface Subscribable { 9 | /** 10 | * Subscribe to the given channel. 11 | * 12 | * @param data The channel prefix, as bytes 13 | * @return This builder object 14 | */ 15 | SubSocketBuilder subscribe(byte[] data); 16 | 17 | /** 18 | * Subscribe to all messages. 19 | * 20 | * @return This builder object 21 | */ 22 | SubSocketBuilder subscribeAll(); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/TransportType.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | /** 4 | * A ØMQ socket can use multiple different underlying transport mechanisms. Each transport mechanism is suited to a 5 | * particular purpose and has its own advantages and drawbacks. 6 | */ 7 | public enum TransportType { 8 | /** 9 | * ØMQ unicast transport using TCP 10 | */ 11 | TCP, 12 | /** 13 | * ØMQ reliable multicast transport using PGM 14 | */ 15 | PGM, 16 | /** 17 | * ØMQ local inter-process communication transport 18 | */ 19 | IPC, 20 | /** 21 | * ØMQ local in-process (inter-thread) communication transport 22 | */ 23 | INPROC 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/TypedReceiver.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | /** 4 | * 5 | * 6 | * @param type 7 | */ 8 | public interface TypedReceiver { 9 | public T deserialize(byte[] buf); 10 | 11 | public T receive(); 12 | 13 | public T receive(MessageFlag flag); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/TypedSender.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | public interface TypedSender { 4 | public byte[] serialize(T t); 5 | 6 | public void send(T t, int flags); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/UdpBeacon.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.util.UUID; 5 | 6 | public class UdpBeacon { 7 | public static final int BEACON_SIZE = 21; // version(1) + uuid(16) + port(2) + protocol_size(2) 8 | 9 | private final byte[] protocol; 10 | private final byte version; 11 | private final UUID uuid; 12 | private final String identity; 13 | private final int port; 14 | 15 | private ByteBuffer buffer; 16 | 17 | public UdpBeacon(ByteBuffer buffer) { 18 | int blockSize = buffer.getShort(); 19 | byte[] protocol = new byte[blockSize]; 20 | buffer.get(protocol); 21 | byte version = buffer.get(); 22 | long msb = buffer.getLong(); 23 | long lsb = buffer.getLong(); 24 | UUID uuid = new UUID(msb, lsb); 25 | int port = buffer.getShort(); 26 | if (port < 0) 27 | port = (0xffff) & port; 28 | 29 | this.protocol = protocol; 30 | this.version = version; 31 | this.uuid = uuid; 32 | this.port = port; 33 | this.identity = uuid.toString().replace("-", "").toUpperCase(); 34 | } 35 | 36 | public UdpBeacon(byte version, String protocol, int port) { 37 | this(version, protocol, UUID.randomUUID(), port); 38 | } 39 | 40 | public UdpBeacon(int version, String protocol, UUID uuid, int port) { 41 | this.protocol = protocol.getBytes(Message.CHARSET); 42 | this.version = (byte) version; 43 | this.uuid = uuid; 44 | this.port = port; 45 | this.identity = uuid.toString().replace("-", "").toUpperCase(); 46 | } 47 | 48 | public String getProtocol() { 49 | return new String(protocol, Message.CHARSET); 50 | } 51 | 52 | public int getVersion() { 53 | return version; 54 | } 55 | 56 | public UUID getUuid() { 57 | return uuid; 58 | } 59 | 60 | public String getIdentity() { 61 | return identity; 62 | } 63 | 64 | public int getPort() { 65 | return port; 66 | } 67 | 68 | public ByteBuffer getBuffer() { 69 | if (buffer == null) { 70 | buffer = ByteBuffer.allocate(calculateSize()); 71 | buffer.putShort((short) protocol.length); 72 | buffer.put(protocol); 73 | buffer.put(version); 74 | buffer.putLong(uuid.getMostSignificantBits()); 75 | buffer.putLong(uuid.getLeastSignificantBits()); 76 | buffer.putShort((short) port); 77 | buffer.flip(); 78 | } 79 | 80 | buffer.rewind(); 81 | return buffer; 82 | } 83 | 84 | private int calculateSize() { 85 | return BEACON_SIZE + protocol.length; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/exception/ContextTerminatedException.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api.exception; 2 | 3 | import org.zeromq.ZMQException; 4 | 5 | /** 6 | * Thrown to indicate the context has been terminated. This exception directly 7 | * maps to the ETERM error code in libzmq. 8 | * 9 | * @author sjohnr 10 | */ 11 | public class ContextTerminatedException extends ZMQRuntimeException { 12 | private static final long serialVersionUID = 7996414013283268950L; 13 | 14 | /** 15 | * Constructor, with ZMQException cause. 16 | * 17 | * @param message The error message 18 | * @param cause The underlying cause 19 | */ 20 | public ContextTerminatedException(String message, ZMQException cause) { 21 | super(message, cause); 22 | } 23 | 24 | /** 25 | * Constructor, with ZMQException cause. 26 | * 27 | * @param cause The underlying cause 28 | */ 29 | public ContextTerminatedException(ZMQException cause) { 30 | super(cause); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/exception/InvalidSocketException.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api.exception; 2 | 3 | import org.zeromq.ZMQ; 4 | import org.zeromq.ZMQException; 5 | 6 | /** 7 | * Thrown to indicate an invalid socket. This exception directly maps to the 8 | * ENOTSOCK error code in libzmq. 9 | * 10 | * @author sjohnr 11 | */ 12 | public class InvalidSocketException extends ZMQRuntimeException { 13 | private static final long serialVersionUID = 4376146106003013395L; 14 | 15 | /** 16 | * Constructor, with ZMQException cause. 17 | * 18 | * @param message The error message 19 | * @param cause The underlying cause 20 | */ 21 | public InvalidSocketException(String message, ZMQException cause) { 22 | super(message, cause); 23 | } 24 | 25 | /** 26 | * Constructor, with ZMQException cause. 27 | * 28 | * @param cause The underlying cause 29 | */ 30 | public InvalidSocketException(ZMQException cause) { 31 | super(cause); 32 | } 33 | 34 | /** 35 | * Constructor, with message. 36 | * 37 | * @param message The error message 38 | */ 39 | public InvalidSocketException(String message) { 40 | super(message, (int) ZMQ.Error.ENOTSOCK.getCode()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/exception/ZMQExceptions.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api.exception; 2 | 3 | import org.zeromq.ZMQ; 4 | import org.zeromq.ZMQException; 5 | 6 | /** 7 | * Helper class for handling exceptions, especially with jzmq. 8 | */ 9 | public class ZMQExceptions { 10 | 11 | private ZMQExceptions() {} 12 | 13 | /** 14 | * Wrap an underlying ZMQException in the appropriate higher level exception. 15 | * 16 | * @param thrown The underlying ZMQException 17 | * @return A new exception, which wraps a ZMQException 18 | */ 19 | public static ZMQRuntimeException wrap(ZMQException thrown) { 20 | if (isContextTerminated(thrown)) { 21 | return new ContextTerminatedException(thrown); 22 | } else if (isInvalidSocket(thrown)) { 23 | return new InvalidSocketException(thrown); 24 | } else { 25 | return new ZMQRuntimeException(thrown); 26 | } 27 | } 28 | 29 | /** 30 | * Helper method to determine if error code is ETERM. 31 | * 32 | * @param thrown A ZMQException, thrown by the library 33 | * @return true if the exception indicates ETERM, false otherwise 34 | */ 35 | public static boolean isContextTerminated(ZMQException thrown) { 36 | return thrown.getErrorCode() == ZMQ.Error.ETERM.getCode(); 37 | } 38 | 39 | /** 40 | * Helper method to determine if error code is ENOTSOCK. 41 | * 42 | * @param thrown A ZMQException, thrown by the library 43 | * @return true if the exception indicates ENOTSOCK, false otherwise 44 | */ 45 | public static boolean isInvalidSocket(ZMQException thrown) { 46 | return thrown.getErrorCode() == ZMQ.Error.ENOTSOCK.getCode() 47 | || thrown.getErrorCode() == ZMQ.Error.EAGAIN.getCode(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/api/exception/ZMQRuntimeException.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api.exception; 2 | 3 | import org.zeromq.ZMQException; 4 | 5 | /** 6 | * General runtime exception, with underlying error code. 7 | * 8 | * @author sjohnr 9 | */ 10 | public class ZMQRuntimeException extends ZMQException { 11 | private static final long serialVersionUID = 2581860056724970418L; 12 | 13 | /** 14 | * Constructor, with ZMQException cause. 15 | * 16 | * @param message The error message 17 | * @param errorCode The original error code 18 | */ 19 | public ZMQRuntimeException(String message, int errorCode) { 20 | super(message, errorCode); 21 | } 22 | 23 | /** 24 | * Constructor, with ZMQException cause. 25 | * 26 | * @param cause The underlying cause 27 | */ 28 | public ZMQRuntimeException(ZMQException cause) { 29 | this(cause.getMessage(), cause); 30 | } 31 | 32 | /** 33 | * Constructor, with ZMQException cause. 34 | * 35 | * @param message The error message 36 | * @param cause The underlying cause 37 | */ 38 | public ZMQRuntimeException(String message, ZMQException cause) { 39 | super(message, cause.getErrorCode()); 40 | initCause(cause); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/beacon/BeaconReactorBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.beacon; 2 | 3 | import org.zeromq.api.BeaconListener; 4 | import org.zeromq.api.BeaconReactor; 5 | import org.zeromq.api.UdpBeacon; 6 | import org.zeromq.jzmq.ManagedContext; 7 | 8 | import java.io.IOException; 9 | 10 | public class BeaconReactorBuilder { 11 | public static class Spec { 12 | public UdpBeacon beacon; 13 | public int port; 14 | public BeaconListener listener; 15 | public long broadcastInterval; 16 | public boolean ignoreLocalAddress = true; 17 | } 18 | 19 | private final ManagedContext context; 20 | private final Spec spec = new Spec(); 21 | 22 | public BeaconReactorBuilder(ManagedContext context) { 23 | this.context = context; 24 | } 25 | 26 | public BeaconReactorBuilder withBeacon(UdpBeacon beacon) { 27 | spec.beacon = beacon; 28 | return this; 29 | } 30 | 31 | public BeaconReactorBuilder withPort(int port) { 32 | spec.port = port; 33 | return this; 34 | } 35 | 36 | public BeaconReactorBuilder withListener(BeaconListener listener) { 37 | spec.listener = listener; 38 | return this; 39 | } 40 | 41 | public BeaconReactorBuilder withBroadcastInterval(long broadcastInterval) { 42 | spec.broadcastInterval = broadcastInterval; 43 | return this; 44 | } 45 | 46 | public BeaconReactorBuilder withIgnoreLocalAddress(boolean ignoreLocalAddress) { 47 | spec.ignoreLocalAddress = ignoreLocalAddress; 48 | return this; 49 | } 50 | 51 | public BeaconReactor build() throws IOException { 52 | assert spec.listener != null; 53 | 54 | BeaconReactorImpl reactor = new BeaconReactorImpl(context, spec.port, spec.beacon); 55 | reactor.setIgnoreLocalAddress(spec.ignoreLocalAddress); 56 | reactor.setListener(spec.listener); 57 | if (spec.broadcastInterval != 0) { 58 | reactor.setBroadcastInterval(spec.broadcastInterval); 59 | } 60 | 61 | return reactor; 62 | } 63 | 64 | public BeaconReactor start() throws IOException { 65 | BeaconReactor reactor = build(); 66 | reactor.start(); 67 | 68 | return reactor; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/beacon/BeaconReactorImpl.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.beacon; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.zeromq.api.BeaconListener; 6 | import org.zeromq.api.BeaconReactor; 7 | import org.zeromq.api.LoopHandler; 8 | import org.zeromq.api.Pollable; 9 | import org.zeromq.api.PollerType; 10 | import org.zeromq.api.Reactor; 11 | import org.zeromq.api.UdpBeacon; 12 | import org.zeromq.jzmq.ManagedContext; 13 | import org.zeromq.jzmq.UdpSocket; 14 | 15 | import java.io.IOException; 16 | import java.net.InetAddress; 17 | import java.net.InetSocketAddress; 18 | import java.nio.ByteBuffer; 19 | 20 | public class BeaconReactorImpl implements BeaconReactor { 21 | private static final Logger log = LoggerFactory.getLogger(BeaconReactorImpl.class); 22 | private static final long DEFAULT_BROADCAST_INTERVAL = 1000L; 23 | 24 | private final ManagedContext context; 25 | private final Reactor reactor; 26 | private final UdpSocket socket; 27 | private final UdpBeacon beacon; 28 | private BeaconListener listener; 29 | private long broadcastInterval = DEFAULT_BROADCAST_INTERVAL; 30 | private boolean ignoreLocalAddress = false; 31 | 32 | public BeaconReactorImpl(ManagedContext context, int broadcastPort, UdpBeacon beacon) throws IOException { 33 | this.context = context; 34 | this.beacon = beacon; 35 | this.socket = new UdpSocket(broadcastPort); 36 | this.reactor = context.buildReactor() 37 | .build(); 38 | } 39 | 40 | @Override 41 | public void start() { 42 | assert listener != null; 43 | reactor.addTimer(broadcastInterval, -1, new SendBeacon()); 44 | reactor.addPollable(context.newPollable(socket.getChannel(), PollerType.POLL_IN), new ReceiveBeacon()); 45 | reactor.start(); 46 | } 47 | 48 | @Override 49 | public void stop() { 50 | reactor.stop(); 51 | } 52 | 53 | public void setListener(BeaconListener listener) { 54 | this.listener = listener; 55 | } 56 | 57 | public void setBroadcastInterval(long broadcastInterval) { 58 | this.broadcastInterval = broadcastInterval; 59 | } 60 | 61 | public void setIgnoreLocalAddress(boolean ignoreLocalAddress) { 62 | this.ignoreLocalAddress = ignoreLocalAddress; 63 | } 64 | 65 | private final class SendBeacon implements LoopHandler { 66 | @Override 67 | public void execute(Reactor reactor, Pollable pollable) { 68 | try { 69 | socket.send(beacon.getBuffer()); 70 | } catch (IOException ex) { 71 | log.error("Unable to send UDP beacon:", ex); 72 | } 73 | } 74 | }; 75 | 76 | private final class ReceiveBeacon implements LoopHandler { 77 | private ByteBuffer buffer = ByteBuffer.allocate(Short.MAX_VALUE); 78 | 79 | @Override 80 | public void execute(Reactor reactor, Pollable pollable) { 81 | try { 82 | int read = socket.receive(buffer); 83 | buffer.rewind(); 84 | if (socket.getSender() == null 85 | || read < UdpBeacon.BEACON_SIZE) { 86 | return; 87 | } 88 | 89 | // Attempt to ignore local addresses 90 | // 91 | // NOTE: This does not seem to work on certain network configurations, 92 | // as the loopback address is returned from InetAddress.getLocalHost() 93 | // but the sender is a resolved address 94 | InetAddress sender = ((InetSocketAddress) socket.getSender()).getAddress(); 95 | if (ignoreLocalAddress && 96 | (socket.getAddress().getHostAddress().equals(sender.getHostAddress()) 97 | || sender.isAnyLocalAddress() 98 | || sender.isLoopbackAddress())) { 99 | return; 100 | } 101 | 102 | UdpBeacon message = new UdpBeacon(buffer); 103 | buffer.rewind(); 104 | if (!beacon.getProtocol().equals(message.getProtocol()) 105 | || beacon.getVersion() != message.getVersion()) { 106 | return; 107 | } 108 | 109 | // Last ditch effort to ignore our own packets 110 | // Only ignores this reactor instance, not others broadcasting on this server 111 | if (ignoreLocalAddress 112 | && beacon.getIdentity().equals(message.getIdentity())) { 113 | return; 114 | } 115 | 116 | listener.onBeacon(sender, message); 117 | } catch (IOException ex) { 118 | log.error("Unable to receive UDP beacon:", ex); 119 | } 120 | } 121 | }; 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/bstar/BinaryStarClient.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.bstar; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.zeromq.api.Backgroundable; 6 | import org.zeromq.api.Context; 7 | import org.zeromq.api.Message; 8 | import org.zeromq.api.MessageFlag; 9 | import org.zeromq.api.PollAdapter; 10 | import org.zeromq.api.Poller; 11 | import org.zeromq.api.PollerType; 12 | import org.zeromq.api.Socket; 13 | 14 | import java.util.concurrent.atomic.AtomicBoolean; 15 | 16 | class BinaryStarClient implements Backgroundable { 17 | private final Logger log = LoggerFactory.getLogger(BinaryStarClient.class); 18 | 19 | /** 20 | * States we can be in at any point in time. 21 | */ 22 | private enum State { 23 | CONNECTING, 24 | ACTIVE, 25 | FORWARDING 26 | } 27 | 28 | private BinaryStarSocketBuilder socketBuilder; 29 | private String url1; 30 | private String url2; 31 | private long heartbeatInterval; 32 | private AtomicBoolean closed = new AtomicBoolean(false); 33 | 34 | public BinaryStarClient(BinaryStarSocketBuilder socketBuilder, String url1, String url2, long heartbeatInterval) { 35 | this.socketBuilder = socketBuilder; 36 | this.url1 = url1; 37 | this.url2 = url2; 38 | this.heartbeatInterval = heartbeatInterval; 39 | } 40 | 41 | @Override 42 | public void run(Context context, Socket pipe) { 43 | Socket socket = null; 44 | Message message = null; 45 | Poller poller = context.buildPoller() 46 | .withInPollable(pipe, new PollAdapter()) 47 | .build(); 48 | 49 | boolean primary = true; 50 | State state = State.CONNECTING; 51 | while (!closed.get()) { 52 | if (state == State.CONNECTING) { 53 | if (socket != null) { 54 | // Old socket is confused; close it and open a new one 55 | poller.unregister(socket); 56 | socket.close(); 57 | primary = !primary; 58 | } 59 | 60 | socket = createSocket(primary); 61 | poller.register(context.newPollable(socket, PollerType.POLL_IN), new PollAdapter()); 62 | 63 | if (message != null) { 64 | // Send request again, on new socket 65 | state = State.FORWARDING; 66 | } else { 67 | state = State.ACTIVE; 68 | } 69 | } else if (state == State.FORWARDING) { 70 | // We send a request, then we work to get a reply 71 | socket.send(message); 72 | 73 | // Poll socket for a reply, with timeout 74 | poller.poll(heartbeatInterval * 2); 75 | 76 | // We use a Lazy Pirate strategy in the client. If there's no 77 | // reply within our timeout, we close the socket and try again. 78 | // In Binary Star, it's the client vote that decides which 79 | // server is primary; the client must therefore try to connect 80 | // to each server in turn: 81 | 82 | Message reply = socket.receiveMessage(MessageFlag.DONT_WAIT); 83 | if (reply != null) { 84 | // We got a reply from the server 85 | log.debug("Server replied OK"); 86 | pipe.send(reply); 87 | message = null; 88 | 89 | state = State.ACTIVE; 90 | } else { 91 | log.warn("No response from server, failing over"); 92 | state = State.CONNECTING; 93 | } 94 | } else { 95 | // Wait for a message from client socket 96 | poller.poll(); 97 | 98 | // Return any additional replies we receive 99 | Message reply = socket.receiveMessage(MessageFlag.DONT_WAIT); 100 | if (reply != null) { 101 | pipe.send(reply); 102 | } else { 103 | message = pipe.receiveMessage(); 104 | if (message != null) { 105 | state = State.FORWARDING; 106 | } 107 | } 108 | } 109 | } 110 | } 111 | 112 | private Socket createSocket(boolean primary) { 113 | String url = primary ? url1 : url2; 114 | log.info("Connecting to server at {}", url); 115 | return socketBuilder.connect(url); 116 | } 117 | 118 | @Override 119 | public void onClose() { 120 | closed.set(true); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/bstar/BinaryStarReactorBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.bstar; 2 | 3 | import org.zeromq.api.BinaryStarReactor; 4 | import org.zeromq.api.BinaryStarReactor.Mode; 5 | import org.zeromq.api.LoopHandler; 6 | import org.zeromq.api.Socket; 7 | import org.zeromq.api.SocketType; 8 | import org.zeromq.jzmq.ManagedContext; 9 | 10 | public class BinaryStarReactorBuilder { 11 | public class Spec { 12 | public Mode mode; 13 | public String local; 14 | public String remote; 15 | public long heartbeatInterval = BinaryStarReactor.BSTAR_HEARTBEAT; 16 | public Socket voter; 17 | 18 | public LoopHandler activeHandler; 19 | public LoopHandler voterHandler; 20 | public LoopHandler passiveHandler; 21 | } 22 | 23 | private ManagedContext context; 24 | private Spec spec; 25 | 26 | public BinaryStarReactorBuilder(ManagedContext context) { 27 | this.context = context; 28 | this.spec = new Spec(); 29 | } 30 | 31 | public BinaryStarReactorBuilder withMode(Mode mode) { 32 | spec.mode = mode; 33 | return this; 34 | } 35 | 36 | public BinaryStarReactorBuilder withLocalUrl(String local) { 37 | spec.local = local; 38 | return this; 39 | } 40 | 41 | public BinaryStarReactorBuilder withRemoteUrl(String remote) { 42 | spec.remote = remote; 43 | return this; 44 | } 45 | 46 | public BinaryStarReactorBuilder withHeartbeatInterval(long heartbeatInterval) { 47 | spec.heartbeatInterval = heartbeatInterval; 48 | return this; 49 | } 50 | 51 | public BinaryStarReactorBuilder withVoterSocket(Socket voter) { 52 | spec.voter = voter; 53 | return this; 54 | } 55 | 56 | public BinaryStarReactorBuilder withVoterSocket(String url) { 57 | Socket socket = context.buildSocket(SocketType.ROUTER) 58 | .bind(url); 59 | 60 | return withVoterSocket(socket); 61 | } 62 | 63 | public BinaryStarReactorBuilder withActiveHandler(LoopHandler activeHandler) { 64 | spec.activeHandler = activeHandler; 65 | return this; 66 | } 67 | 68 | public BinaryStarReactorBuilder withVoterHandler(LoopHandler voterHandler) { 69 | spec.voterHandler = voterHandler; 70 | return this; 71 | } 72 | 73 | public BinaryStarReactorBuilder withPassiveHandler(LoopHandler passiveHandler) { 74 | spec.passiveHandler = passiveHandler; 75 | return this; 76 | } 77 | 78 | public BinaryStarReactor build() { 79 | assert spec.voter != null; 80 | assert spec.voterHandler != null; 81 | 82 | BinaryStarReactor reactor = new BinaryStarReactorImpl(context, spec.mode, spec.local, spec.remote); 83 | reactor.registerVoterSocket(spec.voter); 84 | reactor.setVoterHandler(spec.voterHandler); 85 | reactor.setActiveHandler(spec.activeHandler); 86 | reactor.setPassiveHandler(spec.passiveHandler); 87 | reactor.setHeartbeatInterval(spec.heartbeatInterval); 88 | 89 | return reactor; 90 | } 91 | 92 | public BinaryStarReactor start() { 93 | BinaryStarReactor reactor = build(); 94 | reactor.start(); 95 | 96 | return reactor; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/bstar/BinaryStarSocketBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.bstar; 2 | 3 | import org.zeromq.api.BinaryStarReactor; 4 | import org.zeromq.api.Socket; 5 | import org.zeromq.jzmq.ManagedContext; 6 | import org.zeromq.jzmq.sockets.DealerSocketBuilder; 7 | 8 | public class BinaryStarSocketBuilder extends DealerSocketBuilder { 9 | public class Spec { 10 | public long heartbeatInterval = BinaryStarReactor.BSTAR_HEARTBEAT; 11 | } 12 | 13 | private final Spec spec = new Spec(); 14 | 15 | public BinaryStarSocketBuilder(ManagedContext context) { 16 | super(context); 17 | } 18 | 19 | public BinaryStarSocketBuilder withHeartbeatInterval(long heartbeatInterval) { 20 | spec.heartbeatInterval = heartbeatInterval; 21 | return this; 22 | } 23 | 24 | @Override 25 | public Socket connect(String url, String... additionalUrls) { 26 | Socket socket; 27 | if (additionalUrls.length == 0) { 28 | socket = super.connect(url, additionalUrls); 29 | } else { 30 | assert additionalUrls.length == 1; 31 | socket = fork(url, additionalUrls[0]); 32 | } 33 | 34 | return socket; 35 | } 36 | 37 | @Override 38 | public Socket bind(String url, String... additionalUrls) { 39 | throw new UnsupportedOperationException("Cannot bind to Binary Star server"); 40 | } 41 | 42 | private Socket fork(String url1, String url2) { 43 | BinaryStarClient client = new BinaryStarClient(this, url1, url2, spec.heartbeatInterval); 44 | return context.fork(client); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/clone/CloneClientBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.clone; 2 | 3 | import org.zeromq.api.CloneClient; 4 | import org.zeromq.jzmq.ManagedContext; 5 | 6 | public class CloneClientBuilder { 7 | public class Spec { 8 | public String primaryAddress; 9 | public String backupAddress; 10 | public int primaryPort; 11 | public int backupPort; 12 | public String subtree; 13 | public long heartbeatInterval = 1000L; 14 | } 15 | 16 | private ManagedContext context; 17 | private Spec spec = new Spec(); 18 | 19 | public CloneClientBuilder(ManagedContext context) { 20 | this.context = context; 21 | } 22 | 23 | public CloneClientBuilder withPrimaryAddress(String primaryAddress) { 24 | spec.primaryAddress = primaryAddress; 25 | return this; 26 | } 27 | 28 | public CloneClientBuilder withBackupAddress(String backupAddress) { 29 | spec.backupAddress = backupAddress; 30 | return this; 31 | } 32 | 33 | public CloneClientBuilder withPrimaryPort(int primaryPort) { 34 | spec.primaryPort = primaryPort; 35 | return this; 36 | } 37 | 38 | public CloneClientBuilder withBackupPort(int backupPort) { 39 | spec.backupPort = backupPort; 40 | return this; 41 | } 42 | 43 | public CloneClientBuilder withSubtree(String subtree) { 44 | spec.subtree = subtree; 45 | return this; 46 | } 47 | 48 | public CloneClientBuilder withHeartbeatInterval(long heartbeatInterval) { 49 | spec.heartbeatInterval = heartbeatInterval; 50 | return this; 51 | } 52 | 53 | public CloneClient build() { 54 | CloneClient cloneClient = new CloneClientImpl(context, spec.heartbeatInterval); 55 | if (spec.subtree != null) { 56 | cloneClient.subscribe(spec.subtree); 57 | } 58 | if (spec.primaryAddress != null) { 59 | cloneClient.connect(spec.primaryAddress, spec.primaryPort); 60 | } 61 | if (spec.backupAddress != null) { 62 | cloneClient.connect(spec.backupAddress, spec.backupPort); 63 | } 64 | 65 | return cloneClient; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/clone/CloneClientImpl.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.clone; 2 | 3 | import org.zeromq.api.CloneClient; 4 | import org.zeromq.api.Message; 5 | import org.zeromq.api.Message.Frame; 6 | import org.zeromq.api.Socket; 7 | import org.zeromq.jzmq.ManagedContext; 8 | 9 | import java.util.LinkedHashMap; 10 | import java.util.Map; 11 | 12 | public class CloneClientImpl implements CloneClient { 13 | private static final Frame SUBTREE = Frame.of("SUBTREE"); 14 | private static final Frame CONNECT = Frame.of("CONNECT"); 15 | private static final Frame SET = Frame.of("SET"); 16 | private static final Frame GET = Frame.of("GET"); 17 | private static final Frame GETALL = Frame.of("GETALL"); 18 | 19 | private final Socket pipe; 20 | 21 | public CloneClientImpl(ManagedContext context, long heartbeatInterval) { 22 | this.pipe = context.fork(new CloneClientAgent(context, heartbeatInterval)); 23 | } 24 | 25 | @Override 26 | public void subscribe(String subtree) { 27 | pipe.send(new Message(SUBTREE).addString(subtree)); 28 | } 29 | 30 | @Override 31 | public void connect(String address, int port) { 32 | pipe.send(new Message(CONNECT).addString(address).addInt(port)); 33 | } 34 | 35 | @Override 36 | public void set(String key, String value) { 37 | set(key, value, Integer.MAX_VALUE); 38 | } 39 | 40 | @Override 41 | public void set(String key, String value, long ttl) { 42 | pipe.send(new Message(SET).addString(key).addString(value).addLong(ttl)); 43 | } 44 | 45 | @Override 46 | public String get(String key) { 47 | pipe.send(new Message(GET).addString(key)); 48 | 49 | String value = pipe.receiveMessage().popString(); 50 | if (value.isEmpty()) { 51 | value = null; 52 | } 53 | 54 | return value; 55 | } 56 | 57 | @Override 58 | public Map getAll() { 59 | pipe.send(new Message(GETALL)); 60 | 61 | Map map = new LinkedHashMap<>(); 62 | while (true) { 63 | Message message = pipe.receiveMessage(); 64 | String key = message.popString(), value = message.popString(); 65 | if (key.equals("KTHXBAI")) { 66 | break; 67 | } 68 | 69 | map.put(key, value); 70 | } 71 | 72 | return map; 73 | } 74 | 75 | @Override 76 | public void close() { 77 | pipe.close(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/clone/CloneMessage.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.clone; 2 | 3 | import org.zeromq.api.Message; 4 | import org.zeromq.api.Socket; 5 | 6 | import java.util.Comparator; 7 | import java.util.LinkedHashMap; 8 | import java.util.Map; 9 | import java.util.UUID; 10 | 11 | class CloneMessage implements Cloneable { 12 | private long sequence; 13 | private UUID uuid; 14 | private String key; 15 | private byte[] value; 16 | private Map properties = new LinkedHashMap<>(); 17 | 18 | private long expiresOn; 19 | 20 | public CloneMessage() { 21 | } 22 | 23 | public CloneMessage(String key) { 24 | this.key = key; 25 | } 26 | 27 | public long getSequence() { 28 | return sequence; 29 | } 30 | 31 | public void setSequence(long sequence) { 32 | this.sequence = sequence; 33 | } 34 | 35 | public UUID getUuid() { 36 | return uuid; 37 | } 38 | 39 | public void setRandomUuid() { 40 | setUuid(UUID.randomUUID()); 41 | } 42 | 43 | public void setUuid(UUID uuid) { 44 | this.uuid = uuid; 45 | } 46 | 47 | public String getKey() { 48 | return key; 49 | } 50 | 51 | public void setKey(String key) { 52 | this.key = key; 53 | } 54 | 55 | public byte[] getValue() { 56 | return value; 57 | } 58 | 59 | public void setValue(byte[] value) { 60 | this.value = value; 61 | } 62 | 63 | public Map getProperties() { 64 | return properties; 65 | } 66 | 67 | public void addProperty(String propertyKey, String propertyValue) { 68 | properties.put(propertyKey, propertyValue); 69 | } 70 | 71 | public long ttl() { 72 | String value = properties.get("ttl"); 73 | return (value == null) ? -1 : Long.parseLong(value); 74 | } 75 | 76 | public void ttl(long ttl) { 77 | properties.put("ttl", String.valueOf(ttl)); 78 | } 79 | 80 | public long expiresOn() { 81 | if (expiresOn == 0) { 82 | long ttl = ttl(); 83 | if (ttl < 0) { 84 | expiresOn = Long.MAX_VALUE; 85 | } else { 86 | expiresOn = System.currentTimeMillis() + ttl; 87 | } 88 | } 89 | 90 | return expiresOn; 91 | } 92 | 93 | @Override 94 | public CloneMessage clone() { 95 | CloneMessage clone = null; 96 | try { 97 | clone = (CloneMessage) super.clone(); 98 | clone.properties.putAll(properties); 99 | } catch (CloneNotSupportedException ignored) { 100 | } 101 | 102 | return clone; 103 | } 104 | 105 | /** 106 | * Send a {@link CloneMessage} over the given ØMQ Socket. 107 | * 108 | * @param socket The ØMQ socket 109 | */ 110 | public void send(Socket socket) { 111 | Message message = new Message(); 112 | message.addString(key); 113 | 114 | // Add optional sequence 115 | message.addLong(sequence); 116 | 117 | // Add optional UUID 118 | if (uuid != null) { 119 | message.addString(uuid.toString()); 120 | } else { 121 | message.addEmptyFrame(); 122 | } 123 | 124 | // Add optional properties 125 | StringBuilder sb = new StringBuilder(); 126 | for (Map.Entry entry : properties.entrySet()) { 127 | sb.append(entry.getKey()); 128 | sb.append('='); 129 | sb.append(entry.getValue()); 130 | sb.append('\n'); 131 | } 132 | message.addString(sb.toString()); 133 | 134 | // Add optional value 135 | if (value != null) { 136 | message.addBytes(value); 137 | } else { 138 | message.addEmptyFrame(); 139 | } 140 | 141 | socket.send(message); 142 | } 143 | 144 | /** 145 | * Receive a {@link CloneMessage} over the given ØMQ Socket. 146 | * 147 | * @param socket The ØMQ socket 148 | * @return The received message 149 | */ 150 | public static CloneMessage receive(Socket socket) { 151 | Message message = socket.receiveMessage(); 152 | assert message.size() == 5; 153 | 154 | String key = message.popString(); 155 | long sequence = message.popLong(); 156 | String uuid = message.popString(); 157 | String[] props = message.popString().trim().split("\n"); 158 | byte[] value = message.popBytes(); 159 | 160 | CloneMessage m = new CloneMessage(); 161 | m.setKey(key); 162 | if (value.length > 0) { 163 | m.setValue(value); 164 | } 165 | 166 | // Set sequence 167 | if (sequence > 0) { 168 | m.setSequence(sequence); 169 | } 170 | 171 | // Set optional UUID 172 | if (uuid.length() > 0) { 173 | m.setUuid(UUID.fromString(uuid)); 174 | } 175 | 176 | // Decode properties 177 | if (props.length > 0) { 178 | for (String prop : props) { 179 | if (prop.isEmpty()) { 180 | continue; 181 | } 182 | 183 | assert prop.contains("="); 184 | String[] parts = prop.split("="); 185 | m.addProperty(parts[0], parts[1]); 186 | } 187 | } 188 | 189 | return m; 190 | } 191 | 192 | /** 193 | * Comparator used to sort {@link CloneMessage}s by time-to-live. 194 | */ 195 | public static final Comparator SORT_BY_TTL = new Comparator() { 196 | @Override 197 | public int compare(CloneMessage a, CloneMessage b) { 198 | return Long.compare(a.expiresOn(), b.expiresOn()); 199 | } 200 | }; 201 | } 202 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/clone/CloneServerBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.clone; 2 | 3 | import org.zeromq.api.BinaryStarReactor; 4 | import org.zeromq.api.CloneServer; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | public class CloneServerBuilder { 8 | public class Spec { 9 | public BinaryStarReactor.Mode mode; 10 | public String primaryAddress; 11 | public String backupAddress; 12 | public int primaryPort; 13 | public int backupPort; 14 | public int primaryBstarPort; 15 | public int backupBstarPort; 16 | public long heartbeatInterval = 1000; 17 | } 18 | 19 | private ManagedContext context; 20 | private Spec spec = new Spec(); 21 | 22 | public CloneServerBuilder(ManagedContext context) { 23 | this.context = context; 24 | } 25 | 26 | public CloneServerBuilder withMode(BinaryStarReactor.Mode mode) { 27 | spec.mode = mode; 28 | return this; 29 | } 30 | 31 | public CloneServerBuilder withPrimaryAddress(String primaryAddress) { 32 | spec.primaryAddress = primaryAddress; 33 | return this; 34 | } 35 | 36 | public CloneServerBuilder withBackupAddress(String backupAddress) { 37 | spec.backupAddress = backupAddress; 38 | return this; 39 | } 40 | 41 | public CloneServerBuilder withPrimaryPort(int primaryPort) { 42 | spec.primaryPort = primaryPort; 43 | return this; 44 | } 45 | 46 | public CloneServerBuilder withBackupPort(int backupPort) { 47 | spec.backupPort = backupPort; 48 | return this; 49 | } 50 | 51 | public CloneServerBuilder withPrimaryBinaryStarPort(int primaryBstarPort) { 52 | spec.primaryBstarPort = primaryBstarPort; 53 | return this; 54 | } 55 | 56 | public CloneServerBuilder withBackupBinaryStarPort(int backupBstarPort) { 57 | spec.backupBstarPort = backupBstarPort; 58 | return this; 59 | } 60 | 61 | public CloneServerBuilder withHeartbeatInterval(long heartbeatInterval) { 62 | spec.heartbeatInterval = heartbeatInterval; 63 | return this; 64 | } 65 | 66 | public CloneServer build() { 67 | String peerAddress; 68 | int localPort, peerPort, localBstarPort, peerBstarPort; 69 | if (spec.mode == BinaryStarReactor.Mode.PRIMARY) { 70 | localPort = spec.primaryPort; 71 | peerAddress = spec.backupAddress; 72 | peerPort = spec.backupPort; 73 | localBstarPort = spec.primaryBstarPort; 74 | peerBstarPort = spec.backupBstarPort; 75 | } else { 76 | localPort = spec.backupPort; 77 | peerAddress = spec.primaryAddress; 78 | peerPort = spec.primaryPort; 79 | localBstarPort = spec.backupBstarPort; 80 | peerBstarPort = spec.primaryBstarPort; 81 | } 82 | 83 | CloneServerImpl cloneServer = new CloneServerImpl(context, spec.mode, peerAddress, localPort, peerPort, localBstarPort, peerBstarPort); 84 | cloneServer.setHeartbeatInterval(spec.heartbeatInterval); 85 | 86 | return cloneServer; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/device/DeviceBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.device; 2 | 3 | import org.zeromq.api.DeviceType; 4 | import org.zeromq.api.Socket; 5 | import org.zeromq.api.SocketType; 6 | import org.zeromq.jzmq.ManagedContext; 7 | 8 | public class DeviceBuilder { 9 | public class Spec { 10 | public DeviceType deviceType; 11 | public String frontend; 12 | public String backend; 13 | } 14 | 15 | private ManagedContext context; 16 | private Spec spec = new Spec(); 17 | 18 | public DeviceBuilder(ManagedContext context, DeviceType deviceType) { 19 | this.context = context; 20 | spec.deviceType = deviceType; 21 | } 22 | 23 | public DeviceBuilder withFrontendUrl(String frontend) { 24 | spec.frontend = frontend; 25 | return this; 26 | } 27 | 28 | public DeviceBuilder withBackendUrl(String backend) { 29 | spec.backend = backend; 30 | return this; 31 | } 32 | 33 | public void start() { 34 | switch (spec.deviceType) { 35 | case STREAMER: 36 | startStreamer(); 37 | break; 38 | case FORWARDER: 39 | startForwarder(); 40 | break; 41 | case QUEUE: 42 | startQueue(); 43 | break; 44 | } 45 | } 46 | 47 | private void startStreamer() { 48 | Socket frontend = context.buildSocket(SocketType.PULL) 49 | .bind(spec.frontend); 50 | 51 | Socket backend = context.buildSocket(SocketType.PUSH) 52 | .bind(spec.backend); 53 | 54 | context.forward(frontend, backend); 55 | } 56 | 57 | private void startForwarder() { 58 | Socket frontend = context.buildSocket(SocketType.XSUB) 59 | .bind(spec.frontend); 60 | 61 | Socket backend = context.buildSocket(SocketType.XPUB) 62 | .bind(spec.backend); 63 | 64 | context.forward(frontend, backend); 65 | } 66 | 67 | private void startQueue() { 68 | Socket frontend = context.buildSocket(SocketType.ROUTER) 69 | .bind(spec.frontend); 70 | 71 | Socket backend = context.buildSocket(SocketType.DEALER) 72 | .bind(spec.backend); 73 | 74 | context.forward(frontend, backend); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/examples/PublishSubscribe.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.examples; 2 | 3 | import org.zeromq.ContextFactory; 4 | import org.zeromq.api.Context; 5 | import org.zeromq.api.Socket; 6 | import org.zeromq.api.SocketType; 7 | 8 | public class PublishSubscribe { 9 | public static void main(String[] args) throws Exception { 10 | Context ctx = ContextFactory.createContext(1); 11 | Socket publisher = ctx.buildSocket(SocketType.PUB).bind("inproc://publisher"); 12 | Socket subscriber = ctx.buildSocket(SocketType.SUB).asSubscribable().subscribe("H".getBytes()).connect("inproc://publisher"); 13 | publisher.send("Hello".getBytes()); 14 | System.out.println(new String(subscriber.receive())); 15 | ctx.close(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/examples/PushPull.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.examples; 2 | 3 | import org.zeromq.ContextFactory; 4 | import org.zeromq.api.Context; 5 | import org.zeromq.api.Socket; 6 | import org.zeromq.api.SocketType; 7 | 8 | public class PushPull { 9 | public static void main(String[] args) throws Exception { 10 | Context ctx = ContextFactory.createContext(1); 11 | Socket puller = ctx.buildSocket(SocketType.PULL).bind("inproc://pipeline"); 12 | Socket pusher = ctx.buildSocket(SocketType.PUSH).connect("inproc://pipeline"); 13 | pusher.send("PING".getBytes()); 14 | byte[] buf = puller.receive(); 15 | System.out.println(new String(buf)); 16 | ctx.close(); 17 | } 18 | } -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/examples/RequestReply.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.examples; 2 | 3 | import org.zeromq.ContextFactory; 4 | import org.zeromq.api.Context; 5 | import org.zeromq.api.Socket; 6 | import org.zeromq.api.SocketType; 7 | 8 | public class RequestReply { 9 | public static void main(String[] args) throws Exception { 10 | Context ctx = ContextFactory.createContext(1); 11 | Socket rep = ctx.buildSocket(SocketType.REP).bind("inproc://requestreply"); 12 | Socket req = ctx.buildSocket(SocketType.REQ).connect("inproc://requestreply"); 13 | req.send("PING".getBytes()); 14 | byte[] buf = rep.receive(); 15 | System.out.println(new String(buf)); 16 | rep.send("PONG".getBytes()); 17 | buf = req.receive(); 18 | System.out.println(new String(buf)); 19 | ctx.close(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/poll/PollableImpl.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.poll; 2 | 3 | import org.zeromq.api.Pollable; 4 | import org.zeromq.api.PollerType; 5 | import org.zeromq.api.Socket; 6 | 7 | import java.nio.channels.SelectableChannel; 8 | import java.util.Arrays; 9 | import java.util.EnumSet; 10 | 11 | public class PollableImpl implements Pollable { 12 | private final Socket socket; 13 | private final SelectableChannel channel; 14 | private final PollerType[] options; 15 | 16 | public PollableImpl(Socket socket, PollerType... options) { 17 | this.socket = socket; 18 | this.channel = null; 19 | this.options = options; 20 | } 21 | 22 | public PollableImpl(SelectableChannel channel, PollerType... options) { 23 | this.socket = null; 24 | this.channel = channel; 25 | this.options = options; 26 | } 27 | 28 | @Override 29 | public Socket getSocket() { 30 | return socket; 31 | } 32 | 33 | @Override 34 | public SelectableChannel getChannel() { 35 | return channel; 36 | } 37 | 38 | @Override 39 | public EnumSet getOptions() { 40 | if (options.length == 0) { 41 | return EnumSet.allOf(PollerType.class); 42 | } 43 | return EnumSet.copyOf(Arrays.asList(options)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/poll/PollerBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.poll; 2 | 3 | import org.zeromq.api.PollListener; 4 | import org.zeromq.api.Pollable; 5 | import org.zeromq.api.Poller; 6 | import org.zeromq.api.PollerType; 7 | import org.zeromq.api.Socket; 8 | import org.zeromq.jzmq.ManagedContext; 9 | 10 | import java.nio.channels.SelectableChannel; 11 | import java.util.LinkedHashMap; 12 | import java.util.Map; 13 | 14 | public class PollerBuilder { 15 | 16 | private final ManagedContext context; 17 | private final Map pollablesAndListeners = new LinkedHashMap<>(); 18 | 19 | public PollerBuilder(ManagedContext context) { 20 | this.context = context; 21 | } 22 | 23 | public PollerBuilder withPollable(Pollable pollable, PollListener listener) { 24 | pollablesAndListeners.put(pollable, listener); 25 | return this; 26 | } 27 | 28 | /* 29 | * Socket Pollables. 30 | */ 31 | 32 | public PollerBuilder withInPollable(Socket socket, PollListener listener) { 33 | return withPollable(context.newPollable(socket, PollerType.POLL_IN), listener); 34 | } 35 | 36 | public PollerBuilder withOutPollable(Socket socket, PollListener listener) { 37 | return withPollable(context.newPollable(socket, PollerType.POLL_OUT), listener); 38 | } 39 | 40 | public PollerBuilder withErrorPollable(Socket socket, PollListener listener) { 41 | return withPollable(context.newPollable(socket, PollerType.POLL_ERROR), listener); 42 | } 43 | 44 | public PollerBuilder withInOutPollable(Socket socket, PollListener listener) { 45 | return withPollable(context.newPollable(socket, PollerType.POLL_IN, PollerType.POLL_OUT), listener); 46 | } 47 | 48 | public PollerBuilder withAllPollable(Socket socket, PollListener listener) { 49 | return withPollable(context.newPollable(socket, PollerType.POLL_IN, PollerType.POLL_OUT, PollerType.POLL_ERROR), listener); 50 | } 51 | 52 | /* 53 | * SelectableChannel Pollables. 54 | */ 55 | 56 | public PollerBuilder withInPollable(SelectableChannel channel, PollListener listener) { 57 | return withPollable(context.newPollable(channel, PollerType.POLL_IN), listener); 58 | } 59 | 60 | public PollerBuilder withOutPollable(SelectableChannel channel, PollListener listener) { 61 | return withPollable(context.newPollable(channel, PollerType.POLL_OUT), listener); 62 | } 63 | 64 | public PollerBuilder withErrorPollable(SelectableChannel channel, PollListener listener) { 65 | return withPollable(context.newPollable(channel, PollerType.POLL_ERROR), listener); 66 | } 67 | 68 | public PollerBuilder withInOutPollable(SelectableChannel channel, PollListener listener) { 69 | return withPollable(context.newPollable(channel, PollerType.POLL_IN, PollerType.POLL_OUT), listener); 70 | } 71 | 72 | public PollerBuilder withAllPollable(SelectableChannel channel, PollListener listener) { 73 | return withPollable(context.newPollable(channel, PollerType.POLL_IN, PollerType.POLL_OUT, PollerType.POLL_ERROR), listener); 74 | } 75 | 76 | @Deprecated 77 | public Poller create() { 78 | return build(); 79 | } 80 | 81 | public Poller build() { 82 | return new PollerImpl(context, pollablesAndListeners); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/reactor/PollItem.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.reactor; 2 | 3 | import org.zeromq.api.LoopHandler; 4 | import org.zeromq.api.PollAdapter; 5 | import org.zeromq.api.Pollable; 6 | import org.zeromq.api.Reactor; 7 | 8 | class PollItem extends PollAdapter { 9 | private Reactor reactor; 10 | 11 | public Pollable pollable; 12 | public LoopHandler handler; 13 | public Object[] args; 14 | 15 | public PollItem(Reactor reactor, Pollable pollable, LoopHandler handler) { 16 | this.reactor = reactor; 17 | this.pollable = pollable; 18 | this.handler = handler; 19 | } 20 | 21 | @Override 22 | public void handleIn(Pollable pollable) { 23 | execute(pollable); 24 | } 25 | 26 | @Override 27 | public void handleOut(Pollable pollable) { 28 | execute(pollable); 29 | } 30 | 31 | @Override 32 | public void handleError(Pollable pollable) { 33 | execute(pollable); 34 | } 35 | 36 | private void execute(Pollable pollable) { 37 | handler.execute(reactor, pollable); 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/reactor/ReactorBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.reactor; 2 | 3 | import org.zeromq.api.LoopHandler; 4 | import org.zeromq.api.Pollable; 5 | import org.zeromq.api.PollerType; 6 | import org.zeromq.api.Reactor; 7 | import org.zeromq.api.Socket; 8 | import org.zeromq.jzmq.ManagedContext; 9 | 10 | import java.nio.channels.SelectableChannel; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | public class ReactorBuilder { 14 | private final ManagedContext context; 15 | private final ReactorImpl reactor; 16 | 17 | public ReactorBuilder(ManagedContext context) { 18 | this.context = context; 19 | this.reactor = new ReactorImpl(context); 20 | } 21 | 22 | /* 23 | * Socket Pollables. 24 | */ 25 | 26 | public ReactorBuilder withPollable(Pollable pollable, LoopHandler handler) { 27 | reactor.addPollable(pollable, handler); 28 | return this; 29 | } 30 | 31 | public ReactorBuilder withInPollable(Socket socket, LoopHandler handler) { 32 | return withPollable(context.newPollable(socket, PollerType.POLL_IN), handler); 33 | } 34 | 35 | public ReactorBuilder withOutPollable(Socket socket, LoopHandler handler) { 36 | return withPollable(context.newPollable(socket, PollerType.POLL_OUT), handler); 37 | } 38 | 39 | public ReactorBuilder withErrorPollable(Socket socket, LoopHandler handler) { 40 | return withPollable(context.newPollable(socket, PollerType.POLL_ERROR), handler); 41 | } 42 | 43 | public ReactorBuilder withInOutPollable(Socket socket, LoopHandler handler) { 44 | return withPollable(context.newPollable(socket, PollerType.POLL_IN, PollerType.POLL_OUT), handler); 45 | } 46 | 47 | public ReactorBuilder withAllPollable(Socket socket, LoopHandler handler) { 48 | return withPollable(context.newPollable(socket, PollerType.POLL_IN, PollerType.POLL_OUT, PollerType.POLL_ERROR), handler); 49 | } 50 | 51 | /* 52 | * SelectableChannel Pollables. 53 | */ 54 | 55 | public ReactorBuilder withInPollable(SelectableChannel channel, LoopHandler handler) { 56 | return withPollable(context.newPollable(channel, PollerType.POLL_IN), handler); 57 | } 58 | 59 | public ReactorBuilder withOutPollable(SelectableChannel channel, LoopHandler handler) { 60 | return withPollable(context.newPollable(channel, PollerType.POLL_OUT), handler); 61 | } 62 | 63 | public ReactorBuilder withErrorPollable(SelectableChannel channel, LoopHandler handler) { 64 | return withPollable(context.newPollable(channel, PollerType.POLL_ERROR), handler); 65 | } 66 | 67 | public ReactorBuilder withInOutPollable(SelectableChannel channel, LoopHandler handler) { 68 | return withPollable(context.newPollable(channel, PollerType.POLL_IN, PollerType.POLL_OUT), handler); 69 | } 70 | 71 | public ReactorBuilder withAllPollable(SelectableChannel channel, LoopHandler handler) { 72 | return withPollable(context.newPollable(channel, PollerType.POLL_IN, PollerType.POLL_OUT, PollerType.POLL_ERROR), handler); 73 | } 74 | 75 | /* 76 | * Timer Pollables. 77 | */ 78 | 79 | public ReactorBuilder withTimer(long initialDelay, int numIterations, LoopHandler handler) { 80 | reactor.addTimer(initialDelay, numIterations, handler); 81 | return this; 82 | } 83 | 84 | public ReactorBuilder withTimerOnce(long initialDelay, LoopHandler handler) { 85 | return withTimer(initialDelay, 1, handler); 86 | } 87 | 88 | public ReactorBuilder withTimerOnce(long initialDelay, TimeUnit unit, LoopHandler handler) { 89 | return withTimer(unit.toMillis(initialDelay), 1, handler); 90 | } 91 | 92 | public ReactorBuilder withTimerRepeating(long initialDelay, LoopHandler handler) { 93 | return withTimer(initialDelay, -1, handler); 94 | } 95 | 96 | public ReactorBuilder withTimerRepeating(long initialDelay, TimeUnit unit, LoopHandler handler) { 97 | return withTimer(unit.toMillis(initialDelay), -1, handler); 98 | } 99 | 100 | public Reactor build() { 101 | return reactor; 102 | } 103 | 104 | public void start() { 105 | reactor.start(); 106 | } 107 | 108 | public void run() { 109 | reactor.run(); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/reactor/ReactorImpl.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.reactor; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | import java.util.PriorityQueue; 7 | import java.util.Queue; 8 | import java.util.concurrent.atomic.AtomicBoolean; 9 | 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.zeromq.api.LoopHandler; 13 | import org.zeromq.api.Pollable; 14 | import org.zeromq.api.Poller; 15 | import org.zeromq.api.Reactor; 16 | import org.zeromq.api.exception.ContextTerminatedException; 17 | import org.zeromq.api.exception.InvalidSocketException; 18 | import org.zeromq.jzmq.ManagedContext; 19 | 20 | public class ReactorImpl implements Reactor, Runnable { 21 | private static final Logger log = LoggerFactory.getLogger(Reactor.class); 22 | 23 | private final Thread thread = new Thread(this); 24 | private final AtomicBoolean running = new AtomicBoolean(false); 25 | 26 | private final Poller poller; 27 | private final List pollItems; 28 | private final Queue timers; 29 | 30 | public ReactorImpl(ManagedContext context) { 31 | this.pollItems = new ArrayList<>(); 32 | this.timers = new PriorityQueue<>(); 33 | this.poller = context.buildPoller().build(); 34 | } 35 | 36 | @Override 37 | public void addPollable(Pollable pollable, LoopHandler handler) { 38 | PollItem pollItem = new PollItem(this, pollable, handler); 39 | pollItems.add(pollItem); 40 | poller.register(pollable, pollItem); 41 | } 42 | 43 | @Override 44 | public void addTimer(long initialDelay, int numIterations, LoopHandler handler) { 45 | ReactorTimer timer = new ReactorTimer(initialDelay, numIterations, handler); 46 | timer.recalculate(System.currentTimeMillis()); 47 | 48 | timers.add(timer); 49 | } 50 | 51 | @Override 52 | public void cancel(LoopHandler handler) { 53 | // find the handler in pollers 54 | for (Iterator it = pollItems.iterator(); it.hasNext();) { 55 | PollItem item = it.next(); 56 | if (item.handler == handler) { 57 | it.remove(); 58 | if (poller != null) { 59 | if (item.pollable.getChannel() != null) { 60 | poller.disable(item.pollable.getChannel()); 61 | } else { 62 | poller.disable(item.pollable.getSocket()); 63 | } 64 | } 65 | } 66 | } 67 | 68 | // find the handler in timers 69 | for (Iterator it = timers.iterator(); it.hasNext();) { 70 | if (it.next().handler == handler) { 71 | it.remove(); 72 | } 73 | } 74 | } 75 | 76 | @Override 77 | public void start() { 78 | thread.start(); 79 | } 80 | 81 | @Override 82 | public void stop() { 83 | running.set(false); 84 | try { 85 | thread.join(); 86 | } catch (InterruptedException ignored) { 87 | } 88 | } 89 | 90 | @Override 91 | public void run() { 92 | running.set(true); 93 | 94 | // Main reactor loop 95 | while (running.get()) { 96 | long wait = ticklessTimer(); 97 | try { 98 | /* 99 | * Pollers will execute internally. 100 | * 101 | * NOTE: This call can cause new timers and pollers to be 102 | * registered internally, using a handle to this Reactor. 103 | */ 104 | poller.poll(wait); 105 | } catch (ContextTerminatedException | InvalidSocketException ex) { 106 | break; 107 | } 108 | 109 | // Break out early if shutting down 110 | if (!running.get()) { 111 | break; 112 | } 113 | 114 | // Handle any timers that have now expired 115 | long now = System.currentTimeMillis(); 116 | while (!timers.isEmpty() 117 | && timers.peek().nextFireTime <= now) { 118 | /* 119 | * Remove timer from queue to execute it. 120 | * 121 | * NOTE: This call can cause new timers and pollers to be 122 | * registered internally, using a handle to this Reactor. 123 | */ 124 | ReactorTimer timer = timers.poll(); 125 | timer.execute(this); 126 | 127 | // Re-add repeating timer 128 | if (timer.numIterations > 0 || timer.numIterations == -1) { 129 | timer.recalculate(now); 130 | timers.add(timer); 131 | } 132 | } 133 | } 134 | 135 | log.info("Exiting reactor"); 136 | } 137 | 138 | private long ticklessTimer() { 139 | // Calculate tickless timer, up to 1 hour 140 | long now = System.currentTimeMillis(); 141 | long tickless = now + 1000 * 3600; 142 | if (timers.peek() != null) { 143 | tickless = timers.peek().nextFireTime; 144 | } 145 | 146 | long timeout = tickless - now; 147 | if (timeout < 0) { 148 | timeout = 0; 149 | } 150 | 151 | return timeout; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/reactor/ReactorTimer.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.reactor; 2 | 3 | import java.util.Arrays; 4 | import java.util.Objects; 5 | import org.zeromq.api.LoopHandler; 6 | import org.zeromq.api.Reactor; 7 | 8 | class ReactorTimer implements Comparable { 9 | public long initialDelay; 10 | public int numIterations; 11 | public LoopHandler handler; 12 | 13 | public long nextFireTime = -1; 14 | 15 | public ReactorTimer(long initialDelay, int numIterations, LoopHandler handler) { 16 | this.initialDelay = initialDelay; 17 | this.numIterations = numIterations; 18 | this.handler = handler; 19 | } 20 | 21 | public void recalculate(long now) { 22 | nextFireTime = now + initialDelay; 23 | } 24 | 25 | public void execute(Reactor reactor) { 26 | handler.execute(reactor, null); 27 | 28 | // Decrement counter if applicable 29 | if (numIterations > 0) { 30 | numIterations--; 31 | } 32 | } 33 | 34 | @Override 35 | public int compareTo(ReactorTimer other) { 36 | int result = 0; 37 | if (nextFireTime < other.nextFireTime) { 38 | result = -1; 39 | } else if (nextFireTime > other.nextFireTime) { 40 | result = 1; 41 | } 42 | 43 | return result; 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | int hash = 7; 49 | return hash; 50 | } 51 | 52 | @Override 53 | public boolean equals(Object obj) { 54 | if (this == obj) { 55 | return true; 56 | } 57 | if (obj == null) { 58 | return false; 59 | } 60 | if (getClass() != obj.getClass()) { 61 | return false; 62 | } 63 | final ReactorTimer other = (ReactorTimer) obj; 64 | if (this.initialDelay != other.initialDelay) { 65 | return false; 66 | } 67 | if (this.numIterations != other.numIterations) { 68 | return false; 69 | } 70 | if (this.nextFireTime != other.nextFireTime) { 71 | return false; 72 | } 73 | if (!Objects.equals(this.handler, other.handler)) { 74 | return false; 75 | } 76 | return true; 77 | } 78 | 79 | 80 | } -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/sockets/DealerSocketBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.sockets; 2 | 3 | import org.zeromq.api.SocketType; 4 | import org.zeromq.jzmq.ManagedContext; 5 | 6 | public class DealerSocketBuilder extends SocketBuilder { 7 | public DealerSocketBuilder(ManagedContext context) { 8 | super(context, SocketType.DEALER); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/sockets/PairSocketBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.sockets; 2 | 3 | import org.zeromq.api.SocketType; 4 | import org.zeromq.jzmq.ManagedContext; 5 | 6 | public class PairSocketBuilder extends SocketBuilder { 7 | 8 | public PairSocketBuilder(ManagedContext context) { 9 | super(context, SocketType.PAIR); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/sockets/PubSocketBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.sockets; 2 | 3 | import org.zeromq.api.SocketType; 4 | import org.zeromq.jzmq.ManagedContext; 5 | 6 | public class PubSocketBuilder extends SocketBuilder { 7 | 8 | public PubSocketBuilder(ManagedContext context) { 9 | super(context, SocketType.PUB); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/sockets/PullSocketBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.sockets; 2 | 3 | import org.zeromq.api.SocketType; 4 | import org.zeromq.jzmq.ManagedContext; 5 | 6 | public class PullSocketBuilder extends SocketBuilder { 7 | 8 | public PullSocketBuilder(ManagedContext context) { 9 | super(context, SocketType.PULL); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/sockets/PushSocketBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.sockets; 2 | 3 | import org.zeromq.api.SocketType; 4 | import org.zeromq.jzmq.ManagedContext; 5 | 6 | /** 7 | * For building sockets of type PUSH. 8 | */ 9 | public class PushSocketBuilder extends SocketBuilder { 10 | 11 | public PushSocketBuilder(ManagedContext context) { 12 | super(context, SocketType.PUSH); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/sockets/RepSocketBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.sockets; 2 | 3 | import org.zeromq.api.SocketType; 4 | import org.zeromq.jzmq.ManagedContext; 5 | 6 | public class RepSocketBuilder extends SocketBuilder { 7 | public RepSocketBuilder(ManagedContext managedContext) { 8 | super(managedContext, SocketType.REP); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/sockets/ReqSocketBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.sockets; 2 | 3 | import org.zeromq.api.SocketType; 4 | import org.zeromq.jzmq.ManagedContext; 5 | 6 | public class ReqSocketBuilder extends SocketBuilder { 7 | public ReqSocketBuilder(ManagedContext context) { 8 | super(context, SocketType.REQ); 9 | } 10 | 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/sockets/RouterSocketBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.sockets; 2 | 3 | import org.zeromq.ZMQ; 4 | import org.zeromq.api.Routable; 5 | import org.zeromq.api.Socket; 6 | import org.zeromq.api.SocketType; 7 | import org.zeromq.jzmq.ManagedContext; 8 | 9 | public class RouterSocketBuilder extends SocketBuilder implements Routable { 10 | private boolean routerMandatory = false; 11 | 12 | public RouterSocketBuilder(ManagedContext managedContext) { 13 | super(managedContext, SocketType.ROUTER); 14 | } 15 | 16 | @Override 17 | public Socket connect(String url, String... additionalUrls) { 18 | ZMQ.Socket socket = createConnectableSocketWithStandardSettings(); 19 | socket.setRouterMandatory(routerMandatory); 20 | connect(socket, url, additionalUrls); 21 | return newManagedSocket(socket); 22 | } 23 | 24 | @Override 25 | public Socket bind(String url, String... additionalUrls) { 26 | ZMQ.Socket socket = createBindableSocketWithStandardSettings(); 27 | socket.setRouterMandatory(routerMandatory); 28 | bind(socket, url, additionalUrls); 29 | return newManagedSocket(socket); 30 | } 31 | 32 | @Override 33 | public SocketBuilder withRouterMandatory() { 34 | routerMandatory = true; 35 | return this; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/sockets/SubSocketBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.sockets; 2 | 3 | import org.zeromq.ZMQ; 4 | import org.zeromq.api.Socket; 5 | import org.zeromq.api.SocketType; 6 | import org.zeromq.api.Subscribable; 7 | import org.zeromq.jzmq.ManagedContext; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | public class SubSocketBuilder extends SocketBuilder implements Subscribable { 13 | private List subscriptions = new ArrayList<>(); 14 | 15 | public SubSocketBuilder(ManagedContext context) { 16 | super(context, SocketType.SUB); 17 | } 18 | 19 | @Override 20 | public SubSocketBuilder subscribe(byte[] data) { 21 | byte[] subscription = new byte[data.length]; 22 | System.arraycopy(data, 0, subscription, 0, data.length); 23 | subscriptions.add(subscription); 24 | return this; 25 | } 26 | 27 | @Override 28 | public SubSocketBuilder subscribeAll() { 29 | return subscribe(new byte[0]); 30 | } 31 | 32 | @Override 33 | public Socket connect(String url, String... additionalUrls) { 34 | if (subscriptions.isEmpty()) { 35 | throw new IllegalStateException("You must have a SUB socket subscribe to something before you can connect it."); 36 | } 37 | ZMQ.Socket socket = createConnectableSocketWithStandardSettings(); 38 | for (byte[] subscription : subscriptions) { 39 | socket.subscribe(subscription); 40 | } 41 | connect(socket, url, additionalUrls); 42 | return newManagedSocket(socket); 43 | } 44 | 45 | @Override 46 | public Socket bind(String url, String... additionalUrls) { 47 | if (subscriptions.isEmpty()) { 48 | throw new IllegalStateException("You must have a SUB socket subscribe to something before you can bind it."); 49 | } 50 | ZMQ.Socket socket = createConnectableSocketWithStandardSettings(); 51 | for (byte[] subscription : subscriptions) { 52 | socket.subscribe(subscription); 53 | } 54 | bind(socket, url, additionalUrls); 55 | return newManagedSocket(socket); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/sockets/XPubSocketBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.sockets; 2 | 3 | import org.zeromq.api.SocketType; 4 | import org.zeromq.jzmq.ManagedContext; 5 | 6 | public class XPubSocketBuilder extends SocketBuilder { 7 | 8 | public XPubSocketBuilder(ManagedContext context) { 9 | super(context, SocketType.XPUB); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/zeromq/jzmq/sockets/XSubSocketBuilder.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.jzmq.sockets; 2 | 3 | import org.zeromq.api.SocketType; 4 | import org.zeromq.jzmq.ManagedContext; 5 | 6 | public class XSubSocketBuilder extends SocketBuilder { 7 | 8 | public XSubSocketBuilder(ManagedContext context) { 9 | super(context, SocketType.XSUB); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/guide/GuideHelper.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Message; 4 | import org.zeromq.api.Socket; 5 | import org.zeromq.jzmq.sockets.SocketBuilder; 6 | 7 | import java.util.Random; 8 | 9 | //todo should this be promoted to something like "DebugUtils" and moved into the main API code? 10 | public class GuideHelper { 11 | private static Random rand = new Random(System.currentTimeMillis()); 12 | 13 | /** 14 | * Receives all message parts from socket, prints neatly 15 | */ 16 | public static void dump(Socket socket) { 17 | System.out.println("----------------------------------------"); 18 | while (true) { 19 | byte[] msg = socket.receive(); 20 | print(msg); 21 | if (!socket.hasMoreToReceive()) { 22 | break; 23 | } 24 | } 25 | } 26 | 27 | private static void print(byte[] msg) { 28 | boolean isText = true; 29 | String data = ""; 30 | for (int i = 0; i < msg.length; i++) { 31 | if (msg[i] < 32 || msg[i] > 127) { 32 | isText = false; 33 | } 34 | data += String.format("%02X", msg[i]); 35 | } 36 | if (isText) { 37 | data = new String(msg); 38 | } 39 | 40 | System.out.println(String.format("[%03d] %s", msg.length, data)); 41 | } 42 | 43 | public static void dump(Message message) { 44 | System.out.println("------------------------------------------"); 45 | for (Message.Frame frame : message.getFrames()) { 46 | print(frame.getData()); 47 | } 48 | } 49 | 50 | public static SocketBuilder assignPrintableIdentity(SocketBuilder builder) { 51 | String identity = String.format("%04X-%04X", rand.nextInt(), rand.nextInt()); 52 | 53 | builder.withIdentity(identity.getBytes()); 54 | return builder; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/guide/asyncsrv.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.*; 4 | import org.zeromq.jzmq.ManagedContext; 5 | 6 | import java.util.List; 7 | import java.util.Random; 8 | 9 | public class asyncsrv { 10 | private static final Random random = new Random(System.currentTimeMillis()); 11 | 12 | 13 | private static class ClientTask implements Runnable { 14 | 15 | private final int id; 16 | 17 | private ClientTask(int id) { 18 | this.id = id; 19 | } 20 | 21 | @Override 22 | public void run() { 23 | ManagedContext context = new ManagedContext(); 24 | final String identity = "client-" + id; 25 | Socket client = context.buildSocket(SocketType.DEALER).withIdentity(identity.getBytes()).connect("tcp://localhost:5555"); 26 | 27 | Poller poller = context.buildPoller().withPollable(context.newPollable(client, PollerType.POLL_IN), new PollAdapter() { 28 | @Override 29 | public void handleIn(Socket client) { 30 | byte[] message = client.receive(); 31 | System.out.printf("Client %s received %s%n", identity, new String(message)); 32 | } 33 | }).build(); 34 | 35 | int requestNumber = 0; 36 | while (true) { 37 | // Tick one hundred times per second, pulling in arriving messages 38 | for (int i = 0; i < 100; i++) { 39 | poller.poll(10); 40 | } 41 | System.out.printf("Client %d sent Request #%d%n", id, ++requestNumber); 42 | client.send(("request " + requestNumber).getBytes()); 43 | } 44 | } 45 | } 46 | 47 | private static class ServerWorker implements Runnable { 48 | private final Context context; 49 | private final int id; 50 | 51 | private ServerWorker(Context context, int id) { 52 | this.context = context; 53 | this.id = id; 54 | } 55 | 56 | @Override 57 | public void run() { 58 | Socket worker = context.buildSocket(SocketType.DEALER).connect("inproc://backend"); 59 | System.out.println("Server worker " + id + " started"); 60 | while (true) { 61 | Message message = worker.receiveMessage(); 62 | List frames = message.getFrames(); 63 | byte[] id = frames.get(0).getData(); 64 | byte[] payload = frames.get(1).getData(); 65 | System.out.printf("Server worker %s received %s from %s%n", this.id, new String(payload), new String(id)); 66 | for (int i = 0; i < random.nextInt(5); i++) { 67 | try { 68 | Thread.sleep(1000 / (1 + random.nextInt(8))); 69 | worker.send(message); 70 | } catch (InterruptedException e) { 71 | Thread.currentThread().interrupt(); 72 | break; 73 | } 74 | } 75 | } 76 | } 77 | } 78 | 79 | private static class ServerTask implements Runnable { 80 | @Override 81 | public void run() { 82 | ManagedContext context = new ManagedContext(); 83 | final Socket frontEnd = context.buildSocket(SocketType.ROUTER).bind("tcp://*:5555"); 84 | final Socket backEnd = context.buildSocket(SocketType.DEALER).bind("inproc://backend"); 85 | 86 | for (int i = 0; i < 5; i++) { 87 | new Thread(new ServerWorker(context, i)).start(); 88 | } 89 | 90 | Poller poller = context.buildPoller() 91 | .withPollable(context.newPollable(frontEnd, PollerType.POLL_IN), new PollAdapter() { 92 | @Override 93 | public void handleIn(Socket frontEnd) { 94 | Message message = frontEnd.receiveMessage(); 95 | List frames = message.getFrames(); 96 | System.out.printf("Server received %s from id %s%n", new String(frames.get(1).getData()), new String(frames.get(0).getData())); 97 | backEnd.send(message); 98 | } 99 | }) 100 | .withPollable(context.newPollable(backEnd, PollerType.POLL_IN), new PollAdapter() { 101 | @Override 102 | public void handleIn(Socket backEnd) { 103 | Message message = backEnd.receiveMessage(); 104 | List frames = message.getFrames(); 105 | System.out.printf("Sending to frontEnd %s id %s%n", new String(frames.get(1).getData()), new String(frames.get(0).getData())); 106 | frontEnd.send(message); 107 | } 108 | }) 109 | .build(); 110 | 111 | while (true) { 112 | poller.poll(); 113 | } 114 | 115 | } 116 | } 117 | 118 | public static void main(String[] args) { 119 | for (int i = 0; i < 3; i++) { 120 | new Thread(new ClientTask(i)).start(); 121 | } 122 | new Thread(new ServerTask()).start(); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/test/java/guide/hwclient.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Socket; 4 | import org.zeromq.api.SocketType; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | public class hwclient { 8 | public static void main(String[] args) { 9 | ManagedContext context = new ManagedContext(); 10 | Socket socket = context.buildSocket(SocketType.REQ).connect("tcp://localhost:5555"); 11 | for (int i = 0; i< 10; i++) { 12 | socket.send("Hello".getBytes()); 13 | 14 | byte[] response = socket.receive(); 15 | System.out.println("response = " + new String(response)); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/guide/hwserver.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Socket; 4 | import org.zeromq.api.SocketType; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | public class hwserver { 8 | 9 | public static void main(String[] args) throws InterruptedException { 10 | ManagedContext context = new ManagedContext(); 11 | Socket serverSocket = context.buildSocket(SocketType.REP).bind("tcp://*:5555"); 12 | while (true) { 13 | byte[] message = serverSocket.receive(); 14 | System.out.println("received request: " + new String(message)); 15 | 16 | //do some "work" 17 | Thread.sleep(1000L); 18 | 19 | serverSocket.send("World!".getBytes()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/guide/identity.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Socket; 4 | import org.zeromq.api.SocketType; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | import java.io.IOException; 8 | 9 | import static guide.GuideHelper.dump; 10 | 11 | public class identity { 12 | public static void main(String[] args) throws IOException { 13 | ManagedContext context = new ManagedContext(); 14 | 15 | Socket sink = context.buildSocket(SocketType.ROUTER).bind("inproc://example"); 16 | 17 | Socket anonymous = context.buildSocket(SocketType.REQ).connect("inproc://example"); 18 | anonymous.send("ROUTER uses a generated UUID".getBytes()); 19 | dump(sink); 20 | 21 | Socket identified = context.buildSocket(SocketType.REQ).withIdentity("PEER2".getBytes()) 22 | .connect("inproc://example"); 23 | 24 | identified.send("ROUTER socket uses REQ's socket identity".getBytes()); 25 | dump(sink); 26 | 27 | context.close(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/guide/msgqueue.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Socket; 4 | import org.zeromq.api.SocketType; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | import java.io.IOException; 8 | 9 | public class msgqueue { 10 | public static void main(String[] args) throws IOException { 11 | ManagedContext context = new ManagedContext(); 12 | 13 | Socket frontEnd = context.buildSocket(SocketType.ROUTER).bind("tcp://*:5559"); 14 | Socket backEnd = context.buildSocket(SocketType.DEALER).bind("tcp://*:5560"); 15 | 16 | context.proxy(frontEnd, backEnd); 17 | context.close(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/guide/mspoller.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.PollAdapter; 4 | import org.zeromq.api.Poller; 5 | import org.zeromq.api.PollerType; 6 | import org.zeromq.api.Socket; 7 | import org.zeromq.api.SocketType; 8 | import org.zeromq.jzmq.ManagedContext; 9 | 10 | public class mspoller { 11 | public static void main(String[] args) { 12 | ManagedContext context = new ManagedContext(); 13 | 14 | //connect to the task ventilator 15 | final Socket receiver = context.buildSocket(SocketType.PULL).connect("tcp://localhost:5557"); 16 | 17 | //connect to the weather server 18 | final Socket subscriber = context.buildSocket(SocketType.SUB).asSubscribable() 19 | .subscribe("10001 ".getBytes()) 20 | .connect("tcp://localhost:5556"); 21 | 22 | Poller poller = context.buildPoller() 23 | .withPollable(context.newPollable(receiver, PollerType.POLL_IN), new PollAdapter() { 24 | @Override 25 | public void handleIn(Socket socket) { 26 | byte[] received = receiver.receive(); 27 | System.out.println(new String(received)); 28 | } 29 | }) 30 | .withPollable(context.newPollable(subscriber, PollerType.POLL_IN), new PollAdapter() { 31 | @Override 32 | public void handleIn(Socket socket) { 33 | byte[] subscribed = subscriber.receive(); 34 | System.out.println(new String(subscribed)); 35 | } 36 | }) 37 | .build(); 38 | 39 | while (true) { 40 | poller.poll(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/guide/msreader.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.MessageFlag; 4 | import org.zeromq.api.Socket; 5 | import org.zeromq.api.SocketType; 6 | import org.zeromq.jzmq.ManagedContext; 7 | 8 | public class msreader { 9 | public static void main(String[] args) throws Exception { 10 | ManagedContext context = new ManagedContext(); 11 | 12 | //connect to the task ventilator 13 | final Socket receiver = context.buildSocket(SocketType.PULL).connect("tcp://localhost:5557"); 14 | 15 | //connect to the weather server 16 | final Socket subscriber = context.buildSocket(SocketType.SUB).asSubscribable() 17 | .subscribe("10001 ".getBytes()) 18 | .connect("tcp://localhost:5556"); 19 | 20 | while (true) { 21 | byte[] task; 22 | while ((task = receiver.receive(MessageFlag.DONT_WAIT)) != null) { 23 | System.out.println("task = " + new String(task)); 24 | } 25 | 26 | byte[] update; 27 | while ((update = subscriber.receive(MessageFlag.DONT_WAIT)) != null) { 28 | System.out.println("update = " + new String(update)); 29 | } 30 | 31 | Thread.sleep(1000L); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/guide/mtrelay.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Socket; 4 | import org.zeromq.api.SocketType; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | import java.io.IOException; 8 | 9 | public class mtrelay { 10 | 11 | public static void main(String[] args) throws IOException { 12 | final ManagedContext context = new ManagedContext(); 13 | Socket receiver = context.buildSocket(SocketType.PAIR).bind("inproc://step3"); 14 | new Thread(new Runnable() { 15 | @Override 16 | public void run() { 17 | Socket receiver = context.buildSocket(SocketType.PAIR).bind("inproc://step2"); 18 | new Thread(new Runnable() { 19 | @Override 20 | public void run() { 21 | Socket sender = context.buildSocket(SocketType.PAIR).connect("inproc://step2"); 22 | sender.send("".getBytes()); 23 | } 24 | }).start(); 25 | byte[] message = receiver.receive(); 26 | Socket sender = context.buildSocket(SocketType.PAIR).connect("inproc://step3"); 27 | sender.send(message); 28 | } 29 | }).start(); 30 | receiver.receive(); 31 | System.out.println("Test successful!"); 32 | context.close(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/guide/mtserver.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Socket; 4 | import org.zeromq.api.SocketType; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | public class mtserver { 8 | 9 | public static void main(String[] args) { 10 | final ManagedContext context = new ManagedContext(); 11 | Socket clients = context.buildSocket(SocketType.ROUTER).bind("tcp://*:5555"); 12 | Socket workers = context.buildSocket(SocketType.DEALER).bind("inproc://workers"); 13 | 14 | for (int i = 0; i < 5; i++) { 15 | Runnable worker = new Worker(context); 16 | new Thread(worker).start(); 17 | } 18 | 19 | context.proxy(clients, workers); 20 | } 21 | 22 | private static class Worker implements Runnable { 23 | private final ManagedContext context; 24 | 25 | public Worker(ManagedContext context) { 26 | this.context = context; 27 | } 28 | 29 | @Override 30 | public void run() { 31 | Socket socket = context.buildSocket(SocketType.REP).connect("inproc://workers"); 32 | while (true) { 33 | byte[] request = socket.receive(); 34 | System.out.println("Received request: [" + new String(request) + "]"); 35 | 36 | //do some "work" 37 | try { 38 | Thread.sleep(1000L); 39 | } catch (InterruptedException e) { 40 | Thread.currentThread().interrupt(); 41 | break; 42 | } 43 | 44 | socket.send("World".getBytes()); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/guide/psenvpub.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.MessageFlag; 4 | import org.zeromq.api.Socket; 5 | import org.zeromq.api.SocketType; 6 | import org.zeromq.jzmq.ManagedContext; 7 | 8 | public class psenvpub { 9 | public static void main(String[] args) throws InterruptedException { 10 | ManagedContext context = new ManagedContext(); 11 | Socket publisher = context.buildSocket(SocketType.PUB).bind("tcp://*:5563"); 12 | 13 | while (true) { 14 | publisher.send("A".getBytes(), MessageFlag.SEND_MORE); 15 | publisher.send("We don't want to see this".getBytes()); 16 | 17 | publisher.send("B".getBytes(), MessageFlag.SEND_MORE); 18 | publisher.send("We would like to see this".getBytes()); 19 | Thread.sleep(1000L); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/guide/psenvsub.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Socket; 4 | import org.zeromq.api.SocketType; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | public class psenvsub { 8 | public static void main(String[] args) { 9 | ManagedContext context = new ManagedContext(); 10 | Socket subscriber = context.buildSocket(SocketType.SUB) 11 | .asSubscribable().subscribe("B".getBytes()) 12 | .connect("tcp://localhost:5563"); 13 | 14 | while (true) { 15 | String address = new String(subscriber.receive()); 16 | String contents = new String(subscriber.receive()); 17 | System.out.printf("%s : %s%n", address, contents); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/guide/rrbroker.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.*; 4 | import org.zeromq.jzmq.ManagedContext; 5 | 6 | public class rrbroker { 7 | public static void main(String[] args) { 8 | ManagedContext context = new ManagedContext(); 9 | final Socket frontEnd = context.buildSocket(SocketType.ROUTER).bind("tcp://*:5559"); 10 | final Socket backEnd = context.buildSocket(SocketType.DEALER).bind("tcp://*:5560"); 11 | while (true) { 12 | Poller poller = context.buildPoller() 13 | .withPollable(context.newPollable(frontEnd, PollerType.POLL_IN), new Forwarder(backEnd)) 14 | .withPollable(context.newPollable(backEnd, PollerType.POLL_IN), new Forwarder(frontEnd)) 15 | .build(); 16 | 17 | poller.poll(); 18 | } 19 | 20 | //can't get here 21 | //context.close(); 22 | } 23 | 24 | private static class Forwarder extends PollAdapter { 25 | private final Socket destination; 26 | 27 | public Forwarder(Socket destination) { 28 | this.destination = destination; 29 | } 30 | 31 | @Override 32 | public void handleIn(Socket source) { 33 | boolean done = false; 34 | while (!done) { 35 | byte[] bytes = source.receive(); 36 | done = !source.hasMoreToReceive(); 37 | destination.send(bytes, done ? MessageFlag.NONE : MessageFlag.SEND_MORE); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/guide/rrclient.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Socket; 4 | import org.zeromq.api.SocketType; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | import java.io.IOException; 8 | 9 | public class rrclient { 10 | 11 | public static void main(String[] args) throws IOException { 12 | ManagedContext context = new ManagedContext(); 13 | Socket socket = context.buildSocket(SocketType.REQ).connect("tcp://localhost:5559"); 14 | for (int i = 0; i< 10; i++) { 15 | socket.send("Hello".getBytes()); 16 | byte[] response = socket.receive(); 17 | System.out.printf("Received reply %d [%s]%n", i, new String(response)); 18 | } 19 | context.close(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/guide/rrworker.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Socket; 4 | import org.zeromq.api.SocketType; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | public class rrworker { 8 | public static void main(String[] args) throws InterruptedException { 9 | ManagedContext context = new ManagedContext(); 10 | Socket responder = context.buildSocket(SocketType.REP).connect("tcp://localhost:5560"); 11 | 12 | while (true) { 13 | byte[] request = responder.receive(); 14 | System.out.printf("Received request: [%s]%n", new String(request)); 15 | 16 | Thread.sleep(1000); 17 | responder.send("World".getBytes()); 18 | } 19 | 20 | //can't get here 21 | //context.close(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/guide/rtdealer.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Context; 4 | import org.zeromq.api.MessageFlag; 5 | import org.zeromq.api.Socket; 6 | import org.zeromq.api.SocketType; 7 | import org.zeromq.jzmq.ManagedContext; 8 | 9 | import java.io.IOException; 10 | import java.util.Random; 11 | 12 | public class rtdealer { 13 | public static final int NUMBER_OF_WORKERS = 10; 14 | private static Random random = new Random(System.currentTimeMillis()); 15 | 16 | public static void main(String[] args) throws IOException { 17 | ManagedContext context = new ManagedContext(); 18 | Socket broker = context.buildSocket(SocketType.ROUTER).bind("tcp://*:5671"); 19 | 20 | for (int i = 0; i < 10; i++) { 21 | new Thread(new Worker()).start(); 22 | } 23 | 24 | //run for 5 seconds, then tell the workers they are fired. 25 | long endTime = System.currentTimeMillis() + 5000L; 26 | 27 | int workersFired = 0; 28 | while (true) { 29 | byte[] identity = broker.receive(); 30 | broker.receive(); // envelope delimiter 31 | broker.receive(); // response from worker 32 | broker.send(identity, MessageFlag.SEND_MORE); 33 | broker.send(new byte[0], MessageFlag.SEND_MORE); 34 | if (endTime > System.currentTimeMillis()) { 35 | broker.send("Work harder".getBytes()); 36 | } else { 37 | broker.send("Fired!".getBytes()); 38 | if (++workersFired == NUMBER_OF_WORKERS) { 39 | break; 40 | } 41 | } 42 | } 43 | 44 | context.close(); 45 | } 46 | 47 | private static class Worker implements Runnable { 48 | @Override 49 | public void run() { 50 | Context context = new ManagedContext(); 51 | Socket worker = GuideHelper.assignPrintableIdentity(context.buildSocket(SocketType.DEALER)) 52 | .connect("tcp://localhost:5671"); 53 | int total = 0; 54 | while (true) { 55 | worker.send(new byte[0], MessageFlag.SEND_MORE); 56 | worker.send("Hi Boss".getBytes()); 57 | 58 | worker.receive(); // envelope delimiter 59 | byte[] workload = worker.receive(); 60 | // System.out.printf("[%s] Got '%s' from the boss.%n", Thread.currentThread().getName(), new String(workload)); 61 | if ("Fired!".equals(new String(workload))) { 62 | break; 63 | } 64 | total++; 65 | 66 | //do some random work 67 | try { 68 | Thread.sleep(random.nextInt(500)); 69 | } catch (InterruptedException e) { 70 | Thread.currentThread().interrupt(); 71 | break; 72 | } 73 | } 74 | System.out.printf("[%s] Completed %d tasks%n", Thread.currentThread().getName(), total); 75 | context.close(); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/test/java/guide/rtreq.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Context; 4 | import org.zeromq.api.MessageFlag; 5 | import org.zeromq.api.Socket; 6 | import org.zeromq.api.SocketType; 7 | import org.zeromq.jzmq.ManagedContext; 8 | 9 | import java.io.IOException; 10 | import java.util.Random; 11 | 12 | public class rtreq { 13 | public static final int NUMBER_OF_WORKERS = 10; 14 | private static Random random = new Random(System.currentTimeMillis()); 15 | 16 | public static void main(String[] args) throws IOException { 17 | ManagedContext context = new ManagedContext(); 18 | Socket broker = context.buildSocket(SocketType.ROUTER).bind("tcp://*:5671"); 19 | 20 | for (int i = 0; i < 10; i++) { 21 | new Thread(new Worker()).start(); 22 | } 23 | 24 | //run for 5 seconds, then tell the workers they are fired. 25 | long endTime = System.currentTimeMillis() + 5000L; 26 | 27 | int workersFired = 0; 28 | while (true) { 29 | byte[] identity = broker.receive(); 30 | broker.receive(); // envelope delimiter 31 | broker.receive(); // response from worker 32 | broker.send(identity, MessageFlag.SEND_MORE); 33 | broker.send(new byte[0], MessageFlag.SEND_MORE); 34 | if (endTime > System.currentTimeMillis()) { 35 | broker.send("Work harder".getBytes()); 36 | } 37 | else { 38 | broker.send("Fired!".getBytes()); 39 | if (++workersFired == NUMBER_OF_WORKERS) { 40 | break; 41 | } 42 | } 43 | } 44 | 45 | context.close(); 46 | } 47 | 48 | private static class Worker implements Runnable { 49 | @Override 50 | public void run() { 51 | Context context = new ManagedContext(); 52 | Socket worker = GuideHelper.assignPrintableIdentity(context.buildSocket(SocketType.REQ)) 53 | .connect("tcp://localhost:5671"); 54 | int total = 0; 55 | while (true) { 56 | worker.send("Hi Boss".getBytes()); 57 | byte[] workload = worker.receive(); 58 | // System.out.printf("[%s] Got '%s' from the boss.%n", Thread.currentThread().getName(), new String(workload)); 59 | if ("Fired!".equals(new String(workload))) { 60 | break; 61 | } 62 | total++; 63 | 64 | //do some random work 65 | try { 66 | Thread.sleep(random.nextInt(500)); 67 | } catch (InterruptedException e) { 68 | Thread.currentThread().interrupt(); 69 | break; 70 | } 71 | } 72 | System.out.printf("[%s] Completed %d tasks%n", Thread.currentThread().getName(), total); 73 | context.close(); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/test/java/guide/syncpub.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Socket; 4 | import org.zeromq.api.SocketType; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | public class syncpub { 8 | 9 | private static int NUMBER_OF_SUBSCRIBERS = 5; 10 | 11 | public static void main(String[] args) throws Exception { 12 | ManagedContext context = new ManagedContext(); 13 | 14 | Socket publisher = context.buildSocket(SocketType.PUB).withLinger(5000L).bind("tcp://*:5561"); 15 | Socket syncSocket = context.buildSocket(SocketType.REP).bind("tcp://*:5562"); 16 | 17 | for (int i = 0; i < NUMBER_OF_SUBSCRIBERS; i++) { 18 | syncSocket.receive(); 19 | //send the "start" message 20 | syncSocket.send(new byte[0]); 21 | } 22 | 23 | for (int i = 0; i < 1000000; i++) { 24 | publisher.send("Rhubarb".getBytes()); 25 | } 26 | 27 | publisher.send("END".getBytes()); 28 | 29 | //let the "END" message propagate. 30 | Thread.sleep(1000); 31 | 32 | context.close(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/guide/syncsub.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Socket; 4 | import org.zeromq.api.SocketType; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | public class syncsub { 8 | 9 | public static void main(String[] args) throws Exception { 10 | ManagedContext context = new ManagedContext(); 11 | Socket subscriber = context.buildSocket(SocketType.SUB).asSubscribable() 12 | .subscribe(new byte[0]) 13 | .connect("tcp://localhost:5561"); 14 | 15 | Thread.sleep(1000L); 16 | Socket syncClient = context.buildSocket(SocketType.REQ).connect("tcp://localhost:5562"); 17 | 18 | //send the "ready" 19 | syncClient.send(new byte[0]); 20 | //wait for the "go" message 21 | syncClient.receive(); 22 | 23 | int numberOfUpdates = 0; 24 | while (true) { 25 | byte[] bytes = subscriber.receive(); 26 | numberOfUpdates++; 27 | if ("END".equals(new String(bytes))) { 28 | break; 29 | } 30 | } 31 | System.out.printf("Received %d updates%n", numberOfUpdates); 32 | context.close(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/guide/tasksink.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Socket; 4 | import org.zeromq.api.SocketType; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | import java.io.IOException; 8 | 9 | public class tasksink { 10 | public static void main(String[] args) throws IOException { 11 | ManagedContext context = new ManagedContext(); 12 | Socket sink = context.buildSocket(SocketType.PULL).bind("tcp://*:5558"); 13 | 14 | //wait for the start of a batch... 15 | sink.receive(); 16 | 17 | long startTime = System.currentTimeMillis(); 18 | 19 | for (int i = 0; i < 100; i++) { 20 | String result = new String(sink.receive()); 21 | if (i % 10 == 0) { 22 | System.out.print(":"); 23 | } else { 24 | System.out.print("."); 25 | } 26 | 27 | } 28 | long endTime = System.currentTimeMillis(); 29 | 30 | System.out.println("\ntotal time: " + (endTime - startTime) + " ms"); 31 | 32 | context.close(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/guide/tasksink2.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Socket; 4 | import org.zeromq.api.SocketType; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | import java.io.IOException; 8 | 9 | public class tasksink2 { 10 | public static void main(String[] args) throws IOException, InterruptedException { 11 | ManagedContext context = new ManagedContext(); 12 | Socket receiver = context.buildSocket(SocketType.PULL).bind("tcp://*:5558"); 13 | Socket controller = context.buildSocket(SocketType.PUB).bind("tcp://*:5559"); 14 | 15 | //wait for the batch to start 16 | receiver.receive(); 17 | 18 | long startTime = System.currentTimeMillis(); 19 | 20 | for (int i = 0; i < 100; i++) { 21 | String result = new String(receiver.receive()); 22 | if (i % 10 == 0) { 23 | System.out.print(":"); 24 | } else { 25 | System.out.print("."); 26 | } 27 | 28 | } 29 | long endTime = System.currentTimeMillis(); 30 | 31 | System.out.println("\ntotal time: " + (endTime - startTime) + " ms"); 32 | 33 | controller.send("KILL".getBytes()); 34 | Thread.sleep(1000); // give zeromq a chance to send the last message. 35 | context.close(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/guide/taskvent.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Socket; 4 | import org.zeromq.api.SocketType; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | import java.util.Random; 8 | 9 | public class taskvent { 10 | 11 | public static void main(String[] args) throws Exception { 12 | ManagedContext context = new ManagedContext(); 13 | Socket sender = context.buildSocket(SocketType.PUSH).bind("tcp://*:5557"); 14 | Socket sink = context.buildSocket(SocketType.PUSH).connect("tcp://localhost:5558"); 15 | 16 | System.out.println("Press Enter when the workers are ready..."); 17 | System.in.read(); 18 | System.out.println("Sending tasks to workers..."); 19 | 20 | //The first message signals the start of the batch. 21 | sink.send("0".getBytes()); 22 | 23 | Random random = new Random(System.currentTimeMillis()); 24 | 25 | int totalCost = 0; 26 | for (int i = 0; i < 100; i++) { 27 | int workload = random.nextInt(100) + 1; 28 | totalCost += workload; 29 | System.out.print(workload + "."); 30 | sender.send(String.format("%d", workload).getBytes()); 31 | } 32 | 33 | System.out.println("total expected cost = " + totalCost); 34 | Thread.sleep(1000L); // give 0mq time to deliver the messages. 35 | context.close(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/guide/taskwork.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Socket; 4 | import org.zeromq.api.SocketType; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | public class taskwork { 8 | 9 | public static void main(String[] args) throws InterruptedException { 10 | ManagedContext context = new ManagedContext(); 11 | Socket receiver = context.buildSocket(SocketType.PULL).connect("tcp://localhost:5557"); 12 | Socket sink = context.buildSocket(SocketType.PUSH).connect("tcp://localhost:5558"); 13 | 14 | while(true) { 15 | String workString = new String(receiver.receive()); 16 | long workLoad = Long.parseLong(workString); 17 | System.out.print(workLoad + "."); 18 | 19 | //do the work 20 | Thread.sleep(workLoad); 21 | 22 | sink.send("".getBytes()); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/guide/taskwork2.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.PollAdapter; 4 | import org.zeromq.api.Poller; 5 | import org.zeromq.api.PollerType; 6 | import org.zeromq.api.Socket; 7 | import org.zeromq.api.SocketType; 8 | import org.zeromq.jzmq.ManagedContext; 9 | 10 | import java.util.concurrent.atomic.AtomicBoolean; 11 | 12 | public class taskwork2 { 13 | public static void main(String[] args) { 14 | ManagedContext context = new ManagedContext(); 15 | Socket receiver = context.buildSocket(SocketType.PULL).connect("tcp://localhost:5557"); 16 | final Socket sender = context.buildSocket(SocketType.PUSH).connect("tcp://localhost:5558"); 17 | Socket controller = context.buildSocket(SocketType.SUB) 18 | .asSubscribable().subscribe(new byte[0]) 19 | .connect("tcp://localhost:5559"); 20 | 21 | final AtomicBoolean shouldStop = new AtomicBoolean(false); 22 | Poller poller = context.buildPoller() 23 | .withPollable(context.newPollable(receiver, PollerType.POLL_IN), new Worker(sender)) 24 | .withPollable(context.newPollable(controller, PollerType.POLL_IN), new Stopper(shouldStop)) 25 | .build(); 26 | 27 | while (!shouldStop.get()) { 28 | poller.poll(); 29 | } 30 | } 31 | 32 | private static class Worker extends PollAdapter { 33 | private final Socket sender; 34 | 35 | public Worker(Socket sender) { 36 | this.sender = sender; 37 | } 38 | 39 | @Override 40 | public void handleIn(Socket socket) { 41 | byte[] work = socket.receive(); 42 | try { 43 | Thread.sleep(Long.valueOf(new String(work))); 44 | } catch (InterruptedException e) { 45 | Thread.currentThread().interrupt(); 46 | } 47 | sender.send("".getBytes()); 48 | System.out.print("."); 49 | } 50 | } 51 | 52 | private static class Stopper extends PollAdapter { 53 | private final AtomicBoolean shouldStop; 54 | 55 | public Stopper(AtomicBoolean shouldStop) { 56 | this.shouldStop = shouldStop; 57 | } 58 | 59 | @Override 60 | public void handleIn(Socket socket) { 61 | socket.receive(); 62 | shouldStop.set(true); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/guide/version.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.jzmq.ManagedContext; 4 | 5 | public class version { 6 | 7 | public static void main(String[] args) { 8 | ManagedContext context = new ManagedContext(); 9 | System.out.println("context.getVersionString() = " + context.getVersionString()); 10 | System.out.println("context.getFullVersion() = " + context.getFullVersion()); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/guide/wuclient.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Socket; 4 | import org.zeromq.api.SocketType; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | public class wuclient { 8 | 9 | public static void main(String[] args) { 10 | String filter = args.length == 0 ? "10001 " : args[0]; 11 | 12 | ManagedContext context = new ManagedContext(); 13 | Socket socket = context.buildSocket(SocketType.SUB).asSubscribable() 14 | .subscribe(filter.getBytes()) 15 | .connect("ipc://weather"); 16 | 17 | long totalTemperature = 0L; 18 | int temperatureReadings = 100; 19 | for (int i = 0; i < temperatureReadings; i++) { 20 | byte[] bytes = socket.receive(); 21 | String weatherUpdate = new String(bytes); 22 | System.out.println("weatherUpdate = " + weatherUpdate); 23 | String[] pieces = weatherUpdate.split(" "); 24 | int zipCode = Integer.valueOf(pieces[0]); 25 | int temperature = Integer.valueOf(pieces[1]); 26 | int relativeHumidity = Integer.valueOf(pieces[2]); 27 | totalTemperature += temperature; 28 | } 29 | 30 | long averageTemperature = totalTemperature / temperatureReadings; 31 | System.out.println("average temperature = " + averageTemperature); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/guide/wuproxy.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.MessageFlag; 4 | import org.zeromq.api.Socket; 5 | import org.zeromq.api.SocketType; 6 | import org.zeromq.jzmq.ManagedContext; 7 | 8 | public class wuproxy { 9 | 10 | public static void main(String[] args) throws Exception { 11 | ManagedContext context = new ManagedContext(); 12 | 13 | //this is where the weather server sits 14 | Socket frontEnd = context.buildSocket(SocketType.SUB) 15 | .asSubscribable().subscribe("".getBytes()) 16 | .connect("tcp://192.168.55.210:5556"); 17 | 18 | //this is our public endpoint for subscribers 19 | Socket backend = context.buildSocket(SocketType.PUB).bind("tcp://10.1.1.0:8100"); 20 | 21 | while (!Thread.currentThread().isInterrupted()) { 22 | boolean moreToReceive; 23 | do { 24 | byte[] message = frontEnd.receive(); 25 | moreToReceive = frontEnd.hasMoreToReceive(); 26 | backend.send(message, moreToReceive ? MessageFlag.SEND_MORE : MessageFlag.NONE); 27 | } while (moreToReceive); 28 | } 29 | 30 | context.close(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/guide/wuserver.java: -------------------------------------------------------------------------------- 1 | package guide; 2 | 3 | import org.zeromq.api.Socket; 4 | import org.zeromq.api.SocketType; 5 | import org.zeromq.jzmq.ManagedContext; 6 | 7 | import java.util.Random; 8 | 9 | public class wuserver { 10 | public static void main(String[] args) { 11 | ManagedContext context = new ManagedContext(); 12 | 13 | Socket socket = context.buildSocket(SocketType.PUB).bind("tcp://*:5556", "ipc://weather"); 14 | 15 | Random random = new Random(System.currentTimeMillis()); 16 | while (true) { 17 | int zipCode = random.nextInt(100000) + 1; 18 | int temperature = random.nextInt(215) - 80 + 1; 19 | int relativeHumidity = random.nextInt(50) + 10 + 1; 20 | String update = String.format("%05d %d %d", zipCode, temperature, relativeHumidity); 21 | socket.send(update.getBytes()); 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/BeaconReactorTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.After; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.zeromq.jzmq.ManagedContext; 9 | import org.zeromq.jzmq.beacon.BeaconReactorImpl; 10 | 11 | import java.io.IOException; 12 | import java.net.InetAddress; 13 | import java.util.UUID; 14 | import java.util.concurrent.atomic.AtomicInteger; 15 | 16 | public class BeaconReactorTest { 17 | private ManagedContext context; 18 | private BeaconReactor reactor1; 19 | private BeaconReactor reactor2; 20 | private BeaconReactor reactor3; 21 | 22 | private AtomicInteger beacon1 = new AtomicInteger(); 23 | private AtomicInteger beacon2 = new AtomicInteger(); 24 | private AtomicInteger beacon3 = new AtomicInteger(); 25 | 26 | @Before 27 | public void setUp() throws Exception { 28 | context = new ManagedContext(); 29 | startBeaconReactor1(); 30 | startBeaconReactor2(); 31 | } 32 | 33 | @After 34 | public void tearDown() throws Exception { 35 | reactor1.stop(); 36 | reactor2.stop(); 37 | if (reactor3 != null) { 38 | reactor3.stop(); 39 | } 40 | context.close(); 41 | } 42 | 43 | private void startBeaconReactor1() throws IOException { 44 | reactor2 = context.buildBeaconReactor() 45 | .withPort(1234) 46 | .withIgnoreLocalAddress(false) 47 | .withBroadcastInterval(250) 48 | .withBeacon(new UdpBeacon(1, "TEST", UUID.randomUUID(), 1234)) 49 | .withListener(new BeaconListener() { 50 | @Override 51 | public void onBeacon(InetAddress sender, UdpBeacon beacon) { 52 | beacon1.incrementAndGet(); 53 | } 54 | }) 55 | .start(); 56 | } 57 | 58 | private void startBeaconReactor2() throws IOException { 59 | reactor1 = context.buildBeaconReactor() 60 | .withPort(1234) 61 | .withIgnoreLocalAddress(false) 62 | .withBroadcastInterval(250) 63 | .withBeacon(new UdpBeacon(1, "TEST", UUID.randomUUID(), 1234)) 64 | .withListener(new BeaconListener() { 65 | @Override 66 | public void onBeacon(InetAddress sender, UdpBeacon beacon) { 67 | beacon2.incrementAndGet(); 68 | } 69 | }) 70 | .start(); 71 | } 72 | 73 | private void startBeaconReactor3() throws IOException { 74 | reactor3 = context.buildBeaconReactor() 75 | .withPort(1234) 76 | .withIgnoreLocalAddress(true) 77 | .withBroadcastInterval(250) 78 | .withBeacon(new UdpBeacon(2, "X", UUID.randomUUID(), 1234)) 79 | .withListener(new BeaconListener() { 80 | @Override 81 | public void onBeacon(InetAddress sender, UdpBeacon beacon) { 82 | beacon3.incrementAndGet(); 83 | } 84 | }) 85 | .start(); 86 | } 87 | 88 | @Test 89 | public void testBeaconReactor() throws Exception { 90 | Thread.sleep(550); 91 | 92 | assertEquals(4, beacon1.get()); 93 | assertEquals(4, beacon2.get()); 94 | } 95 | 96 | @Test 97 | public void testBeaconReactor_InvalidBeacon() throws Exception { 98 | startBeaconReactor3(); 99 | Thread.sleep(550); 100 | 101 | assertEquals(4, beacon1.get()); 102 | assertEquals(4, beacon2.get()); 103 | assertEquals(0, beacon3.get()); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/CloneServerTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.After; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.zeromq.jzmq.ManagedContext; 9 | 10 | public class CloneServerTest { 11 | private Context context; 12 | private CloneServer primary; 13 | private CloneServer backup; 14 | private CloneClient client1; 15 | private CloneClient client2; 16 | 17 | @Before 18 | public void setUp() throws Exception { 19 | context = new ManagedContext(); 20 | 21 | primary = context.buildCloneServer() 22 | .withHeartbeatInterval(200) 23 | .withMode(BinaryStarReactor.Mode.PRIMARY) 24 | .withPrimaryAddress("localhost") 25 | .withBackupAddress("localhost") 26 | .withPrimaryPort(5556) 27 | .withBackupPort(5566) 28 | .withPrimaryBinaryStarPort(5003) 29 | .withBackupBinaryStarPort(5004) 30 | .build(); 31 | 32 | backup = context.buildCloneServer() 33 | .withHeartbeatInterval(200) 34 | .withMode(BinaryStarReactor.Mode.BACKUP) 35 | .withPrimaryAddress("localhost") 36 | .withBackupAddress("localhost") 37 | .withPrimaryPort(5556) 38 | .withBackupPort(5566) 39 | .withPrimaryBinaryStarPort(5003) 40 | .withBackupBinaryStarPort(5004) 41 | .build(); 42 | 43 | primary.start(); 44 | Thread.sleep(250); 45 | backup.start(); 46 | Thread.sleep(1000); 47 | 48 | client1 = context.buildCloneClient() 49 | .withHeartbeatInterval(200) 50 | .withPrimaryAddress("localhost") 51 | .withBackupAddress("localhost") 52 | .withPrimaryPort(5556) 53 | .withBackupPort(5566) 54 | .withSubtree("/client/") 55 | .build(); 56 | 57 | client2 = context.buildCloneClient() 58 | .withHeartbeatInterval(200) 59 | .withPrimaryAddress("localhost") 60 | .withBackupAddress("localhost") 61 | .withPrimaryPort(5556) 62 | .withBackupPort(5566) 63 | .withSubtree("/client/") 64 | .build(); 65 | 66 | Thread.sleep(250); 67 | } 68 | 69 | @After 70 | public void tearDown() throws Exception { 71 | backup.stop(); 72 | primary.stop(); 73 | context.terminate(); 74 | context.close(); 75 | } 76 | 77 | @Test 78 | public void testSet() throws Exception { 79 | client1.set("/client/key", "value1", 60); 80 | assertEquals("value1", waitAndGet(client1, "value1")); 81 | assertEquals("value1", waitAndGet(client2, "value1")); 82 | 83 | client2.set("/client/key", "value2", 60); 84 | assertEquals("value2", waitAndGet(client2, "value2")); 85 | assertEquals("value2", waitAndGet(client1, "value2")); 86 | 87 | System.out.println("Finished"); 88 | } 89 | 90 | private static String waitAndGet(CloneClient client, String expected) throws InterruptedException { 91 | while (true) { 92 | String value = client.get("/client/key"); 93 | if (value == null || !value.equals(expected)) { 94 | Thread.sleep(25); 95 | } else { 96 | return value; 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/DealerRepTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import junit.framework.TestCase; 4 | import org.junit.After; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.zeromq.ContextFactory; 8 | 9 | import static org.junit.Assert.assertArrayEquals; 10 | 11 | public class DealerRepTest extends TestCase { 12 | private Context context; 13 | 14 | @Before 15 | @Override 16 | public void setUp() { 17 | context = ContextFactory.createContext(1); 18 | } 19 | 20 | @After 21 | @Override 22 | public void tearDown() throws Exception { 23 | context.close(); 24 | } 25 | 26 | @Test(timeout = 1000) 27 | public void testDealerRep() throws Exception { 28 | Socket dealerSocket = context.buildSocket(SocketType.DEALER).bind("inproc://serverSocket"); 29 | Socket replySocket = context.buildSocket(SocketType.REP).connect("inproc://serverSocket"); 30 | 31 | dealerSocket.send("returnAddress".getBytes(), MessageFlag.SEND_MORE); 32 | dealerSocket.send("".getBytes(), MessageFlag.SEND_MORE); 33 | dealerSocket.send("request".getBytes()); 34 | 35 | byte[] request = replySocket.receive(); 36 | assertArrayEquals("request".getBytes(), request); 37 | replySocket.send("response".getBytes()); 38 | 39 | assertArrayEquals("returnAddress".getBytes(), dealerSocket.receive()); 40 | assertArrayEquals("".getBytes(), dealerSocket.receive()); 41 | assertArrayEquals("response".getBytes(), dealerSocket.receive()); 42 | } 43 | 44 | @Test 45 | public void testBrokenStuff() throws Exception { 46 | Socket testServer = context.buildSocket(SocketType.REP).bind("inproc://borken"); 47 | Socket testSocket = context.buildSocket(SocketType.REQ).connect("inproc://borken"); 48 | testSocket.send("".getBytes(), MessageFlag.SEND_MORE); 49 | testSocket.send("hello, there".getBytes()); 50 | byte[] received = testServer.receive(); 51 | assertEquals(0, received.length); 52 | testServer.receive(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/DeviceBuilderTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.After; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.zeromq.jzmq.ManagedContext; 9 | 10 | import java.util.HashSet; 11 | import java.util.Set; 12 | 13 | public class DeviceBuilderTest { 14 | private ManagedContext context; 15 | 16 | @Before 17 | public void setUp() { 18 | context = new ManagedContext(); 19 | } 20 | 21 | @After 22 | public void tearDown() throws Exception { 23 | context.terminate(); 24 | context.close(); 25 | } 26 | 27 | @Test 28 | public void testStreamer() throws Exception { 29 | context.buildDevice(DeviceType.STREAMER) 30 | .withFrontendUrl("inproc://streamer-frontend") 31 | .withBackendUrl("inproc://streamer-backend") 32 | .start(); 33 | 34 | Socket frontend1 = context.buildSocket(SocketType.PUSH) 35 | .connect("inproc://streamer-frontend"); 36 | Socket frontend2 = context.buildSocket(SocketType.PUSH) 37 | .connect("inproc://streamer-frontend"); 38 | Socket backend1 = context.buildSocket(SocketType.PULL) 39 | .connect("inproc://streamer-backend"); 40 | Socket backend2 = context.buildSocket(SocketType.PULL) 41 | .connect("inproc://streamer-backend"); 42 | 43 | frontend1.send(new Message(1)); 44 | frontend2.send(new Message(2)); 45 | frontend2.send(new Message(3)); 46 | frontend1.send(new Message(4)); 47 | 48 | Set messages = new HashSet<>(); 49 | messages.add(backend1.receiveMessage().popInt()); 50 | messages.add(backend1.receiveMessage().popInt()); 51 | messages.add(backend2.receiveMessage().popInt()); 52 | messages.add(backend2.receiveMessage().popInt()); 53 | assertEquals(4, messages.size()); 54 | } 55 | 56 | @Test 57 | public void testForwarder() throws Exception { 58 | context.buildDevice(DeviceType.FORWARDER) 59 | .withFrontendUrl("inproc://forwarder-frontend") 60 | .withBackendUrl("inproc://forwarder-backend") 61 | .start(); 62 | 63 | Socket frontend1 = context.buildSocket(SocketType.PUB) 64 | .connect("inproc://forwarder-frontend"); 65 | Socket frontend2 = context.buildSocket(SocketType.PUB) 66 | .connect("inproc://forwarder-frontend"); 67 | 68 | Socket backend1 = context.buildSocket(SocketType.SUB) 69 | .asSubscribable().subscribeAll() 70 | .connect("inproc://forwarder-backend"); 71 | Socket backend2 = context.buildSocket(SocketType.SUB) 72 | .asSubscribable().subscribeAll() 73 | .connect("inproc://forwarder-backend"); 74 | 75 | // Give slow joiner some time 76 | Thread.sleep(25); 77 | 78 | frontend1.send(new Message(1)); 79 | frontend2.send(new Message(2)); 80 | frontend2.send(new Message(3)); 81 | frontend2.send(new Message(4)); 82 | 83 | assertEquals(1, backend1.receiveMessage().popInt()); 84 | assertEquals(1, backend2.receiveMessage().popInt()); 85 | assertEquals(2, backend1.receiveMessage().popInt()); 86 | assertEquals(2, backend2.receiveMessage().popInt()); 87 | assertEquals(3, backend1.receiveMessage().popInt()); 88 | assertEquals(3, backend2.receiveMessage().popInt()); 89 | assertEquals(4, backend1.receiveMessage().popInt()); 90 | assertEquals(4, backend2.receiveMessage().popInt()); 91 | } 92 | 93 | @Test 94 | public void testQueue() throws Exception { 95 | context.buildDevice(DeviceType.QUEUE) 96 | .withFrontendUrl("inproc://queue-frontend") 97 | .withBackendUrl("inproc://queue-backend") 98 | .start(); 99 | 100 | Socket frontend1 = context.buildSocket(SocketType.REQ) 101 | .connect("inproc://queue-frontend"); 102 | Socket frontend2 = context.buildSocket(SocketType.REQ) 103 | .connect("inproc://queue-frontend"); 104 | 105 | Socket backend1 = context.buildSocket(SocketType.REP) 106 | .connect("inproc://queue-backend"); 107 | Socket backend2 = context.buildSocket(SocketType.REP) 108 | .connect("inproc://queue-backend"); 109 | 110 | Set messages = new HashSet<>(); 111 | frontend1.send(new Message(1)); 112 | frontend2.send(new Message(2)); 113 | 114 | messages.add(backend1.receiveMessage().popInt()); 115 | messages.add(backend2.receiveMessage().popInt()); 116 | 117 | backend1.send(new Message(3)); 118 | backend2.send(new Message(4)); 119 | messages.add(frontend1.receiveMessage().popInt()); 120 | messages.add(frontend2.receiveMessage().popInt()); 121 | assertEquals(4, messages.size()); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/ForkTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import static junit.framework.Assert.assertEquals; 4 | import static org.junit.Assert.assertTrue; 5 | 6 | import java.util.concurrent.atomic.AtomicBoolean; 7 | 8 | import org.junit.After; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | import org.zeromq.ContextFactory; 12 | 13 | public class ForkTest { 14 | private Context context; 15 | 16 | @Before 17 | public void setUp() { 18 | context = ContextFactory.createContext(1); 19 | } 20 | 21 | @After 22 | public void tearDown() { 23 | } 24 | 25 | @Test 26 | public void testFork() throws Exception { 27 | Socket pipe = context.fork(new Backgroundable() { 28 | @Override 29 | public void run(Context context, Socket pipe) { 30 | pipe.send("hello".getBytes()); 31 | assertEquals("hi", new String(pipe.receive())); 32 | } 33 | 34 | @Override 35 | public void onClose() { 36 | // TODO Auto-generated method stub 37 | 38 | } 39 | }); 40 | 41 | assertEquals("hello", new String(pipe.receive())); 42 | pipe.send("hi".getBytes()); 43 | 44 | context.close(); 45 | } 46 | 47 | @Test 48 | public void testBackgroundable() throws Exception { 49 | final AtomicBoolean closed = new AtomicBoolean(false); 50 | Socket req = context.buildSocket(SocketType.REQ) 51 | .bind("inproc://background-test"); 52 | 53 | // background thread will handle this socket 54 | context.buildSocket(SocketType.REP) 55 | .withBackgroundable(new Backgroundable() { 56 | @Override 57 | public void run(Context context, Socket socket) { 58 | assertEquals("hello", new String(socket.receive())); 59 | socket.send("hello, world".getBytes()); 60 | } 61 | 62 | @Override 63 | public void onClose() { 64 | closed.set(true); 65 | } 66 | }) 67 | .connect("inproc://background-test"); 68 | 69 | req.send("hello".getBytes()); 70 | assertEquals("hello, world", new String(req.receive())); 71 | 72 | context.close(); 73 | assertTrue(closed.get()); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/PollerTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.zeromq.jzmq.ManagedContext; 7 | 8 | import java.util.concurrent.atomic.AtomicBoolean; 9 | 10 | import static junit.framework.Assert.assertTrue; 11 | import static org.junit.Assert.assertArrayEquals; 12 | 13 | public class PollerTest { 14 | private Context context; 15 | 16 | @Before 17 | public void setUp() { 18 | context = new ManagedContext(); 19 | } 20 | 21 | @After 22 | public void tearDown() throws Exception { 23 | context.close(); 24 | } 25 | 26 | @Test(timeout = 1000) 27 | public void testPollIn() throws Exception { 28 | Socket server = context.buildSocket(SocketType.REP).bind("inproc://repSocket"); 29 | final AtomicBoolean requestReceived = new AtomicBoolean(false); 30 | Poller testClass = context.buildPoller() 31 | .withPollable(context.newPollable(server, PollerType.POLL_IN), new PollAdapter() { 32 | @Override 33 | public void handleIn(Socket socket) { 34 | byte[] request = socket.receive(); 35 | assertArrayEquals("hello".getBytes(), request); 36 | requestReceived.set(true); 37 | } 38 | }) 39 | .build(); 40 | 41 | Socket request = context.buildSocket(SocketType.REQ).connect("inproc://repSocket"); 42 | request.send("hello".getBytes()); 43 | 44 | testClass.poll(100L); 45 | assertTrue(requestReceived.get()); 46 | } 47 | 48 | @Test(timeout = 1000) 49 | public void testPollOut() throws Exception { 50 | Socket server = context.buildSocket(SocketType.REP).bind("inproc://repSocket"); 51 | 52 | Socket requester = context.buildSocket(SocketType.REQ).connect("inproc://repSocket"); 53 | Poller testClass = context.buildPoller() 54 | .withPollable(context.newPollable(requester, PollerType.POLL_OUT), new PollAdapter() { 55 | @Override 56 | public void handleOut(Socket socket) { 57 | socket.send("hello".getBytes()); 58 | } 59 | }) 60 | .build(); 61 | 62 | 63 | testClass.poll(100L); 64 | 65 | byte[] message = server.receive(); 66 | assertArrayEquals("hello".getBytes(), message); 67 | } 68 | 69 | //todo write a test for the error polling...how do we reliably generate an error on a socket? 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/ProxyTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.zeromq.jzmq.ManagedContext; 7 | 8 | import static org.junit.Assert.assertArrayEquals; 9 | 10 | public class ProxyTest { 11 | private Context context; 12 | 13 | @Before 14 | public void setUp() { 15 | context = new ManagedContext(); 16 | } 17 | 18 | @After 19 | public void tearDown() throws Exception { 20 | context.terminate(); 21 | context.close(); 22 | } 23 | 24 | @Test 25 | public void testProxy() throws Exception { 26 | //have to do this in a separate thread, since the proxy method blocks until the context is closed. 27 | Thread thread = new Thread(new Runnable() { 28 | @Override 29 | public void run() { 30 | Socket requesterEndpoint = context.buildSocket(SocketType.ROUTER).bind("inproc://requests"); 31 | Socket workerEndpoint = context.buildSocket(SocketType.DEALER).bind("inproc://work"); 32 | context.proxy(workerEndpoint, requesterEndpoint); 33 | } 34 | }); 35 | thread.start(); 36 | //give it a bit of time to start up. 37 | Thread.sleep(100L); 38 | 39 | Socket client = this.context.buildSocket(SocketType.REQ).connect("inproc://requests"); 40 | Socket worker = this.context.buildSocket(SocketType.REP).connect("inproc://work"); 41 | client.send("hello".getBytes()); 42 | byte[] response = worker.receive(); 43 | assertArrayEquals("hello".getBytes(), response); 44 | 45 | worker.send("goodbye".getBytes()); 46 | byte[] response2 = client.receive(); 47 | assertArrayEquals("goodbye".getBytes(), response2); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/PubSubTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.zeromq.jzmq.ManagedContext; 7 | 8 | import static junit.framework.Assert.assertEquals; 9 | 10 | public class PubSubTest { 11 | private ManagedContext context; 12 | 13 | @Before 14 | public void setUp() { 15 | context = new ManagedContext(); 16 | } 17 | 18 | @After 19 | public void tearDown() throws Exception { 20 | context.close(); 21 | } 22 | 23 | @Test(timeout = 1000) 24 | public void testPubSub() throws Exception { 25 | Socket publisher = context.buildSocket(SocketType.PUB).bind("inproc://publisher"); 26 | Socket subscriber = context.buildSocket(SocketType.SUB).asSubscribable().subscribe("H".getBytes()).connect("inproc://publisher"); 27 | publisher.send("Hello".getBytes()); 28 | byte[] contents = subscriber.receive(); 29 | assertEquals("Hello", new String(contents)); 30 | } 31 | 32 | @Test(timeout = 1000) 33 | public void testMultipleSubscribers() throws Exception { 34 | Socket publisher = context.buildSocket(SocketType.PUB).bind("inproc://publisher"); 35 | Socket subscriber1 = context.buildSocket(SocketType.SUB).asSubscribable().subscribe("H".getBytes()).connect("inproc://publisher"); 36 | Socket subscriber2 = context.buildSocket(SocketType.SUB).asSubscribable().subscribe("H".getBytes()).connect("inproc://publisher"); 37 | publisher.send("Hello".getBytes()); 38 | assertEquals("Hello", new String(subscriber1.receive())); 39 | assertEquals("Hello", new String(subscriber2.receive())); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/PushPullTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import junit.framework.TestCase; 4 | import org.junit.After; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.zeromq.ContextFactory; 8 | 9 | public class PushPullTest extends TestCase { 10 | private Context context; 11 | 12 | @Before 13 | @Override 14 | public void setUp() { 15 | context = ContextFactory.createContext(1); 16 | } 17 | 18 | @After 19 | @Override 20 | public void tearDown() throws Exception { 21 | context.close(); 22 | } 23 | 24 | @Test 25 | public void testSimplePushPull() throws Exception { 26 | String expected = "PING"; 27 | Socket puller = context.buildSocket(SocketType.PULL).bind("ipc://pushpull.ipc"); 28 | Socket pusher = context.buildSocket(SocketType.PUSH).connect("ipc://pushpull.ipc"); 29 | pusher.send(expected.getBytes()); 30 | byte[] actual = puller.receive(); 31 | assertEquals(expected, new String(actual)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/QueueTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.zeromq.jzmq.ManagedContext; 7 | 8 | import static org.junit.Assert.assertArrayEquals; 9 | 10 | public class QueueTest { 11 | private Context context; 12 | 13 | @Before 14 | public void setUp() { 15 | context = new ManagedContext(); 16 | } 17 | 18 | @After 19 | public void tearDown() throws Exception { 20 | context.terminate(); 21 | context.close(); 22 | } 23 | 24 | @Test 25 | public void testProxy() throws Exception { 26 | Socket requesterEndpoint = context.buildSocket(SocketType.ROUTER).bind("inproc://requests"); 27 | Socket workerEndpoint = context.buildSocket(SocketType.DEALER).bind("inproc://work"); 28 | context.queue(workerEndpoint, requesterEndpoint); 29 | 30 | //give it a bit of time to start up. 31 | Thread.sleep(100L); 32 | 33 | Socket client = this.context.buildSocket(SocketType.REQ).connect("inproc://requests"); 34 | Socket worker = this.context.buildSocket(SocketType.REP).connect("inproc://work"); 35 | client.send("hello".getBytes()); 36 | byte[] response = worker.receive(); 37 | assertArrayEquals("hello".getBytes(), response); 38 | 39 | worker.send("goodbye".getBytes()); 40 | byte[] response2 = client.receive(); 41 | assertArrayEquals("goodbye".getBytes(), response2); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/ReactorTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.After; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.zeromq.jzmq.ManagedContext; 9 | import org.zeromq.jzmq.reactor.ReactorBuilder; 10 | 11 | import java.util.concurrent.atomic.AtomicInteger; 12 | 13 | public class ReactorTest { 14 | private ManagedContext context; 15 | private Socket in; 16 | private Socket out; 17 | 18 | private AtomicInteger safe = new AtomicInteger(); 19 | 20 | @Before 21 | public void setUp() throws Exception { 22 | context = new ManagedContext(); 23 | out = context.buildSocket(SocketType.PUB).bind("inproc://test"); 24 | in = context.buildSocket(SocketType.SUB).asSubscribable().subscribe("".getBytes()).connect("inproc://test"); 25 | Thread.sleep(15); 26 | } 27 | 28 | @After 29 | public void tearDown() throws Exception { 30 | context.terminate(); 31 | context.close(); 32 | } 33 | 34 | @Test 35 | public void testTimer() throws Exception { 36 | Reactor reactor = context.buildReactor() 37 | .withTimer(10, 25, new LoopHandler() { 38 | @Override 39 | public void execute(Reactor reactor, Pollable pollable) { 40 | safe.incrementAndGet(); 41 | } 42 | }) 43 | .build(); 44 | 45 | reactor.start(); 46 | Thread.sleep(500); 47 | assertEquals(25, safe.get()); 48 | } 49 | 50 | @Test 51 | public void testTimers_1000() throws Exception { 52 | LoopHandler handler = new LoopHandler() { 53 | @Override 54 | public void execute(Reactor reactor, Pollable pollable) { 55 | safe.incrementAndGet(); 56 | } 57 | }; 58 | 59 | ReactorBuilder builder = context.buildReactor(); 60 | for (int i = 0; i < 1000; i++) { 61 | builder.withTimer(100, (i % 10) + 1, handler); 62 | } 63 | 64 | Reactor reactor = builder.build(); 65 | reactor.start(); 66 | Thread.sleep(1250); 67 | assertEquals(5500, safe.get()); 68 | } 69 | 70 | @Test 71 | public void testTimers_100000() throws Exception { 72 | LoopHandler handler = new LoopHandler() { 73 | @Override 74 | public void execute(Reactor reactor, Pollable pollable) { 75 | safe.incrementAndGet(); 76 | } 77 | }; 78 | 79 | ReactorBuilder builder = context.buildReactor(); 80 | for (int i = 0; i < 100000; i++) { 81 | builder.withTimer(100, (i % 10) + 1, handler); 82 | } 83 | 84 | Reactor reactor = builder.build(); 85 | reactor.start(); 86 | Thread.sleep(1250); 87 | assertEquals(550000, safe.get()); 88 | } 89 | 90 | @Test 91 | public void testPoller() throws Exception { 92 | Reactor reactor = context.buildReactor() 93 | .withInPollable(in, new LoopHandler() { 94 | @Override 95 | public void execute(Reactor reactor, Pollable pollable) { 96 | assertEquals("Hello", new String(pollable.getSocket().receive())); 97 | safe.incrementAndGet(); 98 | } 99 | }) 100 | .build(); 101 | 102 | reactor.start(); 103 | out.send("Hello".getBytes()); 104 | out.send("Hello".getBytes()); 105 | Thread.sleep(50); 106 | out.send("Hello".getBytes()); 107 | Thread.sleep(250); 108 | assertEquals(3, safe.get()); 109 | } 110 | 111 | @Test 112 | public void testPollers_1000() throws Exception { 113 | ReactorBuilder builder = context.buildReactor(); 114 | LoopHandler handler = new LoopHandler() { 115 | @Override 116 | public void execute(Reactor reactor, Pollable pollable) { 117 | assertEquals("Hello", new String(pollable.getSocket().receive())); 118 | safe.incrementAndGet(); 119 | } 120 | }; 121 | 122 | for (int i = 0; i < 1000; i++) { 123 | Socket s = context.buildSocket(SocketType.SUB) 124 | .asSubscribable().subscribe("".getBytes()) 125 | .connect("inproc://test"); 126 | builder.withInPollable(s, handler); 127 | } 128 | 129 | Reactor reactor = builder.build(); 130 | reactor.start(); 131 | out.send("Hello".getBytes()); 132 | out.send("Hello".getBytes()); 133 | Thread.sleep(50); 134 | out.send("Hello".getBytes()); 135 | Thread.sleep(250); 136 | assertEquals(3000, safe.get()); 137 | } 138 | 139 | @Test 140 | public void testMultiple() throws Exception { 141 | Reactor reactor = context.buildReactor() 142 | .withTimer(10, 25, new LoopHandler() { 143 | @Override 144 | public void execute(Reactor reactor, Pollable pollable) { 145 | safe.incrementAndGet(); 146 | } 147 | }) 148 | .withInPollable(in, new LoopHandler() { 149 | @Override 150 | public void execute(Reactor reactor, Pollable pollable) { 151 | assertEquals("Hello", new String(pollable.getSocket().receive())); 152 | safe.incrementAndGet(); 153 | } 154 | }) 155 | .build(); 156 | 157 | reactor.start(); 158 | out.send("Hello".getBytes()); 159 | out.send("Hello".getBytes()); 160 | out.send("Hello".getBytes()); 161 | Thread.sleep(500); 162 | assertEquals(28, safe.get()); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/ReqRepTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.zeromq.jzmq.ManagedContext; 7 | 8 | import static org.junit.Assert.assertArrayEquals; 9 | 10 | public class ReqRepTest { 11 | 12 | private ManagedContext context; 13 | 14 | @Before 15 | public void setUp() { 16 | context = new ManagedContext(); 17 | } 18 | 19 | @After 20 | public void tearDown() throws Exception{ 21 | context.close(); 22 | } 23 | 24 | @Test(timeout = 1000) 25 | public void testReqRep() throws Exception { 26 | Socket repSocket = context.buildSocket(SocketType.REP).bind("inproc://serverSocket"); 27 | Socket requestSocket = context.buildSocket(SocketType.REQ).connect("inproc://serverSocket"); 28 | requestSocket.send("request".getBytes()); 29 | byte[] request = repSocket.receive(); 30 | assertArrayEquals("request".getBytes(), request); 31 | repSocket.send("response".getBytes()); 32 | byte[] response = requestSocket.receive(); 33 | assertArrayEquals("response".getBytes(), response); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/RoutedMessageTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import static junit.framework.Assert.assertEquals; 4 | import static junit.framework.Assert.assertTrue; 5 | import static org.junit.Assert.assertArrayEquals; 6 | 7 | import java.util.Arrays; 8 | import java.util.List; 9 | 10 | import org.junit.Rule; 11 | import org.junit.Test; 12 | import org.junit.rules.ExpectedException; 13 | import org.zeromq.api.Message.Frame; 14 | 15 | public class RoutedMessageTest { 16 | 17 | @Rule 18 | public ExpectedException expectedException = ExpectedException.none(); 19 | 20 | @Test 21 | public void testGetRoutes() throws Exception { 22 | RoutedMessage testClass = new RoutedMessage(); 23 | testClass.addFrames(new Message( 24 | Arrays.asList(new Message.Frame("address1".getBytes()), 25 | RoutedMessage.Route.BLANK, 26 | new Message.Frame("payload".getBytes())))); 27 | 28 | List result = testClass.getRoutes(); 29 | assertEquals(1, result.size()); 30 | assertEquals(new RoutedMessage.Route("address1".getBytes()), result.get(0)); 31 | } 32 | 33 | @Test 34 | public void testGetRoutes_multiple() throws Exception { 35 | RoutedMessage testClass = new RoutedMessage(); 36 | testClass.addFrames(new Message(Arrays.asList( 37 | new Message.Frame("address1".getBytes()), 38 | RoutedMessage.Route.BLANK, 39 | new Message.Frame("address2".getBytes()), 40 | RoutedMessage.Route.BLANK, 41 | new Message.Frame("payload".getBytes())))); 42 | 43 | List result = testClass.getRoutes(); 44 | assertEquals(2, result.size()); 45 | assertEquals(new RoutedMessage.Route("address1".getBytes()), result.get(0)); 46 | assertEquals(new RoutedMessage.Route("address2".getBytes()), result.get(1)); 47 | } 48 | 49 | @Test 50 | public void testPayload_multipleRoutes() throws Exception { 51 | RoutedMessage testClass = new RoutedMessage(); 52 | testClass.addFrames(new Message(Arrays.asList( 53 | new Message.Frame("address1".getBytes()), 54 | RoutedMessage.Route.BLANK, 55 | new Message.Frame("address2".getBytes()), 56 | RoutedMessage.Route.BLANK, 57 | new Message.Frame("payload".getBytes())))); 58 | 59 | Message result = testClass.getPayload(); 60 | assertArrayEquals("payload".getBytes(), result.getFirstFrame().getData()); 61 | } 62 | 63 | @Test 64 | public void testGetRoutes_noRoutes() throws Exception { 65 | RoutedMessage testClass = new RoutedMessage(); 66 | testClass.addFrame(Frame.of("payload")); 67 | 68 | List result = testClass.getRoutes(); 69 | assertTrue(result.isEmpty()); 70 | } 71 | 72 | @Test 73 | public void testUnwrap_noRoutes() throws Exception { 74 | RoutedMessage testClass = new RoutedMessage(); 75 | testClass.addFrame(Frame.of("payload")); 76 | 77 | expectedException.expect(IllegalStateException.class); 78 | expectedException.expectMessage("Cannot unwrap an unrouted message."); 79 | 80 | testClass.unwrap(); 81 | } 82 | 83 | @Test 84 | public void testUnwrap() throws Exception { 85 | RoutedMessage testClass = new RoutedMessage(); 86 | testClass.addFrames(new Message(Arrays.asList( 87 | new Message.Frame("address1".getBytes()), 88 | RoutedMessage.Route.BLANK, 89 | new Message.Frame("address2".getBytes()), 90 | RoutedMessage.Route.BLANK, 91 | new Message.Frame("payload".getBytes())))); 92 | 93 | 94 | assertEquals(2, testClass.getRoutes().size()); 95 | 96 | assertArrayEquals("address1".getBytes(), testClass.unwrap().getAddress()); 97 | assertEquals(1, testClass.getRoutes().size()); 98 | 99 | assertArrayEquals("address2".getBytes(), testClass.unwrap().getAddress()); 100 | assertEquals(0, testClass.getRoutes().size()); 101 | } 102 | 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/RouterDealerTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import junit.framework.TestCase; 4 | 5 | import org.junit.After; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.zeromq.ContextFactory; 9 | 10 | public class RouterDealerTest extends TestCase { 11 | private Context context; 12 | 13 | @Before 14 | @Override 15 | public void setUp() { 16 | context = ContextFactory.createContext(1); 17 | } 18 | 19 | @After 20 | @Override 21 | public void tearDown() throws Exception { 22 | context.close(); 23 | } 24 | 25 | @Test(timeout = 1000) 26 | public void testRoutingToCorrectDealerFromRouter() throws Exception { 27 | Socket router = context.buildSocket(SocketType.ROUTER).bind("ipc://router.ipc"); 28 | Socket dealer1 = context.buildSocket(SocketType.DEALER).withIdentity("A".getBytes()) 29 | .connect("ipc://router.ipc"); 30 | Socket dealer2 = context.buildSocket(SocketType.DEALER).withIdentity("B".getBytes()) 31 | .connect("ipc://router.ipc"); 32 | 33 | // Unfortunately you have to wait until the dealers connect or dealer1.receive will block. Add poll later 34 | Thread.sleep(100); 35 | router.send("A".getBytes(), MessageFlag.SEND_MORE); 36 | router.send("END".getBytes()); 37 | 38 | String expected = new String(dealer1.receive()); 39 | assertEquals("END", expected); 40 | 41 | router.send("B".getBytes(), MessageFlag.SEND_MORE); 42 | router.send("END".getBytes()); 43 | 44 | expected = new String(dealer2.receive()); 45 | assertEquals("END", expected); 46 | } 47 | 48 | @Test(timeout = 1000) 49 | public void testDealerToRouter() throws Exception { 50 | Socket router = context.buildSocket(SocketType.ROUTER).bind("ipc://router.ipc"); 51 | Socket dealer = context.buildSocket(SocketType.DEALER).withIdentity("A".getBytes()).connect("ipc://router.ipc"); 52 | 53 | dealer.send("PING".getBytes()); 54 | byte[] id = router.receive(); 55 | byte[] expected = router.receive(); 56 | 57 | assertEquals("A", new String(id)); 58 | assertEquals("PING", new String(expected)); 59 | 60 | router.send(id, MessageFlag.SEND_MORE); 61 | router.send("END".getBytes()); 62 | 63 | expected = dealer.receive(); 64 | assertEquals("END", new String(expected)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/RouterTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.zeromq.api.exception.ZMQRuntimeException; 7 | import org.zeromq.jzmq.ManagedContext; 8 | 9 | public class RouterTest { 10 | private ManagedContext context; 11 | 12 | @Before 13 | public void setUp() { 14 | context = new ManagedContext(); 15 | } 16 | 17 | @After 18 | public void tearDown() throws Exception{ 19 | context.close(); 20 | } 21 | 22 | @Test(expected=ZMQRuntimeException.class) 23 | public void testRouterMandatory() throws Exception { 24 | Socket testClass = context.buildSocket(SocketType.ROUTER) 25 | .asRoutable().withRouterMandatory() 26 | .bind("inproc://testRouter"); 27 | 28 | Socket endpoint = context.buildSocket(SocketType.REQ).connect("inproc://testRouter"); 29 | 30 | endpoint.send("test".getBytes()); 31 | testClass.send("hello".getBytes(), MessageFlag.SEND_MORE); 32 | testClass.send(new byte[0], MessageFlag.SEND_MORE); 33 | testClass.send("message".getBytes()); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/SocketBuilderTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.zeromq.jzmq.ManagedContext; 7 | import org.zeromq.jzmq.sockets.SocketBuilder; 8 | 9 | import static junit.framework.Assert.assertNull; 10 | import static junit.framework.Assert.assertTrue; 11 | 12 | public class SocketBuilderTest { 13 | 14 | private ManagedContext context; 15 | 16 | @Before 17 | public void setUp() { 18 | context = new ManagedContext(); 19 | } 20 | 21 | @After 22 | public void tearDown() throws Exception{ 23 | context.close(); 24 | } 25 | 26 | @Test 27 | public void testSendTimeout() throws Exception { 28 | SocketBuilder testClass = new SocketBuilder(context, SocketType.REQ); 29 | Socket reqSocket = testClass.withSendTimeout(100).bind("inproc://testSendTimeout"); 30 | boolean result = reqSocket.send("Hello".getBytes()); 31 | assertTrue(!result); 32 | } 33 | 34 | @Test 35 | public void testReceiveTimeout() throws Exception { 36 | SocketBuilder testClass = new SocketBuilder(context, SocketType.REP); 37 | Socket repSocket = testClass.withReceiveTimeout(100).bind("inproc://testReceiveTimeout"); 38 | byte[] result = repSocket.receive(); 39 | assertNull(result); 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/SocketTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import static junit.framework.Assert.assertEquals; 4 | 5 | import org.junit.After; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.zeromq.api.exception.ContextTerminatedException; 11 | import org.zeromq.api.exception.InvalidSocketException; 12 | import org.zeromq.jzmq.ManagedContext; 13 | 14 | public class SocketTest { 15 | 16 | private static final Logger log = LoggerFactory.getLogger(SocketTest.class); 17 | private ManagedContext context; 18 | 19 | @Before 20 | public void setUp() { 21 | this.context = new ManagedContext(1); 22 | } 23 | 24 | @After 25 | public void tearDown() { 26 | context.close(); 27 | } 28 | 29 | @Test(expected=InvalidSocketException.class) 30 | public void testClosedSocket() { 31 | Context shadow = context.shadow(); 32 | Socket pub = shadow.buildSocket(SocketType.PUB) 33 | .bind("inproc://socket-test"); 34 | Socket sub = shadow.buildSocket(SocketType.SUB) 35 | .asSubscribable() 36 | .subscribe("".getBytes()) 37 | .connect("inproc://socket-test"); 38 | 39 | pub.send("hello".getBytes()); 40 | assertEquals("hello", new String(sub.receive())); 41 | 42 | shadow.close(); 43 | pub.send("hello, world".getBytes()); 44 | } 45 | 46 | @Test(timeout=1000) 47 | public void testTerminatedContext() throws InterruptedException { 48 | Socket req = context.buildSocket(SocketType.REQ) 49 | .bind("inproc://socket-test"); 50 | 51 | ManagedContext shadow = context.shadow(); 52 | /*final Socket rep = */ 53 | shadow.buildSocket(SocketType.REP) 54 | .withBackgroundable(new Backgroundable() { 55 | @Override 56 | public void run(Context context, Socket socket) { 57 | assertEquals("hello", new String(socket.receive())); 58 | socket.send("hello, world".getBytes()); 59 | try { 60 | socket.receive(); 61 | } catch (ContextTerminatedException ignored) { 62 | } 63 | 64 | socket.close(); 65 | log.info("Closed REP socket, exiting..."); 66 | } 67 | 68 | @Override 69 | public void onClose() { 70 | // TODO Auto-generated method stub 71 | 72 | } 73 | }) 74 | .connect("inproc://socket-test"); 75 | 76 | req.send("hello".getBytes()); 77 | assertEquals("hello, world", new String(req.receive())); 78 | 79 | Thread.sleep(10); 80 | context.close(); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/api/SocketsTest.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.api; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Test; 6 | import org.zeromq.Sockets; 7 | 8 | public class SocketsTest { 9 | @Test 10 | public void testPushPull() { 11 | try (Socket push = Sockets.bind(SocketType.PUSH, "tcp://*:5991"); 12 | Socket pull = Sockets.connect(SocketType.PULL, "tcp://127.0.0.1:5991")) { 13 | push.send(new Message("Hello")); 14 | assertEquals("Hello", pull.receiveMessage().popString()); 15 | } 16 | } 17 | 18 | @Test 19 | public void testPubSub() throws Exception { 20 | try (Socket pub = Sockets.bind(SocketType.PUB, "tcp://*:5992"); 21 | Socket sub = Sockets.buildSocket(SocketType.SUB) 22 | .asSubscribable().subscribeAll() 23 | .connect("tcp://127.0.0.1:5992")) { 24 | Thread.sleep(250); 25 | pub.send(new Message("Hello")); 26 | 27 | assertEquals("Hello", sub.receiveMessage().popString()); 28 | } 29 | } 30 | 31 | @Test 32 | public void testReqRepWithPoller() { 33 | try (Socket req = Sockets.bind(SocketType.REQ, "tcp://*:5993"); 34 | Socket rep = Sockets.connect(SocketType.REP, "tcp://127.0.0.1:5993")) { 35 | Poller poller = Sockets.newPoller(new PollAdapter(), req, rep); 36 | req.send(new Message("World")); 37 | poller.poll(); 38 | rep.send(new Message("Hello, " + rep.receiveMessage().popString())); 39 | poller.poll(); 40 | 41 | assertEquals("Hello, World", req.receiveMessage().popString()); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/client/BackupStar.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.client; 2 | 3 | import org.zeromq.api.LoopHandler; 4 | import org.zeromq.api.Pollable; 5 | import org.zeromq.api.Reactor; 6 | import org.zeromq.api.SocketType; 7 | import org.zeromq.jzmq.ManagedContext; 8 | import org.zeromq.jzmq.bstar.BinaryStarReactorImpl; 9 | 10 | public class BackupStar { 11 | /** 12 | * @param args 13 | */ 14 | public static void main(String[] args) { 15 | String local = "tcp://localhost:5556"; 16 | if (args.length >= 1) { 17 | local = args[0]; 18 | } 19 | 20 | String remote = "tcp://localhost:5555"; 21 | if (args.length >= 2) { 22 | remote = args[1]; 23 | } 24 | 25 | String voter = "tcp://localhost:5558"; 26 | if (args.length >= 3) { 27 | remote = args[2]; 28 | } 29 | 30 | ManagedContext context = new ManagedContext(); 31 | BinaryStarReactorImpl binaryStar = new BinaryStarReactorImpl(context, BinaryStarReactorImpl.Mode.BACKUP, local, remote); 32 | binaryStar.registerVoterSocket(context.buildSocket(SocketType.PULL).bind(voter)); 33 | binaryStar.setVoterHandler(new MyHandler("backup-voter")); 34 | binaryStar.setActiveHandler(new MyHandler("backup-active")); 35 | binaryStar.setPassiveHandler(new MyHandler("backup-passive")); 36 | binaryStar.start(); 37 | 38 | try { 39 | Thread.sleep(Long.MAX_VALUE); 40 | } catch (InterruptedException ignored) { 41 | } 42 | 43 | context.terminate(); 44 | context.close(); 45 | } 46 | 47 | public static class MyHandler implements LoopHandler { 48 | private String label; 49 | 50 | public MyHandler(String label) { 51 | this.label = label; 52 | } 53 | 54 | @Override 55 | public void execute(Reactor reactor, Pollable pollable) { 56 | System.out.println(label); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/client/CloneClientMain.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.client; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.zeromq.Patterns; 6 | import org.zeromq.api.CloneClient; 7 | 8 | import java.util.Random; 9 | 10 | public class CloneClientMain { 11 | private static final Logger log = LoggerFactory.getLogger(CloneClientMain.class); 12 | 13 | /** 14 | * @param args 15 | */ 16 | public static void main(String[] args) throws Exception { 17 | final Thread thread = Thread.currentThread(); 18 | final CloneClient cloneClient = Patterns.newCloneClient("localhost", "localhost", "/client/"); 19 | 20 | Random rand = new Random(System.nanoTime()); 21 | while (!thread.isInterrupted()) { 22 | // Set random value, check it was stored 23 | String key = String.format("%s%d", "/client/", rand.nextInt(10000)); 24 | String value = String.format("%d", rand.nextInt(1000000)); 25 | log.info("Publishing update: {}={}", key, value); 26 | cloneClient.set(key, value, rand.nextInt(30)); 27 | Thread.sleep(1000); 28 | } 29 | 30 | Runtime.getRuntime().addShutdownHook(new Thread() { 31 | @Override 32 | public void run() { 33 | log.info("Stopping CloneClient..."); 34 | thread.interrupt(); 35 | try { 36 | thread.join(); 37 | } catch (InterruptedException ignored) { 38 | } 39 | log.info("CloneClient stopped"); 40 | } 41 | }); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/client/CloneServerMain.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.client; 2 | 3 | import org.zeromq.Patterns; 4 | import org.zeromq.api.BinaryStarReactor; 5 | 6 | public class CloneServerMain { 7 | /** 8 | * @param args 9 | */ 10 | public static void main(String[] args) { 11 | assert (args.length == 1); 12 | 13 | BinaryStarReactor.Mode mode = (args[0].equals("--primary")) 14 | ? BinaryStarReactor.Mode.PRIMARY 15 | : BinaryStarReactor.Mode.BACKUP; 16 | Patterns.newCloneServer(mode, "localhost", "localhost"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/org/zeromq/client/PrimaryStar.java: -------------------------------------------------------------------------------- 1 | package org.zeromq.client; 2 | 3 | import org.zeromq.api.LoopHandler; 4 | import org.zeromq.api.Pollable; 5 | import org.zeromq.api.Reactor; 6 | import org.zeromq.api.SocketType; 7 | import org.zeromq.jzmq.ManagedContext; 8 | import org.zeromq.jzmq.bstar.BinaryStarReactorImpl; 9 | 10 | public class PrimaryStar { 11 | /** 12 | * @param args 13 | */ 14 | public static void main(String[] args) { 15 | String local = "tcp://localhost:5555"; 16 | if (args.length >= 1) { 17 | local = args[0]; 18 | } 19 | 20 | String remote = "tcp://localhost:5556"; 21 | if (args.length >= 2) { 22 | remote = args[1]; 23 | } 24 | 25 | String voter = "tcp://localhost:5557"; 26 | if (args.length >= 3) { 27 | remote = args[2]; 28 | } 29 | 30 | ManagedContext context = new ManagedContext(); 31 | BinaryStarReactorImpl binaryStar = new BinaryStarReactorImpl(context, BinaryStarReactorImpl.Mode.PRIMARY, local, remote); 32 | binaryStar.registerVoterSocket(context.buildSocket(SocketType.PULL).bind(voter)); 33 | binaryStar.setVoterHandler(new MyHandler("primary-voter")); 34 | binaryStar.setActiveHandler(new MyHandler("primary-active")); 35 | binaryStar.setPassiveHandler(new MyHandler("primary-passive")); 36 | binaryStar.start(); 37 | 38 | try { 39 | Thread.sleep(Long.MAX_VALUE); 40 | } catch (InterruptedException ignored) { 41 | } 42 | 43 | context.terminate(); 44 | context.close(); 45 | } 46 | 47 | public static class MyHandler implements LoopHandler { 48 | private String label; 49 | 50 | public MyHandler(String label) { 51 | this.label = label; 52 | } 53 | 54 | @Override 55 | public void execute(Reactor reactor, Pollable pollable) { 56 | System.out.println(label); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | --------------------------------------------------------------------------------