* This implementation is based on the {@link ZStar} one (TODO via inheritance now but this is not totally stamped and the use of the ZAgent would probably limit the collateral damages if changed)
* so you should be first familiar with the metaphor there.
*
* To extensively sum up:
*
* A side or endpoint designates the same thing: the thread where lives one of the two parts of the Actor system.
*
* An actor has 2 sides (with a trial to use theater terms for fun (: and hopefully clarity :)
*
* - the Corbeille side, or control side
*
* This is where one can {@link #send(ZMsg) send} and {@link #recv() receive} control messages to the underneath actor via the ZActor and/or its agent.
*
* The ZActor lives on this side and is a way to safely communicate with the distant provided Actor
*
* Note: Corbeille is a french word designing the most privileged seats in the theater,
* 1st floor, just above the orchestra (Wikipedia...).
* It was the place where the King was standing during the shows, with the best seat of course!
*
* Fast users who would want to communicate with the distant {@link Actor} can use
* {@link #send(ZMsg)} or {@link #recv()} from the ZActor as the ZActor is itself an agent!
*
* - the Plateau side, or background side where all the performances are made by the provided actor.
*
* The provided {@link Actor} is living on the Plateau.
*
* The Plateau is made of the Stage where {@link Actor#stage(Socket, Socket, ZPoller, int) the effective processing occurs} and of the Backstage
* where the provided actor can {@link Actor#backstage(Socket, ZPoller, int) send and receive} control messages to and from the ZActor.
*
* From this side, the work is done via callbacks using the template-method pattern, applied with interfaces (?)
*
*
* The main purpose (or at least its intent) of this class is to clarify the contracts, roles, responsibilities and action levers related to the Plateau.
*
* The provided Actor will not be alone to do the processing of each loop.
*
* It will be helped by a double responsible for passing the appropriate structures at the right moment.
* As a developer point of view, this double helps also to limit the complexity of the process.
* However Double is an uncommon one, capturing all the lights while letting the Actor taking care of all the invisible work in the shadows.
* And this is one of the points where we begin to reach the limits of the metaphor...
*
* The ZActor takes care of the establishment of the background processing, calling the provided Actor
* at appropriate times via its Double. It can also manage the {@link #sign() exited} state on the control side,
* if using the provided {@link #send(ZMsg)} or {@link #recv()} methods.
*
* It also takes care of the automatic closing of sockets and context if it had to create one.
*
* An {@link Actor actor} is basically a contract interface that anyone who uses this ZActor SHALL comply to.
* TODO This interface is still a little bit tough, as instead of the 5+2 Star callbacks, here are 10!
* But they allow you to have a hand on the key points of the looping, restart a new actor if needed, ...
* Anyway, adapters like a {@link SimpleActor simple one} or a {@link Duo duo} are present to help you on that, reducing the amount of
* methods to write.
*
* Example of code for a minimalistic actor with no socket handling other than the control pipe:
*
*
*
* {@code
Actor acting = new ZActor.SimpleActor()
{
public List createSockets(ZContext ctx, Object[] args)
{
assert ("TEST".equals(args[0]));
return Arrays.asList(ctx.createSocket(ZMQ.PUB));
}
public boolean backstage(Socket pipe, ZPoller poller, int events)
{
String cmd = pipe.recvStr();
if ("HELLO".equals(cmd)) {
pipe.send("WORLD");
// end of the actor
return false;
}
return true;
}
};
ZActor actor = new ZActor(acting, "LOCK", Arrays.asList("TEST").toArray());
Socket pipe = actor.pipe();
boolean rc = pipe.send("HELLO");
assert (rc);
ZMsg msg = actor.recv();
String world = msg.popString();
assert ("WORLD".equals(world));
msg = actor.recv();
assert (msg == null);
rc = actor.sign();
assert (!rc);
rc = actor.send("whatever");
assert (!rc);
// don't try to use the pipe
}
*/
// remote controlled background message processing API for 0MQ.
public class ZActor extends ZStar
// once on stage, any actor IS a star
{
/**
* Defines the contract for the acting instance.
*
*/
// contract interface for acting on the distant stage
// TODO what can be done to reduce the amount of methods ? Split interface?
public interface Actor
{
/**
* This is the grand premiere!
* Called before the creation of the first double and the sockets
* 2nd in the order call of the global acting.
*
* @param pipe the backstage control pipe
* @return the name of the upcoming performance
*/
String premiere(Socket pipe);
/**
* Creates and initializes sockets for the double.
* This is done at each creation of a new double.
* 3rd in the order call of the global acting.
* 1st in the order call of the new double.
*
* @param ctx the context used to create sockets
* @param args the arguments passed as parameters of the ZActor
* @return a list of created sockets that will be managed by the double. Not null.
*/
List createSockets(ZContext ctx, Object[] args);
/**
* Called when the double is started, before the first loop.
* 4th in the order call of the global acting.
* 2nd in the order call of the new double.
*
* @param pipe the backstage control pipe
* @param sockets the managed sockets that were created in the previous step
* @param poller the poller where to eventually register the sockets for events
*/
void start(Socket pipe, List sockets, ZPoller poller);
/**
* Called every time just before a loop starts.
* 5th in the order call of the global acting.
* 3nd in the order call of the new double.
* 1st in the order call of the new loop.
*
* @param pipe the backstage control pipe
* @param poller the poller of the double
* @return the timeout of the coming loop. -1 to block, 0 to not wait, > 0 to wait till max the returned duration in milliseconds
*/
long looping(Socket pipe, ZPoller poller);
/**
* Called when the actor received a control message from its pipe during a loop.
* 2nd in the order call of the new loop.
*
* @param pipe the backstage control pipe receiving the message
* @param poller the poller of the double.
* @param events the events source of the call
* @return true in case of success, false to stop the double.
*/
boolean backstage(Socket pipe, ZPoller poller, int events);
/**
* The actor received a message from the created sockets during a loop.
* 2nd ex-aequo in the order call of the new loop.
*
* @param socket the socket receiving the message
* @param pipe the backstage control pipe
* @param poller the poller of the double.
* @param events the events source of the call
* @return true in case of success, false to stop the double.
*/
boolean stage(Socket socket, Socket pipe, ZPoller poller, int events);
/**
* Called at the end of each loop.
* 3rd in the order call of the new loop.
*
* @param pipe the backstage control pipe
* @param poller the poller of the double.
* @return true to continue with the current double, false to stop it.
*/
boolean looped(Socket pipe, ZPoller poller);
/**
* Called when a created socket has been closed.
* The process of destroying the double has already started.
*
* @param socket the closed socked.
*/
void closed(Socket socket);
/**
* Called when the current double has been destroyed.
* Last in the order call of the double.
*
* @param pipe the backstage control pipe
* @param poller the poller of the double.
* @return true to restart a new double, false to stop the acting process
*/
boolean destroyed(Socket pipe, ZPoller poller);
/**
* Called when the stage is finished.
* This is the last call to the actor.
* Last in the order call of the global acting.
*
* @param pipe the backstage control pipe
* @return true to spread the word of the actor's leaving
*/
boolean finished(Socket pipe);
}
/**
* Simple adapter for an actor, with no sockets, blocking calls and immediate termination.
*/
// simple contract implementation for acting on the stage
public static class SimpleActor implements Actor
{
@Override
public String premiere(final Socket pipe)
{
// do nothing
return "?";
}
@Override
public List createSockets(final ZContext ctx,
final Object[] args)
{
return Collections.emptyList();
}
@Override
public void start(final Socket pipe, final List sockets,
final ZPoller poller)
{
// do nothing
}
@Override
public long looping(Socket pipe, ZPoller poller)
{
// blocking loop
return -1;
}
@Override
public boolean backstage(final Socket pipe, final ZPoller poller,
final int events)
{
// stop looping
return false;
}
@Override
public boolean stage(final Socket socket, final Socket pipe,
final ZPoller poller, int events)
{
// stop looping
return false;
}
@Override
public boolean looped(final Socket pipe, final ZPoller poller)
{
// continue with the same double
return true;
}
@Override
public void closed(final Socket socket)
{
// do nothing
}
@Override
public boolean destroyed(final Socket pipe, ZPoller poller)
{
// no restart
return false;
}
@Override
public boolean finished(final Socket pipe)
{
// mot de la fin if not null
return true;
}
}
/**
* Another actor will be called just before the main one,
* without participating to the decisions.
*/
// contract implementation for a duo actor on the stage
public static class Duo implements Actor
{
// the actor that will play an active role on the stage
private final Actor main;
// the actor that will play a passive role on the stage
private final Actor shadow;
public Duo(final Actor main, final Actor shadow)
{
super();
assert (main != null);
assert (shadow != null);
this.main = main;
this.shadow = shadow;
}
@Override
public String premiere(final Socket pipe)
{
shadow.premiere(pipe);
return main.premiere(pipe);
}
@Override
public List createSockets(final ZContext ctx,
final Object[] args)
{
shadow.createSockets(ctx, args);
return main.createSockets(ctx, args);
}
@Override
public void start(final Socket pipe, final List sockets,
final ZPoller poller)
{
shadow.start(pipe, sockets, poller);
main.start(pipe, sockets, poller);
}
@Override
public long looping(Socket pipe, ZPoller poller)
{
shadow.looping(pipe, poller);
return main.looping(pipe, poller);
}
@Override
public boolean backstage(final Socket pipe, final ZPoller poller,
final int events)
{
shadow.backstage(pipe, poller, events);
return main.backstage(pipe, poller, events);
}
@Override
public boolean stage(final Socket socket, final Socket pipe,
final ZPoller poller, final int events)
{
shadow.stage(socket, pipe, poller, events);
return main.stage(socket, pipe, poller, events);
}
@Override
public boolean looped(final Socket pipe, final ZPoller poller)
{
shadow.looped(pipe, poller);
return main.looped(pipe, poller);
}
@Override
public void closed(final Socket socket)
{
shadow.closed(socket);
main.closed(socket);
}
@Override
public boolean destroyed(final Socket pipe, final ZPoller poller)
{
shadow.destroyed(pipe, poller);
return main.destroyed(pipe, poller);
}
@Override
public boolean finished(final Socket pipe)
{
shadow.finished(pipe);
return main.finished(pipe);
}
}
/**
* Creates a new ZActor.
*
* @param actor
* the actor handling messages from either stage and backstage
* @param args
* the optional arguments that will be passed to the distant actor
*/
public ZActor(Actor actor, final String motdelafin, Object... args)
{
this(null, null, actor, motdelafin, args);
}
/**
* Creates a new ZActor.
*
* @param selector
* the creator of the selector used on the Plateau.
* @param actor
* the actor handling messages from either stage and backstage
* @param args
* the optional arguments that will be passed to the distant actor
*/
public ZActor(final SelectorCreator selector, final Actor actor, final String motdelafin, final Object... args)
{
this(null, selector, actor, motdelafin, args);
}
/**
* Creates a new ZActor.
*
* @param context
* the main context used. If null, a new context will be created
* and closed at the stop of the operation.
* If not null, it is the responsibility of the caller to close it.
*
* @param selector
* the creator of the selector used on the Plateau.
* @param actor
* the actor handling messages from either stage and backstage
* @param args
* the optional arguments that will be passed to the distant actor
*/
public ZActor(final ZContext context, final SelectorCreator selector,
final Actor actor, final String motdelafin, final Object[] args)
{
super(context, selector, new ActorFortune(actor), motdelafin, args);
}
// actor creator
private static final class ActorFortune implements Fortune
{
private final Actor actor;
public ActorFortune(Actor actor)
{
assert (actor != null);
this.actor = actor;
}
@Override
public String premiere(Socket mic, Object[] args)
{
return actor.premiere(mic);
}
@Override
public Star create(ZContext ctx, Socket pipe, Selector sel,
int count, Star previous, Object[] args)
{
Star star = new ZActor.Double(ctx, pipe, sel, actor, args);
return star;
}
@Override
public boolean interview(Socket mic)
{
return actor.finished(mic);
}
@Override
public void party(ZContext ctx)
{
}
}
// double for the loops, easing life for the actor
private static final class Double implements EventsHandler, Star
{
// poller used for the loop
private final ZPoller poller;
// control pipe for Backstage side
private final Socket pipe;
// managed sockets
private final List sockets;
// actor responsible for processing messages
private final Actor actor;
// creates a new double
public Double(final ZContext ctx, final Socket pipe,
final Selector selector, final Actor actor,
final Object[] args)
{
this.pipe = pipe;
this.actor = actor;
final List created = actor.createSockets(ctx, args);
assert (created != null);
sockets = new ArrayList(created);
poller = new ZPoller(selector);
poller.setGlobalHandler(this);
}
// before starting the loops
@Override
public void prepare()
{
poller.register(pipe, ZPoller.POLLIN);
actor.start(pipe, Collections.unmodifiableList(sockets), poller);
}
// gives the number of events to process
@Override
public int breathe()
{
long timeout = actor.looping(pipe, poller);
return poller.poll(timeout);
// events have been dispatched,
}
// acting takes place, return true to continue till the end
@Override
public boolean act(int events)
{
// act is actually already finished for handlers
return events >= 0; // Context is not shut down
}
// a loop just finished, return true to continue acting
@Override
public boolean entract()
{
return actor.looped(pipe, poller);
}
// destroys the double
@Override
public boolean renews()
{
// close every managed sockets
Iterator iter = sockets.iterator();
while (iter.hasNext()) {
final Socket socket = iter.next();
iter.remove();
if (socket != null) {
poller.unregister(socket);
socket.close();
// call back the actor to inform that a socket has been closed.
actor.closed(socket);
}
}
// let the actor decide if the stage restarts a new double
return actor.destroyed(pipe, poller);
}
@Override
public boolean events(SelectableChannel channel, int events)
{
// TODO dispatch events from channels
return true;
}
// an event has occurred on a registered socket
@Override
public boolean events(final Socket socket, final int events)
{
if (socket != pipe) {
// Process a stage message, time to play
return actor.stage(socket, pipe, poller, events);
}
else {
// Process a control message, time to update your playing
return actor.backstage(pipe, poller, events);
}
}
}
}
jeromq-0.3.5/src/main/java/org/zeromq/ZAgent.java 0000664 0000000 0000000 00000017150 12551504772 0021623 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package org.zeromq;
import java.io.IOException;
import java.nio.channels.Selector;
import java.util.Arrays;
import org.zeromq.ZMQ.Socket;
/**
* First implementation of an agent for a remotely controlled background service for 0MQ.
* Used in conjunction with a ZStar, but not mandatory.
*
* An agent is a mechanism allowing to send messages from one thread to another, and to receive messages from this other thread.
*
* Its built-in implementation provides an easy communication-lock
* system that will close the access once the remote thread is finished.
*
* Are proposed for you a restrained set of simple but powerful messaging commands for a quick learning curve
* and an access to the underlying Socket for advanced usage.
*/
// agent for a remote controlled background message processing API for 0MQ.
// contract to be agent of a star
public interface ZAgent
{
/**
* Receives a control message sent from the Plateau in the Corbeille.
* The call is blocking.
*
* @return the received message or null if the context was shut down.
*/
ZMsg recv();
/**
* Receives a control message sent from the Plateau in the Corbeille.
* The call is blocking depending on the parameter.
*
* @param wait true to make a blocking call, false to not wait, and possibly return null
* @return the received message or null if the context was shut down or if no message if not blocking.
*/
ZMsg recv(boolean wait);
/**
* Sends a control message from the Corbeille to the Plateau.
*
* @param message the message to send
* @return true if the message was sent, otherwise false (if the distant Star is dead for example)
*/
boolean send(ZMsg message);
/**
* Sends a control message from Corbeille side to the Plateau side.
*
* @param msg the message to send
* @param destroy true to destroy the message after sending it.
* @return true if the message was sent, otherwise false (if the distant Star is dead for example)
*/
boolean send(ZMsg msg, boolean destroy);
/**
* Sends a control message from the Corbeille to the Plateau side.
*
* @param word the message to send
* @return true if the message was sent, otherwise false (if the distant Star is dead for example)
*/
boolean send(String word);
/**
* Sends a control message from the Corbeille to the Plateau side.
*
* @param word the message to send
* @param more true to send more strings in a single message
* @return true if the message was sent, otherwise false (if the distant Star is dead for example)
*/
boolean send(String word, boolean more);
/**
* Gives a sign if the distant Star is here.
*
* @return true if here, otherwise false
*/
boolean sign();
/**
* Forcely destroys the Star.
* @deprecated not sure it is useful or recommended
*/
@Deprecated
void nova();
/**
* Returns the socket used for communication.
* For advanced usage.
*
* @return the socket used to communicate with the distant Star.
*/
Socket pipe();
public static class Creator
{
public static ZAgent create(Socket pipe, String lock)
{
return new SimpleAgent(pipe, lock);
}
}
/**
* Creates a very simple agent with an easy lock mechanism.
*/
public static final class SimpleAgent implements ZAgent
{
// the pipe used for communicating with the star
private final Socket pipe;
// the key used to lock the agent.
private final byte[] lock;
// the locked state.
private boolean locked;
/**
* Creates a new simple agent.
*
* @param pipe the pipe used to send control messages to the distant IStar.
* @param lock the lock to use. If null, the locking mechanism is omitted.
*/
public SimpleAgent(Socket pipe, String lock)
{
this.pipe = pipe;
this.lock = lock == null ? null : lock.getBytes(ZMQ.CHARSET);
}
@Override
public boolean sign()
{
return !locked;
}
@Override
public ZMsg recv()
{
return recv(true);
}
@Override
public ZMsg recv(boolean wait)
{
if (locked) {
return null;
}
ZMsg msg = ZMsg.recvMsg(pipe, wait ? 0 : ZMQ.DONTWAIT);
if (msg == null) {
return null;
}
final ZFrame frame = msg.peek();
byte[] key = frame.getData();
if (lock != null && Arrays.equals(lock, key)) {
locked = true;
// this is the last message anyway, and not a one for a public display
msg = null;
pipe.close();
}
return msg;
}
@Override
public boolean send(ZMsg message)
{
if (locked) {
return false;
}
return message.send(pipe);
}
@Override
public boolean send(String word)
{
if (locked) {
return false;
}
return pipe.send(word);
}
@Override
public boolean send(String word, boolean more)
{
if (locked) {
return false;
}
return pipe.send(word, more ? ZMQ.SNDMORE : 0);
}
@Override
public boolean send(ZMsg msg, boolean destroy)
{
if (locked) {
return false;
}
return msg.send(pipe, destroy);
}
@Override
public Socket pipe()
{
return pipe;
}
@Override
public void nova()
{
pipe.close();
}
}
/**
* Creates a selector and destroys it.
*/
// Contract for selector creation.
// will be called in backstage side.
public static interface SelectorCreator
{
/**
* Creates and opens a selector.
*
* @return the opened selector.
*/
Selector create() throws IOException;
/**
* Destroys the previously opened selector.
* @param selector the selector to close
*/
void destroy(Selector selector) throws IOException;
}
// very simple selector creator
public static class VerySimpleSelectorCreator implements SelectorCreator
{
@Override
public Selector create() throws IOException
{
return Selector.open();
}
@Override
public void destroy(Selector selector) throws IOException
{
if (selector != null) {
selector.close();
}
}
}
}
jeromq-0.3.5/src/main/java/org/zeromq/ZBeacon.java 0000664 0000000 0000000 00000017250 12551504772 0021755 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package org.zeromq;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.DatagramChannel;
import java.util.Arrays;
public class ZBeacon
{
public static final long DEFAULT_BROADCAST_INTERVAL = 1000L;
public static final String DEFAULT_BROADCAST_HOST = "255.255.255.255";
private final int port;
private InetAddress broadcastInetAddress;
private final BroadcastClient broadcastClient;
private final BroadcastServer broadcastServer;
private final byte[] beacon;
private byte[] prefix = {};
private long broadcastInterval = DEFAULT_BROADCAST_INTERVAL;
private Listener listener = null;
public ZBeacon(int port, byte[] beacon)
{
this(DEFAULT_BROADCAST_HOST, port, beacon);
}
public ZBeacon(String host, int port, byte[] beacon)
{
this(host, port, beacon, true);
}
public ZBeacon(String host, int port, byte[] beacon, boolean ignoreLocalAddress)
{
this.port = port;
this.beacon = beacon;
try {
broadcastInetAddress = InetAddress.getByName(host);
}
catch (UnknownHostException unknownHostException) {
throw new RuntimeException(unknownHostException);
}
broadcastServer = new BroadcastServer(ignoreLocalAddress);
broadcastServer.setDaemon(true);
broadcastClient = new BroadcastClient();
broadcastClient.setDaemon(true);
}
public void start()
{
if (listener != null) {
broadcastServer.start();
}
broadcastClient.start();
}
public void stop() throws InterruptedException
{
if (broadcastClient != null) {
broadcastClient.interrupt();
broadcastClient.join();
}
if (broadcastServer != null) {
broadcastServer.interrupt();
broadcastServer.join();
}
}
public void setPrefix(byte[] prefix)
{
this.prefix = prefix;
}
public byte[] getPrefix()
{
return prefix;
}
public void setListener(Listener listener)
{
this.listener = listener;
}
public Listener getListener()
{
return listener;
}
/**
* All beacons with matching prefix are passed to a listener.
*/
public interface Listener
{
void onBeacon(InetAddress sender, byte[] beacon);
}
/**
* The broadcast client periodically sends beacons via UDP to the network.
*/
private class BroadcastClient extends Thread
{
private DatagramChannel broadcastChannel;
private final InetSocketAddress broadcastInetSocketAddress;
public BroadcastClient()
{
broadcastInetSocketAddress = new InetSocketAddress(broadcastInetAddress, port);
}
@Override
public void run()
{
try {
broadcastChannel = DatagramChannel.open();
broadcastChannel.socket().setBroadcast(true);
while (!interrupted()) {
try {
broadcastChannel.send(ByteBuffer.wrap(beacon), broadcastInetSocketAddress);
Thread.sleep(broadcastInterval);
}
catch (InterruptedException interruptedException) {
break;
}
catch (Exception exception) {
throw new RuntimeException(exception);
}
}
}
catch (IOException ioException) {
throw new RuntimeException(ioException);
}
finally {
try {
broadcastChannel.close();
}
catch (IOException ioException) {
throw new RuntimeException(ioException);
}
}
}
}
/**
* The broadcast server receives beacons.
*/
private class BroadcastServer extends Thread
{
private DatagramChannel handle; // Socket for send/recv
private final boolean ignoreLocalAddress;
public BroadcastServer(boolean ignoreLocalAddress)
{
this.ignoreLocalAddress = ignoreLocalAddress;
try {
// Create UDP socket
handle = DatagramChannel.open();
handle.configureBlocking(false);
DatagramSocket sock = handle.socket();
sock.setReuseAddress(true);
sock.bind(new InetSocketAddress(InetAddress.getByAddress(new byte[] { 0, 0, 0, 0 }), port));
}
catch (IOException ioException) {
throw new RuntimeException(ioException);
}
}
@Override
public void run()
{
ByteBuffer buffer = ByteBuffer.allocate(65535);
SocketAddress sender;
int size;
while (!interrupted()) {
buffer.clear();
try {
int read = buffer.remaining();
sender = handle.receive(buffer);
if (sender == null) {
continue;
}
InetAddress senderAddress = ((InetSocketAddress) sender).getAddress();
if (ignoreLocalAddress &&
(InetAddress.getLocalHost().getHostAddress().equals(senderAddress.getHostAddress())
|| senderAddress.isAnyLocalAddress()
|| senderAddress.isLoopbackAddress())) {
continue;
}
size = read - buffer.remaining();
handleMessage(buffer, size, senderAddress);
}
catch (ClosedChannelException ioException) {
break;
}
catch (IOException ioException) {
throw new RuntimeException(ioException);
}
}
handle.socket().close();
}
private void handleMessage(ByteBuffer buffer, int size, InetAddress from)
{
if (size < prefix.length) {
return;
}
byte[] bytes = buffer.array();
// Compare prefix
for (int i = 0; i < prefix.length; i++) {
if (bytes[i] != prefix[i]) {
return;
}
}
listener.onBeacon(from, Arrays.copyOf(bytes, size));
}
}
public long getBroadcastInterval()
{
return broadcastInterval;
}
public void setBroadcastInterval(long broadcastInterval)
{
this.broadcastInterval = broadcastInterval;
}
}
jeromq-0.3.5/src/main/java/org/zeromq/ZContext.java 0000664 0000000 0000000 00000013616 12551504772 0022214 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package org.zeromq;
import java.io.Closeable;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
import zmq.ZError;
/**
* ZContext provides a high-level ZeroMQ context management class
*
* It manages open sockets in the context and automatically closes these before terminating the context.
* It provides a simple way to set the linger timeout on sockets, and configure contexts for number of I/O threads.
* Sets-up signal (interrupt) handling for the process.
*
*/
public class ZContext implements Closeable
{
/**
* Reference to underlying Context object
*/
private volatile Context context;
/**
* List of sockets managed by this ZContext
*/
private List sockets;
/**
* Number of io threads allocated to this context, default 1
*/
private int ioThreads;
/**
* Linger timeout, default 0
*/
private int linger;
/**
* HWM timeout, default 1
*/
private int hwm;
/**
* Indicates if context object is owned by main thread
* (useful for multi-threaded applications)
*/
private boolean main;
/**
* Class Constructor
*/
public ZContext()
{
this(1);
}
public ZContext(int ioThreads)
{
sockets = new CopyOnWriteArrayList();
this.ioThreads = ioThreads;
linger = 0;
main = true;
}
/**
* Destructor. Call this to gracefully terminate context and close any managed 0MQ sockets
*/
public void destroy()
{
for (Socket socket : sockets) {
try {
socket.setLinger(linger);
}
catch (ZError.CtxTerminatedException e) {
}
socket.close();
}
sockets.clear();
// Only terminate context if we are on the main thread
if (isMain() && context != null) {
context.term();
}
context = null;
}
/**
* Creates a new managed socket within this ZContext instance.
* Use this to get automatic management of the socket at shutdown
* @param type
* socket type (see ZMQ static class members)
* @return
* Newly created Socket object
*/
public Socket createSocket(int type)
{
// Create and register socket
Socket socket = getContext().socket(type);
sockets.add(socket);
return socket;
}
/**
* Destroys managed socket within this context
* and remove from sockets list
* @param s
* org.zeromq.Socket object to destroy
*/
public void destroySocket(Socket s)
{
if (s == null) {
return;
}
if (sockets.contains(s)) {
try {
s.setLinger(linger);
}
catch (ZError.CtxTerminatedException e) {
}
s.close();
sockets.remove(s);
}
}
/**
* Creates new shadow context.
* Shares same underlying org.zeromq.Context instance but has own list
* of managed sockets, io thread count etc.
* @param ctx Original ZContext to create shadow of
* @return New ZContext
*/
public static ZContext shadow(ZContext ctx)
{
ZContext shadow = new ZContext();
shadow.setContext(ctx.getContext());
shadow.setMain(false);
return shadow;
}
/**
* @return the ioThreads
*/
public int getIoThreads()
{
return ioThreads;
}
/**
* @param ioThreads the ioThreads to set
*/
public void setIoThreads(int ioThreads)
{
this.ioThreads = ioThreads;
}
/**
* @return the linger
*/
public int getLinger()
{
return linger;
}
/**
* @param linger the linger to set
*/
public void setLinger(int linger)
{
this.linger = linger;
}
/**
* @return the HWM
*/
public int getHWM()
{
return hwm;
}
/**
* @param hwm the HWM to set
*/
public void setHWM(int hwm)
{
this.hwm = hwm;
}
/**
* @return the main
*/
public boolean isMain()
{
return main;
}
/**
* @param main the main to set
*/
public void setMain(boolean main)
{
this.main = main;
}
/**
* @return the context
*/
public Context getContext()
{
Context result = context;
if (result == null) {
synchronized (this) {
result = context;
if (result == null) {
result = ZMQ.context(ioThreads);
context = result;
}
}
}
return result;
}
/**
* @param ctx sets the underlying org.zeromq.Context associated with this ZContext wrapper object
*/
public void setContext(Context ctx)
{
this.context = ctx;
}
/**
* @return the sockets
*/
public List getSockets()
{
return sockets;
}
@Override
public void close()
{
destroy();
}
}
jeromq-0.3.5/src/main/java/org/zeromq/ZFrame.java 0000664 0000000 0000000 00000026244 12551504772 0021623 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package org.zeromq;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays;
import org.zeromq.ZMQ.Socket;
/**
* ZFrame
*
* The ZFrame class provides methods to send and receive single message
* frames across 0MQ sockets. A 'frame' corresponds to one underlying zmq_msg_t in the libzmq code.
* When you read a frame from a socket, the more() method indicates if the frame is part of an
* unfinished multipart message. The send() method normally destroys the frame, but with the ZFRAME_REUSE flag, you can send
* the same frame many times. Frames are binary, and this class has no special support for text data.
*
*/
public class ZFrame
{
public static final int MORE = ZMQ.SNDMORE;
public static final int REUSE = 128; // no effect at java
public static final int DONTWAIT = ZMQ.DONTWAIT;
private boolean more;
private byte[] data;
/**
* Class Constructor
* Creates an empty frame.
* (Useful when reading frames from a 0MQ Socket)
*/
protected ZFrame()
{
}
/**
* Class Constructor
* Copies message data into ZFrame object
* @param data
* Data to copy into ZFrame object
*/
public ZFrame(byte[] data)
{
if (data != null) {
this.data = data;
}
}
/**
* Class Constructor
* Copies String into frame data
* @param data
*/
public ZFrame(String data)
{
if (data != null) {
this.data = data.getBytes(ZMQ.CHARSET);
}
}
/**
* Destructor.
*/
public void destroy()
{
if (hasData()) {
data = null;
}
}
/**
* @return the data
*/
public byte[] getData()
{
return data;
}
/**
* @return More flag, true if last read had MORE message parts to come
*/
public boolean hasMore()
{
return more;
}
/**
* Returns byte size of frame, if set, else 0
* @return
* Number of bytes in frame data, else 0
*/
public int size()
{
if (hasData()) {
return data.length;
}
else {
return 0;
}
}
/**
* Convenience method to ascertain if this frame contains some message data
* @return
* True if frame contains data
*/
public boolean hasData()
{
return data != null;
}
/**
* Internal method to call org.zeromq.Socket send() method.
* @param socket
* 0MQ socket to send on
* @param flags
* Valid send() method flags, defined in org.zeromq.ZMQ class
* @return
* True if success, else False
*/
public boolean send(Socket socket, int flags)
{
if (socket == null) {
throw new IllegalArgumentException("socket parameter must be set");
}
return socket.send(data, flags);
}
/**
* Sends frame to socket if it contains any data.
* Frame contents are kept after the send.
* @param socket
* 0MQ socket to send frame
* @param flags
* Valid send() method flags, defined in org.zeromq.ZMQ class
* @return
* True if success, else False
*/
public boolean sendAndKeep(Socket socket, int flags)
{
return send(socket, flags);
}
/**
* Sends frame to socket if it contains any data.
* Frame contents are kept after the send.
* Uses default behaviour of Socket.send() method, with no flags set
* @param socket
* 0MQ socket to send frame
* @return
* True if success, else False
*/
public boolean sendAndKeep(Socket socket)
{
return sendAndKeep(socket, 0);
}
/**
* Sends frame to socket if it contains data.
* Use this method to send a frame and destroy the data after.
* @param socket
* 0MQ socket to send frame
* @param flags
* Valid send() method flags, defined in org.zeromq.ZMQ class
* @return
* True if success, else False
*/
public boolean sendAndDestroy(Socket socket, int flags)
{
boolean ret = send(socket, flags);
if (ret) {
destroy();
}
return ret;
}
/**
* Sends frame to socket if it contains data.
* Use this method to send an isolated frame and destroy the data after.
* Uses default behaviour of Socket.send() method, with no flags set
* @param socket
* 0MQ socket to send frame
* @return
* True if success, else False
*/
public boolean sendAndDestroy(Socket socket)
{
return sendAndDestroy(socket, 0);
}
/**
* Creates a new frame that duplicates an existing frame
* @return
* Duplicate of frame; message contents copied into new byte array
*/
public ZFrame duplicate()
{
return new ZFrame(this.data);
}
/**
* Returns true if both frames have byte - for byte identical data
* @param other
* The other ZFrame to compare
* @return
* True if both ZFrames have same byte-identical data, else false
*/
public boolean hasSameData(ZFrame other)
{
if (other == null) {
return false;
}
if (size() == other.size()) {
return Arrays.equals(data, other.data);
}
return false;
}
/**
* Sets new contents for frame
* @param data
* New byte array contents for frame
*/
public void reset(String data)
{
this.data = data.getBytes(ZMQ.CHARSET);
}
/**
* Sets new contents for frame
* @param data
* New byte array contents for frame
*/
public void reset(byte[] data)
{
this.data = data;
}
/**
* @return frame data as a printable hex string
*/
public String strhex()
{
String hexChar = "0123456789ABCDEF";
StringBuilder b = new StringBuilder();
for (byte aData : data) {
int b1 = aData >>> 4 & 0xf;
int b2 = aData & 0xf;
b.append(hexChar.charAt(b1));
b.append(hexChar.charAt(b2));
}
return b.toString();
}
/**
* String equals.
* Uses String compareTo for the comparison (lexigraphical)
* @param str
* String to compare with frame data
* @return
* True if frame body data matches given string
*/
public boolean streq(String str)
{
if (!hasData()) {
return false;
}
return new String(this.data, ZMQ.CHARSET).compareTo(str) == 0;
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ZFrame zFrame = (ZFrame) o;
return Arrays.equals(data, zFrame.data);
}
@Override
public int hashCode()
{
return Arrays.hashCode(data);
}
/**
* Returns a human - readable representation of frame's data
* @return
* A text string or hex-encoded string if data contains any non-printable ASCII characters
*/
public String toString()
{
if (!hasData()) {
return "";
}
// Dump message as text or hex-encoded string
boolean isText = true;
for (byte aData : data) {
if (aData < 32) {
isText = false;
break;
}
}
if (isText) {
return new String(data, ZMQ.CHARSET);
}
else {
return strhex();
}
}
/**
* Internal method to call recv on the socket.
* Does not trap any ZMQExceptions but expects caling routine to handle them.
* @param socket
* 0MQ socket to read from
* @return
* byte[] data
*/
private byte[] recv(Socket socket, int flags)
{
if (socket == null) {
throw new IllegalArgumentException("socket parameter must not be null");
}
data = socket.recv(flags);
more = socket.hasReceiveMore();
return data;
}
/**
* Receives single frame from socket, returns the received frame object, or null if the recv
* was interrupted. Does a blocking recv, if you want to not block then use
* recvFrame(socket, ZMQ.DONTWAIT);
*
* @param socket
* Socket to read from
* @return
* received frame, else null
*/
public static ZFrame recvFrame(Socket socket)
{
return ZFrame.recvFrame(socket, 0);
}
/**
* Receive a new frame off the socket, Returns newly-allocated frame, or
* null if there was no input waiting, or if the read was interrupted.
* @param socket
* Socket to read from
* @param flags
* Pass flags to 0MQ socket.recv call
* @return
* received frame, else null
*/
public static ZFrame recvFrame(Socket socket, int flags)
{
ZFrame f = new ZFrame();
byte [] data = f.recv(socket, flags);
if (data == null) {
return null;
}
return f;
}
public void print(String prefix)
{
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
if (prefix != null) {
pw.printf("%s", prefix);
}
byte []data = getData();
int size = size();
boolean isBin = false;
int charNbr;
for (charNbr = 0; charNbr < size; charNbr++) {
if (data[charNbr] < 9 || data[charNbr] > 127) {
isBin = true;
}
}
pw.printf("[%03d] ", size);
int maxSize = isBin ? 35 : 70;
String elipsis = "";
if (size > maxSize) {
size = maxSize;
elipsis = "...";
}
for (charNbr = 0; charNbr < size; charNbr++) {
if (isBin) {
pw.printf("%02X", data[charNbr]);
}
else {
pw.printf("%c", data[charNbr]);
}
}
pw.printf("%s\n", elipsis);
pw.flush();
pw.close();
try {
sw.close();
}
catch (IOException e) {
}
System.out.print(sw.toString());
}
}
jeromq-0.3.5/src/main/java/org/zeromq/ZLoop.java 0000664 0000000 0000000 00000030421 12551504772 0021472 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package org.zeromq;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Poller;
/**
* The ZLoop class provides an event-driven reactor pattern. The reactor
* handles zmq.PollItem items (pollers or writers, sockets or fds), and
* once-off or repeated timers. Its resolution is 1 msec. It uses a tickless
* timer to reduce CPU interrupts in inactive processes.
*/
public class ZLoop
{
public interface IZLoopHandler
{
public int handle(ZLoop loop, PollItem item, Object arg);
}
private class SPoller
{
PollItem item;
IZLoopHandler handler;
Object arg;
int errors; // If too many errors, kill poller
protected SPoller(PollItem item, IZLoopHandler handler, Object arg)
{
this.item = item;
this.handler = handler;
this.arg = arg;
errors = 0;
}
};
private class STimer
{
int delay;
int times;
IZLoopHandler handler;
Object arg;
long when; // Clock time when alarm goes off
public STimer(int delay, int times, IZLoopHandler handler,
Object arg)
{
this.delay = delay;
this.times = times;
this.handler = handler;
this.arg = arg;
this.when = -1;
}
}
private final List pollers; // List of poll items
private final List timers; // List of timers
private int pollSize; // Size of poll set
private Poller pollset; // zmq_poll set
private SPoller[] pollact; // Pollers for this poll set
private boolean dirty; // True if pollset needs rebuilding
private boolean verbose; // True if verbose tracing wanted
private final List
* - the event-driven way
*
* {@code
*
ZPoller poller = ...
poller.setGlobalHandler(...)
ZPoller.EventsHandler handler = ...
// The events method of the handler will be called
poller.register(channel, handler, ZPoller.IN);
// The events method of the global handler will be called
poller.register(socket, ZPoller.POLLOUT);
poller.poll(-1L);
// handlers have been called
}
* The motivations of this rewriting are:
*
* - the bare poller use {@link zmq.ZMQ#poll(zmq.PollItem[], int, long) this method} who does not allow
* to choose the selector used for polling, relying on a ThreadLocal, which is dangerous.
*
* - the bare poller use algorithms tailored for languages with manual allocation.
* No need here as Java allows more flexibility. TODO There still may be a small penalty cost.
*
*/
// Poller for 0MQ.
public class ZPoller implements Closeable
{
// contract for events
public static interface EventsHandler
{
/**
* Called when the poller intercepts events.
*
* @param socket the socket with events
* @param events the interesting events as an ORed combination of IN, OUT, ERR
* @return true to continue the polling, false to stop it
*/
boolean events(Socket socket, int events);
/**
* Called when the poller intercepts events.
*
* @param channel the channel with events
* @param events the interesting events as an ORed combination of IN, OUT, ERR
* @return true to continue the polling, false to stop it
*/
boolean events(SelectableChannel channel, int events);
}
// contract for items. Useful for providing own implementation.
public static interface ItemHolder
{
// the inner ZMQ poll item
zmq.PollItem item();
// the related ZeroMQ socket
Socket socket();
// the associated events handler
EventsHandler handler();
}
// contract for items creation. Useful for delegating.
public static interface ItemCreator
{
/**
* Creates a new holder for a poll item.
*
* @param socket the socket to poll
* @param handler the optional handler for polled events
* @param events the interested events
* @return a new poll item holder
*/
ItemHolder create(Socket socket, EventsHandler handler, int events);
/**
* Creates a new holder for a poll item.
*
* @param channel the channel to poll
* @param handler the optional handler for polled events.
* @param events the interested events
* @return a new poll item holder
*/
ItemHolder create(SelectableChannel channel, EventsHandler handler, int events);
}
// re-re-implementation of poll item
public static class ZPollItem extends ZMQ.PollItem implements ItemHolder
{
private final EventsHandler handler;
public ZPollItem(final Socket socket, final EventsHandler handler, int ops)
{
super(socket, ops);
this.handler = handler;
}
public ZPollItem(final SelectableChannel channel, final EventsHandler handler, final int ops)
{
super(channel, ops);
this.handler = handler;
}
@Override
public zmq.PollItem item()
{
return base();
}
@Override
public Socket socket()
{
return getSocket();
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((item() == null) ? 0 : item().hashCode());
result = prime * result + ((getRawSocket() == null) ? 0 : getRawSocket().hashCode());
result = prime * result + ((socket() == null) ? 0 : socket().hashCode());
result = prime * result + ((handler() == null) ? 0 : handler().hashCode());
return result;
}
@Override
public boolean equals(final Object obj)
{
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof ItemHolder)) {
return false;
}
ItemHolder other = (ItemHolder) obj;
if (item() == null) {
if (other.item() != null) {
return false;
}
}
else if (!item().equals(other.item())) {
return false;
}
if (item().getRawSocket() == null) {
if (other.item().getRawSocket() != null) {
return false;
}
}
else if (!item().getRawSocket().equals(other.item().getRawSocket())) {
return false;
}
if (socket() == null) {
if (other.socket() != null) {
return false;
}
}
else if (!socket().equals(other.socket())) {
return false;
}
if (handler() == null) {
if (other.handler() != null) {
return false;
}
}
else if (!handler().equals(other.handler())) {
return false;
}
return true;
}
@Override
public EventsHandler handler()
{
return handler;
}
}
/******************************************************************************/
/* 0MQ socket events */
/******************************************************************************/
/**
* These values can be ORed to specify what we want to poll for.
*/
public static final int POLLIN = Poller.POLLIN;
public static final int POLLOUT = Poller.POLLOUT;
public static final int POLLERR = Poller.POLLERR;
// same values with shorter writing
public static final int IN = POLLIN;
public static final int OUT = POLLOUT;
public static final int ERR = POLLERR;
/**
* Creates a new poller based on the current one.
* This will be a shadow poller, sharing the same selector and items creator.
* The global events handler will not be shared.
*
* @param poller the main poller.
*/
public ZPoller(final ZPoller poller)
{
this(poller.creator, poller.selector);
}
/**
* Creates a new poller with a given selector for operational polling.
*
* @param selector the selector to use for polling.
*/
public ZPoller(final Selector selector)
{
this(new SimpleCreator(), selector);
}
/**
* Creates a new poller based on the current one.
* This will be a shadow poller, sharing the same selector.
* The global events handler will not be shared.
*
* @param creator the items creator
* @param poller the main poller.
*/
public ZPoller(final ItemCreator creator, final ZPoller poller)
{
this(creator, poller.selector);
}
/**
* Creates a new poller.
*
* @param creator the items creator
* @param selector the selector to use for polling.
*/
public ZPoller(final ItemCreator creator, final Selector selector)
{
this.creator = creator;
this.selector = selector;
items = new HashMap>();
all = createContainer(0);
}
// creates a new poll item
protected ItemHolder create(final Socket socket, final EventsHandler handler, final int events)
{
assert (socket != null);
return creator.create(socket, handler, events);
}
// creates a new poll item
protected ItemHolder create(final SelectableChannel channel, final EventsHandler handler, final int events)
{
assert (channel != null);
return creator.create(channel, handler, events);
}
/**
* Sets the global events handler for all registered sockets.
*
* @param globalHandler the events handler to set
*/
public void setGlobalHandler(final EventsHandler globalHandler)
{
this.globalHandler = globalHandler;
}
/**
* Returns the global events handler for all registered sockets.
*
* @return the global events handler for all registered sockets.
*/
public EventsHandler getGlobalHandler()
{
return globalHandler;
}
/**
* Register a Socket for polling on specified events.
*
* @param socket the registering socket.
* @param handler the events handler for this socket
* @param events the events to listen to, as a mask composed by ORing POLLIN, POLLOUT and POLLERR.
* @return true if registered, otherwise false
*/
public final boolean register(final Socket socket,
final EventsHandler handler, final int events)
{
if (socket == null) {
return false;
}
return add(socket, create(socket, handler, events));
}
public final boolean register(final Socket socket, final EventsHandler handler)
{
return register(socket, handler, POLLIN | POLLOUT | POLLERR);
}
public final boolean register(final Socket socket, final int events)
{
return register(socket, globalHandler, events);
}
/**
* Register a SelectableChannel for polling on specified events.
*
* @param channel the registering channel.
* @param handler the events handler for this socket
* @param events the events to listen to, as a mask composed by XORing POLLIN, POLLOUT and POLLERR.
* @return true if registered, otherwise false
*/
public final boolean register(final SelectableChannel channel,
final EventsHandler handler, final int events)
{
if (channel == null) {
return false;
}
return add(channel, create(channel, handler, events));
}
public final boolean register(final SelectableChannel channel, final EventsHandler handler)
{
return register(channel, handler, IN | OUT | ERR);
}
public final boolean register(final SelectableChannel channel, final int events)
{
return register(channel, globalHandler, events);
}
/**
* Register an ItemHolder for polling on specified events.
*
* @param item the registering item.
* @return true if registered, otherwise false
*/
public final boolean register(final ItemHolder item)
{
return add(null, item);
}
/**
* Unregister a Socket or SelectableChannel for polling on the specified events.
*
* @param socketOrChannel the Socket or SelectableChannel to be unregistered
* @return true if unregistered, otherwise false
* TODO would it be useful to unregister only for specific events ?
*/
public final boolean unregister(final Object socketOrChannel)
{
if (socketOrChannel == null) {
return false;
}
Set items = this.items.remove(socketOrChannel);
boolean rc = items != null;
if (rc) {
all.removeAll(items);
}
return rc;
}
/******************************************************************************/
/* POLLING | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |*/
/******************************************************************************/
/**
* Issue a poll call, using the specified timeout value.
*
* Since ZeroMQ 3.0, the timeout parameter is in milliseconds,
* but prior to this the unit was microseconds.
*
* @param timeout
* the timeout, as per zmq_poll ();
* if -1, it will block indefinitely until an event
* happens; if 0, it will return immediately;
* otherwise, it will wait for at most that many
* milliseconds/microseconds (see above).
*
* @see "http://api.zeromq.org/3-0:zmq-poll"
*
* @return how many objects where signaled by poll ()
*/
public int poll(final long timeout)
{
return poll(timeout, true);
}
/**
* Issue a poll call, using the specified timeout value.
*
* @param timeout the timeout, as per zmq_poll ();
* @param dispatchEvents true to dispatch events using items handler and the global one.
* @see "http://api.zeromq.org/3-0:zmq-poll"
*
* @return how many objects where signaled by poll ()
*/
protected int poll(final long timeout, final boolean dispatchEvents)
{
// get all the raw items
final Collection all = items();
final Set pollItems = new HashSet(all.size());
for (ItemHolder holder : all) {
pollItems.add(holder.item());
}
// polling time
final int rc = poll(selector, timeout, pollItems);
if (!dispatchEvents) {
// raw result
return rc;
}
if (dispatch(all, pollItems.size())) {
// returns event counts after dispatch if everything went fine
return rc;
}
// error in dispatching
return -1;
}
// does the effective polling
protected int poll(final Selector selector, final long tout,
final Collection items)
{
final int size = items.size();
return zmq.ZMQ.poll(selector,
items.toArray(new zmq.PollItem[size]), size,
tout);
}
/**
* Dispatches the polled events.
*
* @param all the items used for dispatching
* @param size the number of items to dispatch
* @return true if correctly dispatched, false in case of error
*/
protected boolean dispatch(final Collection all, int size)
{
ItemHolder[] array = all.toArray(new ItemHolder[all.size()]);
// protected against handlers unregistering during this loop
for (ItemHolder holder : array) {
EventsHandler handler = holder.handler();
if (handler == null) {
handler = globalHandler;
}
if (handler == null) {
// no handler, short-circuit
continue;
}
final zmq.PollItem item = holder.item();
final int events = item.readyOps();
if (events <= 0) {
// no events, short-circuit
continue;
}
final Socket socket = holder.socket();
final SelectableChannel channel = holder.item().getRawSocket();
if (socket != null) {
assert (channel == null);
// dispatch on socket
if (!handler.events(socket, events)) {
return false;
}
}
if (channel != null) {
// dispatch on channel
assert (socket == null);
if (!handler.events(channel, events)) {
return false;
}
}
}
return true;
}
// dispatches all the polled events to their respective handlers
public boolean dispatch()
{
return dispatch(all, all.size());
}
/******************************************************************************/
/*| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | POLLING */
/******************************************************************************/
/**
* Tells if a channel is readable from this poller.
*
* @param channel the channel to ask for.
* @return true if readable, otherwise false
*/
public boolean isReadable(final SelectableChannel channel)
{
return readable((Object) channel);
}
public boolean readable(final SelectableChannel channel)
{
return readable((Object) channel);
}
/**
* Tells if a socket is readable from this poller.
*
* @param socket the socket to ask for.
* @return true if readable, otherwise false
*/
public boolean isReadable(final Socket socket)
{
return readable(socket);
}
public boolean readable(final Socket socket)
{
return readable((Object) socket);
}
// checks for read event
public boolean readable(final Object socketOrChannel)
{
final zmq.PollItem it = filter(socketOrChannel, IN);
if (it == null) {
return false;
}
return it.isReadable();
}
/**
* Tells if a channel is writable from this poller.
*
* @param channel the channel to ask for.
* @return true if writable, otherwise false
*/
public boolean isWritable(final SelectableChannel channel)
{
return writable((Object) channel);
}
public boolean writable(final SelectableChannel channel)
{
return writable((Object) channel);
}
/**
* Tells if a socket is writable from this poller.
*
* @param socket the socket to ask for.
* @return true if writable, otherwise false
*/
public boolean isWritable(final Socket socket)
{
return writable((Object) socket);
}
public boolean writable(final Socket socket)
{
return writable((Object) socket);
}
// checks for write event
public boolean writable(final Object socketOrChannel)
{
final zmq.PollItem it = filter(socketOrChannel, OUT);
if (it == null) {
return false;
}
return it.isWritable();
}
/**
* Tells if a channel is in error from this poller.
*
* @param channel the channel to ask for.
* @return true if in error, otherwise false
*/
public boolean isError(final SelectableChannel channel)
{
return error((Object) channel);
}
public boolean error(final SelectableChannel channel)
{
return error((Object) channel);
}
/**
* Tells if a socket is in error from this poller.
*
* @param socket the socket to ask for.
* @return true if in error, otherwise false
*/
public boolean isError(final Socket socket)
{
return error((Object) socket);
}
public boolean error(final Socket socket)
{
return error((Object) socket);
}
// checks for error event
public boolean error(final Object socketOrChannel)
{
final zmq.PollItem it = filter(socketOrChannel, ERR);
if (it == null) {
return false;
}
return it.isError();
}
/**
* Destroys the poller. Does actually nothing.
*/
@Override
public void close() throws IOException
{
// we didn't create the selector,
// it is not our responsibility to close it.
// selector.close();
}
/**
* Destroys the poller and the associated selector without exception.
*/
public void destroy()
{
try {
close();
}
catch (IOException e) {
e.printStackTrace();
}
}
// selector used for polling
private final Selector selector;
// creator of items
private final ItemCreator creator;
// managed items
private final Map> items;
// all managed items to avoid penalty cost when dispatching
private final Set all;
// TODO set of handlers, each with its specified events?
// optional global events handler
private EventsHandler globalHandler;
// simple creator for poll items
private static class SimpleCreator implements ItemCreator
{
@Override
public ItemHolder create(final Socket socket,
final EventsHandler handler, final int events)
{
return new ZPollItem(socket, handler, events);
}
@Override
public ItemHolder create(final SelectableChannel channel,
final EventsHandler handler, final int events)
{
return new ZPollItem(channel, handler, events);
}
}
// add an item to this poller
protected boolean add(Object socketOrChannel, final ItemHolder holder)
{
if (socketOrChannel == null) {
Socket socket = holder.socket();
SelectableChannel ch = holder.item().getRawSocket();
if (socket == null) {
// not a socket
assert (ch != null);
socketOrChannel = ch;
}
if (ch == null) {
// not a channel
assert (socket != null);
socketOrChannel = socket;
}
}
assert (socketOrChannel != null);
Set holders = items.get(socketOrChannel);
if (holders == null) {
holders = createContainer(1);
items.put(socketOrChannel, holders);
}
final boolean rc = holders.add(holder);
if (rc) {
all.add(holder);
}
return rc;
}
// create the container of holders
protected Set createContainer(int size)
{
return new HashSet(size);
}
// gets all the items of this poller
protected Collection items()
{
return all;
}
// gets all the items of this poller regarding the given input
protected Iterable items(final Object socketOrChannel)
{
final Set set = items.get(socketOrChannel);
if (set == null) {
return Collections.emptySet();
}
return set;
}
// filters items to get the first one matching the criteria, or null if none found
protected zmq.PollItem filter(final Object socketOrChannel, int events)
{
if (socketOrChannel == null) {
return null;
}
final Iterable items = items(socketOrChannel);
for (ItemHolder item : items) {
final zmq.PollItem it = item.item();
if ((it.interestOps() & events) > 0) {
return it;
}
}
return null;
}
}
jeromq-0.3.5/src/main/java/org/zeromq/ZProxy.java 0000664 0000000 0000000 00000112165 12551504772 0021710 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package org.zeromq;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.zeromq.ZActor.Actor;
import org.zeromq.ZAgent.SelectorCreator;
import org.zeromq.ZMQ.Socket;
import zmq.Msg;
import zmq.SocketBase;
/**
* Implementation of a remotely controlled proxy for 0MQ, using {@link ZActor}.
*
* The goals of this implementation are to delegate the creation of sockets
* in a background thread via a callback interface to ensure their correct use
* and to provide ultimately to end-users the following features.
*
* Basic features:
*
*
Remote Control
*
*
Start: if was paused, flushes the pending messages
*
Pause: lets the socket queues accumulate messages according to their types
*
Stop: Shutdowns the proxy, can be restarted
*
Status: Retrieves the status of the proxy
*
Cold Restart: Closes and recreates the connections
*
{@link #restart(ZMsg) Hot Restart}: User-defined behavior with custom messages
*
{@link #configure(ZMsg) Configure}: User-defined behavior with custom messages
*
{@link #command(String, boolean) ...}: Custom commands of your own
*
Exit: Definitive shutdown of the proxy and its control
*
* All the non-custom commands can be performed in asynchronous or synchronous mode.
*
*
*
Proxy mechanism ensured by pluggable pumps
*
*
with built-in low-level {@link ZmqPump} (zmq.ZMQ): useful for performances
*
with built-in high-level {@link ZPump} (ZeroMQ): useful for {@link ZPump.Transformer message transformation}, lower performances
*
with your own-custom proxy pump implementing a {@link Pump 1-method interface}
*
*
*
* You can have all the above non-customizable features in about these lines of code:
*
*
* {@code
final ZProxy.Proxy provider = new ZProxy.SimpleProxy()
{
public Socket create(ZContext ctx, ZProxy.Plug place, Object[] args)
{
assert ("TEST".equals(args[0]);
Socket socket = null;
if (place == ZProxy.Plug.FRONT) {
socket = ctx.createSocket(ZMQ.ROUTER);
}
if (place == ZProxy.Plug.BACK) {
socket = ctx.createSocket(ZMQ.DEALER);
}
return socket;
}
public void configure(Socket socket, ZProxy.Plug place, Object[] args)
{
assert ("TEST".equals(args[0]);
int port = -1;
if (place == ZProxy.Plug.FRONT) {
port = socket.bind("tcp://127.0.0.1:6660");
}
if (place == ZProxy.Plug.BACK) {
port = socket.bind("tcp://127.0.0.1:6661");
}
if (place == ZProxy.Plug.CAPTURE && socket != null) {
socket.bind("tcp://127.0.0.1:4263");
}
}
};
ZProxy proxy = ZProxy.newProxy("ProxyOne", provider, "ABRACADABRA", Arrays.asList("TEST"));
}
*
* Once created, the proxy is not started. You have to perform first a start command on it.
* This choice was made because it is easier for a user to start it with one line of code than for the code to internally handle
* different possible starting states (after all, someone may want the proxy started but paused at first or configured in a specific way?)
* and because the a/sync stuff was funnier. Life is unfair ...
* Or maybe an idea is floating in the air?
*
*
* You can then use it like this:
*
* {@code
final boolean async = false, sync = true;
String status = null;
status = proxy.status();
status = proxy.pause(sync);
status = proxy.start(async);
ZMsg msg = proxy.restart(new ZMsg());
status = proxy.status(async);
status = proxy.stop(sync);
boolean here = proxy.sign();
ZMsg cfg = new ZMsg();
msg.add("CONFIG-1");
ZMsg rcvd = proxy.configure(cfg);
proxy.exit(async);
status = proxy.status(sync);
assert (!proxy.started());
}
*
*
* A {@link #command(Command, boolean) programmatic interface} with enums is also available.
*
*
*/
// Proxy for 0MQ.
public class ZProxy
{
/**
* Possible places for sockets in the proxy.
*/
public static enum Plug
{
FRONT, // The position of the frontend socket.
BACK, // The position of the backend socket.
CAPTURE; // The position of the capture socket.
}
// Contract for socket creation and customizable configuration in proxy threading.
public static interface Proxy
{
/**
* Creates and initializes (bind, options ...) the socket for the given plug in the proxy.
* The proxy will close them afterwards, and the context as well if not provided in the constructor.
* There is no need to keep a reference on the created socket or the context given in parameter.
*
* @param ctx the context used for initialization.
* @param place the position for the future created socket in the proxy.
* @param args the optional array of arguments that has been passed at the creation of the ZProxy.
* @return the created socket. Possibly null only for capture.
*/
Socket create(ZContext ctx, Plug place, Object[] args);
/**
* Configures the given socket.
*
* @param socket the socket to configure
* @param place the position for the socket in the proxy
* @param args the optional array of arguments that has been passed at the creation of the ZProxy.
*/
void configure(Socket socket, Plug place, Object[] args);
/**
* Performs a hot restart of the given socket.
* Usually an unbind/bind but you can use whatever method you like.
*
* @param cfg the custom configuration message sent by the control.
* @param socket the socket to hot restart
* @param place the position for the socket in the proxy
* @param args the optional array of arguments that has been passed at the creation of the ZProxy.
* @return true to perform a cold restart instead, false to do nothing. All the results will be collected from calls for all plugs.
* If any of them returns true, the cold restart is performed.
*/
boolean restart(ZMsg cfg, Socket socket, Plug place, Object[] args);
/**
* Configures the proxy with a custom message.
*
* Note: you need to send one (1) mandatory custom response message with the pipe before the end of this call.
*
* @param pipe the control pipe
* @param cfg the custom configuration message sent by the control
* @param frontend the frontend socket
* @param backend the backend socket
* @param capture the optional capture socket
* @param args the optional array of arguments that has been passed at the creation of the ZProxy.
* @return true to continue the proxy, false to exit
*/
boolean configure(Socket pipe, ZMsg cfg, Socket frontend, Socket backend,
Socket capture, Object[] args);
/**
* Handles a custom command not recognized by the proxy.
*
* Note: you need to send the current state at the end of the call.
*
* @param pipe the control pipe
* @param cmd the unrecognized command
* @param frontend the frontend socket
* @param backend the backend socket
* @param capture the optional capture socket
* @param args the optional array of arguments that has been passed at the creation of the ZProxy.
*
* @return true to continue the proxy, false to exit
*/
boolean custom(Socket pipe, String cmd, Socket frontend, Socket backend, Socket capture, Object[] args);
// this may be useful
public abstract static class SimpleProxy implements Proxy
{
@Override
public boolean restart(ZMsg cfg, Socket socket, Plug place,
Object[] args)
{
return true;
}
@Override
public boolean configure(Socket pipe, ZMsg cfg,
Socket frontend, Socket backend, Socket capture, Object[] args)
{
return true;
}
@Override
public boolean custom(Socket pipe, String cmd, Socket frontend, Socket backend, Socket capture, Object[] args)
{
return true;
}
}
}
/**
* Creates a new proxy in a ZeroMQ way.
* This proxy will be less efficient than the
* {@link #newZProxy(ZContext, String, org.zeromq.ZProxy.Proxy, String, Object...) low-level one}.
*
* @param ctx the context used for the proxy.
* Possibly null, in this case a new context will be created and automatically destroyed afterwards.
* @param name the name of the proxy. Possibly null.
* @param selector the creator of the selector used for the internal polling. Not null.
* @param sockets the sockets creator of the proxy. Not null.
* @param args an optional array of arguments that will be passed at the creation.
*
* @return the created proxy.
*/
// creates a new proxy
public static ZProxy newZProxy(ZContext ctx, String name,
SelectorCreator selector, Proxy sockets, String motdelafin, Object... args)
{
return new ZProxy(ctx, name, selector, sockets, new ZPump(), null, args);
}
public static ZProxy newZProxy(ZContext ctx, String name, Proxy sockets, String motdelafin, Object... args)
{
return new ZProxy(ctx, name, null, sockets, new ZPump(), motdelafin, args);
}
/**
* Creates a new low-level proxy for better performances.
*
* @param ctx the context used for the proxy.
* Possibly null, in this case a new context will be created and automatically destroyed afterwards.
* @param name the name of the proxy. Possibly null.
* @param selector the creator of the selector used for the internal polling. Not null.
* @param sockets the sockets creator of the proxy. Not null.
* @param args an optional array of arguments that will be passed at the creation.
*
* @return the created proxy.
*/
// creates a new low-level proxy
public static ZProxy newProxy(ZContext ctx, String name,
SelectorCreator selector, Proxy sockets, String motdelafin, Object... args)
{
return new ZProxy(ctx, name, selector, sockets, new ZmqPump(), motdelafin, args);
}
public static ZProxy newProxy(ZContext ctx, String name, Proxy sockets, String motdelafin, Object... args)
{
return new ZProxy(ctx, name, null, sockets, new ZmqPump(), motdelafin, args);
}
/**
* Starts the proxy.
*
* @param sync true to read the status in synchronous way, false for asynchronous mode
* @return the read status
*/
public String start(boolean sync)
{
return command(START, sync);
}
/**
* Pauses the proxy.
* A paused proxy will cease processing messages, causing
* them to be queued up and potentially hit the high-water mark on the
* frontend or backend socket, causing messages to be dropped, or writing
* applications to block.
*
* @param sync true to read the status in synchronous way, false for asynchronous mode
* @return the read status
*/
public String pause(boolean sync)
{
return command(PAUSE, sync);
}
/**
* Stops the proxy.
*
* @param sync true to read the status in synchronous way, false for asynchronous mode
* @return the read status
*/
public String stop(boolean sync)
{
return command(STOP, sync);
}
/**
* Sends a command message to the proxy actor.
* Can be useful for programmatic interfaces.
* Does not works with commands {@link #CONFIG CONFIG} and {@link #RESTART RESTART}.
*
* @param command the command to execute.
* @param sync true to read the status in synchronous way, false for asynchronous mode
* @return the read status
*/
public String command(String command, boolean sync)
{
assert (!command.equals(CONFIG));
assert (!command.equals(RESTART));
if (command.equals(STATUS)) {
return status(sync);
}
if (command.equals(EXIT)) {
return exit(sync);
}
// consume the status in the pipe
String status = recvStatus();
if (agent.send(command)) {
// the pipe is refilled
if (sync) {
status(true);
}
}
return status;
}
/**
* Sends a command message to the proxy actor.
* Can be useful for programmatic interfaces.
* Does not works with commands {@link Command#CONFIG CONFIG} and {@link Command#RESTART RESTART}.
*
* @param command the command to execute.
* @param sync true to read the status in synchronous way, false for asynchronous mode
* @return the read state
*/
public State command(Command command, boolean sync)
{
return State.valueOf(command(command.name(), sync));
}
/**
* Sends a command message to the proxy actor.
* Can be useful for programmatic interfaces.
* Works only with commands {@link Command#CONFIG CONFIG} and {@link Command#RESTART RESTART}.
*
* @param command the command to execute.
* @param msg the custom message to transmit.
* @param sync true to read the status in synchronous way, false for asynchronous mode
* @return the response message
*/
public ZMsg command(Command command, ZMsg msg, boolean sync)
{
if (command == Command.CONFIG) {
return configure(msg);
}
if (command == Command.RESTART) {
String status = restart(msg);
msg = new ZMsg();
msg.add(status);
return msg;
}
return null;
}
/**
* Configures the proxy.
* The distant side has to send back one (1) mandatory response message.
*
* @param msg the custom message sent as configuration tip
* @return the mandatory response message of the configuration.
*/
public ZMsg configure(ZMsg msg)
{
msg.addFirst(CONFIG);
if (agent.send(msg)) {
// consume the status in the pipe
recvStatus();
ZMsg reply = agent.recv();
assert (reply != null);
// refill the pipe with status
agent.send(STATUS);
return reply;
}
return null;
}
/**
* Restarts the proxy. Stays alive.
*
* @param hot null to make a cold restart (closing then re-creation of the sockets)
* or a configuration message to perform a configurable hot restart,
*/
public String restart(ZMsg hot)
{
ZMsg msg = new ZMsg();
msg.add(RESTART);
if (hot == null) {
msg.add(Boolean.toString(false));
}
else {
msg.add(Boolean.toString(true));
// FIXME better way to append 1 message into another ?
for (int index = 0; index < hot.size(); ++index) {
ZFrame frame = hot.pop();
msg.add(frame);
}
}
String status = EXITED;
if (agent.send(msg)) {
status = status(false);
}
return status;
}
/**
* Stops the proxy and exits.
*
* @param sync true to read the status in synchronous way, false for asynchronous mode
* @return the read status
*/
public String exit(boolean sync)
{
String status = EXITED;
if (agent.send(EXIT)) {
if (sync) {
return await();
}
status = status(false);
}
return status;
}
// Waits for the completion of this proxy, like in old style.
private String await()
{
String status = status(true);
while (!Thread.currentThread().isInterrupted()) {
if (EXITED.equals(status)) {
break;
}
if (!agent.sign()) {
return EXITED;
}
status = status(false);
}
return status;
}
/**
* Inquires for the status of the proxy.
* This call is synchronous.
*/
public String status()
{
return status(true);
}
/**
* Inquires for the status of the proxy.
*
* @param sync true to read the status in synchronous way, false for asynchronous mode.
* If false, you get the last cached status of the proxy
*/
public String status(boolean sync)
{
String status = recvStatus();
if (agent.send(STATUS) && sync) {
// wait for the response to emulate sync
status = recvStatus();
// AND refill a status
if (!agent.send(STATUS)) {
// TODO and in case of error? Let's handle it with exception for now
throw new RuntimeException("Unable to send the status message");
}
}
return status;
}
// receives the last known state of the proxy
private String recvStatus()
{
if (!agent.sign()) {
return EXITED;
}
// receive the status response
final ZMsg msg = agent.recv();
if (msg == null) {
return EXITED;
}
String status = msg.popString();
msg.destroy();
return status;
}
/**
* Binary inquiry for the status of the proxy.
*/
public boolean isStarted()
{
return started();
}
/**
* Binary inquiry for the status of the proxy.
*/
public boolean started()
{
String status = status(true);
return STARTED.equals(status);
}
// to handle commands in a more java-centric way
public static enum Command
{
START,
PAUSE,
STOP,
RESTART,
EXIT,
STATUS,
CONFIG;
}
// commands for the control pipe
private static final String START = Command.START.name();
private static final String PAUSE = Command.PAUSE.name();
private static final String STOP = Command.STOP.name();
private static final String RESTART = Command.RESTART.name();
private static final String EXIT = Command.EXIT.name();
private static final String STATUS = Command.STATUS.name();
private static final String CONFIG = Command.CONFIG.name();
// to handle states in a more java-centric way
public static enum State
{
ALIVE,
STARTED,
PAUSED,
STOPPED,
EXITED;
}
// state responses from the control pipe
public static final String STARTED = State.STARTED.name();
public static final String PAUSED = State.PAUSED.name();
public static final String STOPPED = State.STOPPED.name();
public static final String EXITED = State.EXITED.name();
// defines the very first time where no command changing the state has been issued
public static final String ALIVE = State.ALIVE.name();
private static final AtomicInteger counter = new AtomicInteger();
// the endpoint to the distant proxy actor
private final ZAgent agent;
/**
* Creates a new unnamed proxy.
*
* @param selector the creator of the selector used for the proxy.
* @param creator the creator of the sockets of the proxy.
*/
public ZProxy(SelectorCreator selector, Proxy creator,
String motdelafin, Object ... args)
{
this(null, null, selector, creator, null, motdelafin, args);
}
/**
* Creates a new named proxy.
*
* @param name the name of the proxy (used in threads naming).
* @param selector the creator of the selector used for the proxy.
* @param creator the creator of the sockets of the proxy.
*/
public ZProxy(String name, SelectorCreator selector,
Proxy creator, String motdelafin, Object... args)
{
this(null, name, selector, creator, null, motdelafin, args);
}
/**
* Creates a new named proxy.
*
* @param ctx the main context used.
* If null, a new context will be created and closed at the stop of the operation.
* If not null, it is the responsibility of the call to close it.
* @param name the name of the proxy (used in threads naming).
* @param selector the creator of the selector used for the proxy.
* @param sockets the creator of the sockets of the proxy.
* @param pump the pump used for the proxy
*/
public ZProxy(ZContext ctx, String name, SelectorCreator selector,
Proxy sockets, Pump pump, String motdelafin, Object... args)
{
super();
// arguments parsing
if (pump == null) {
pump = new ZmqPump();
}
int count = 1;
count += args.length;
Object[] vars = null;
vars = new Object[count];
vars[0] = sockets;
Actor shadow = null;
// copy the arguments and retrieve the last optional shadow given in input
for (int index = 0; index < args.length; ++index) {
Object arg = args[index];
if (arg instanceof Actor) {
shadow = (Actor) arg;
}
vars[index + 1] = arg;
}
// handle the actor
int id = counter.incrementAndGet();
Actor actor = new ProxyActor(name, pump, id);
if (shadow != null) {
actor = new ZActor.Duo(actor, shadow);
}
ZActor zactor = new ZActor(ctx, selector, actor, motdelafin, vars);
agent = zactor.agent(); // the zactor is also its own agent
}
// defines a pump that will flow messages from one socket to another
public static interface Pump
{
/**
* Transfers a message from one source to one destination, with an optional capture.
*
* @param src the plug of the source socket
* @param source the socket where to receive the message from.
* @param capture the optional sockets where to send the message to. Possibly null.
* @param dst the plug of the destination socket
* @param destination the socket where to send the message to.
*
* @return false in case of error or interruption, true if successfully transferred the message
*/
boolean flow(Plug src, Socket source, Socket capture,
Plug dst, Socket destination);
}
// acts in background to proxy messages
private static final class ProxyActor extends ZActor.SimpleActor
{
// the states container of the proxy
private static final class State
{
// are we alive ?
private boolean alive = false;
// are we started ?
private boolean started = false;
// are we paused ?
private boolean paused = false;
// controls creation of a new agent if asked of a cold restart
private boolean restart = false;
// one-shot configuration for hot restart
private ZMsg hot;
}
// the state of the proxy
private final State state = new State();
// used to transfer message from one socket to another
private final Pump transport;
// the nice name of the proxy
private final String name;
// the provider of the sockets
private Proxy provider;
// the sockets creator user arguments
private Object[] args;
private Socket frontend;
private Socket backend;
private Socket capture;
// creates a new Proxy actor.
public ProxyActor(String name, Pump transport, int id)
{
if (name == null) {
// default basic name
this.name = String.format("ZProxy-%sd", id);
}
else {
this.name = name;
}
this.transport = transport;
}
@Override
public String premiere(Socket pipe)
{
return name;
}
// creates the sockets before the start of the proxy
@Override
public List createSockets(ZContext ctx, Object[] args)
{
provider = (Proxy) args[0];
this.args = new Object[args.length - 1];
System.arraycopy(args, 1, this.args, 0, this.args.length);
frontend = provider.create(ctx, Plug.FRONT, this.args);
capture = provider.create(ctx, Plug.CAPTURE, this.args);
backend = provider.create(ctx, Plug.BACK, this.args);
assert (frontend != null);
assert (backend != null);
return Arrays.asList(frontend, backend);
}
@Override
public void start(Socket pipe, List sockets, ZPoller poller)
{
// init the state machine
state.alive = true;
ZMsg reply = new ZMsg();
reply.add(ALIVE);
reply.send(pipe);
}
// Process a control message
@Override
public boolean backstage(Socket pipe, ZPoller poller, int events)
{
assert (state.hot == null);
String cmd = pipe.recvStr();
// a message has been received from the API
if (START.equals(cmd)) {
start(poller);
return status().send(pipe);
}
else if (STOP.equals(cmd)) {
stop(poller);
return status().send(pipe);
}
else if (PAUSE.equals(cmd)) {
pause(poller, true);
return status().send(pipe);
}
else if (RESTART.equals(cmd)) {
String val = pipe.recvStr();
boolean hot = Boolean.parseBoolean(val);
return restart(pipe, poller, hot);
}
else if (STATUS.equals(cmd)) {
return status().send(pipe);
}
else if (CONFIG.equals(cmd)) {
ZMsg cfg = ZMsg.recvMsg(pipe);
boolean rc = provider.configure(pipe, cfg, frontend, backend, capture, args);
cfg.destroy();
return rc;
}
else if (EXIT.equals(cmd)) {
// stops the proxy and the agent.
// the status will be sent at the end of the loop
}
else {
return provider.custom(pipe, cmd, frontend, backend, capture, args);
}
return false;
}
// returns the status
private ZMsg status()
{
ZMsg reply = new ZMsg();
if (!state.alive) {
reply.add(EXITED);
return reply;
}
if (state.started) {
if (state.paused) {
reply.add(PAUSED);
}
else {
reply.add(STARTED);
}
}
else {
reply.add(STOPPED);
}
return reply;
}
// starts the proxy sockets
private boolean start(ZPoller poller)
{
if (!state.started) {
state.started = true;
provider.configure(frontend, Plug.FRONT, args);
provider.configure(backend, Plug.BACK, args);
provider.configure(capture, Plug.CAPTURE, args);
}
if (!state.paused) {
pause(poller, false);
}
return true;
}
// pauses the proxy sockets
private boolean pause(ZPoller poller, boolean pause)
{
state.paused = pause;
if (pause) {
poller.unregister(frontend);
poller.unregister(backend);
// TODO why not a mechanism for eventually flushing the sockets during the pause?
}
else {
poller.register(frontend, ZPoller.POLLIN);
poller.register(backend, ZPoller.POLLIN);
// Now Wait also until there are either requests or replies to process.
}
return true;
}
private boolean stop(ZPoller poller)
{
// restart the actor in stopped state
state.started = false;
// close connections
state.restart = true;
return true;
}
// handles the restart command in both modes
private boolean restart(Socket pipe, ZPoller poller, boolean hot)
{
if (hot) {
assert (provider != null);
state.hot = ZMsg.recvMsg(pipe);
state.restart = true;
// continue with the same agent
return true;
}
else {
state.restart = true;
// stop the loop and restart a new agent
// with the same started state
// the next loop will refill the updated status
return false;
}
}
@Override
public long looping(Socket pipe, ZPoller poller)
{
state.hot = null;
return super.looping(pipe, poller);
}
// a message has been received for the proxy to process
@Override
public boolean stage(Socket socket, Socket pipe, ZPoller poller,
int events)
{
if (socket == frontend) {
// Process a request.
return transport.flow(
Plug.FRONT, frontend,
capture,
Plug.BACK, backend);
}
if (socket == backend) {
// Process a reply.
return transport.flow(
Plug.BACK, backend,
capture,
Plug.FRONT, frontend);
}
return false;
}
@Override
public boolean looped(Socket pipe, ZPoller poller)
{
if (state.restart && state.hot != null) {
// caught the hot restart
ZMsg cfg = state.hot;
state.hot = null;
state.restart = false;
boolean cold;
ZMsg dup = cfg.duplicate();
cold = provider.restart(dup, frontend, Plug.FRONT, this.args);
dup.destroy();
dup = cfg.duplicate();
cold |= provider.restart(dup, backend, Plug.BACK, this.args);
dup.destroy();
dup = cfg.duplicate();
cold |= provider.restart(dup, capture, Plug.CAPTURE, this.args);
dup.destroy();
cfg.destroy();
// we perform a cold restart if the provider says so
state.restart = cold;
}
return true;
}
// called in the proxy thread when it stopped.
@Override
public boolean destroyed(Socket pipe, ZPoller poller)
{
if (capture != null) {
capture.close();
}
if (!state.restart) {
state.alive = false;
status().send(pipe);
}
return state.restart;
}
}
/**
* A pump that reads a message as a whole before transmitting it.
* It offers a way to transform messages for capture and destination.
*/
public static class ZPump implements Pump
{
private static final Identity IDENTITY = new Identity();
// the messages transformer
private final Transformer transformer;
// transforms one message into another
public static interface Transformer
{
/**
* Transforms a ZMsg into another ZMsg.
* Please note that this will be used during the message transfer,
* so lengthy operations will have a cost on performances by definition.
* If you return back another message than the one given in input, then this one has to be destroyed by you.
* @param msg the message to transform
* @param src the source plug
* @param dst the destination plug
* @return the transformed message
*/
ZMsg transform(ZMsg msg, Plug src, Plug dst);
}
private static class Identity implements Transformer
{
@Override
public ZMsg transform(ZMsg msg, Plug src, Plug dst)
{
return msg;
}
}
public ZPump()
{
this(null);
}
public ZPump(Transformer transformer)
{
super();
this.transformer = transformer == null ? IDENTITY : transformer;
}
@Override
public boolean flow(Plug splug, Socket source, Socket capture,
Plug dplug, Socket destination)
{
boolean success = false;
// we read the whole message
ZMsg msg = ZMsg.recvMsg(source);
if (msg == null) {
return false;
}
if (capture != null) {
// Copy transformed message to capture socket if any message
// TODO what if the transformer modifies or destroys the original message ?
ZMsg cpt = transformer.transform(msg, splug, Plug.CAPTURE);
// boolean destroy = !msg.equals(cpt); // TODO ?? which one
boolean destroy = msg != cpt;
success = cpt.send(capture, destroy);
if (!success) {
// not successful, but we can still try to send it to the destination
}
}
ZMsg dst = transformer.transform(msg, splug, dplug);
// we send the whole transformed message
success = dst.send(destination);
// finished
msg.destroy();
return success;
}
}
/**
* A specialized transport for better transmission purposes
* that will send each packets individually instead of the whole message.
*/
private static final class ZmqPump implements Pump
{
// transfers each message as a whole by sending each packet received to the capture socket
@Override
public boolean flow(Plug splug, Socket source, Socket capture,
Plug dplug, Socket destination)
{
boolean rc;
SocketBase src = source.base();
SocketBase dst = destination.base();
SocketBase cpt = capture == null ? null : capture.base();
// we transfer the whole message
while (true) {
// we read the packet
Msg msg = src.recv(0);
if (msg == null) {
return false;
}
long more = src.getSocketOpt(zmq.ZMQ.ZMQ_RCVMORE);
if (more < 0) {
return false;
}
// Copy message to capture socket if any packet
if (cpt != null) {
Msg ctrl = new Msg(msg);
rc = cpt.send(ctrl, more > 0 ? zmq.ZMQ.ZMQ_SNDMORE : 0);
if (!rc) {
// not successful, but we can still try to send it to the destination
}
}
// we send the packet
rc = dst.send(msg, more > 0 ? zmq.ZMQ.ZMQ_SNDMORE : 0);
if (!rc) {
return false;
}
if (more == 0) {
break;
}
}
return true;
}
}
}
jeromq-0.3.5/src/main/java/org/zeromq/ZStar.java 0000664 0000000 0000000 00000050412 12551504772 0021474 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package org.zeromq;
import java.io.IOException;
import java.nio.channels.Selector;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZThread.IAttachedRunnable;
/**
* First implementation for the base of a remotely controlled background service for 0MQ.
*
*
* A side or endpoint designates the same thing: the thread where lives one of the two parts of the system.
*
* A {@link ZStar Star} has 2 sides (with a trial to use theater terms for fun (: and hopefully clarity :)
*
* - the Corbeille side, or control side
*
* This is where one can {@link ZAgent#send(ZMsg) send} and {@link ZAgent#recv() receive} control messages to the underneath star via the ZStar agent.
*
* The ZStar lives on this side and is a way to safely communicate with the distant provided star.
*
* Note: Corbeille is a french word designing the most privileged places in the theater where the King was standing,
* 1st floor, just above the orchestra (Wikipedia...).
*
*
* - the Plateau side, or background side where all the performances are made by the provided star.
*
* The provided star is living on the Plateau.
*
* The Plateau is made of the Stage where effective acting takes place and of the Wings
* where the provided star can perform control decisions to stop or continue the acting.
*
* From this side, the work is done via callbacks using the template-method pattern, applied with interfaces (?)
*
* Communication between the 2 sides is ensured by {@link #pipe() pipes} that SHALL NEVER be mixed between background and control sides.
*
* Instead, each side use its own pipe to communicate with the other one, transmitting only 0MQ messages.
* The main purpose of this class is to ease this separation and to provide contracts, responsibilities and action levers for each side.
*
* For example, instead of using pipe() which is useful to have more control, fast users would want to call {@link #agent()} to get the agent
* or directly call {@link #send(ZMsg)} or {@link #recv()} from the ZStar as the ZStar is itself an agent!
*
* The ZStar takes care of the establishment of the background processing, calling the provided star
* at appropriate times. It can also manage the {@link ZAgent#sign() exited} state on the control side,
* if providing a non-null "Mot de la Fin".
*
* It also takes care of the closing of sockets and context if it had to create one.
*
* A {@link Star star} is basically a contract interface that anyone who uses this ZStar to create a background service SHALL comply to.
*
* For an example of code, please refer to the {@link ZActor} source code.
*
*/
// remote controlled background message processing API for 0MQ.
public class ZStar implements ZAgent
{
/**
* Contract interface when acting in plain sight.
*/
// contract interface for acting with the spot lights on
public static interface Star
{
/**
* Called when the star is in the wings.
* Hint: Can be used to initialize the service, or ...
* Key point: no loop has started already.
*/
void prepare();
/**
* Called when the star in on stage, just before acting.
* Hint: Can be used to poll events or get input/events from other sources, or ...
* Key point: a loop just started.
*
* @return the number of events to process
*/
int breathe();
/**
* Where acting takes place ...
* Hint: Can be used to process the events or input acquired from the previous step, or ...
* Key point: in the middle of a loop.
* Decision: to act on the next loop or not
*
* @param events the number of events to process
* @return true to continue till the end of the act, false to stop loopS here.
*/
boolean act(int events);
/**
* Called as an interval between each act.
* Hint: Can be used to perform decisions to continue next loop or not, or to send computed data to outputs, or ...
* Key point: at the end of a loop.
* Decision: to act on the next loop or not
*
* @return true to continue acting, false to stop loopS here.
*/
boolean entract();
/**
* Does the star want to renew for a new performance ?
* Hint: Can be used to perform decisions to continue looping or not, or to send computed data to outputs, or ...
* Key point: the inner looping mechanism just ended
* Decision: to exit or not
*
* @return true to restart acting, false to leave here
*/
boolean renews();
}
/**
* Utility class with callback for when the Star has finished its performances.
*/
public static interface TimeTaker
{
/**
* Called when the show is finished but no cleaning is still done.
* Useful to make the background thread wait a little bit, for example.
*
* @param ctx the shadow context
*/
void party(ZContext ctx);
}
// party time easily done. Wait for the specified amount of time
public static void party(long time, TimeUnit unit)
{
LockSupport.parkNanos(TimeUnit.NANOSECONDS.convert(time, unit));
}
// contract for a creator of stars
public static interface Fortune extends TimeTaker
{
/**
* This is the grand premiere!
* Called when the star enters the plateau.
* The show is about to begin. Inform the public about that.
* Called before the creation of the first star and its sockets
*
* @param mic the pipe to the Corbeille side
* @param args the arguments passed as parameters of the star constructor
*
* @return the name of the upcoming performance.
*/
String premiere(Socket mic, Object[] args);
/**
* Creates a star.
*
* @param ctx the context used for the creation of the sockets
* @param mic the pipe to the Corbeille side
* @param sel the selector used for polling
* @param count the number of times a star was created.
* @param previous the previous star if any (null at the first creation)
* @param args the arguments passed as parameters of the star constructor
*
* @return a new star is born!
*/
Star create(ZContext ctx, Socket mic, Selector sel, int count, Star previous, Object[] args);
/**
* The show is over.
* Called when the show is over.
*
* @param mic the pipe to the Corbeille side
* @return true to allow to spread the word and close all future communications
*/
boolean interview(Socket mic);
}
/**
* Returns the Corbeille endpoint.
* Can be used to send or receive control messages to the distant star via Backstage.
*
* @return the agent/mailbox used to send and receive control messages to and from the star.
*/
public ZAgent agent()
{
return agent;
}
/**
* Creates a new ZStar.
*
* @param actor the creator of stars on the Plateau
* @param lock the final word used to mark the end of the star. Null to disable this mechanism.
* @param args the optional arguments that will be passed to the distant star
*/
public ZStar(Fortune actor, String lock, Object... args)
{
this(null, new VerySimpleSelectorCreator(), actor, lock, args);
}
/**
* Creates a new ZStar.
*
* @param selector the creator of the selector used on the Plateau.
* @param fortune the creator of stars on the Plateau
* @param motdelafin the final word used to mark the end of the star. Null to disable this mechanism.
* @param args the optional arguments that will be passed to the distant star
*/
public ZStar(SelectorCreator selector, Fortune fortune, String motdelafin, Object... args)
{
this(null, selector, fortune, motdelafin, args);
}
/**
* Creates a new ZStar.
*
* @param context
* the main context used. If null, a new context will be created
* and closed at the stop of the operation.
* If not null, it is the responsibility of the caller to close it.
*
* @param selector the creator of the selector used on the Plateau.
* @param fortune the creator of stars on the Plateau
* @param motdelafin the final word used to mark the end of the star. Null to disable this mechanism.
* @param bags the optional arguments that will be passed to the distant star
*/
public ZStar(final ZContext context, final SelectorCreator selector,
final Fortune fortune, String motdelafin, final Object[] bags)
{
super();
assert (fortune != null);
// entering platform to load trucks
// the story writer
SelectorCreator feather = selector;
if (selector == null) {
// initialize selector
feather = new VerySimpleSelectorCreator();
}
// initialize the context
ZContext chef = context;
ZContext producer = null;
if (chef == null) {
// no context provided, create one
chef = new ZContext();
// it will be destroyed, so this is the main context
producer = chef;
}
// retrieve the last optional set and entourage given in input
Set set = null;
Entourage entourage = null;
for (Object bag : bags) {
if (bag instanceof Set) {
set = (Set) bag;
}
if (bag instanceof Entourage) {
entourage = (Entourage) bag;
}
}
if (set == null) {
set = new SimpleSet();
}
final List train = new ArrayList(6 + bags.length);
train.add(set);
train.add(fortune);
train.add(feather);
train.add(producer);
train.add(entourage);
train.add(motdelafin);
// 6 mandatory wagons
train.addAll(Arrays.asList(bags));
// now going to the plateau
Socket phone = ZThread.fork(chef, new Plateau(), train.toArray());
agent = agent(phone, motdelafin);
}
// communicating agent with the star for the Corbeille side
private final ZAgent agent;
/**
* Creates a new agent for the star.
*
* This method is called in the constructor so don't rely on private members to do the job.
* Apart from that, it is the last call so can be safely overridden from the ZStar point-of-view
* BUT if you don't make it final, one of your subclass could make you misery...
*
* @param phone the socket used to communicate with the star
* @param secret the specific keyword indicating the death of the star and locking the agent. Null to override the lock mechanism.
* @return the newly created agent for the star.
*/
protected ZAgent agent(Socket phone, String secret)
{
return ZAgent.Creator.create(phone, secret);
}
// the plateau where the acting will take place (stage and backstage), or
// the forked runnable containing the loop processing all messages in the background
private static final class Plateau implements IAttachedRunnable
{
private static final AtomicInteger shows = new AtomicInteger();
// id if unnamed
private final int number = shows.incrementAndGet();
@Override
public void run(final Object[] train,
final ZContext chef,
final Socket mic)
{
final int mandat = 6;
// end of a trip can be a bit messy...
Fortune star = (Fortune) train[1];
final Entourage entourage = (Entourage) train[4];
final ZContext producer = (ZContext) train[3];
final SelectorCreator feather = (SelectorCreator) train[2];
final Set set = (Set) train[0];
// the word informing the world that the plateau is closed and the star vanished
final String gossip = (String) train[5];
// prune our mandatory transit variables from the arguments
final Object[] bags = new Object[train.length - mandat];
System.arraycopy(train, mandat, bags, 0, bags.length);
// leaving unloaded platform
if (entourage != null) {
entourage.breakaleg(chef, star, mic, bags);
}
Selector story = null;
// now entering artistic zone
try {
// create the selector used for polling operations
story = feather.create();
// Premiere !
String name = star.premiere(mic, bags);
// put the name of the performance on the front door with lightnings
set.lights(name, number);
// star is entering the wings
showMustGoOn(chef, set, story, mic, star, bags);
// star is leaving the plateau
}
catch (IOException e) {
// Who stole the story? There is no play if there is no story! C'est un scandale!
e.printStackTrace();
// TODO enhance error
}
finally {
// star is interviewed about this event
boolean tell = star.interview(mic);
if (tell && gossip != null) {
// inform the Corbeille side of the future closing of the plateau and the vanishing of the star
mic.send(gossip);
}
// we are not in a hurry at this point when cleaning up the remains of a good show ...
star.party(chef);
star = null;
if (entourage != null) {
entourage.party(chef);
}
// Sober again ...
// show is over, time to close
chef.close();
if (producer != null) {
// this is a self-generated context, destroy it
producer.close();
}
try {
feather.destroy(story);
}
catch (IOException e) {
// really ?
e.printStackTrace();
}
}
}
/******************************************************************************/
/* TAP TAP TAP | | TAP | | TAP | | TAP | | | | | | | | | | | | | | | | | | | |*/
/******************************************************************************/
// starts the performance
private void showMustGoOn(final ZContext chef, final Set set, final Selector story,
final Socket phone, final Fortune fortune, final Object[] bags)
{
int shows = 0;
/** on the spot lights, the star in only an actor **/
Star actor = null;
/** double-while-loop enables the restarting of a new star for the same acting on the same stage **/
/// so existing sockets can be closed and recreated in order to perform a cold restart or a stop **/
do {
actor = fortune.create(chef, phone, story, shows++, actor, bags);
/** a new star is born! And an acting one! **/
actor.prepare();
/** actor is leaving the wings **/
while (!set.fire()) {
/** actor decides when the act will begin **/
int events = actor.breathe();
/** perform a new act of the show **/
if (!actor.act(events)) {
// Context has been shut down
break;
}
/** end of the act, back to the wings **/
if (!actor.entract()) {
// star has decided to stop acting
break;
}
}
}
while (actor.renews());
// star is leaving the Plateau and the show
}
/******************************************************************************/
/* | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |*/
/******************************************************************************/
// NB: never use green color on the stage floor of a french theater. Or something bad will happen...
}
@Override
public ZMsg recv()
{
return agent.recv();
}
@Override
public ZMsg recv(boolean wait)
{
return agent.recv(wait);
}
@Override
public boolean send(ZMsg message)
{
return agent.send(message);
}
@Override
public boolean send(ZMsg msg, boolean destroy)
{
return agent.send(msg, destroy);
}
@Override
public boolean send(String word)
{
return agent.send(word);
}
@Override
public boolean send(String word, boolean more)
{
return agent.send(word, more);
}
@Override
public Socket pipe()
{
return agent.pipe();
}
@Override
public boolean sign()
{
return agent.sign();
}
@Override
public void nova()
{
agent.nova();
}
public static interface Set
{
/**
* Puts the performance name on the front door with big lights.
* @param name the name of the performance.
* @param id the performance number.
*/
void lights(String name, int id);
/**
* Is the set on fire ?
* @return true if it is time to leave the place.
*/
boolean fire();
}
public static class SimpleSet implements Set
{
@Override
public boolean fire()
{
return Thread.currentThread().isInterrupted();
}
@Override
public void lights(String name, int id)
{
if (name == null) {
name = createDefaultName("Star-%d", id);
}
Thread.currentThread().setName(name);
}
public static String createDefaultName(final String format, final int id)
{
return String.format(format, id);
}
}
/**
* Utility class with calls surrounding the execution of the Star.
*/
public static interface Entourage extends TimeTaker
{
/**
* Called when the show is about to start.
* Can be a useful point in the whole process from time to time.
*
* @param ctx the context provided in the creation step
* @param fortune the creator of stars
* @param phone the socket used to communicate with the Agent
* @param bags the optional arguments that were passed at the creation
*/
void breakaleg(ZContext ctx, Fortune fortune, Socket phone, Object[] bags);
// well ...
}
}
jeromq-0.3.5/src/main/java/org/zeromq/ZThread.java 0000664 0000000 0000000 00000007245 12551504772 0022000 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package org.zeromq;
import org.zeromq.ZMQ.Socket;
public class ZThread
{
private ZThread()
{
}
public interface IAttachedRunnable
{
public void run(Object[] args, ZContext ctx, Socket pipe);
}
public interface IDetachedRunnable
{
public void run(Object[] args);
}
private static class ShimThread extends Thread
{
private ZContext ctx;
private IAttachedRunnable attachedRunnable;
private IDetachedRunnable detachedRunnable;
private Object[] args;
private Socket pipe;
protected ShimThread(ZContext ctx, IAttachedRunnable runnable, Object [] args, Socket pipe)
{
assert (ctx != null);
assert (pipe != null);
assert (runnable != null);
this.ctx = ctx;
this.attachedRunnable = runnable;
this.args = args;
this.pipe = pipe;
}
public ShimThread(IDetachedRunnable runnable, Object[] args)
{
assert (runnable != null);
this.detachedRunnable = runnable;
this.args = args;
}
@Override
public void run()
{
if (attachedRunnable != null) {
attachedRunnable.run(args, ctx, pipe);
ctx.destroy();
}
else {
detachedRunnable.run(args);
}
}
}
// --------------------------------------------------------------------------
// Create a detached thread. A detached thread operates autonomously
// and is used to simulate a separate process. It gets no ctx, and no
// pipe.
public static void start(IDetachedRunnable runnable, Object ... args)
{
// Prepare child thread
Thread shim = new ShimThread(runnable, args);
shim.setDaemon(true);
shim.start();
}
// --------------------------------------------------------------------------
// Create an attached thread. An attached thread gets a ctx and a PAIR
// pipe back to its parent. It must monitor its pipe, and exit if the
// pipe becomes unreadable. Returns pipe, or null if there was an error.
public static Socket fork(ZContext ctx, IAttachedRunnable runnable, Object ... args)
{
Socket pipe = ctx.createSocket(ZMQ.PAIR);
if (pipe != null) {
pipe.bind(String.format("inproc://zctx-pipe-%d", pipe.hashCode()));
}
else {
return null;
}
// Connect child pipe to our pipe
ZContext ccontext = ZContext.shadow(ctx);
Socket cpipe = ccontext.createSocket(ZMQ.PAIR);
if (cpipe == null) {
return null;
}
cpipe.connect(String.format("inproc://zctx-pipe-%d", pipe.hashCode()));
// Prepare child thread
Thread shim = new ShimThread(ccontext, runnable, args, cpipe);
shim.start();
return pipe;
}
}
jeromq-0.3.5/src/main/java/zmq/ 0000775 0000000 0000000 00000000000 12551504772 0016267 5 ustar 00root root 0000000 0000000 jeromq-0.3.5/src/main/java/zmq/Address.java 0000664 0000000 0000000 00000005522 12551504772 0020523 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.net.Inet6Address;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
public class Address
{
public interface IZAddress
{
String toString();
void resolve(String name, boolean ip4only);
SocketAddress address();
};
private final String protocol;
private final String address;
private final boolean ipv4only;
private IZAddress resolved;
public Address(final String protocol, final String address, final boolean ipv4only)
{
this.protocol = protocol;
this.address = address;
this.ipv4only = ipv4only;
resolved = null;
}
public Address(SocketAddress socketAddress)
{
InetSocketAddress sockAddr = (InetSocketAddress) socketAddress;
this.address = sockAddr.getAddress().getHostAddress() + ":" + sockAddr.getPort();
protocol = "tcp";
resolved = null;
ipv4only = !(sockAddr.getAddress() instanceof Inet6Address);
}
@Override
public String toString()
{
if (protocol.equals("tcp") && isResolved()) {
return resolved.toString();
}
else if (protocol.equals("ipc") && isResolved()) {
return resolved.toString();
}
else if (!protocol.isEmpty() && !address.isEmpty()) {
return protocol + "://" + address;
}
else {
return "";
}
}
public String protocol()
{
return protocol;
}
public String address()
{
return address;
}
public IZAddress resolved()
{
return resolved;
}
public boolean isResolved()
{
return resolved != null;
}
public boolean resolve()
{
if (protocol.equals("tcp")) {
resolved = new TcpAddress();
resolved.resolve(address, ipv4only);
return true;
}
else if (protocol.equals("ipc")) {
resolved = new IpcAddress();
resolved.resolve(address, true);
return true;
}
else {
return false;
}
}
}
jeromq-0.3.5/src/main/java/zmq/Blob.java 0000664 0000000 0000000 00000003114 12551504772 0020007 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.util.Arrays;
public class Blob
{
private final byte[] buf;
private Blob(byte[] data)
{
buf = data;
}
public static Blob createBlob(byte[] data, boolean copy)
{
if (copy) {
byte[] b = new byte[data.length];
System.arraycopy(data, 0, b, 0, data.length);
return new Blob(b);
}
else {
return new Blob(data);
}
}
public int size()
{
return buf.length;
}
public byte[] data()
{
return buf;
}
@Override
public boolean equals(Object t)
{
if (t instanceof Blob) {
return Arrays.equals(buf, ((Blob) t).buf);
}
return false;
}
@Override
public int hashCode()
{
return Arrays.hashCode(buf);
}
}
jeromq-0.3.5/src/main/java/zmq/Clock.java 0000664 0000000 0000000 00000002734 12551504772 0020173 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
public class Clock
{
// TSC timestamp of when last time measurement was made.
// private long last_tsc;
// Physical time corresponding to the TSC above (in milliseconds).
// private long last_time;
private Clock()
{
}
// High precision timestamp.
public static long nowUS()
{
return System.nanoTime() * 1000L;
}
// Low precision timestamp. In tight loops generating it can be
// 10 to 100 times faster than the high precision timestamp.
public static long nowMS()
{
return System.currentTimeMillis();
}
// CPU's timestamp counter. Returns 0 if it's not available.
public static long rdtsc()
{
return 0;
}
}
jeromq-0.3.5/src/main/java/zmq/Command.java 0000664 0000000 0000000 00000006611 12551504772 0020514 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
// This structure defines the commands that can be sent between threads.
class Command
{
// Object to process the command.
private final ZObject destination;
private final Type type;
public enum Type {
// Sent to I/O thread to let it know that it should
// terminate itself.
STOP,
// Sent to I/O object to make it register with its I/O thread
PLUG,
// Sent to socket to let it know about the newly created object.
OWN,
// Attach the engine to the session. If engine is NULL, it informs
// session that the connection have failed.
ATTACH,
// Sent from session to socket to establish pipe(s) between them.
// Caller have used inc_seqnum beforehand sending the command.
BIND,
// Sent by pipe writer to inform dormant pipe reader that there
// are messages in the pipe.
ACTIVATE_READ,
// Sent by pipe reader to inform pipe writer about how many
// messages it has read so far.
ACTIVATE_WRITE,
// Sent by pipe reader to writer after creating a new inpipe.
// The parameter is actually of type pipe_t::upipe_t, however,
// its definition is private so we'll have to do with void*.
HICCUP,
// Sent by pipe reader to pipe writer to ask it to terminate
// its end of the pipe.
PIPE_TERM,
// Pipe writer acknowledges pipe_term command.
PIPE_TERM_ACK,
// Sent by I/O object ot the socket to request the shutdown of
// the I/O object.
TERM_REQ,
// Sent by socket to I/O object to start its shutdown.
TERM,
// Sent by I/O object to the socket to acknowledge it has
// shut down.
TERM_ACK,
// Transfers the ownership of the closed socket
// to the reaper thread.
REAP,
// Closed socket notifies the reaper that it's already deallocated.
REAPED,
// Sent by reaper thread to the term thread when all the sockets
// are successfully deallocated.
DONE
}
Object arg;
public Command(ZObject destination, Type type)
{
this(destination, type, null);
}
public Command(ZObject destination, Type type, Object arg)
{
this.destination = destination;
this.type = type;
this.arg = arg;
}
public ZObject destination()
{
return destination;
}
public Type type()
{
return type;
}
@Override
public String toString()
{
return super.toString() + "[" + type + ", " + destination + "]";
}
}
jeromq-0.3.5/src/main/java/zmq/Config.java 0000664 0000000 0000000 00000006473 12551504772 0020351 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
public enum Config
{
// Number of new messages in message pipe needed to trigger new memory
// allocation. Setting this parameter to 256 decreases the impact of
// memory allocation by approximately 99.6%
MESSAGE_PIPE_GRANULARITY (256),
// Commands in pipe per allocation event.
COMMAND_PIPE_GRANULARITY (16),
// Determines how often does socket poll for new commands when it
// still has unprocessed messages to handle. Thus, if it is set to 100,
// socket will process 100 inbound messages before doing the poll.
// If there are no unprocessed messages available, poll is done
// immediately. Decreasing the value trades overall latency for more
// real-time behaviour (less latency peaks).
INBOUND_POLL_RATE (100),
// Maximal batching size for engines with receiving functionality.
// So, if there are 10 messages that fit into the batch size, all of
// them may be read by a single 'recv' system call, thus avoiding
// unnecessary network stack traversals.
IN_BATCH_SIZE (8192),
// Maximal batching size for engines with sending functionality.
// So, if there are 10 messages that fit into the batch size, all of
// them may be written by a single 'send' system call, thus avoiding
// unnecessary network stack traversals.
OUT_BATCH_SIZE (8192),
// Maximal delta between high and low watermark.
MAX_WM_DELTA (1024),
// Maximum number of events the I/O thread can process in one go.
MAX_IO_EVENTS (256),
// Maximal delay to process command in API thread (in CPU ticks).
// 3,000,000 ticks equals to 1 - 2 milliseconds on current CPUs.
// Note that delay is only applied when there is continuous stream of
// messages to process. If not so, commands are processed immediately.
MAX_COMMAND_DELAY (3000000),
// Low-precision clock precision in CPU ticks. 1ms. Value of 1000000
// should be OK for CPU frequencies above 1GHz. If should work
// reasonably well for CPU frequencies above 500MHz. For lower CPU
// frequencies you may consider lowering this value to get best
// possible latencies.
CLOCK_PRECISION (1000000),
// Maximum transport data unit size for PGM (TPDU).
PGM_MAX_TPDU (1500),
// On some OSes the signaler has to be emulated using a TCP
// connection. In such cases following port is used.
SIGNALER_PORT (5905);
private final int value;
private Config(int value)
{
this.value = value;
}
public int getValue()
{
return value;
}
}
jeromq-0.3.5/src/main/java/zmq/Ctx.java 0000664 0000000 0000000 00000033610 12551504772 0017673 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//Context object encapsulates all the global state associated with
// the library.
public class Ctx
{
// Information associated with inproc endpoint. Note that endpoint options
// are registered as well so that the peer can access them without a need
// for synchronisation, handshaking or similar.
static class Endpoint
{
public final SocketBase socket;
public final Options options;
public Endpoint(SocketBase socket, Options options)
{
this.socket = socket;
this.options = options;
}
}
// Used to check whether the object is a context.
private int tag;
// Sockets belonging to this context. We need the list so that
// we can notify the sockets when zmq_term() is called. The sockets
// will return ETERM then.
private final List sockets;
// List of unused thread slots.
private final Deque emptySlots;
// If true, init has been called but no socket has been created
// yet. Launching of I/O threads is delayed.
private AtomicBoolean starting = new AtomicBoolean(true);
// If true, zmq_term was already called.
private boolean terminating;
// Synchronisation of accesses to global slot-related data:
// sockets, emptySlots, terminating. It also synchronises
// access to zombie sockets as such (as opposed to slots) and provides
// a memory barrier to ensure that all CPU cores see the same data.
private final Lock slotSync;
// The reaper thread.
private Reaper reaper;
// I/O threads.
private final List ioThreads;
// Array of pointers to mailboxes for both application and I/O threads.
private int slotCount;
private Mailbox[] slots;
// Mailbox for zmq_term thread.
private final Mailbox termMailbox;
// List of inproc endpoints within this context.
private final Map endpoints;
// Synchronisation of access to the list of inproc endpoints.
private final Lock endpointsSync;
// Maximum socket ID.
private static AtomicInteger maxSocketId = new AtomicInteger(0);
// Maximum number of sockets that can be opened at the same time.
private int maxSockets;
// Number of I/O threads to launch.
private int ioThreadCount;
// Does context wait (possibly forever) on termination?
private boolean blocky;
// Synchronisation of access to context options.
private final Lock optSync;
public static final int TERM_TID = 0;
public static final int REAPER_TID = 1;
public Ctx()
{
tag = 0xabadcafe;
terminating = false;
reaper = null;
slotCount = 0;
slots = null;
maxSockets = ZMQ.ZMQ_MAX_SOCKETS_DFLT;
ioThreadCount = ZMQ.ZMQ_IO_THREADS_DFLT;
blocky = true;
slotSync = new ReentrantLock();
endpointsSync = new ReentrantLock();
optSync = new ReentrantLock();
termMailbox = new Mailbox("terminater");
emptySlots = new ArrayDeque();
ioThreads = new ArrayList();
sockets = new ArrayList();
endpoints = new HashMap();
}
private void destroy() throws IOException
{
for (IOThread it : ioThreads) {
it.stop();
}
for (IOThread it : ioThreads) {
it.close();
}
if (reaper != null) {
reaper.close();
}
termMailbox.close();
tag = 0xdeadbeef;
}
// Returns false if object is not a context.
public boolean checkTag()
{
return tag == 0xabadcafe;
}
// This function is called when user invokes zmq_term. If there are
// no more sockets open it'll cause all the infrastructure to be shut
// down. If there are open sockets still, the deallocation happens
// after the last one is closed.
public void terminate()
{
tag = 0xdeadbeef;
if (!starting.get()) {
slotSync.lock();
try {
// Check whether termination was already underway, but interrupted and now
// restarted.
boolean restarted = terminating;
terminating = true;
// First attempt to terminate the context.
if (!restarted) {
// First send stop command to sockets so that any blocking calls
// can be interrupted. If there are no sockets we can ask reaper
// thread to stop.
for (SocketBase socket : sockets) {
socket.stop();
}
if (sockets.isEmpty()) {
reaper.stop();
}
}
}
finally {
slotSync.unlock();
}
// Wait till reaper thread closes all the sockets.
Command cmd = termMailbox.recv(-1);
if (cmd == null) {
throw new IllegalStateException();
}
assert (cmd.type() == Command.Type.DONE);
slotSync.lock();
try {
assert (sockets.isEmpty());
}
finally {
slotSync.unlock();
}
}
// Deallocate the resources.
try {
destroy();
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
public boolean set(int option, int optval)
{
if (option == ZMQ.ZMQ_MAX_SOCKETS && optval >= 1) {
optSync.lock();
try {
maxSockets = optval;
}
finally {
optSync.unlock();
}
}
else
if (option == ZMQ.ZMQ_IO_THREADS && optval >= 0) {
optSync.lock();
try {
ioThreadCount = optval;
}
finally {
optSync.unlock();
}
}
else
if (option == ZMQ.ZMQ_BLOCKY && optval >= 0) {
optSync.lock();
try {
blocky = (optval != 0);
}
finally {
optSync.unlock();
}
}
else {
return false;
}
return true;
}
public int get(int option)
{
int rc = 0;
if (option == ZMQ.ZMQ_MAX_SOCKETS) {
rc = maxSockets;
}
else if (option == ZMQ.ZMQ_IO_THREADS) {
rc = ioThreadCount;
}
else if (option == ZMQ.ZMQ_BLOCKY) {
rc = blocky ? 1 : 0;
}
else {
throw new IllegalArgumentException("option = " + option);
}
return rc;
}
public SocketBase createSocket(int type)
{
SocketBase s = null;
slotSync.lock();
try {
if (starting.compareAndSet(true, false)) {
// Initialize the array of mailboxes. Additional three slots are for
// zmq_term thread and reaper thread.
int mazmq;
int ios;
optSync.lock();
try {
mazmq = maxSockets;
ios = ioThreadCount;
}
finally {
optSync.unlock();
}
slotCount = mazmq + ios + 2;
slots = new Mailbox[slotCount];
//alloc_assert (slots);
// Initialize the infrastructure for zmq_term thread.
slots[TERM_TID] = termMailbox;
// Create the reaper thread.
reaper = new Reaper(this, REAPER_TID);
//alloc_assert (reaper);
slots[REAPER_TID] = reaper.getMailbox();
reaper.start();
// Create I/O thread objects and launch them.
for (int i = 2; i != ios + 2; i++) {
IOThread ioThread = new IOThread(this, i);
//alloc_assert (io_thread);
ioThreads.add(ioThread);
slots[i] = ioThread.getMailbox();
ioThread.start();
}
// In the unused part of the slot array, create a list of empty slots.
for (int i = (int) slotCount - 1;
i >= (int) ios + 2; i--) {
emptySlots.add(i);
slots[i] = null;
}
}
// Once zmq_term() was called, we can't create new sockets.
if (terminating) {
throw new ZError.CtxTerminatedException();
}
// If maxSockets limit was reached, return error.
if (emptySlots.isEmpty()) {
throw new IllegalStateException("EMFILE");
}
// Choose a slot for the socket.
int slot = emptySlots.pollLast();
// Generate new unique socket ID.
int sid = maxSocketId.incrementAndGet();
// Create the socket and register its mailbox.
s = SocketBase.create(type, this, slot, sid);
if (s == null) {
emptySlots.addLast(slot);
return null;
}
sockets.add(s);
slots[slot] = s.getMailbox();
}
finally {
slotSync.unlock();
}
return s;
}
public void destroySocket(SocketBase socket)
{
slotSync.lock();
// Free the associated thread slot.
try {
int tid = socket.getTid();
emptySlots.add(tid);
slots[tid] = null;
// Remove the socket from the list of sockets.
sockets.remove(socket);
// If zmq_term() was already called and there are no more socket
// we can ask reaper thread to terminate.
if (terminating && sockets.isEmpty()) {
reaper.stop();
}
}
finally {
slotSync.unlock();
}
}
// Returns reaper thread object.
ZObject getReaper()
{
return reaper;
}
// Send command to the destination thread.
void sendCommand(int tid, final Command command)
{
slots[tid].send(command);
}
// Returns the I/O thread that is the least busy at the moment.
// Affinity specifies which I/O threads are eligible (0 = all).
// Returns NULL if no I/O thread is available.
IOThread chooseIoThread(long affinity)
{
if (ioThreads.isEmpty()) {
return null;
}
// Find the I/O thread with minimum load.
int minLoad = -1;
IOThread selectedIoThread = null;
for (int i = 0; i != ioThreads.size(); i++) {
if (affinity == 0 || (affinity & (1L << i)) > 0) {
int load = ioThreads.get(i).getLoad();
if (selectedIoThread == null || load < minLoad) {
minLoad = load;
selectedIoThread = ioThreads.get(i);
}
}
}
return selectedIoThread;
}
// Management of inproc endpoints.
boolean registerEndpoint(String addr, Endpoint endpoint)
{
endpointsSync.lock();
Endpoint inserted = null;
try {
inserted = endpoints.put(addr, endpoint);
}
finally {
endpointsSync.unlock();
}
if (inserted != null) {
return false;
}
return true;
}
void unregisterEndpoints(SocketBase socket)
{
endpointsSync.lock();
try {
Iterator> it = endpoints.entrySet().iterator();
while (it.hasNext()) {
Entry e = it.next();
if (e.getValue().socket == socket) {
it.remove();
}
}
}
finally {
endpointsSync.unlock();
}
}
Endpoint findEndpoint(String addr)
{
Endpoint endpoint = null;
endpointsSync.lock();
try {
endpoint = endpoints.get(addr);
if (endpoint == null) {
//ZError.errno(ZError.ECONNREFUSED);
return new Endpoint(null, new Options());
}
// Increment the command sequence number of the peer so that it won't
// get deallocated until "bind" command is issued by the caller.
// The subsequent 'bind' has to be called with inc_seqnum parameter
// set to false, so that the seqnum isn't incremented twice.
endpoint.socket.incSeqnum();
}
finally {
endpointsSync.unlock();
}
return endpoint;
}
}
jeromq-0.3.5/src/main/java/zmq/Dealer.java 0000664 0000000 0000000 00000007236 12551504772 0020336 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
public class Dealer extends SocketBase
{
public static class DealerSession extends SessionBase
{
public DealerSession(IOThread ioThread, boolean connect,
SocketBase socket, final Options options,
final Address addr)
{
super(ioThread, connect, socket, options, addr);
}
}
// Messages are fair-queued from inbound pipes. And load-balanced to
// the outbound pipes.
private final FQ fq;
private final LB lb;
// Have we prefetched a message.
private boolean prefetched;
private Msg prefetchedMsg;
// Holds the prefetched message.
public Dealer(Ctx parent, int tid, int sid)
{
super(parent, tid, sid);
prefetched = false;
options.type = ZMQ.ZMQ_DEALER;
fq = new FQ();
lb = new LB();
// TODO: Uncomment the following line when DEALER will become true DEALER
// rather than generic dealer socket.
// If the socket is closing we can drop all the outbound requests. There'll
// be noone to receive the replies anyway.
// options.delayOnClose = false;
options.recvIdentity = true;
}
@Override
protected void xattachPipe(Pipe pipe, boolean icanhasall)
{
assert (pipe != null);
fq.attach(pipe);
lb.attach(pipe);
}
@Override
protected boolean xsend(Msg msg)
{
return lb.send(msg, errno);
}
@Override
protected Msg xrecv()
{
return xxrecv();
}
private Msg xxrecv()
{
Msg msg = null;
// If there is a prefetched message, return it.
if (prefetched) {
msg = prefetchedMsg;
prefetched = false;
prefetchedMsg = null;
return msg;
}
// DEALER socket doesn't use identities. We can safely drop it and
while (true) {
msg = fq.recv(errno);
if (msg == null) {
return null;
}
if ((msg.flags() & Msg.IDENTITY) == 0) {
break;
}
}
return msg;
}
@Override
protected boolean xhasIn()
{
// We may already have a message pre-fetched.
if (prefetched) {
return true;
}
// Try to read the next message to the pre-fetch buffer.
prefetchedMsg = xxrecv();
if (prefetchedMsg == null) {
return false;
}
prefetched = true;
return true;
}
@Override
protected boolean xhasOut()
{
return lb.hasOut();
}
@Override
protected void xreadActivated(Pipe pipe)
{
fq.activated(pipe);
}
@Override
protected void xwriteActivated(Pipe pipe)
{
lb.activated(pipe);
}
@Override
protected void xpipeTerminated(Pipe pipe)
{
fq.terminated(pipe);
lb.terminated(pipe);
}
}
jeromq-0.3.5/src/main/java/zmq/Decoder.java 0000664 0000000 0000000 00000013203 12551504772 0020476 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.nio.ByteBuffer;
// Helper base class for decoders that know the amount of data to read
// in advance at any moment. Knowing the amount in advance is a property
// of the protocol used. 0MQ framing protocol is based size-prefixed
// paradigm, which qualifies it to be parsed by this class.
// On the other hand, XML-based transports (like XMPP or SOAP) don't allow
// for knowing the size of data to read in advance and should use different
// decoding algorithms.
//
// This class implements the state machine that parses the incoming buffer.
// Derived class should implement individual state machine actions.
public class Decoder extends DecoderBase
{
private static final int ONE_BYTE_SIZE_READY = 0;
private static final int EIGHT_BYTE_SIZE_READY = 1;
private static final int FLAGS_READY = 2;
private static final int MESSAGE_READY = 3;
private final byte[] tmpbuf;
private Msg inProgress;
private final long maxmsgsize;
private IMsgSink msgSink;
public Decoder(int bufsize, long maxmsgsize)
{
super(bufsize);
this.maxmsgsize = maxmsgsize;
tmpbuf = new byte[8];
// At the beginning, read one byte and go to oneByteSizeReady state.
nextStep(tmpbuf, 1, ONE_BYTE_SIZE_READY);
}
// Set the receiver of decoded messages.
@Override
public void setMsgSink(IMsgSink msgSink)
{
this.msgSink = msgSink;
}
@Override
protected boolean next()
{
switch(state()) {
case ONE_BYTE_SIZE_READY:
return oneByteSizeReady();
case EIGHT_BYTE_SIZE_READY:
return eightByteSizeReady();
case FLAGS_READY:
return flagsReady();
case MESSAGE_READY:
return messageReady();
default:
return false;
}
}
private boolean oneByteSizeReady()
{
// First byte of size is read. If it is 0xff(-1 for java byte) read 8-byte size.
// Otherwise allocate the buffer for message data and read the
// message data into it.
byte first = tmpbuf[0];
if (first == -1) {
nextStep(tmpbuf, 8, EIGHT_BYTE_SIZE_READY);
}
else {
// There has to be at least one byte (the flags) in the message).
if (first == 0) {
decodingError();
return false;
}
int size = (int) first;
if (size < 0) {
size = (0xFF) & first;
}
// inProgress is initialised at this point so in theory we should
// close it before calling msgInitWithSize, however, it's a 0-byte
// message and thus we can treat it as uninitialised...
if (maxmsgsize >= 0 && (long) (size - 1) > maxmsgsize) {
decodingError();
return false;
}
else {
inProgress = new Msg(size - 1);
}
nextStep(tmpbuf, 1, FLAGS_READY);
}
return true;
}
private boolean eightByteSizeReady()
{
// 8-byte payload length is read. Allocate the buffer
// for message body and read the message data into it.
final long payloadLength = ByteBuffer.wrap(tmpbuf).getLong();
// There has to be at least one byte (the flags) in the message).
if (payloadLength <= 0) {
decodingError();
return false;
}
// Message size must not exceed the maximum allowed size.
if (maxmsgsize >= 0 && payloadLength - 1 > maxmsgsize) {
decodingError();
return false;
}
// Message size must fit within range of size_t data type.
if (payloadLength - 1 > Integer.MAX_VALUE) {
decodingError();
return false;
}
final int msgSize = (int) (payloadLength - 1);
// inProgress is initialized at this point so in theory we should
// close it before calling init_size, however, it's a 0-byte
// message and thus we can treat it as uninitialized...
inProgress = new Msg(msgSize);
nextStep(tmpbuf, 1, FLAGS_READY);
return true;
}
private boolean flagsReady()
{
// Store the flags from the wire into the message structure.
int first = tmpbuf[0];
inProgress.setFlags(first & Msg.MORE);
nextStep(inProgress,
MESSAGE_READY);
return true;
}
private boolean messageReady()
{
// Message is completely read. Push it further and start reading
// new message. (inProgress is a 0-byte message after this point.)
if (msgSink == null) {
return false;
}
int rc = msgSink.pushMsg(inProgress);
if (rc != 0) {
return false;
}
nextStep(tmpbuf, 1, ONE_BYTE_SIZE_READY);
return true;
}
}
jeromq-0.3.5/src/main/java/zmq/DecoderBase.java 0000664 0000000 0000000 00000013124 12551504772 0021273 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.nio.ByteBuffer;
// Helper base class for decoders that know the amount of data to read
// in advance at any moment. Knowing the amount in advance is a property
// of the protocol used. 0MQ framing protocol is based size-prefixed
// paradigm, which qualifies it to be parsed by this class.
// On the other hand, XML-based transports (like XMPP or SOAP) don't allow
// for knowing the size of data to read in advance and should use different
// decoding algorithms.
//
// This class implements the state machine that parses the incoming buffer.
// Derived class should implement individual state machine actions.
public abstract class DecoderBase implements IDecoder
{
// Where to store the read data.
private byte[] readBuf;
private int readPos;
// How much data to read before taking next step.
protected int toRead;
// The buffer for data to decode.
private int bufsize;
private ByteBuffer buf;
private int state;
boolean zeroCopy;
public DecoderBase(int bufsize)
{
state = -1;
toRead = 0;
this.bufsize = bufsize;
if (bufsize > 0) {
buf = ByteBuffer.allocateDirect(bufsize);
}
readBuf = null;
zeroCopy = false;
}
// Returns a buffer to be filled with binary data.
public ByteBuffer getBuffer()
{
// If we are expected to read large message, we'll opt for zero-
// copy, i.e. we'll ask caller to fill the data directly to the
// message. Note that subsequent read(s) are non-blocking, thus
// each single read reads at most SO_RCVBUF bytes at once not
// depending on how large is the chunk returned from here.
// As a consequence, large messages being received won't block
// other engines running in the same I/O thread for excessive
// amounts of time.
ByteBuffer b;
if (toRead >= bufsize) {
zeroCopy = true;
b = ByteBuffer.wrap(readBuf);
b.position(readPos);
}
else {
zeroCopy = false;
b = buf;
b.clear();
}
return b;
}
// Processes the data in the buffer previously allocated using
// get_buffer function. size_ argument specifies nemuber of bytes
// actually filled into the buffer. Function returns number of
// bytes actually processed.
public int processBuffer(ByteBuffer buf, int size)
{
// Check if we had an error in previous attempt.
if (state() < 0) {
return -1;
}
// In case of zero-copy simply adjust the pointers, no copying
// is required. Also, run the state machine in case all the data
// were processed.
if (zeroCopy) {
readPos += size;
toRead -= size;
while (toRead == 0) {
if (!next()) {
if (state() < 0) {
return -1;
}
return size;
}
}
return size;
}
int pos = 0;
while (true) {
// Try to get more space in the message to fill in.
// If none is available, return.
while (toRead == 0) {
if (!next()) {
if (state() < 0) {
return -1;
}
return pos;
}
}
// If there are no more data in the buffer, return.
if (pos == size) {
return pos;
}
// Copy the data from buffer to the message.
int toCopy = Math.min(toRead, size - pos);
buf.get(readBuf, readPos, toCopy);
readPos += toCopy;
pos += toCopy;
toRead -= toCopy;
}
}
protected void nextStep(Msg msg, int state)
{
nextStep(msg.data(), msg.size(), state);
}
protected void nextStep(byte[] buf, int toRead, int state)
{
readBuf = buf;
readPos = 0;
this.toRead = toRead;
this.state = state;
}
protected int state()
{
return state;
}
protected void state(int state)
{
this.state = state;
}
protected void decodingError()
{
state(-1);
}
// Returns true if the decoder has been fed all required data
// but cannot proceed with the next decoding step.
// False is returned if the decoder has encountered an error.
@Override
public boolean stalled()
{
// Check whether there was decoding error.
if (!next()) {
return false;
}
while (toRead == 0) {
if (!next()) {
return next();
}
}
return false;
}
protected abstract boolean next();
}
jeromq-0.3.5/src/main/java/zmq/Dist.java 0000664 0000000 0000000 00000013631 12551504772 0020041 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.util.ArrayList;
import java.util.List;
class Dist
{
// List of outbound pipes.
//typedef array_t pipes_t;
private final List pipes;
// Number of all the pipes to send the next message to.
private int matching;
// Number of active pipes. All the active pipes are located at the
// beginning of the pipes array. These are the pipes the messages
// can be sent to at the moment.
private int active;
// Number of pipes eligible for sending messages to. This includes all
// the active pipes plus all the pipes that we can in theory send
// messages to (the HWM is not yet reached), but sending a message
// to them would result in partial message being delivered, ie. message
// with initial parts missing.
private int eligible;
// True if last we are in the middle of a multipart message.
private boolean more;
public Dist()
{
matching = 0;
active = 0;
eligible = 0;
more = false;
pipes = new ArrayList();
}
// Adds the pipe to the distributor object.
public void attach(Pipe pipe)
{
// If we are in the middle of sending a message, we'll add new pipe
// into the list of eligible pipes. Otherwise we add it to the list
// of active pipes.
if (more) {
pipes.add(pipe);
//pipes.swap (eligible, pipes.size() - 1);
Utils.swap(pipes, eligible, pipes.size() - 1);
eligible++;
}
else {
pipes.add(pipe);
//pipes.swap (active, pipes.size() - 1);
Utils.swap(pipes, active, pipes.size() - 1);
active++;
eligible++;
}
}
// Mark the pipe as matching. Subsequent call to sendToMatching
// will send message also to this pipe.
public void match(Pipe pipe)
{
int idx = pipes.indexOf(pipe);
// If pipe is already matching do nothing.
if (idx < matching) {
return;
}
// If the pipe isn't eligible, ignore it.
if (idx >= eligible) {
return;
}
// Mark the pipe as matching.
Utils.swap(pipes, idx, matching);
matching++;
}
// Mark all pipes as non-matching.
public void unmatch()
{
matching = 0;
}
// Removes the pipe from the distributor object.
public void terminated(Pipe pipe)
{
// Remove the pipe from the list; adjust number of matching, active and/or
// eligible pipes accordingly.
if (pipes.indexOf(pipe) < matching) {
Utils.swap(pipes, pipes.indexOf(pipe), matching - 1);
matching--;
}
if (pipes.indexOf(pipe) < active) {
Utils.swap(pipes, pipes.indexOf(pipe), active - 1);
active--;
}
if (pipes.indexOf(pipe) < eligible) {
Utils.swap(pipes, pipes.indexOf(pipe), eligible - 1);
eligible--;
}
pipes.remove(pipe);
}
// Activates pipe that have previously reached high watermark.
public void activated(Pipe pipe)
{
// Move the pipe from passive to eligible state.
Utils.swap(pipes, pipes.indexOf(pipe), eligible);
eligible++;
// If there's no message being sent at the moment, move it to
// the active state.
if (!more) {
Utils.swap(pipes, eligible - 1, active);
active++;
}
}
// Send the message to all the outbound pipes.
public boolean sendToAll(Msg msg)
{
matching = active;
return sendToMatching(msg);
}
// Send the message to the matching outbound pipes.
public boolean sendToMatching(Msg msg)
{
// Is this end of a multipart message?
boolean msgMore = msg.hasMore();
// Push the message to matching pipes.
distribute(msg);
// If mutlipart message is fully sent, activate all the eligible pipes.
if (!msgMore) {
active = eligible;
}
more = msgMore;
return true;
}
// Put the message to all active pipes.
private void distribute(Msg msg)
{
// If there are no matching pipes available, simply drop the message.
if (matching == 0) {
return;
}
for (int i = 0; i < matching; ++i) {
if (!write(pipes.get(i), msg)) {
--i; // Retry last write because index will have been swapped
}
}
}
public boolean hasOut()
{
return true;
}
// Write the message to the pipe. Make the pipe inactive if writing
// fails. In such a case false is returned.
private boolean write(Pipe pipe, Msg msg)
{
if (!pipe.write(msg)) {
Utils.swap(pipes, pipes.indexOf(pipe), matching - 1);
matching--;
Utils.swap(pipes, pipes.indexOf(pipe), active - 1);
active--;
Utils.swap(pipes, active, eligible - 1);
eligible--;
return false;
}
if (!msg.hasMore()) {
pipe.flush();
}
return true;
}
}
jeromq-0.3.5/src/main/java/zmq/Encoder.java 0000664 0000000 0000000 00000006234 12551504772 0020516 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.nio.ByteBuffer;
public class Encoder extends EncoderBase
{
private static final int SIZE_READY = 0;
private static final int MESSAGE_READY = 1;
private Msg inProgress;
private final byte[] tmpbuf;
private IMsgSource msgSource;
public Encoder(int bufsize)
{
super(bufsize);
tmpbuf = new byte[10];
// Write 0 bytes to the batch and go to messageReady state.
nextStep((byte[]) null, 0, MESSAGE_READY, true);
}
@Override
public void setMsgSource(IMsgSource msgSource)
{
this.msgSource = msgSource;
}
@Override
protected boolean next()
{
switch(state()) {
case SIZE_READY:
return sizeReady();
case MESSAGE_READY:
return messageReady();
default:
return false;
}
}
private boolean sizeReady()
{
// Write message body into the buffer.
nextStep(inProgress.data(), inProgress.size(),
MESSAGE_READY, !inProgress.hasMore());
return true;
}
private boolean messageReady()
{
// Destroy content of the old message.
//inProgress.close ();
// Read new message. If there is none, return false.
// Note that new state is set only if write is successful. That way
// unsuccessful write will cause retry on the next state machine
// invocation.
if (msgSource == null) {
return false;
}
inProgress = msgSource.pullMsg();
if (inProgress == null) {
return false;
}
// Get the message size.
int size = inProgress.size();
// Account for the 'flags' byte.
size++;
// For messages less than 255 bytes long, write one byte of message size.
// For longer messages write 0xff escape character followed by 8-byte
// message size. In both cases 'flags' field follows.
if (size < 255) {
tmpbuf[0] = (byte) size;
tmpbuf[1] = (byte) (inProgress.flags() & Msg.MORE);
nextStep(tmpbuf, 2, SIZE_READY, false);
}
else {
ByteBuffer b = ByteBuffer.wrap(tmpbuf);
b.put((byte) 0xff);
b.putLong(size);
b.put((byte) (inProgress.flags() & Msg.MORE));
nextStep(tmpbuf, 10, SIZE_READY, false);
}
return true;
}
}
jeromq-0.3.5/src/main/java/zmq/EncoderBase.java 0000664 0000000 0000000 00000013012 12551504772 0021301 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public abstract class EncoderBase implements IEncoder
{
// Where to get the data to write from.
private byte[] writeBuf;
private FileChannel writeChannel;
private int writePos;
// Next step. If set to -1, it means that associated data stream
// is dead.
private int next;
// If true, first byte of the message is being written.
@SuppressWarnings("unused")
private boolean beginning;
// How much data to write before next step should be executed.
private int toWrite;
// The buffer for encoded data.
private ByteBuffer buffer;
private int bufferSize;
private boolean error;
protected EncoderBase(int bufferSize)
{
this.bufferSize = bufferSize;
buffer = ByteBuffer.allocateDirect(bufferSize);
error = false;
}
// The function returns a batch of binary data. The data
// are filled to a supplied buffer. If no buffer is supplied (data_
// points to NULL) decoder object will provide buffer of its own.
@Override
public Transfer getData(ByteBuffer buffer)
{
if (buffer == null) {
buffer = this.buffer;
}
buffer.clear();
while (buffer.hasRemaining()) {
// If there are no more data to return, run the state machine.
// If there are still no data, return what we already have
// in the buffer.
if (toWrite == 0) {
// If we are to encode the beginning of a new message,
// adjust the message offset.
if (!next()) {
break;
}
}
// If there is file channel to send,
// send current buffer and the channel together
if (writeChannel != null) {
buffer.flip();
Transfer t = new Transfer.FileChannelTransfer(buffer, writeChannel,
(long) writePos, (long) toWrite);
writePos = 0;
toWrite = 0;
return t;
}
// If there are no data in the buffer yet and we are able to
// fill whole buffer in a single go, let's use zero-copy.
// There's no disadvantage to it as we cannot stuck multiple
// messages into the buffer anyway. Note that subsequent
// write(s) are non-blocking, thus each single write writes
// at most SO_SNDBUF bytes at once not depending on how large
// is the chunk returned from here.
// As a consequence, large messages being sent won't block
// other engines running in the same I/O thread for excessive
// amounts of time.
if (this.buffer.position() == 0 && toWrite >= bufferSize) {
Transfer t;
ByteBuffer b = ByteBuffer.wrap(writeBuf);
b.position(writePos);
t = new Transfer.ByteBufferTransfer(b);
writePos = 0;
toWrite = 0;
return t;
}
// Copy data to the buffer. If the buffer is full, return.
int toCopy = Math.min(toWrite, buffer.remaining());
if (toCopy > 0) {
buffer.put(writeBuf, writePos, toCopy);
writePos += toCopy;
toWrite -= toCopy;
}
}
buffer.flip();
return new Transfer.ByteBufferTransfer(buffer);
}
@Override
public boolean hasData()
{
return toWrite > 0;
}
protected int state()
{
return next;
}
protected void state(int state)
{
next = state;
}
protected void encodingError()
{
error = true;
}
public final boolean isError()
{
return error;
}
protected abstract boolean next();
protected void nextStep(Msg msg, int state, boolean beginning)
{
if (msg == null) {
nextStep(null, 0, state, beginning);
}
else {
nextStep(msg.data(), msg.size(), state, beginning);
}
}
protected void nextStep(byte[] buf, int toWrite,
int next, boolean beginning)
{
writeBuf = buf;
writeChannel = null;
writePos = 0;
this.toWrite = toWrite;
this.next = next;
this.beginning = beginning;
}
protected void nextStep(FileChannel ch, long pos, long toWrite,
int next, boolean beginning)
{
writeBuf = null;
writeChannel = ch;
writePos = (int) pos;
this.toWrite = (int) toWrite;
this.next = next;
this.beginning = beginning;
}
}
jeromq-0.3.5/src/main/java/zmq/FQ.java 0000664 0000000 0000000 00000011221 12551504772 0017435 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.util.ArrayList;
import java.util.List;
// Class manages a set of inbound pipes. On receive it performs fair
// queueing so that senders gone berserk won't cause denial of
// service for decent senders.
class FQ
{
// Inbound pipes.
private final List pipes;
// Number of active pipes. All the active pipes are located at the
// beginning of the pipes array.
private int active;
// Index of the next bound pipe to read a message from.
private int current;
// If true, part of a multipart message was already received, but
// there are following parts still waiting in the current pipe.
private boolean more;
public FQ()
{
active = 0;
current = 0;
more = false;
pipes = new ArrayList();
}
public void attach(Pipe pipe)
{
pipes.add(pipe);
Utils.swap(pipes, active, pipes.size() - 1);
active++;
}
public void terminated(Pipe pipe)
{
final int index = pipes.indexOf(pipe);
// Remove the pipe from the list; adjust number of active pipes
// accordingly.
if (index < active) {
active--;
Utils.swap(pipes, index, active);
if (current == active) {
current = 0;
}
}
pipes.remove(pipe);
}
public void activated(Pipe pipe)
{
// Move the pipe to the list of active pipes.
Utils.swap(pipes, pipes.indexOf(pipe), active);
active++;
}
public Msg recv(ValueReference errno)
{
return recvPipe(errno, null);
}
public Msg recvPipe(ValueReference errno, ValueReference pipe)
{
// Round-robin over the pipes to get the next message.
while (active > 0) {
// Try to fetch new message. If we've already read part of the message
// subsequent part should be immediately available.
Msg msg = pipes.get(current).read();
boolean fetched = msg != null;
// Note that when message is not fetched, current pipe is deactivated
// and replaced by another active pipe. Thus we don't have to increase
// the 'current' pointer.
if (fetched) {
if (pipe != null) {
pipe.set(pipes.get(current));
}
more = msg.hasMore();
if (!more) {
current = (current + 1) % active;
}
return msg;
}
// Check the atomicity of the message.
// If we've already received the first part of the message
// we should get the remaining parts without blocking.
assert (!more);
active--;
Utils.swap(pipes, current, active);
if (current == active) {
current = 0;
}
}
// No message is available. Initialise the output parameter
// to be a 0-byte message.
errno.set(ZError.EAGAIN);
return null;
}
public boolean hasIn()
{
// There are subsequent parts of the partly-read message available.
if (more) {
return true;
}
// Note that messing with current doesn't break the fairness of fair
// queueing algorithm. If there are no messages available current will
// get back to its original value. Otherwise it'll point to the first
// pipe holding messages, skipping only pipes with no messages available.
while (active > 0) {
if (pipes.get(current).checkRead()) {
return true;
}
// Deactivate the pipe.
active--;
Utils.swap(pipes, current, active);
if (current == active) {
current = 0;
}
}
return false;
}
}
jeromq-0.3.5/src/main/java/zmq/IDecoder.java 0000664 0000000 0000000 00000001762 12551504772 0020616 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.nio.ByteBuffer;
public interface IDecoder
{
public void setMsgSink(IMsgSink msgSink);
public ByteBuffer getBuffer();
public int processBuffer(ByteBuffer buffer, int size);
public boolean stalled();
}
jeromq-0.3.5/src/main/java/zmq/IEncoder.java 0000664 0000000 0000000 00000002247 12551504772 0020627 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.nio.ByteBuffer;
public interface IEncoder
{
// Set message producer.
public void setMsgSource(IMsgSource msgSource);
// The function returns a batch of binary data. The data
// are filled to a supplied buffer. If no buffer is supplied (data_
// is null) encoder will provide buffer of its own.
public Transfer getData(ByteBuffer buffer);
public boolean hasData();
}
jeromq-0.3.5/src/main/java/zmq/IEngine.java 0000664 0000000 0000000 00000002530 12551504772 0020450 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
// Abstract interface to be implemented by various engines.
public interface IEngine
{
// Plug the engine to the session.
void plug(IOThread ioThread, SessionBase session);
// Terminate and deallocate the engine. Note that 'detached'
// events are not fired on termination.
void terminate();
// This method is called by the session to signalise that more
// messages can be written to the pipe.
void activateIn();
// This method is called by the session to signalise that there
// are messages to send available.
void activateOut();
}
jeromq-0.3.5/src/main/java/zmq/IMsgSink.java 0000664 0000000 0000000 00000001716 12551504772 0020623 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
public interface IMsgSink
{
// Delivers a message. Returns true if successful; false otherwise.
// The function takes ownership of the passed message.
public int pushMsg(Msg msg);
}
jeromq-0.3.5/src/main/java/zmq/IMsgSource.java 0000664 0000000 0000000 00000001623 12551504772 0021154 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
public interface IMsgSource
{
// Fetch a message. Returns a Msg instance if successful; null otherwise.
public Msg pullMsg();
}
jeromq-0.3.5/src/main/java/zmq/IOObject.java 0000664 0000000 0000000 00000006612 12551504772 0020575 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.nio.channels.SelectableChannel;
// Simple base class for objects that live in I/O threads.
// It makes communication with the poller object easier and
// makes defining unneeded event handlers unnecessary.
public class IOObject implements IPollEvents
{
private Poller poller;
private IPollEvents handler;
public IOObject(IOThread ioThread)
{
if (ioThread != null) {
plug(ioThread);
}
}
// When migrating an object from one I/O thread to another, first
// unplug it, then migrate it, then plug it to the new thread.
public void plug(IOThread ioThread)
{
assert (ioThread != null);
assert (poller == null);
// Retrieve the poller from the thread we are running in.
poller = ioThread.getPoller();
}
public void unplug()
{
assert (poller != null);
// Forget about old poller in preparation to be migrated
// to a different I/O thread.
poller = null;
handler = null;
}
public final void addHandle(SelectableChannel handle)
{
poller.addHandle(handle, this);
}
public final void removeHandle(SelectableChannel handle)
{
poller.removeHandle(handle);
}
public final void setPollIn(SelectableChannel handle)
{
poller.setPollIn(handle);
}
public final void setPollOut(SelectableChannel handle)
{
poller.setPollOut(handle);
}
public final void setPollConnect(SelectableChannel handle)
{
poller.setPollConnect(handle);
}
public final void setPollAccept(SelectableChannel handle)
{
poller.setPollAccept(handle);
}
public final void resetPollIn(SelectableChannel handle)
{
poller.resetPollOn(handle);
}
public final void resetPollOut(SelectableChannel handle)
{
poller.resetPollOut(handle);
}
@Override
public final void inEvent()
{
handler.inEvent();
}
@Override
public final void outEvent()
{
handler.outEvent();
}
@Override
public final void connectEvent()
{
handler.connectEvent();
}
@Override
public final void acceptEvent()
{
handler.acceptEvent();
}
@Override
public final void timerEvent(int id)
{
handler.timerEvent(id);
}
public final void addTimer(long timeout, int id)
{
poller.addTimer(timeout, this, id);
}
public final void setHandler(IPollEvents handler)
{
this.handler = handler;
}
public void cancelTimer(int id)
{
poller.cancelTimer(this, id);
}
}
jeromq-0.3.5/src/main/java/zmq/IOThread.java 0000664 0000000 0000000 00000006004 12551504772 0020571 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.io.Closeable;
import java.io.IOException;
import java.nio.channels.SelectableChannel;
public class IOThread extends ZObject implements IPollEvents, Closeable
{
// I/O thread accesses incoming commands via this mailbox.
private final Mailbox mailbox;
// Handle associated with mailbox' file descriptor.
private final SelectableChannel mailboxHandle;
// I/O multiplexing is performed using a poller object.
private final Poller poller;
final String name;
public IOThread(Ctx ctx, int tid)
{
super(ctx, tid);
name = "iothread-" + tid;
poller = new Poller(name);
mailbox = new Mailbox(name);
mailboxHandle = mailbox.getFd();
poller.addHandle(mailboxHandle, this);
poller.setPollIn(mailboxHandle);
}
public void start()
{
poller.start();
}
@Override
public void close() throws IOException
{
poller.destroy();
mailbox.close();
}
public void stop()
{
sendStop();
}
public Mailbox getMailbox()
{
return mailbox;
}
public int getLoad()
{
return poller.getLoad();
}
@Override
public void inEvent()
{
// TODO: Do we want to limit number of commands I/O thread can
// process in a single go?
while (true) {
// Get the next command. If there is none, exit.
Command cmd = mailbox.recv(0);
if (cmd == null) {
break;
}
// Process the command.
cmd.destination().processCommand(cmd);
}
}
@Override
public void outEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void connectEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void acceptEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void timerEvent(int id)
{
throw new UnsupportedOperationException();
}
public Poller getPoller()
{
assert (poller != null);
return poller;
}
protected void processStop()
{
poller.removeHandle(mailboxHandle);
poller.stop();
}
}
jeromq-0.3.5/src/main/java/zmq/IPollEvents.java 0000664 0000000 0000000 00000002354 12551504772 0021342 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
public interface IPollEvents
{
// Called by I/O thread when file descriptor is ready for reading.
void inEvent();
// Called by I/O thread when file descriptor is ready for writing.
void outEvent();
// Called by I/O thread when file descriptor might be ready for connecting.
void connectEvent();
// Called by I/O thread when file descriptor is ready for accept.
void acceptEvent();
// Called when timer expires.
void timerEvent(int id);
}
jeromq-0.3.5/src/main/java/zmq/IpcAddress.java 0000664 0000000 0000000 00000003304 12551504772 0021153 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
public class IpcAddress implements Address.IZAddress
{
private String name;
private InetSocketAddress address;
@Override
public String toString()
{
if (name == null) {
return "";
}
return "ipc://" + name;
}
@Override
public void resolve(String name, boolean ip4only)
{
this.name = name;
int hash = name.hashCode();
if (hash < 0) {
hash = -hash;
}
hash = hash % 55536;
hash += 10000;
try {
address = new InetSocketAddress(InetAddress.getByName(null), hash);
}
catch (UnknownHostException e) {
throw new IllegalArgumentException(e);
}
}
@Override
public SocketAddress address()
{
return address;
}
}
jeromq-0.3.5/src/main/java/zmq/IpcConnecter.java 0000664 0000000 0000000 00000002021 12551504772 0021501 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
public class IpcConnecter extends TcpConnecter
{
public IpcConnecter(IOThread ioThread,
SessionBase session, final Options options,
final Address addr, boolean wait)
{
super(ioThread, session, options, addr, wait);
}
}
jeromq-0.3.5/src/main/java/zmq/IpcListener.java 0000664 0000000 0000000 00000003020 12551504772 0021346 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.net.InetSocketAddress;
// fake Unix domain socket
public class IpcListener extends TcpListener
{
private final IpcAddress address;
public IpcListener(IOThread ioThread, SocketBase socket, final Options options)
{
super(ioThread, socket, options);
address = new IpcAddress();
}
// Get the bound address for use with wildcards
public String getAddress()
{
return address.toString();
}
// Set address to listen on.
public int setAddress(String addr)
{
address.resolve(addr, false);
InetSocketAddress sock = (InetSocketAddress) address.address();
String fake = sock.getAddress().getHostAddress() + ":" + sock.getPort();
return super.setAddress(fake);
}
}
jeromq-0.3.5/src/main/java/zmq/LB.java 0000664 0000000 0000000 00000010173 12551504772 0017431 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.util.ArrayList;
import java.util.List;
public class LB
{
// List of outbound pipes.
private final List pipes;
// Number of active pipes. All the active pipes are located at the
// beginning of the pipes array.
private int active;
// Points to the last pipe that the most recent message was sent to.
private int current;
// True if last we are in the middle of a multipart message.
private boolean more;
// True if we are dropping current message.
private boolean dropping;
public LB()
{
active = 0;
current = 0;
more = false;
dropping = false;
pipes = new ArrayList();
}
public void attach(Pipe pipe)
{
pipes.add(pipe);
activated(pipe);
}
public void terminated(Pipe pipe)
{
int index = pipes.indexOf(pipe);
// If we are in the middle of multipart message and current pipe
// have disconnected, we have to drop the remainder of the message.
if (index == current && more) {
dropping = true;
}
// Remove the pipe from the list; adjust number of active pipes
// accordingly.
if (index < active) {
active--;
Utils.swap(pipes, index, active);
if (current == active) {
current = 0;
}
}
pipes.remove(pipe);
}
public void activated(Pipe pipe)
{
// Move the pipe to the list of active pipes.
Utils.swap(pipes, pipes.indexOf(pipe), active);
active++;
}
public boolean send(Msg msg, ValueReference errno)
{
// Drop the message if required. If we are at the end of the message
// switch back to non-dropping mode.
if (dropping) {
more = msg.hasMore();
dropping = more;
// msg_.close();
return true;
}
while (active > 0) {
if (pipes.get(current).write(msg)) {
break;
}
assert (!more);
active--;
if (current < active) {
Utils.swap(pipes, current, active);
}
else {
current = 0;
}
}
// If there are no pipes we cannot send the message.
if (active == 0) {
errno.set(ZError.EAGAIN);
return false;
}
// If it's final part of the message we can flush it downstream and
// continue round-robining (load balance).
more = msg.hasMore();
if (!more) {
pipes.get(current).flush();
if (++current >= active) {
current = 0;
}
}
return true;
}
public boolean hasOut()
{
// If one part of the message was already written we can definitely
// write the rest of the message.
if (more) {
return true;
}
while (active > 0) {
// Check whether a pipe has room for another message.
if (pipes.get(current).checkWrite()) {
return true;
}
// Deactivate the pipe.
active--;
Utils.swap(pipes, current, active);
if (current == active) {
current = 0;
}
}
return false;
}
}
jeromq-0.3.5/src/main/java/zmq/Mailbox.java 0000664 0000000 0000000 00000007362 12551504772 0020535 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.io.Closeable;
import java.io.IOException;
import java.nio.channels.SelectableChannel;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Mailbox
implements Closeable
{
// The pipe to store actual commands.
private final YPipe cpipe;
// Signaler to pass signals from writer thread to reader thread.
private final Signaler signaler;
// There's only one thread receiving from the mailbox, but there
// is arbitrary number of threads sending. Given that ypipe requires
// synchronised access on both of its endpoints, we have to synchronise
// the sending side.
private final Lock sync;
// True if the underlying pipe is active, ie. when we are allowed to
// read commands from it.
private boolean active;
// mailbox name, for better debugging
private final String name;
public Mailbox(String name)
{
cpipe = new YPipe(Config.COMMAND_PIPE_GRANULARITY.getValue());
sync = new ReentrantLock();
signaler = new Signaler();
// Get the pipe into passive state. That way, if the users starts by
// polling on the associated file descriptor it will get woken up when
// new command is posted.
Command cmd = cpipe.read();
assert (cmd == null);
active = false;
this.name = name;
}
public SelectableChannel getFd()
{
return signaler.getFd();
}
public void send(final Command cmd)
{
boolean ok = false;
sync.lock();
try {
cpipe.write(cmd, false);
ok = cpipe.flush();
}
finally {
sync.unlock();
}
if (!ok) {
signaler.send();
}
}
public Command recv(long timeout)
{
Command cmd = null;
// Try to get the command straight away.
if (active) {
cmd = cpipe.read();
if (cmd != null) {
return cmd;
}
// If there are no more commands available, switch into passive state.
active = false;
signaler.recv();
}
// Wait for signal from the command sender.
boolean rc = signaler.waitEvent(timeout);
if (!rc) {
return null;
}
// We've got the signal. Now we can switch into active state.
active = true;
// Get a command.
cmd = cpipe.read();
assert (cmd != null);
return cmd;
}
@Override
public void close() throws IOException
{
// TODO: Retrieve and deallocate commands inside the cpipe.
// Work around problem that other threads might still be in our
// send() method, by waiting on the mutex before disappearing.
sync.lock();
sync.unlock();
signaler.close();
}
@Override
public String toString()
{
return super.toString() + "[" + name + "]";
}
}
jeromq-0.3.5/src/main/java/zmq/Msg.java 0000664 0000000 0000000 00000012371 12551504772 0017664 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class Msg
{
enum Type {
DATA,
DELIMITER
}
public static final int MORE = 1;
public static final int COMMAND = 2;
public static final int IDENTITY = 64;
public static final int SHARED = 128;
private int flags;
private Type type;
private int size;
private byte[] data;
private ByteBuffer buf;
public Msg()
{
this.type = Type.DATA;
this.flags = 0;
this.size = 0;
this.buf = ByteBuffer.wrap(new byte[0]).order(ByteOrder.BIG_ENDIAN);
this.data = buf.array();
}
public Msg(int capacity)
{
this.type = Type.DATA;
this.flags = 0;
this.size = capacity;
this.buf = ByteBuffer.wrap(new byte[capacity]).order(ByteOrder.BIG_ENDIAN);
this.data = buf.array();
}
public Msg(byte[] src)
{
if (src == null) {
src = new byte[0];
}
this.type = Type.DATA;
this.flags = 0;
this.size = src.length;
this.data = src;
this.buf = ByteBuffer.wrap(src).order(ByteOrder.BIG_ENDIAN);
}
public Msg(final ByteBuffer src)
{
if (src == null) {
throw new IllegalArgumentException("ByteBuffer cannot be null");
}
if (src.position() > 0) {
throw new IllegalArgumentException("ByteBuffer position is not zero, did you forget to flip it?");
}
this.type = Type.DATA;
this.flags = 0;
this.buf = src.duplicate();
if (buf.hasArray()) {
this.data = buf.array();
}
else {
this.data = null;
}
this.size = buf.remaining();
}
public Msg(final Msg m)
{
if (m == null) {
throw new IllegalArgumentException("Msg cannot be null");
}
this.type = m.type;
this.flags = m.flags;
this.size = m.size;
this.buf = m.buf != null ? m.buf.duplicate() : null;
this.data = new byte[this.size];
System.arraycopy(m.data, 0, this.data, 0, m.size);
}
public boolean isIdentity()
{
return (flags & IDENTITY) == IDENTITY;
}
public boolean isDelimiter()
{
return type == Type.DELIMITER;
}
public boolean check()
{
return true; // type >= TYPE_MIN && type <= TYPE_MAX;
}
public int flags()
{
return flags;
}
public boolean hasMore()
{
return (flags & MORE) > 0;
}
public void setFlags(int flags)
{
this.flags |= flags;
}
public void initDelimiter()
{
type = Type.DELIMITER;
flags = 0;
}
public byte[] data()
{
if (buf.isDirect()) {
int length = buf.remaining();
byte[] bytes = new byte[length];
buf.duplicate().get(bytes);
return bytes;
}
return data;
}
public ByteBuffer buf()
{
return buf.duplicate();
}
public int size()
{
return size;
}
public void resetFlags(int f)
{
flags = flags & ~f;
}
public byte get()
{
return buf.get();
}
public byte get(int index)
{
return buf.get(index);
}
public Msg put(byte b)
{
buf.put(b);
return this;
}
public Msg put(int index, byte b)
{
buf.put(index, b);
return this;
}
public Msg put(byte[] src)
{
return put(src, 0, src.length);
}
public Msg put(byte[] src, int off, int len)
{
if (src == null) {
return this;
}
buf.put(src, off, len);
return this;
}
public Msg put(ByteBuffer src)
{
buf.put(src);
return this;
}
public int getBytes(int index, byte[] dst, int off, int len)
{
int count = Math.min(len, size);
if (buf.isDirect()) {
ByteBuffer dup = buf.duplicate();
dup.position(index);
dup.put(dst, off, count);
return count;
}
System.arraycopy(data, index, dst, off, count);
return count;
}
public int getBytes(int index, ByteBuffer bb, int len)
{
int count = Math.min(bb.remaining(), size - index);
count = Math.min(count, len);
bb.put(buf);
return count;
}
@Override
public String toString()
{
return String.format("#zmq.Msg{type=%s, size=%s, flags=%s}", type, size, flags);
}
}
jeromq-0.3.5/src/main/java/zmq/Mtrie.java 0000664 0000000 0000000 00000030646 12551504772 0020223 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.util.HashSet;
import java.util.Set;
//Multi-trie. Each node in the trie is a set of pointers to pipes.
public class Mtrie
{
private Set pipes;
private int min;
private int count;
private int liveNodes;
private Mtrie[] next;
public interface IMtrieHandler
{
void invoke(Pipe pipe, byte[] data, int size, Object arg);
}
public Mtrie()
{
min = 0;
count = 0;
liveNodes = 0;
pipes = null;
next = null;
}
public boolean add(byte[] prefix, Pipe pipe)
{
return addHelper(prefix, 0, pipe);
}
// Add key to the trie. Returns true if it's a new subscription
// rather than a duplicate.
public boolean add(byte[] prefix, int start, Pipe pipe)
{
return addHelper(prefix, start, pipe);
}
private boolean addHelper(byte[] prefix, int start, Pipe pipe)
{
// We are at the node corresponding to the prefix. We are done.
if (prefix == null || prefix.length == start) {
boolean result = pipes == null;
if (pipes == null) {
pipes = new HashSet();
}
pipes.add(pipe);
return result;
}
byte c = prefix[start];
if (c < min || c >= min + count) {
// The character is out of range of currently handled
// characters. We have to extend the table.
if (count == 0) {
min = c;
count = 1;
next = null;
}
else if (count == 1) {
int oldc = min;
Mtrie oldp = next[0];
count = (min < c ? c - min : min - c) + 1;
next = new Mtrie[count];
min = Math.min(min, c);
next[oldc - min] = oldp;
}
else if (min < c) {
// The new character is above the current character range.
count = c - min + 1;
next = realloc(next, count, true);
}
else {
// The new character is below the current character range.
count = (min + count) - c;
next = realloc(next, count, false);
min = c;
}
}
// If next node does not exist, create one.
if (count == 1) {
if (next == null) {
next = new Mtrie[1];
next[0] = new Mtrie();
++liveNodes;
//alloc_assert (next.node);
}
return next[0].addHelper(prefix, start + 1, pipe);
}
else {
if (next[c - min] == null) {
next[c - min] = new Mtrie();
++liveNodes;
//alloc_assert (next.table [c - min]);
}
return next[c - min].addHelper(prefix, start + 1, pipe);
}
}
private Mtrie[] realloc(Mtrie[] table, int size, boolean ended)
{
return Utils.realloc(Mtrie.class, table, size, ended);
}
// Remove all subscriptions for a specific peer from the trie.
// If there are no subscriptions left on some topics, invoke the
// supplied callback function.
public boolean rm(Pipe pipe, IMtrieHandler func, Object arg)
{
return rmHelper(pipe, new byte[0], 0, 0, func, arg);
}
private boolean rmHelper(Pipe pipe, byte[] buff, int buffsize, int maxBuffSize,
IMtrieHandler func, Object arg)
{
// Remove the subscription from this node.
if (pipes != null && pipes.remove(pipe) && pipes.isEmpty()) {
func.invoke(null, buff, buffsize, arg);
pipes = null;
}
// Adjust the buffer.
if (buffsize >= maxBuffSize) {
maxBuffSize = buffsize + 256;
buff = Utils.realloc(buff, maxBuffSize);
}
// If there are no subnodes in the trie, return.
if (count == 0) {
return true;
}
// If there's one subnode (optimisation).
if (count == 1) {
buff[buffsize] = (byte) min;
buffsize++;
next[0].rmHelper(pipe, buff, buffsize, maxBuffSize,
func, arg);
// Prune the node if it was made redundant by the removal
if (next[0].isRedundant()) {
next = null;
count = 0;
--liveNodes;
assert (liveNodes == 0);
}
return true;
}
// If there are multiple subnodes.
//
// New min non-null character in the node table after the removal
int newMin = min + count - 1;
// New max non-null character in the node table after the removal
int newMax = min;
for (int c = 0; c != count; c++) {
buff[buffsize] = (byte) (min + c);
if (next[c] != null) {
next[c].rmHelper(pipe, buff, buffsize + 1,
maxBuffSize, func, arg);
// Prune redundant nodes from the mtrie
if (next[c].isRedundant()) {
next[c] = null;
assert (liveNodes > 0);
--liveNodes;
}
else {
// The node is not redundant, so it's a candidate for being
// the new min/max node.
//
// We loop through the node array from left to right, so the
// first non-null, non-redundant node encountered is the new
// minimum index. Conversely, the last non-redundant, non-null
// node encountered is the new maximum index.
if (c + min < newMin) {
newMin = c + min;
}
if (c + min > newMax) {
newMax = c + min;
}
}
}
}
assert (count > 1);
// Free the node table if it's no longer used.
if (liveNodes == 0) {
next = null;
count = 0;
}
// Compact the node table if possible
else if (liveNodes == 1) {
// If there's only one live node in the table we can
// switch to using the more compact single-node
// representation
assert (newMin == newMax);
assert (newMin >= min && newMin < min + count);
Mtrie node = next [newMin - min];
assert (node != null);
next = null;
next = new Mtrie[]{node};
count = 1;
min = newMin;
}
else if (newMin > min || newMax < min + count - 1) {
assert (newMax - newMin + 1 > 1);
Mtrie[] oldTable = next;
assert (newMin > min || newMax < min + count - 1);
assert (newMin >= min);
assert (newMax <= min + count - 1);
assert (newMax - newMin + 1 < count);
count = newMax - newMin + 1;
next = new Mtrie[count];
System.arraycopy(oldTable, (newMin - min), next, 0, count);
min = newMin;
}
return true;
}
// Remove specific subscription from the trie. Return true is it was
// actually removed rather than de-duplicated.
public boolean rm(byte[] prefix, int start, Pipe pipe)
{
return rmHelper(prefix, start, pipe);
}
private boolean rmHelper(byte[] prefix, int start, Pipe pipe)
{
if (prefix == null || prefix.length == start) {
if (pipes != null) {
boolean erased = pipes.remove(pipe);
assert (erased);
if (pipes.isEmpty()) {
pipes = null;
}
}
return pipes == null;
}
byte c = prefix[start];
if (count == 0 || c < min || c >= min + count) {
return false;
}
Mtrie nextNode =
count == 1 ? next[0] : next[c - min];
if (nextNode == null) {
return false;
}
boolean ret = nextNode.rmHelper(prefix, start + 1, pipe);
if (nextNode.isRedundant()) {
assert (count > 0);
if (count == 1) {
next = null;
count = 0;
--liveNodes;
assert (liveNodes == 0);
}
else {
next[c - min] = null;
assert (liveNodes > 1);
--liveNodes;
// Compact the table if possible
if (liveNodes == 1) {
// If there's only one live node in the table we can
// switch to using the more compact single-node
// representation
int i;
for (i = 0; i < count; ++i) {
if (next[i] != null) {
break;
}
}
assert (i < count);
min += i;
count = 1;
Mtrie old = next [i];
next = new Mtrie [] { old };
}
else if (c == min) {
// We can compact the table "from the left"
int i;
for (i = 1; i < count; ++i) {
if (next[i] != null) {
break;
}
}
assert (i < count);
min += i;
count -= i;
next = realloc(next, count, true);
}
else if (c == min + count - 1) {
// We can compact the table "from the right"
int i;
for (i = 1; i < count; ++i) {
if (next[count - 1 - i] != null) {
break;
}
}
assert (i < count);
count -= i;
next = realloc(next, count, false);
}
}
}
return ret;
}
// Signal all the matching pipes.
public void match(byte[] data, int size, IMtrieHandler func, Object arg)
{
Mtrie current = this;
int idx = 0;
while (true) {
// Signal the pipes attached to this node.
if (current.pipes != null) {
for (Pipe it : current.pipes) {
func.invoke(it, null, 0, arg);
}
}
// If we are at the end of the message, there's nothing more to match.
if (size == 0) {
break;
}
// If there are no subnodes in the trie, return.
if (current.count == 0) {
break;
}
byte c = data[idx];
// If there's one subnode (optimisation).
if (current.count == 1) {
if (c != current.min) {
break;
}
current = current.next[0];
idx++;
size--;
continue;
}
// If there are multiple subnodes.
if (c < current.min || c >=
current.min + current.count) {
break;
}
if (current.next[c - current.min] == null) {
break;
}
current = current.next[c - current.min];
idx++;
size--;
}
}
private boolean isRedundant()
{
return pipes == null && liveNodes == 0;
}
}
jeromq-0.3.5/src/main/java/zmq/MultiMap.java 0000664 0000000 0000000 00000015106 12551504772 0020665 0 ustar 00root root 0000000 0000000 /*
Copyright other contributors as noted in the AUTHORS file.
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class MultiMap, V> implements Map
{
private long id;
private final HashMap values;
private final TreeMap> keys;
public MultiMap()
{
id = 0;
values = new HashMap();
keys = new TreeMap>();
}
public class MultiMapEntry implements Map.Entry
{
private K key;
private V value;
public MultiMapEntry(K key, V value)
{
this.key = key;
this.value = value;
}
@Override
public K getKey()
{
return key;
}
@Override
public V getValue()
{
return value;
}
@Override
public V setValue(V value)
{
V old = this.value;
this.value = value;
return old;
}
}
public class MultiMapEntrySet implements Set>, Iterator>
{
private MultiMap map;
private Iterator>> it;
private Iterator iit;
private K key;
private long id;
public MultiMapEntrySet(MultiMap map)
{
this.map = map;
}
@Override
public boolean add(Map.Entry arg0)
{
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection extends Map.Entry> arg0)
{
throw new UnsupportedOperationException();
}
@Override
public void clear()
{
throw new UnsupportedOperationException();
}
@Override
public boolean contains(Object arg0)
{
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(Collection> arg0)
{
throw new UnsupportedOperationException();
}
@Override
public boolean isEmpty()
{
throw new UnsupportedOperationException();
}
@Override
public Iterator> iterator()
{
it = map.keys.entrySet().iterator();
return this;
}
@Override
public boolean remove(Object arg0)
{
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection> arg0)
{
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection> arg0)
{
throw new UnsupportedOperationException();
}
@Override
public int size()
{
throw new UnsupportedOperationException();
}
@Override
public Object[] toArray()
{
throw new UnsupportedOperationException();
}
@Override
public T[] toArray(T[] arg0)
{
throw new UnsupportedOperationException();
}
@Override
public boolean hasNext()
{
if (iit == null || !iit.hasNext()) {
if (!it.hasNext()) {
return false;
}
Map.Entry> item = it.next();
key = item.getKey();
iit = item.getValue().iterator();
}
return true;
}
@Override
public Map.Entry next()
{
id = iit.next();
return new MultiMapEntry(key, map.values.get(id));
}
@Override
public void remove()
{
iit.remove();
map.values.remove(id);
if (map.keys.get(key).isEmpty()) {
it.remove();
}
}
}
@Override
public void clear()
{
keys.clear();
values.clear();
}
@Override
public boolean containsKey(Object key)
{
return keys.containsKey(key);
}
@Override
public boolean containsValue(Object value)
{
return values.containsValue(value);
}
@Override
public Set> entrySet()
{
return new MultiMapEntrySet(this);
}
@Override
public V get(Object key)
{
ArrayList l = keys.get(key);
if (l == null) {
return null;
}
return values.get(l.get(0));
}
@Override
public boolean isEmpty()
{
return keys.isEmpty();
}
@Override
public Set keySet()
{
return keys.keySet();
}
@Override
public V put(K key, V value)
{
ArrayList ids = keys.get(key);
if (ids == null) {
ids = new ArrayList();
ids.add(id);
keys.put(key, ids);
}
else {
ids.add(id);
}
values.put(id, value);
id++;
return null;
}
@Override
public void putAll(Map extends K, ? extends V> src)
{
for (Entry extends K, ? extends V> o : src.entrySet()) {
put(o.getKey(), o.getValue());
}
}
@Override
public V remove(Object key)
{
ArrayList l = keys.get(key);
if (l == null) {
return null;
}
V old = values.remove(l.remove(0));
if (l.isEmpty()) {
keys.remove(key);
}
return old;
}
@Override
public int size()
{
return values.size();
}
@Override
public Collection values()
{
return values.values();
}
}
jeromq-0.3.5/src/main/java/zmq/Options.java 0000664 0000000 0000000 00000026746 12551504772 0020604 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import zmq.TcpAddress.TcpAddressMask;
public class Options
{
// High-water marks for message pipes.
int sendHwm;
int recvHwm;
// I/O thread affinity.
long affinity;
// Socket identity
byte identitySize;
byte[] identity; // [256];
// Last socket endpoint resolved URI
String lastEndpoint;
// Maximum tranfer rate [kb/s]. Default 100kb/s.
int rate;
// Reliability time interval [ms]. Default 10 seconds.
int recoveryIvl;
// Sets the time-to-live field in every multicast packet sent.
int multicastHops;
// SO_SNDBUF and SO_RCVBUF to be passed to underlying transport sockets.
int sndbuf;
int rcvbuf;
// Socket type.
int type;
// Linger time, in milliseconds.
int linger;
// Minimum interval between attempts to reconnect, in milliseconds.
// Default 100ms
int reconnectIvl;
// Maximum interval between attempts to reconnect, in milliseconds.
// Default 0 (unused)
int reconnectIvlMax;
// Maximum backlog for pending connections.
int backlog;
// Maximal size of message to handle.
long maxMsgSize;
// The timeout for send/recv operations for this socket.
int recvTimeout;
int sendTimeout;
// If 1, indicates the use of IPv4 sockets only, it will not be
// possible to communicate with IPv6-only hosts. If 0, the socket can
// connect to and accept connections from both IPv4 and IPv6 hosts.
int ipv4only;
// If 1, connecting pipes are not attached immediately, meaning a send()
// on a socket with only connecting pipes would block
int delayAttachOnConnect;
// If true, session reads all the pending messages from the pipe and
// sends them to the network when socket is closed.
boolean delayOnClose;
// If true, socket reads all the messages from the pipe and delivers
// them to the user when the peer terminates.
boolean delayOnDisconnect;
// If 1, (X)SUB socket should filter the messages. If 0, it should not.
boolean filter;
// If true, the identity message is forwarded to the socket.
boolean recvIdentity;
// TCP keep-alive settings.
// Defaults to -1 = do not change socket options
int tcpKeepAlive;
int tcpKeepAliveCnt;
int tcpKeepAliveIdle;
int tcpKeepAliveIntvl;
// TCP accept() filters
//typedef std::vector tcp_accept_filters_t;
final List tcpAcceptFilters;
// ID of the socket.
int socketId;
Class extends DecoderBase> decoder;
Class extends EncoderBase> encoder;
public Options()
{
sendHwm = 1000;
recvHwm = 1000;
affinity = 0;
identitySize = 0;
rate = 100;
recoveryIvl = 10000;
multicastHops = 1;
sndbuf = 0;
rcvbuf = 0;
type = -1;
linger = -1;
reconnectIvl = 100;
reconnectIvlMax = 0;
backlog = 100;
maxMsgSize = -1;
recvTimeout = -1;
sendTimeout = -1;
ipv4only = 1;
delayAttachOnConnect = 0;
delayOnClose = true;
delayOnDisconnect = true;
filter = false;
recvIdentity = false;
tcpKeepAlive = -1;
tcpKeepAliveCnt = -1;
tcpKeepAliveIdle = -1;
tcpKeepAliveIntvl = -1;
socketId = 0;
identity = null;
tcpAcceptFilters = new ArrayList();
decoder = null;
encoder = null;
}
@SuppressWarnings("unchecked")
public void setSocketOpt(int option, Object optval)
{
switch (option) {
case ZMQ.ZMQ_SNDHWM:
sendHwm = (Integer) optval;
if (sendHwm < 0) {
throw new IllegalArgumentException("sendHwm " + optval);
}
return;
case ZMQ.ZMQ_RCVHWM:
recvHwm = (Integer) optval;
if (recvHwm < 0) {
throw new IllegalArgumentException("recvHwm " + optval);
}
return;
case ZMQ.ZMQ_AFFINITY:
affinity = (Long) optval;
return;
case ZMQ.ZMQ_IDENTITY:
byte[] val;
if (optval instanceof String) {
val = ((String) optval).getBytes(ZMQ.CHARSET);
}
else if (optval instanceof byte[]) {
val = (byte[]) optval;
}
else {
throw new IllegalArgumentException("identity " + optval);
}
if (val == null || val.length > 255) {
throw new IllegalArgumentException("identity must not be null or less than 255 " + optval);
}
identity = Arrays.copyOf(val, val.length);
identitySize = (byte) identity.length;
return;
case ZMQ.ZMQ_RATE:
rate = (Integer) optval;
return;
case ZMQ.ZMQ_RECOVERY_IVL:
recoveryIvl = (Integer) optval;
return;
case ZMQ.ZMQ_SNDBUF:
sndbuf = (Integer) optval;
return;
case ZMQ.ZMQ_RCVBUF:
rcvbuf = (Integer) optval;
return;
case ZMQ.ZMQ_LINGER:
linger = (Integer) optval;
return;
case ZMQ.ZMQ_RECONNECT_IVL:
reconnectIvl = (Integer) optval;
if (reconnectIvl < -1) {
throw new IllegalArgumentException("reconnectIvl " + optval);
}
return;
case ZMQ.ZMQ_RECONNECT_IVL_MAX:
reconnectIvlMax = (Integer) optval;
if (reconnectIvlMax < 0) {
throw new IllegalArgumentException("reconnectIvlMax " + optval);
}
return;
case ZMQ.ZMQ_BACKLOG:
backlog = (Integer) optval;
return;
case ZMQ.ZMQ_MAXMSGSIZE:
maxMsgSize = (Long) optval;
return;
case ZMQ.ZMQ_MULTICAST_HOPS:
multicastHops = (Integer) optval;
return;
case ZMQ.ZMQ_RCVTIMEO:
recvTimeout = (Integer) optval;
return;
case ZMQ.ZMQ_SNDTIMEO:
sendTimeout = (Integer) optval;
return;
case ZMQ.ZMQ_IPV4ONLY:
ipv4only = (Integer) optval;
if (ipv4only != 0 && ipv4only != 1) {
throw new IllegalArgumentException("ipv4only only accepts 0 or 1 " + optval);
}
return;
case ZMQ.ZMQ_TCP_KEEPALIVE:
tcpKeepAlive = (Integer) optval;
if (tcpKeepAlive != -1 && tcpKeepAlive != 0 && tcpKeepAlive != 1) {
throw new IllegalArgumentException("tcpKeepAlive only accepts one of -1,0,1 " + optval);
}
return;
case ZMQ.ZMQ_DELAY_ATTACH_ON_CONNECT:
delayAttachOnConnect = (Integer) optval;
if (delayAttachOnConnect != 0 && delayAttachOnConnect != 1) {
throw new IllegalArgumentException("delayAttachOnConnect only accept 0 or 1 " + optval);
}
return;
case ZMQ.ZMQ_TCP_KEEPALIVE_CNT:
case ZMQ.ZMQ_TCP_KEEPALIVE_IDLE:
case ZMQ.ZMQ_TCP_KEEPALIVE_INTVL:
// not supported
return;
case ZMQ.ZMQ_TCP_ACCEPT_FILTER:
String filterStr = (String) optval;
if (filterStr == null) {
tcpAcceptFilters.clear();
}
else if (filterStr.length() == 0 || filterStr.length() > 255) {
throw new IllegalArgumentException("tcp_accept_filter " + optval);
}
else {
TcpAddressMask filter = new TcpAddressMask();
filter.resolve(filterStr, ipv4only == 1);
tcpAcceptFilters.add(filter);
}
return;
case ZMQ.ZMQ_ENCODER:
if (optval instanceof String) {
try {
encoder = Class.forName((String) optval).asSubclass(EncoderBase.class);
}
catch (ClassNotFoundException e) {
throw new IllegalArgumentException(e);
}
}
else if (optval instanceof Class) {
encoder = (Class extends EncoderBase>) optval;
}
else {
throw new IllegalArgumentException("encoder " + optval);
}
return;
case ZMQ.ZMQ_DECODER:
if (optval instanceof String) {
try {
decoder = Class.forName((String) optval).asSubclass(DecoderBase.class);
}
catch (ClassNotFoundException e) {
throw new IllegalArgumentException(e);
}
}
else if (optval instanceof Class) {
decoder = (Class extends DecoderBase>) optval;
}
else {
throw new IllegalArgumentException("decoder " + optval);
}
return;
default:
throw new IllegalArgumentException("Unknown Option " + option);
}
}
public Object getsockopt(int option)
{
switch (option) {
case ZMQ.ZMQ_SNDHWM:
return sendHwm;
case ZMQ.ZMQ_RCVHWM:
return recvHwm;
case ZMQ.ZMQ_AFFINITY:
return affinity;
case ZMQ.ZMQ_IDENTITY:
return identity;
case ZMQ.ZMQ_RATE:
return rate;
case ZMQ.ZMQ_RECOVERY_IVL:
return recoveryIvl;
case ZMQ.ZMQ_SNDBUF:
return sndbuf;
case ZMQ.ZMQ_RCVBUF:
return rcvbuf;
case ZMQ.ZMQ_TYPE:
return type;
case ZMQ.ZMQ_LINGER:
return linger;
case ZMQ.ZMQ_RECONNECT_IVL:
return reconnectIvl;
case ZMQ.ZMQ_RECONNECT_IVL_MAX:
return reconnectIvlMax;
case ZMQ.ZMQ_BACKLOG:
return backlog;
case ZMQ.ZMQ_MAXMSGSIZE:
return maxMsgSize;
case ZMQ.ZMQ_MULTICAST_HOPS:
return multicastHops;
case ZMQ.ZMQ_RCVTIMEO:
return recvTimeout;
case ZMQ.ZMQ_SNDTIMEO:
return sendTimeout;
case ZMQ.ZMQ_IPV4ONLY:
return ipv4only;
case ZMQ.ZMQ_TCP_KEEPALIVE:
return tcpKeepAlive;
case ZMQ.ZMQ_DELAY_ATTACH_ON_CONNECT:
return delayAttachOnConnect;
case ZMQ.ZMQ_TCP_KEEPALIVE_CNT:
case ZMQ.ZMQ_TCP_KEEPALIVE_IDLE:
case ZMQ.ZMQ_TCP_KEEPALIVE_INTVL:
// not supported
return 0;
case ZMQ.ZMQ_LAST_ENDPOINT:
return lastEndpoint;
default:
throw new IllegalArgumentException("option=" + option);
}
}
}
jeromq-0.3.5/src/main/java/zmq/Own.java 0000664 0000000 0000000 00000017726 12551504772 0017712 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
// Base class for objects forming a part of ownership hierarchy.
// It handles initialisation and destruction of such objects.
abstract class Own extends ZObject
{
protected final Options options;
// True if termination was already initiated. If so, we can destroy
// the object if there are no more child objects or pending term acks.
private boolean terminating;
// Sequence number of the last command sent to this object.
private final AtomicLong sendSeqnum;
// Sequence number of the last command processed by this object.
private long processedSeqnum;
// Socket owning this object. It's responsible for shutting down
// this object.
private Own owner;
// List of all objects owned by this socket. We are responsible
// for deallocating them before we quit.
//typedef std::set owned_t;
private final Set owned;
// Number of events we have to get before we can destroy the object.
private int termAcks;
// Note that the owner is unspecified in the constructor.
// It'll be supplied later on when the object is plugged in.
// The object is not living within an I/O thread. It has it's own
// thread outside of 0MQ infrastructure.
public Own(Ctx parent, int tid)
{
super(parent, tid);
terminating = false;
sendSeqnum = new AtomicLong(0);
processedSeqnum = 0;
owner = null;
termAcks = 0;
options = new Options();
owned = new HashSet();
}
// The object is living within I/O thread.
public Own(IOThread ioThread, Options options)
{
super(ioThread);
this.options = options;
terminating = false;
sendSeqnum = new AtomicLong(0);
processedSeqnum = 0;
owner = null;
termAcks = 0;
owned = new HashSet();
}
public abstract void destroy();
// A place to hook in when phyicallal destruction of the object
// is to be delayed.
protected void processDestroy()
{
destroy();
}
private void setOwner(Own owner)
{
assert (this.owner == null);
this.owner = owner;
}
// When another owned object wants to send command to this object
// it calls this function to let it know it should not shut down
// before the command is delivered.
void incSeqnum()
{
// This function may be called from a different thread!
sendSeqnum.incrementAndGet();
}
protected void processSeqnum()
{
// Catch up with counter of processed commands.
processedSeqnum++;
// We may have catched up and still have pending terms acks.
checkTermAcks();
}
// Launch the supplied object and become its owner.
protected void launchChild(Own object)
{
// Specify the owner of the object.
object.setOwner(this);
// Plug the object into the I/O thread.
sendPlug(object);
// Take ownership of the object.
sendOwn(this, object);
}
// Terminate owned object
protected void termChild(Own object)
{
processTermReq(object);
}
@Override
protected void processTermReq(Own object)
{
// When shutting down we can ignore termination requests from owned
// objects. The termination request was already sent to the object.
if (terminating) {
return;
}
// If I/O object is well and alive let's ask it to terminate.
// If not found, we assume that termination request was already sent to
// the object so we can safely ignore the request.
if (!owned.contains(object)) {
return;
}
owned.remove(object);
registerTermAcks(1);
// Note that this object is the root of the (partial shutdown) thus, its
// value of linger is used, rather than the value stored by the children.
sendTerm(object, options.linger);
}
protected void processOwn(Own object)
{
// If the object is already being shut down, new owned objects are
// immediately asked to terminate. Note that linger is set to zero.
if (terminating) {
registerTermAcks(1);
sendTerm(object, 0);
return;
}
// Store the reference to the owned object.
owned.add(object);
}
// Ask owner object to terminate this object. It may take a while
// while actual termination is started. This function should not be
// called more than once.
protected void terminate()
{
// If termination is already underway, there's no point
// in starting it anew.
if (terminating) {
return;
}
// As for the root of the ownership tree, there's noone to terminate it,
// so it has to terminate itself.
if (owner == null) {
processTerm(options.linger);
return;
}
// If I am an owned object, I'll ask my owner to terminate me.
sendTermReq(owner, this);
}
// Returns true if the object is in process of termination.
protected boolean isTerminating()
{
return terminating;
}
// Term handler is protocted rather than private so that it can
// be intercepted by the derived class. This is useful to add custom
// steps to the beginning of the termination process.
@Override
protected void processTerm(int linger)
{
// Double termination should never happen.
assert (!terminating);
// Send termination request to all owned objects.
for (Own it : owned) {
sendTerm(it, linger);
}
registerTermAcks(owned.size());
owned.clear();
// Start termination process and check whether by chance we cannot
// terminate immediately.
terminating = true;
checkTermAcks();
}
// Use following two functions to wait for arbitrary events before
// terminating. Just add number of events to wait for using
// register_tem_acks functions. When event occurs, call
// remove_term_ack. When number of pending acks reaches zero
// object will be deallocated.
public void registerTermAcks(int count)
{
termAcks += count;
}
public void unregisterTermAck()
{
assert (termAcks > 0);
termAcks--;
// This may be a last ack we are waiting for before termination...
checkTermAcks();
}
@Override
protected void processTermAck()
{
unregisterTermAck();
}
private void checkTermAcks()
{
if (terminating && processedSeqnum == sendSeqnum.get() &&
termAcks == 0) {
// Sanity check. There should be no active children at this point.
assert (owned.isEmpty());
// The root object has nobody to confirm the termination to.
// Other nodes will confirm the termination to the owner.
if (owner != null) {
sendTermAck(owner);
}
// Deallocate the resources.
processDestroy();
}
}
}
jeromq-0.3.5/src/main/java/zmq/Pair.java 0000664 0000000 0000000 00000005735 12551504772 0020037 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
public class Pair extends SocketBase
{
public static class PairSession extends SessionBase
{
public PairSession(IOThread ioThread, boolean connect,
SocketBase socket, final Options options,
final Address addr)
{
super(ioThread, connect, socket, options, addr);
}
}
private Pipe pipe;
public Pair(Ctx parent, int tid, int sid)
{
super(parent, tid, sid);
options.type = ZMQ.ZMQ_PAIR;
}
@Override
protected void xattachPipe(Pipe pipe, boolean icanhasall)
{
assert (pipe != null);
// ZMQ_PAIR socket can only be connected to a single peer.
// The socket rejects any further connection requests.
if (this.pipe == null) {
this.pipe = pipe;
}
else {
pipe.terminate(false);
}
}
@Override
protected void xpipeTerminated(Pipe pipe)
{
if (this.pipe == pipe) {
this.pipe = null;
}
}
@Override
protected void xreadActivated(Pipe pipe)
{
// There's just one pipe. No lists of active and inactive pipes.
// There's nothing to do here.
}
@Override
protected void xwriteActivated(Pipe pipe)
{
// There's just one pipe. No lists of active and inactive pipes.
// There's nothing to do here.
}
@Override
protected boolean xsend(Msg msg)
{
if (pipe == null || !pipe.write(msg)) {
errno.set(ZError.EAGAIN);
return false;
}
if ((msg.flags() & ZMQ.ZMQ_SNDMORE) == 0) {
pipe.flush();
}
return true;
}
@Override
protected Msg xrecv()
{
// Deallocate old content of the message.
Msg msg = pipe == null ? null : pipe.read();
if (msg == null) {
// Initialise the output parameter to be a 0-byte message.
errno.set(ZError.EAGAIN);
return null;
}
return msg;
}
@Override
protected boolean xhasIn()
{
return pipe != null && pipe.checkRead();
}
@Override
protected boolean xhasOut()
{
return pipe != null && pipe.checkWrite();
}
}
jeromq-0.3.5/src/main/java/zmq/Pipe.java 0000664 0000000 0000000 00000042010 12551504772 0020024 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
// Note that pipe can be stored in three different arrays.
// The array of inbound pipes (1), the array of outbound pipes (2) and
// the generic array of pipes to deallocate (3).
class Pipe extends ZObject
{
interface IPipeEvents
{
void readActivated(Pipe pipe);
void writeActivated(Pipe pipe);
void hiccuped(Pipe pipe);
void pipeTerminated(Pipe pipe);
}
// Underlying pipes for both directions.
private YPipe inpipe;
private YPipe outpipe;
// Can the pipe be read from / written to?
private boolean inActive;
private boolean outActive;
// High watermark for the outbound pipe.
private int hwm;
// Low watermark for the inbound pipe.
private int lwm;
// Number of messages read and written so far.
private long msgsRead;
private long msgsWritten;
// Last received peer's msgsRead. The actual number in the peer
// can be higher at the moment.
private long peersMsgsRead;
// The pipe object on the other side of the pipepair.
private Pipe peer;
// Sink to send events to.
private IPipeEvents sink;
// State of the pipe endpoint. Active is common state before any
// termination begins. Delimited means that delimiter was read from
// pipe before term command was received. Pending means that term
// command was already received from the peer but there are still
// pending messages to read. Terminating means that all pending
// messages were already read and all we are waiting for is ack from
// the peer. Terminated means that 'terminate' was explicitly called
// by the user. Double_terminated means that user called 'terminate'
// and then we've got term command from the peer as well.
enum State {
ACTIVE,
DELIMITED,
PENDING,
TERMINATING,
TERMINATED,
DOUBLE_TERMINATED
}
private State state;
// If true, we receive all the pending inbound messages before
// terminating. If false, we terminate immediately when the peer
// asks us to.
private boolean delay;
// Identity of the writer. Used uniquely by the reader side.
private Blob identity;
// JeroMQ only
private ZObject parent;
// Constructor is private. Pipe can only be created using
// pipepair function.
private Pipe(ZObject parent, YPipe inpipe, YPipe outpipe,
int inhwm, int outhwm, boolean delay)
{
super(parent);
this.inpipe = inpipe;
this.outpipe = outpipe;
inActive = true;
outActive = true;
hwm = outhwm;
lwm = computeLwm(inhwm);
msgsRead = 0;
msgsWritten = 0;
peersMsgsRead = 0;
peer = null;
sink = null;
state = State.ACTIVE;
this.delay = delay;
this.parent = parent;
}
// Create a pipepair for bi-directional transfer of messages.
// First HWM is for messages passed from first pipe to the second pipe.
// Second HWM is for messages passed from second pipe to the first pipe.
// Delay specifies how the pipe behaves when the peer terminates. If true
// pipe receives all the pending messages before terminating, otherwise it
// terminates straight away.
public static void pipepair(ZObject[] parents, Pipe[] pipes, int[] hwms,
boolean[] delays)
{
// Creates two pipe objects. These objects are connected by two ypipes,
// each to pass messages in one direction.
YPipe upipe1 = new YPipe(Config.MESSAGE_PIPE_GRANULARITY.getValue());
YPipe upipe2 = new YPipe(Config.MESSAGE_PIPE_GRANULARITY.getValue());
pipes[0] = new Pipe(parents[0], upipe1, upipe2,
hwms[1], hwms[0], delays[0]);
pipes[1] = new Pipe(parents[1], upipe2, upipe1,
hwms[0], hwms[1], delays[1]);
pipes[0].setPeer(pipes[1]);
pipes[1].setPeer(pipes[0]);
}
// Pipepair uses this function to let us know about
// the peer pipe object.
private void setPeer(Pipe peer)
{
// Peer can be set once only.
assert (peer != null);
this.peer = peer;
}
// Specifies the object to send events to.
public void setEventSink(IPipeEvents sink)
{
assert (this.sink == null);
this.sink = sink;
}
// Pipe endpoint can store an opaque ID to be used by its clients.
public void setIdentity(Blob identity)
{
this.identity = identity;
}
public Blob getIdentity()
{
return identity;
}
// Returns true if there is at least one message to read in the pipe.
public boolean checkRead()
{
if (!inActive || (state != State.ACTIVE && state != State.PENDING)) {
return false;
}
// Check if there's an item in the pipe.
if (!inpipe.checkRead()) {
inActive = false;
return false;
}
// If the next item in the pipe is message delimiter,
// initiate termination process.
if (isDelimiter(inpipe.probe())) {
Msg msg = inpipe.read();
assert (msg != null);
delimit();
return false;
}
return true;
}
// Reads a message to the underlying pipe.
public Msg read()
{
if (!inActive || (state != State.ACTIVE && state != State.PENDING)) {
return null;
}
Msg msg = inpipe.read();
if (msg == null) {
inActive = false;
return null;
}
// If delimiter was read, start termination process of the pipe.
if (msg.isDelimiter()) {
delimit();
return null;
}
if (!msg.hasMore()) {
msgsRead++;
}
if (lwm > 0 && msgsRead % lwm == 0) {
sendActivateWrite(peer, msgsRead);
}
return msg;
}
// Checks whether messages can be written to the pipe. If writing
// the message would cause high watermark the function returns false.
public boolean checkWrite()
{
if (!outActive || state != State.ACTIVE) {
return false;
}
boolean full = hwm > 0 && msgsWritten - peersMsgsRead == (long) (hwm);
if (full) {
outActive = false;
return false;
}
return true;
}
// Writes a message to the underlying pipe. Returns false if the
// message cannot be written because high watermark was reached.
public boolean write(Msg msg)
{
if (!checkWrite()) {
return false;
}
boolean more = msg.hasMore();
outpipe.write(msg, more);
if (!more) {
msgsWritten++;
}
return true;
}
// Remove unfinished parts of the outbound message from the pipe.
public void rollback()
{
// Remove incomplete message from the outbound pipe.
Msg msg;
if (outpipe != null) {
while ((msg = outpipe.unwrite()) != null) {
assert ((msg.flags() & Msg.MORE) > 0);
}
}
}
// Flush the messages downsteam.
public void flush()
{
// The peer does not exist anymore at this point.
if (state == State.TERMINATING) {
return;
}
if (outpipe != null && !outpipe.flush()) {
sendActivateRead(peer);
}
}
@Override
protected void processActivateRead()
{
if (!inActive && (state == State.ACTIVE || state == State.PENDING)) {
inActive = true;
sink.readActivated(this);
}
}
@Override
protected void processActivateWrite(long msgsRead)
{
// Remember the peers's message sequence number.
peersMsgsRead = msgsRead;
if (!outActive && state == State.ACTIVE) {
outActive = true;
sink.writeActivated(this);
}
}
@SuppressWarnings("unchecked")
@Override
protected void processHiccup(Object pipe)
{
// Destroy old outpipe. Note that the read end of the pipe was already
// migrated to this thread.
assert (outpipe != null);
outpipe.flush();
while (outpipe.read() != null) {
// do nothing
}
// Plug in the new outpipe.
assert (pipe != null);
outpipe = (YPipe) pipe;
outActive = true;
// If appropriate, notify the user about the hiccup.
if (state == State.ACTIVE) {
sink.hiccuped(this);
}
}
@Override
protected void processPipeTerm()
{
// This is the simple case of peer-induced termination. If there are no
// more pending messages to read, or if the pipe was configured to drop
// pending messages, we can move directly to the terminating state.
// Otherwise we'll hang up in pending state till all the pending messages
// are sent.
if (state == State.ACTIVE) {
if (!delay) {
state = State.TERMINATING;
outpipe = null;
sendPipeTermAck(peer);
}
else {
state = State.PENDING;
}
return;
}
// Delimiter happened to arrive before the term command. Now we have the
// term command as well, so we can move straight to terminating state.
if (state == State.DELIMITED) {
state = State.TERMINATING;
outpipe = null;
sendPipeTermAck(peer);
return;
}
// This is the case where both ends of the pipe are closed in parallel.
// We simply reply to the request by ack and continue waiting for our
// own ack.
if (state == State.TERMINATED) {
state = State.DOUBLE_TERMINATED;
outpipe = null;
sendPipeTermAck(peer);
return;
}
// pipe_term is invalid in other states.
assert (false);
}
@Override
protected void processPipeTermAck()
{
// Notify the user that all the references to the pipe should be dropped.
assert (sink != null);
sink.pipeTerminated(this);
// In terminating and double_terminated states there's nothing to do.
// Simply deallocate the pipe. In terminated state we have to ack the
// peer before deallocating this side of the pipe. All the other states
// are invalid.
if (state == State.TERMINATED) {
outpipe = null;
sendPipeTermAck(peer);
}
else {
assert (state == State.TERMINATING || state == State.DOUBLE_TERMINATED);
}
// We'll deallocate the inbound pipe, the peer will deallocate the outbound
// pipe (which is an inbound pipe from its point of view).
// First, delete all the unread messages in the pipe. We have to do it by
// hand because msg_t doesn't have automatic destructor. Then deallocate
// the ypipe itself.
while (inpipe.read() != null) {
// do nothing
}
inpipe = null;
// Deallocate the pipe object
}
// Ask pipe to terminate. The termination will happen asynchronously
// and user will be notified about actual deallocation by 'terminated'
// event. If delay is true, the pending messages will be processed
// before actual shutdown.
public void terminate(boolean delay)
{
// Overload the value specified at pipe creation.
this.delay = delay;
// If terminate was already called, we can ignore the duplicit invocation.
if (state == State.TERMINATED || state == State.DOUBLE_TERMINATED) {
return;
}
// If the pipe is in the final phase of async termination, it's going to
// closed anyway. No need to do anything special here.
else if (state == State.TERMINATING) {
return;
}
// The simple sync termination case. Ask the peer to terminate and wait
// for the ack.
else if (state == State.ACTIVE) {
sendPipeTerm(peer);
state = State.TERMINATED;
}
// There are still pending messages available, but the user calls
// 'terminate'. We can act as if all the pending messages were read.
else if (state == State.PENDING && !this.delay) {
outpipe = null;
sendPipeTermAck(peer);
state = State.TERMINATING;
}
// If there are pending messages still available, do nothing.
else if (state == State.PENDING) {
// do nothing
}
// We've already got delimiter, but not term command yet. We can ignore
// the delimiter and ack synchronously terminate as if we were in
// active state.
else if (state == State.DELIMITED) {
sendPipeTerm(peer);
state = State.TERMINATED;
}
// There are no other states.
else {
assert (false);
}
// Stop outbound flow of messages.
outActive = false;
if (outpipe != null) {
// Drop any unfinished outbound messages.
rollback();
// Write the delimiter into the pipe. Note that watermarks are not
// checked; thus the delimiter can be written even when the pipe is full.
Msg msg = new Msg();
msg.initDelimiter();
outpipe.write(msg, false);
flush();
}
}
// Returns true if the message is delimiter; false otherwise.
private static boolean isDelimiter(Msg msg)
{
return msg.isDelimiter();
}
// Computes appropriate low watermark from the given high watermark.
private static int computeLwm(int hwm)
{
// Compute the low water mark. Following point should be taken
// into consideration:
//
// 1. LWM has to be less than HWM.
// 2. LWM cannot be set to very low value (such as zero) as after filling
// the queue it would start to refill only after all the messages are
// read from it and thus unnecessarily hold the progress back.
// 3. LWM cannot be set to very high value (such as HWM-1) as it would
// result in lock-step filling of the queue - if a single message is
// read from a full queue, writer thread is resumed to write exactly one
// message to the queue and go back to sleep immediately. This would
// result in low performance.
//
// Given the 3. it would be good to keep HWM and LWM as far apart as
// possible to reduce the thread switching overhead to almost zero,
// say HWM-LWM should be max_wm_delta.
//
// That done, we still we have to account for the cases where
// HWM < max_wm_delta thus driving LWM to negative numbers.
// Let's make LWM 1/2 of HWM in such cases.
return (hwm > Config.MAX_WM_DELTA.getValue() * 2) ?
hwm - Config.MAX_WM_DELTA.getValue() : (hwm + 1) / 2;
}
// Handler for delimiter read from the pipe.
private void delimit()
{
if (state == State.ACTIVE) {
state = State.DELIMITED;
return;
}
if (state == State.PENDING) {
outpipe = null;
sendPipeTermAck(peer);
state = State.TERMINATING;
return;
}
// Delimiter in any other state is invalid.
assert (false);
}
// Temporaraily disconnects the inbound message stream and drops
// all the messages on the fly. Causes 'hiccuped' event to be generated
// in the peer.
public void hiccup()
{
// If termination is already under way do nothing.
if (state != State.ACTIVE) {
return;
}
// We'll drop the pointer to the inpipe. From now on, the peer is
// responsible for deallocating it.
inpipe = null;
// Create new inpipe.
inpipe = new YPipe(Config.MESSAGE_PIPE_GRANULARITY.getValue());
inActive = true;
// Notify the peer about the hiccup.
sendHiccup(peer, inpipe);
}
@Override
public String toString()
{
return super.toString() + "[" + parent + "]";
}
}
jeromq-0.3.5/src/main/java/zmq/PollItem.java 0000664 0000000 0000000 00000007336 12551504772 0020670 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
public class PollItem
{
private SocketBase socket;
private SelectableChannel channel;
private int zinterest;
private int interest;
private int ready;
public PollItem(SocketBase socket)
{
this.socket = socket;
channel = null;
zinterest = -1;
interest = -1;
}
public PollItem(SocketBase socket, int ops)
{
this.socket = socket;
channel = null;
init(ops);
}
public PollItem(SelectableChannel channel, int ops)
{
socket = null;
this.channel = channel;
init(ops);
}
private void init(int ops)
{
zinterest = ops;
int interest = 0;
if ((ops & ZMQ.ZMQ_POLLIN) > 0) {
interest |= SelectionKey.OP_READ;
}
if ((ops & ZMQ.ZMQ_POLLOUT) > 0) {
if (socket != null) { // ZMQ Socket get readiness from the mailbox
interest |= SelectionKey.OP_READ;
}
else {
interest |= SelectionKey.OP_WRITE;
}
}
this.interest = interest;
ready = 0;
}
public final boolean isReadable()
{
return (ready & ZMQ.ZMQ_POLLIN) > 0;
}
public final boolean isWritable()
{
return (ready & ZMQ.ZMQ_POLLOUT) > 0;
}
public final boolean isError()
{
return (ready & ZMQ.ZMQ_POLLERR) > 0;
}
public final SocketBase getSocket()
{
return socket;
}
public final SelectableChannel getRawSocket()
{
return channel;
}
protected final SelectableChannel getChannel()
{
if (socket != null) {
return socket.getFD();
}
else {
return channel;
}
}
public final int interestOps()
{
return interest;
}
public final int interestOps(int ops)
{
init(ops);
return interest;
}
public final int readyOps(SelectionKey key, int nevents)
{
ready = 0;
if (socket != null) {
int events = socket.getSocketOpt(ZMQ.ZMQ_EVENTS);
if (events < 0) {
return -1;
}
if ((zinterest & ZMQ.ZMQ_POLLOUT) > 0 && (events & ZMQ.ZMQ_POLLOUT) > 0) {
ready |= ZMQ.ZMQ_POLLOUT;
}
if ((zinterest & ZMQ.ZMQ_POLLIN) > 0 && (events & ZMQ.ZMQ_POLLIN) > 0) {
ready |= ZMQ.ZMQ_POLLIN;
}
}
else if (nevents > 0) {
if (key.isReadable()) {
ready |= ZMQ.ZMQ_POLLIN;
}
if (key.isWritable()) {
ready |= ZMQ.ZMQ_POLLOUT;
}
if (!key.isValid() || key.isAcceptable() || key.isConnectable()) {
ready |= ZMQ.ZMQ_POLLERR;
}
}
return ready;
}
public final int readyOps()
{
return ready;
}
}
jeromq-0.3.5/src/main/java/zmq/Poller.java 0000664 0000000 0000000 00000017423 12551504772 0020376 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.io.IOException;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
public class Poller extends PollerBase implements Runnable
{
private static class PollSet
{
protected IPollEvents handler;
protected SelectionKey key;
protected int ops;
protected boolean cancelled;
protected PollSet(IPollEvents handler)
{
this.handler = handler;
key = null;
cancelled = false;
ops = 0;
}
}
// This table stores data for registered descriptors.
private final Map fdTable;
// If true, there's at least one retired event source.
private final AtomicBoolean retired = new AtomicBoolean(false);
// If true, thread is in the process of shutting down.
private volatile boolean stopping;
private volatile boolean stopped;
private Thread worker;
private Selector selector;
private final String name;
public Poller()
{
this("poller");
}
public Poller(String name)
{
this.name = name;
stopping = false;
stopped = false;
fdTable = new HashMap();
try {
selector = Selector.open();
}
catch (IOException e) {
throw new ZError.IOException(e);
}
}
public void destroy()
{
if (!stopped) {
try {
worker.join();
}
catch (InterruptedException e) {
}
}
try {
selector.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
public final void addHandle(SelectableChannel fd, IPollEvents events)
{
fdTable.put(fd, new PollSet(events));
adjustLoad(1);
}
public final void removeHandle(SelectableChannel handle)
{
fdTable.get(handle).cancelled = true;
retired.set(true);
// Decrease the load metric of the thread.
adjustLoad(-1);
}
public final void setPollIn(SelectableChannel handle)
{
register(handle, SelectionKey.OP_READ, false);
}
public final void resetPollOn(SelectableChannel handle)
{
register(handle, SelectionKey.OP_READ, true);
}
public final void setPollOut(SelectableChannel handle)
{
register(handle, SelectionKey.OP_WRITE, false);
}
public final void resetPollOut(SelectableChannel handle)
{
register(handle, SelectionKey.OP_WRITE, true);
}
public final void setPollConnect(SelectableChannel handle)
{
register(handle, SelectionKey.OP_CONNECT, false);
}
public final void setPollAccept(SelectableChannel handle)
{
register(handle, SelectionKey.OP_ACCEPT, false);
}
private final void register(SelectableChannel handle, int ops, boolean negate)
{
PollSet pollset = fdTable.get(handle);
if (negate) {
pollset.ops = pollset.ops & ~ops;
}
else {
pollset.ops = pollset.ops | ops;
}
if (pollset.key != null) {
pollset.key.interestOps(pollset.ops);
}
else {
retired.set(true);
}
}
public void start()
{
worker = new Thread(this, name);
worker.setDaemon(true);
worker.start();
}
public void stop()
{
stopping = true;
selector.wakeup();
}
@Override
public void run()
{
int returnsImmediately = 0;
while (!stopping) {
// Execute any due timers.
long timeout = executeTimers();
while (retired.compareAndSet(true, false)) {
Iterator> it = fdTable.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = it.next();
SelectableChannel ch = entry.getKey();
PollSet pollset = entry.getValue();
if (pollset.key == null) {
try {
pollset.key = ch.register(selector, pollset.ops, pollset.handler);
}
catch (ClosedChannelException e) {
}
}
if (pollset.cancelled || !ch.isOpen()) {
if (pollset.key != null) {
pollset.key.cancel();
}
it.remove();
}
}
}
// Wait for events.
int rc;
long start = System.currentTimeMillis();
try {
rc = selector.select(timeout);
}
catch (IOException e) {
throw new ZError.IOException(e);
}
if (rc == 0) {
// Guess JDK epoll bug
if (timeout == 0 ||
System.currentTimeMillis() - start < timeout / 2) {
returnsImmediately++;
}
else {
returnsImmediately = 0;
}
if (returnsImmediately > 10) {
rebuildSelector();
returnsImmediately = 0;
}
continue;
}
Iterator it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
IPollEvents evt = (IPollEvents) key.attachment();
it.remove();
try {
if (key.isReadable()) {
evt.inEvent();
}
else if (key.isAcceptable()) {
evt.acceptEvent();
}
else if (key.isConnectable()) {
evt.connectEvent();
}
if (key.isWritable()) {
evt.outEvent();
}
}
catch (CancelledKeyException e) {
// channel might have been closed
}
}
}
stopped = true;
}
private void rebuildSelector()
{
Selector newSelector;
try {
newSelector = Selector.open();
}
catch (IOException e) {
throw new ZError.IOException(e);
}
try {
selector.close();
}
catch (IOException e) {
}
selector = newSelector;
for (PollSet pollSet : fdTable.values()) {
pollSet.key = null;
}
retired.set(true);
}
}
jeromq-0.3.5/src/main/java/zmq/PollerBase.java 0000664 0000000 0000000 00000010417 12551504772 0021165 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
abstract class PollerBase
{
// Load of the poller. Currently the number of file descriptors
// registered.
private final AtomicInteger load;
private final class TimerInfo
{
IPollEvents sink;
int id;
public TimerInfo(IPollEvents sink, int id)
{
this.sink = sink;
this.id = id;
}
}
private final Map timers;
private final Map addingTimers;
protected PollerBase()
{
load = new AtomicInteger(0);
timers = new MultiMap();
addingTimers = new MultiMap();
}
// Returns load of the poller. Note that this function can be
// invoked from a different thread!
public final int getLoad()
{
return load.get();
}
// Called by individual poller implementations to manage the load.
protected void adjustLoad(int amount)
{
load.addAndGet(amount);
}
// Add a timeout to expire in timeout_ milliseconds. After the
// expiration timerEvent on sink_ object will be called with
// argument set to id_.
public void addTimer(long timeout, IPollEvents sink, int id)
{
long expiration = Clock.nowMS() + timeout;
TimerInfo info = new TimerInfo(sink, id);
addingTimers.put(expiration, info);
}
// Cancel the timer created by sink_ object with ID equal to id_.
public void cancelTimer(IPollEvents sink, int id)
{
// Complexity of this operation is O(n). We assume it is rarely used.
if (!addingTimers.isEmpty()) {
timers.putAll(addingTimers);
addingTimers.clear();
}
Iterator> it = timers.entrySet().iterator();
while (it.hasNext()) {
TimerInfo v = it.next().getValue();
if (v.sink == sink && v.id == id) {
it.remove();
return;
}
}
// Timer not found.
assert (false);
}
// Executes any timers that are due. Returns number of milliseconds
// to wait to match the next timer or 0 meaning "no timers".
protected long executeTimers()
{
if (!addingTimers.isEmpty()) {
timers.putAll(addingTimers);
addingTimers.clear();
}
// Fast track.
if (timers.isEmpty()) {
return 0L;
}
// Get the current time.
long current = Clock.nowMS();
// Execute the timers that are already due.
Iterator> it = timers.entrySet().iterator();
while (it.hasNext()) {
Entry o = it.next();
// If we have to wait to execute the item, same will be true about
// all the following items (multimap is sorted). Thus we can stop
// checking the subsequent timers and return the time to wait for
// the next timer (at least 1ms).
if (o.getKey() > current) {
return o.getKey() - current;
}
// Trigger the timer.
o.getValue().sink.timerEvent(o.getValue().id);
// Remove it from the list of active timers.
it.remove();
}
if (!addingTimers.isEmpty()) {
return executeTimers();
}
// There are no more timers.
return 0L;
}
}
jeromq-0.3.5/src/main/java/zmq/Proxy.java 0000664 0000000 0000000 00000010676 12551504772 0020265 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.io.IOException;
import java.nio.channels.Selector;
public class Proxy
{
private Proxy()
{
}
public static boolean proxy(SocketBase frontend,
SocketBase backend, SocketBase capture)
{
// The algorithm below assumes ratio of requests and replies processed
// under full load to be 1:1.
// TODO: The current implementation drops messages when
// any of the pipes becomes full.
boolean success = true;
int rc;
long more;
Msg msg;
PollItem[] items = new PollItem[2];
items[0] = new PollItem(frontend, ZMQ.ZMQ_POLLIN);
items[1] = new PollItem(backend, ZMQ.ZMQ_POLLIN);
Selector selector;
try {
selector = Selector.open();
}
catch (IOException e) {
throw new ZError.IOException(e);
}
try {
while (!Thread.currentThread().isInterrupted()) {
// Wait while there are either requests or replies to process.
rc = ZMQ.poll(selector, items, -1);
if (rc < 0) {
return false;
}
// Process a request.
if (items[0].isReadable()) {
while (true) {
msg = frontend.recv(0);
if (msg == null) {
return false;
}
more = frontend.getSocketOpt(ZMQ.ZMQ_RCVMORE);
if (more < 0) {
return false;
}
// Copy message to capture socket if any
if (capture != null) {
Msg ctrl = new Msg(msg);
success = capture.send(ctrl, more > 0 ? ZMQ.ZMQ_SNDMORE : 0);
if (!success) {
return false;
}
}
success = backend.send(msg, more > 0 ? ZMQ.ZMQ_SNDMORE : 0);
if (!success) {
return false;
}
if (more == 0) {
break;
}
}
}
// Process a reply.
if (items[1].isReadable()) {
while (true) {
msg = backend.recv(0);
if (msg == null) {
return false;
}
more = backend.getSocketOpt(ZMQ.ZMQ_RCVMORE);
if (more < 0) {
return false;
}
// Copy message to capture socket if any
if (capture != null) {
Msg ctrl = new Msg(msg);
success = capture.send(ctrl, more > 0 ? ZMQ.ZMQ_SNDMORE : 0);
if (!success) {
return false;
}
}
success = frontend.send(msg, more > 0 ? ZMQ.ZMQ_SNDMORE : 0);
if (!success) {
return false;
}
if (more == 0) {
break;
}
}
}
}
}
finally {
try {
selector.close();
}
catch (Exception e) {
}
}
return true;
}
}
jeromq-0.3.5/src/main/java/zmq/Pub.java 0000664 0000000 0000000 00000002665 12551504772 0017671 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
public class Pub extends XPub
{
public static class PubSession extends XPub.XPubSession
{
public PubSession(IOThread ioThread, boolean connect,
SocketBase socket, Options options, Address addr)
{
super(ioThread, connect, socket, options, addr);
}
}
public Pub(Ctx parent, int tid, int sid)
{
super(parent, tid, sid);
options.type = ZMQ.ZMQ_PUB;
}
@Override
protected Msg xrecv()
{
// Messages cannot be received from PUB socket.
throw new UnsupportedOperationException();
}
@Override
protected boolean xhasIn()
{
return false;
}
}
jeromq-0.3.5/src/main/java/zmq/Pull.java 0000664 0000000 0000000 00000003472 12551504772 0020054 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
class Pull extends SocketBase
{
public static class PullSession extends SessionBase
{
public PullSession(IOThread ioThread, boolean connect,
SocketBase socket, final Options options,
final Address addr)
{
super(ioThread, connect, socket, options, addr);
}
}
// Fair queueing object for inbound pipes.
private final FQ fq;
public Pull(Ctx parent, int tid, int sid)
{
super(parent, tid, sid);
options.type = ZMQ.ZMQ_PULL;
fq = new FQ();
}
@Override
protected void xattachPipe(Pipe pipe, boolean icanhasall)
{
assert (pipe != null);
fq.attach(pipe);
}
@Override
protected void xreadActivated(Pipe pipe)
{
fq.activated(pipe);
}
@Override
protected void xpipeTerminated(Pipe pipe)
{
fq.terminated(pipe);
}
@Override
public Msg xrecv()
{
return fq.recv(errno);
}
@Override
protected boolean xhasIn()
{
return fq.hasIn();
}
}
jeromq-0.3.5/src/main/java/zmq/Push.java 0000664 0000000 0000000 00000003527 12551504772 0020060 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
public class Push extends SocketBase
{
public static class PushSession extends SessionBase
{
public PushSession(IOThread ioThread, boolean connect,
SocketBase socket, final Options options,
final Address addr)
{
super(ioThread, connect, socket, options, addr);
}
}
// Load balancer managing the outbound pipes.
private final LB lb;
public Push(Ctx parent, int tid, int sid)
{
super(parent, tid, sid);
options.type = ZMQ.ZMQ_PUSH;
lb = new LB();
}
@Override
protected void xattachPipe(Pipe pipe, boolean icanhasall)
{
assert (pipe != null);
lb.attach(pipe);
}
@Override
protected void xwriteActivated(Pipe pipe)
{
lb.activated(pipe);
}
@Override
protected void xpipeTerminated(Pipe pipe)
{
lb.terminated(pipe);
}
@Override
public boolean xsend(Msg msg)
{
return lb.send(msg, errno);
}
@Override
protected boolean xhasOut()
{
return lb.hasOut();
}
}
jeromq-0.3.5/src/main/java/zmq/Reaper.java 0000664 0000000 0000000 00000007265 12551504772 0020362 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.io.Closeable;
import java.io.IOException;
import java.nio.channels.SelectableChannel;
public class Reaper extends ZObject implements IPollEvents, Closeable
{
// Reaper thread accesses incoming commands via this mailbox.
private final Mailbox mailbox;
// Handle associated with mailbox' file descriptor.
private SelectableChannel mailboxHandle;
// I/O multiplexing is performed using a poller object.
private final Poller poller;
// Number of sockets being reaped at the moment.
private int sockets;
// If true, we were already asked to terminate.
private volatile boolean terminating;
private String name;
public Reaper(Ctx ctx, int tid)
{
super(ctx, tid);
sockets = 0;
terminating = false;
name = "reaper-" + tid;
poller = new Poller(name);
mailbox = new Mailbox(name);
mailboxHandle = mailbox.getFd();
poller.addHandle(mailboxHandle, this);
poller.setPollIn(mailboxHandle);
}
@Override
public void close() throws IOException
{
poller.destroy();
mailbox.close();
}
public Mailbox getMailbox()
{
return mailbox;
}
public void start()
{
poller.start();
}
public void stop()
{
if (!terminating) {
sendStop();
}
}
@Override
public void inEvent()
{
while (true) {
// Get the next command. If there is none, exit.
Command cmd = mailbox.recv(0);
if (cmd == null) {
break;
}
// Process the command.
cmd.destination().processCommand(cmd);
}
}
@Override
public void outEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void connectEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void acceptEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void timerEvent(int id)
{
throw new UnsupportedOperationException();
}
@Override
protected void processStop()
{
terminating = true;
// If there are no sockets being reaped finish immediately.
if (sockets == 0) {
sendDone();
poller.removeHandle(mailboxHandle);
poller.stop();
}
}
@Override
protected void processReap(SocketBase socket)
{
// Add the socket to the poller.
socket.startReaping(poller);
++sockets;
}
@Override
protected void processReaped()
{
--sockets;
// If reaped was already asked to terminate and there are no more sockets,
// finish immediately.
if (sockets == 0 && terminating) {
sendDone();
poller.removeHandle(mailboxHandle);
poller.stop();
}
}
}
jeromq-0.3.5/src/main/java/zmq/Rep.java 0000664 0000000 0000000 00000007726 12551504772 0017674 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
public class Rep extends Router
{
public static class RepSession extends Router.RouterSession
{
public RepSession(IOThread ioThread, boolean connect,
SocketBase socket, final Options options,
final Address addr)
{
super(ioThread, connect, socket, options, addr);
}
}
// If true, we are in process of sending the reply. If false we are
// in process of receiving a request.
private boolean sendingReply;
// If true, we are starting to receive a request. The beginning
// of the request is the backtrace stack.
private boolean requestBegins;
public Rep(Ctx parent, int tid, int sid)
{
super(parent, tid, sid);
sendingReply = false;
requestBegins = true;
options.type = ZMQ.ZMQ_REP;
}
@Override
protected boolean xsend(Msg msg)
{
// If we are in the middle of receiving a request, we cannot send reply.
if (!sendingReply) {
throw new IllegalStateException("Cannot send another reply");
}
boolean more = msg.hasMore();
// Push message to the reply pipe.
boolean rc = super.xsend(msg);
if (!rc) {
return rc;
}
// If the reply is complete flip the FSM back to request receiving state.
if (!more) {
sendingReply = false;
}
return true;
}
@Override
protected Msg xrecv()
{
// If we are in middle of sending a reply, we cannot receive next request.
if (sendingReply) {
throw new IllegalStateException("Cannot receive another request");
}
Msg msg = null;
// First thing to do when receiving a request is to copy all the labels
// to the reply pipe.
if (requestBegins) {
while (true) {
msg = super.xrecv();
if (msg == null) {
return null;
}
if (msg.hasMore()) {
// Empty message part delimits the traceback stack.
boolean bottom = (msg.size() == 0);
// Push it to the reply pipe.
boolean rc = super.xsend(msg);
assert (rc);
if (bottom) {
break;
}
}
else {
// If the traceback stack is malformed, discard anything
// already sent to pipe (we're at end of invalid message).
super.rollback();
}
}
requestBegins = false;
}
// Get next message part to return to the user.
msg = super.xrecv();
if (msg == null) {
return null;
}
// If whole request is read, flip the FSM to reply-sending state.
if (!msg.hasMore()) {
sendingReply = true;
requestBegins = true;
}
return msg;
}
@Override
protected boolean xhasIn()
{
return !sendingReply && super.xhasIn();
}
@Override
protected boolean xhasOut()
{
return sendingReply && super.xhasOut();
}
}
jeromq-0.3.5/src/main/java/zmq/Req.java 0000664 0000000 0000000 00000012171 12551504772 0017663 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
public class Req extends Dealer
{
// If true, request was already sent and reply wasn't received yet or
// was raceived partially.
private boolean receivingReply;
// If true, we are starting to send/recv a message. The first part
// of the message must be empty message part (backtrace stack bottom).
private boolean messageBegins;
public Req(Ctx parent, int tid, int sid)
{
super(parent, tid, sid);
receivingReply = false;
messageBegins = true;
options.type = ZMQ.ZMQ_REQ;
}
@Override
public boolean xsend(Msg msg)
{
// If we've sent a request and we still haven't got the reply,
// we can't send another request.
if (receivingReply) {
errno.set(ZError.EFSM);
return false;
}
// First part of the request is the request identity.
if (messageBegins) {
Msg bottom = new Msg();
bottom.setFlags(Msg.MORE);
boolean rc = super.xsend(bottom);
if (!rc) {
return rc;
}
messageBegins = false;
}
boolean more = msg.hasMore();
boolean rc = super.xsend(msg);
if (!rc) {
return rc;
}
// If the request was fully sent, flip the FSM into reply-receiving state.
if (!more) {
receivingReply = true;
messageBegins = true;
}
return true;
}
@Override
protected Msg xrecv()
{
// If request wasn't send, we can't wait for reply.
if (!receivingReply) {
errno.set(ZError.EFSM);
return null;
}
Msg msg = null;
// First part of the reply should be the original request ID.
if (messageBegins) {
msg = super.xrecv();
if (msg == null) {
return null;
}
// TODO: This should also close the connection with the peer!
if (!msg.hasMore() || msg.size() != 0) {
while (true) {
msg = super.xrecv();
assert (msg != null);
if (!msg.hasMore()) {
break;
}
}
errno.set(ZError.EAGAIN);
return null;
}
messageBegins = false;
}
msg = super.xrecv();
if (msg == null) {
return null;
}
// If the reply is fully received, flip the FSM into request-sending state.
if (!msg.hasMore()) {
receivingReply = false;
messageBegins = true;
}
return msg;
}
@Override
public boolean xhasIn()
{
// TODO: Duplicates should be removed here.
return receivingReply && super.xhasIn();
}
@Override
public boolean xhasOut()
{
return !receivingReply && super.xhasOut();
}
public static class ReqSession extends Dealer.DealerSession
{
enum State {
IDENTITY,
BOTTOM,
BODY
};
private State state;
public ReqSession(IOThread ioThread, boolean connect,
SocketBase socket, final Options options,
final Address addr)
{
super(ioThread, connect, socket, options, addr);
state = State.IDENTITY;
}
@Override
public int pushMsg(Msg msg)
{
switch (state) {
case BOTTOM:
if (msg.hasMore() && msg.size() == 0) {
state = State.BODY;
return super.pushMsg(msg);
}
break;
case BODY:
if (msg.hasMore()) {
return super.pushMsg(msg);
}
if (msg.flags() == 0) {
state = State.BOTTOM;
return super.pushMsg(msg);
}
break;
case IDENTITY:
if (msg.flags() == 0) {
state = State.BOTTOM;
return super.pushMsg(msg);
}
break;
}
socket.errno.set(ZError.EFAULT);
return -1;
}
public void reset()
{
super.reset();
state = State.IDENTITY;
}
}
}
jeromq-0.3.5/src/main/java/zmq/Router.java 0000664 0000000 0000000 00000030507 12551504772 0020417 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
//TODO: This class uses O(n) scheduling. Rewrite it to use O(1) algorithm.
public class Router extends SocketBase
{
public static class RouterSession extends SessionBase
{
public RouterSession(IOThread ioThread, boolean connect,
SocketBase socket, final Options options,
final Address addr)
{
super(ioThread, connect, socket, options, addr);
}
}
// Fair queueing object for inbound pipes.
private final FQ fq;
// True iff there is a message held in the pre-fetch buffer.
private boolean prefetched;
// If true, the receiver got the message part with
// the peer's identity.
private boolean identitySent;
// Holds the prefetched identity.
private Msg prefetchedId;
// Holds the prefetched message.
private Msg prefetchedMsg;
// If true, more incoming message parts are expected.
private boolean moreIn;
class Outpipe
{
private Pipe pipe;
private boolean active;
public Outpipe(Pipe pipe, boolean active)
{
this.pipe = pipe;
this.active = active;
}
};
// We keep a set of pipes that have not been identified yet.
private final Set anonymousPipes;
// Outbound pipes indexed by the peer IDs.
private final Map outpipes;
// The pipe we are currently writing to.
private Pipe currentOut;
// If true, more outgoing message parts are expected.
private boolean moreOut;
// Peer ID are generated. It's a simple increment and wrap-over
// algorithm. This value is the next ID to use (if not used already).
private int nextPeerId;
// If true, report EHOSTUNREACH to the caller instead of silently dropping
// the message targeting an unknown peer.
private boolean mandatory;
private boolean handover;
public Router(Ctx parent, int tid, int sid)
{
super(parent, tid, sid);
prefetched = false;
identitySent = false;
moreIn = false;
currentOut = null;
moreOut = false;
nextPeerId = Utils.generateRandom();
mandatory = false;
handover = false;
options.type = ZMQ.ZMQ_ROUTER;
fq = new FQ();
prefetchedId = new Msg();
prefetchedMsg = new Msg();
anonymousPipes = new HashSet();
outpipes = new HashMap();
// TODO: Uncomment the following line when ROUTER will become true ROUTER
// rather than generic router socket.
// If peer disconnect there's noone to send reply to anyway. We can drop
// all the outstanding requests from that peer.
// options.delayOnDisconnect = false;
options.recvIdentity = true;
}
@Override
public void xattachPipe(Pipe pipe, boolean icanhasall)
{
assert (pipe != null);
boolean identityOk = identifyPeer(pipe);
if (identityOk) {
fq.attach(pipe);
}
else {
anonymousPipes.add(pipe);
}
}
@Override
public boolean xsetsockopt(int option, Object optval)
{
if (option == ZMQ.ZMQ_ROUTER_MANDATORY) {
mandatory = (Integer) optval == 1;
return true;
}
if (option == ZMQ.ZMQ_ROUTER_HANDOVER) {
handover = (Integer) optval == 1;
return true;
}
return false;
}
@Override
public void xpipeTerminated(Pipe pipe)
{
if (!anonymousPipes.remove(pipe)) {
Outpipe old = outpipes.remove(pipe.getIdentity());
assert (old != null);
fq.terminated(pipe);
if (pipe == currentOut) {
currentOut = null;
}
}
}
@Override
public void xreadActivated(Pipe pipe)
{
if (!anonymousPipes.contains(pipe)) {
fq.activated(pipe);
}
else {
boolean identityOk = identifyPeer(pipe);
if (identityOk) {
anonymousPipes.remove(pipe);
fq.attach(pipe);
}
}
}
@Override
public void xwriteActivated(Pipe pipe)
{
for (Map.Entry it : outpipes.entrySet()) {
if (it.getValue().pipe == pipe) {
assert (!it.getValue().active);
it.getValue().active = true;
return;
}
}
assert (false);
}
@Override
protected boolean xsend(Msg msg)
{
// If this is the first part of the message it's the ID of the
// peer to send the message to.
if (!moreOut) {
assert (currentOut == null);
// If we have malformed message (prefix with no subsequent message)
// then just silently ignore it.
// TODO: The connections should be killed instead.
if (msg.hasMore()) {
moreOut = true;
// Find the pipe associated with the identity stored in the prefix.
// If there's no such pipe just silently ignore the message, unless
// mandatory is set.
Blob identity = Blob.createBlob(msg.data(), true);
Outpipe op = outpipes.get(identity);
if (op != null) {
currentOut = op.pipe;
if (!currentOut.checkWrite()) {
op.active = false;
currentOut = null;
if (mandatory) {
moreOut = false;
errno.set(ZError.EAGAIN);
return false;
}
}
}
else if (mandatory) {
moreOut = false;
errno.set(ZError.EHOSTUNREACH);
return false;
}
}
return true;
}
// Check whether this is the last part of the message.
moreOut = msg.hasMore();
// Push the message into the pipe. If there's no out pipe, just drop it.
if (currentOut != null) {
boolean ok = currentOut.write(msg);
if (!ok) {
currentOut = null;
}
else if (!moreOut) {
currentOut.flush();
currentOut = null;
}
}
return true;
}
@Override
protected Msg xrecv()
{
Msg msg = null;
if (prefetched) {
if (!identitySent) {
msg = prefetchedId;
prefetchedId = null;
identitySent = true;
}
else {
msg = prefetchedMsg;
prefetchedMsg = null;
prefetched = false;
}
moreIn = msg.hasMore();
return msg;
}
ValueReference pipe = new ValueReference();
msg = fq.recvPipe(errno, pipe);
// It's possible that we receive peer's identity. That happens
// after reconnection. The current implementation assumes that
// the peer always uses the same identity.
// TODO: handle the situation when the peer changes its identity.
while (msg != null && msg.isIdentity()) {
msg = fq.recvPipe(errno, pipe);
}
if (msg == null) {
return null;
}
assert (pipe.get() != null);
// If we are in the middle of reading a message, just return the next part.
if (moreIn) {
moreIn = msg.hasMore();
}
else {
// We are at the beginning of a message.
// Keep the message part we have in the prefetch buffer
// and return the ID of the peer instead.
prefetchedMsg = msg;
prefetched = true;
Blob identity = pipe.get().getIdentity();
msg = new Msg(identity.data());
msg.setFlags(Msg.MORE);
identitySent = true;
}
return msg;
}
// Rollback any message parts that were sent but not yet flushed.
protected void rollback()
{
if (currentOut != null) {
currentOut.rollback();
currentOut = null;
moreOut = false;
}
}
@Override
protected boolean xhasIn()
{
// If we are in the middle of reading the messages, there are
// definitely more parts available.
if (moreIn) {
return true;
}
// We may already have a message pre-fetched.
if (prefetched) {
return true;
}
// Try to read the next message.
// The message, if read, is kept in the pre-fetch buffer.
ValueReference pipe = new ValueReference();
prefetchedMsg = fq.recvPipe(errno, pipe);
// It's possible that we receive peer's identity. That happens
// after reconnection. The current implementation assumes that
// the peer always uses the same identity.
// TODO: handle the situation when the peer changes its identity.
while (prefetchedMsg != null && prefetchedMsg.isIdentity()) {
prefetchedMsg = fq.recvPipe(errno, pipe);
}
if (prefetchedMsg == null) {
return false;
}
assert (pipe.get() != null);
Blob identity = pipe.get().getIdentity();
prefetchedId = new Msg(identity.data());
prefetchedId.setFlags(Msg.MORE);
prefetched = true;
identitySent = false;
return true;
}
@Override
protected boolean xhasOut()
{
// In theory, ROUTER socket is always ready for writing. Whether actual
// attempt to write succeeds depends on whitch pipe the message is going
// to be routed to.
return true;
}
private boolean identifyPeer(Pipe pipe)
{
Blob identity;
Msg msg = pipe.read();
if (msg == null) {
return false;
}
if (msg.size() == 0) {
// Fall back on the auto-generation
ByteBuffer buf = ByteBuffer.allocate(5);
buf.put((byte) 0);
buf.putInt(nextPeerId++);
identity = Blob.createBlob(buf.array(), false);
}
else {
identity = Blob.createBlob(msg.data(), true);
if (outpipes.containsKey(identity)) {
if (!handover) {
return false;
}
// We will allow the new connection to take over this
// identity. Temporarily assign a new identity to the
// existing pipe so we can terminate it asynchronously.
ByteBuffer buf = ByteBuffer.allocate(5);
buf.put((byte) 0);
buf.putInt(nextPeerId++);
Blob newIdentity = Blob.createBlob(buf.array(), false);
// Remove the existing identity entry to allow the new
// connection to take the identity.
Outpipe existingOutpipe = outpipes.remove(identity);
existingOutpipe.pipe.setIdentity(newIdentity);
outpipes.put(newIdentity, existingOutpipe);
existingOutpipe.pipe.terminate(true);
}
}
pipe.setIdentity(identity);
// Add the record into output pipes lookup table
Outpipe outpipe = new Outpipe(pipe, true);
outpipes.put(identity, outpipe);
return true;
}
}
jeromq-0.3.5/src/main/java/zmq/SessionBase.java 0000664 0000000 0000000 00000035024 12551504772 0021354 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.util.HashSet;
import java.util.Set;
class SessionBase extends Own implements
Pipe.IPipeEvents, IPollEvents,
IMsgSink, IMsgSource
{
// If true, this session (re)connects to the peer. Otherwise, it's
// a transient session created by the listener.
private boolean connect;
// Pipe connecting the session to its socket.
private Pipe pipe;
// This set is added to with pipes we are disconnecting, but haven't yet completed
private final Set terminatingPipes;
// This flag is true if the remainder of the message being processed
// is still in the in pipe.
private boolean incompleteIn;
// True if termination have been suspended to push the pending
// messages to the network.
private boolean pending;
// The protocol I/O engine connected to the session.
private IEngine engine;
// The socket the session belongs to.
protected SocketBase socket;
// I/O thread the session is living in. It will be used to plug in
// the engines into the same thread.
private IOThread ioThread;
// ID of the linger timer
private static final int LINGER_TIMER_ID = 0x20;
// True is linger timer is running.
private boolean hasLingerTimer;
// If true, identity has been sent/received from the network.
private boolean identitySent;
private boolean identityReceived;
// Protocol and address to use when connecting.
private final Address addr;
private IOObject ioObject;
public static SessionBase create(IOThread ioThread, boolean connect,
SocketBase socket, Options options, Address addr)
{
SessionBase s = null;
switch (options.type) {
case ZMQ.ZMQ_REQ:
s = new Req.ReqSession(ioThread, connect,
socket, options, addr);
break;
case ZMQ.ZMQ_DEALER:
s = new Dealer.DealerSession(ioThread, connect,
socket, options, addr);
break;
case ZMQ.ZMQ_REP:
s = new Rep.RepSession(ioThread, connect,
socket, options, addr);
break;
case ZMQ.ZMQ_ROUTER:
s = new Router.RouterSession(ioThread, connect,
socket, options, addr);
break;
case ZMQ.ZMQ_PUB:
s = new Pub.PubSession(ioThread, connect,
socket, options, addr);
break;
case ZMQ.ZMQ_XPUB:
s = new XPub.XPubSession(ioThread, connect,
socket, options, addr);
break;
case ZMQ.ZMQ_SUB:
s = new Sub.SubSession(ioThread, connect,
socket, options, addr);
break;
case ZMQ.ZMQ_XSUB:
s = new XSub.XSubSession(ioThread, connect,
socket, options, addr);
break;
case ZMQ.ZMQ_PUSH:
s = new Push.PushSession(ioThread, connect,
socket, options, addr);
break;
case ZMQ.ZMQ_PULL:
s = new Pull.PullSession(ioThread, connect,
socket, options, addr);
break;
case ZMQ.ZMQ_PAIR:
s = new Pair.PairSession(ioThread, connect,
socket, options, addr);
break;
default:
throw new IllegalArgumentException("type=" + options.type);
}
return s;
}
public SessionBase(IOThread ioThread, boolean connect,
SocketBase socket, Options options, Address addr)
{
super(ioThread, options);
ioObject = new IOObject(ioThread);
this.connect = connect;
pipe = null;
incompleteIn = false;
pending = false;
engine = null;
this.socket = socket;
this.ioThread = ioThread;
hasLingerTimer = false;
identitySent = false;
identityReceived = false;
this.addr = addr;
terminatingPipes = new HashSet();
}
@Override
public void destroy()
{
assert (pipe == null);
// If there's still a pending linger timer, remove it.
if (hasLingerTimer) {
ioObject.cancelTimer(LINGER_TIMER_ID);
hasLingerTimer = false;
}
// Close the engine.
if (engine != null) {
engine.terminate();
}
}
// To be used once only, when creating the session.
public void attachPipe(Pipe pipe)
{
assert (!isTerminating());
assert (this.pipe == null);
assert (pipe != null);
this.pipe = pipe;
this.pipe.setEventSink(this);
}
public Msg pullMsg()
{
// First message to send is identity
if (!identitySent) {
Msg msg = new Msg(options.identitySize);
msg.put(options.identity, 0, options.identitySize);
identitySent = true;
incompleteIn = false;
return msg;
}
if (pipe == null) {
return null;
}
Msg msg = pipe.read();
if (msg == null) {
return null;
}
incompleteIn = msg.hasMore();
return msg;
}
@Override
public int pushMsg(Msg msg)
{
// First message to receive is identity (if required).
if (!identityReceived) {
msg.setFlags(Msg.IDENTITY);
identityReceived = true;
if (!options.recvIdentity) {
return 0;
}
}
if (pipe != null && pipe.write(msg)) {
return 0;
}
return ZError.EAGAIN;
}
protected void reset()
{
// Restore identity flags.
identitySent = false;
identityReceived = false;
}
public void flush()
{
if (pipe != null) {
pipe.flush();
}
}
// Remove any half processed messages. Flush unflushed messages.
// Call this function when engine disconnect to get rid of leftovers.
private void cleanPipes()
{
if (pipe != null) {
// Get rid of half-processed messages in the out pipe. Flush any
// unflushed messages upstream.
pipe.rollback();
pipe.flush();
// Remove any half-read message from the in pipe.
while (incompleteIn) {
Msg msg = pullMsg();
if (msg == null) {
assert (!incompleteIn);
break;
}
// msg.close ();
}
}
}
@Override
public void pipeTerminated(Pipe pipe)
{
// Drop the reference to the deallocated pipe.
assert (this.pipe == pipe || terminatingPipes.contains(pipe));
if (this.pipe == pipe) {
// If this is our current pipe, remove it
this.pipe = null;
if (hasLingerTimer) {
ioObject.cancelTimer(LINGER_TIMER_ID);
hasLingerTimer = false;
}
}
else {
// Remove the pipe from the detached pipes set
terminatingPipes.remove(pipe);
}
// If we are waiting for pending messages to be sent, at this point
// we are sure that there will be no more messages and we can proceed
// with termination safely.
if (pending && this.pipe == null && terminatingPipes.isEmpty()) {
pending = false;
super.processTerm(0);
}
}
@Override
public void readActivated(Pipe pipe)
{
// Skip activating if we're detaching this pipe
if (this.pipe != pipe) {
assert (terminatingPipes.contains(pipe));
return;
}
if (engine != null) {
engine.activateOut();
}
else {
this.pipe.checkRead();
}
}
@Override
public void writeActivated(Pipe pipe)
{
// Skip activating if we're detaching this pipe
if (this.pipe != pipe) {
assert (terminatingPipes.contains(pipe));
return;
}
if (engine != null) {
engine.activateIn();
}
}
@Override
public void hiccuped(Pipe pipe)
{
// Hiccups are always sent from session to socket, not the other
// way round.
throw new UnsupportedOperationException("Must Override");
}
public SocketBase getSocket()
{
return socket;
}
@Override
protected void processPlug()
{
ioObject.setHandler(this);
if (connect) {
startConnecting(false);
}
}
@Override
protected void processAttach(IEngine engine)
{
assert (engine != null);
// Create the pipe if it does not exist yet.
if (pipe == null && !isTerminating()) {
ZObject[] parents = {this, socket};
Pipe[] pipes = {null, null};
int[] hwms = {options.recvHwm, options.sendHwm};
boolean[] delays = {options.delayOnClose, options.delayOnDisconnect};
Pipe.pipepair(parents, pipes, hwms, delays);
// Plug the local end of the pipe.
pipes[0].setEventSink(this);
// Remember the local end of the pipe.
assert (pipe == null);
pipe = pipes[0];
// Ask socket to plug into the remote end of the pipe.
sendBind(socket, pipes[1]);
}
// Plug in the engine.
assert (this.engine == null);
this.engine = engine;
this.engine.plug(ioThread, this);
}
public void detach()
{
// Engine is dead. Let's forget about it.
engine = null;
// Remove any half-done messages from the pipes.
cleanPipes();
// Send the event to the derived class.
detached();
// Just in case there's only a delimiter in the pipe.
if (pipe != null) {
pipe.checkRead();
}
}
protected void processTerm(int linger)
{
assert (!pending);
// If the termination of the pipe happens before the term command is
// delivered there's nothing much to do. We can proceed with the
// stadard termination immediately.
if (pipe == null && terminatingPipes.isEmpty()) {
super.processTerm(0);
return;
}
pending = true;
// If there's finite linger value, delay the termination.
// If linger is infinite (negative) we don't even have to set
// the timer.
if (linger > 0) {
assert (!hasLingerTimer);
ioObject.addTimer(linger, LINGER_TIMER_ID);
hasLingerTimer = true;
}
// Start pipe termination process. Delay the termination till all messages
// are processed in case the linger time is non-zero.
if (pipe != null) {
pipe.terminate(linger != 0);
// TODO: Should this go into pipe_t::terminate ?
// In case there's no engine and there's only delimiter in the
// pipe it wouldn't be ever read. Thus we check for it explicitly.
pipe.checkRead();
}
}
@Override
public void timerEvent(int id)
{
// Linger period expired. We can proceed with termination even though
// there are still pending messages to be sent.
assert (id == LINGER_TIMER_ID);
hasLingerTimer = false;
// Ask pipe to terminate even though there may be pending messages in it.
assert (pipe != null);
pipe.terminate(false);
}
private void detached()
{
// Transient session self-destructs after peer disconnects.
if (!connect) {
terminate();
return;
}
// For delayed connect situations, terminate the pipe
// and reestablish later on
if (pipe != null && options.delayAttachOnConnect == 1
&& !addr.protocol().equals("pgm") && !addr.protocol().equals("epgm")) {
pipe.hiccup();
pipe.terminate(false);
terminatingPipes.add(pipe);
pipe = null;
}
reset();
// Reconnect.
if (options.reconnectIvl != -1) {
startConnecting(true);
}
// For subscriber sockets we hiccup the inbound pipe, which will cause
// the socket object to resend all the subscriptions.
if (pipe != null && (options.type == ZMQ.ZMQ_SUB || options.type == ZMQ.ZMQ_XSUB)) {
pipe.hiccup();
}
}
private void startConnecting(boolean wait)
{
assert (connect);
// Choose I/O thread to run connecter in. Given that we are already
// running in an I/O thread, there must be at least one available.
IOThread ioThread = chooseIoThread(options.affinity);
assert (ioThread != null);
// Create the connecter object.
if (addr.protocol().equals("tcp")) {
TcpConnecter connecter = new TcpConnecter(
ioThread, this, options, addr, wait);
launchChild(connecter);
return;
}
if (addr.protocol().equals("ipc")) {
IpcConnecter connecter = new IpcConnecter(
ioThread, this, options, addr, wait);
launchChild(connecter);
return;
}
assert (false);
}
@Override
public String toString()
{
return super.toString() + "[" + options.socketId + "]";
}
@Override
public void inEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void outEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void connectEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void acceptEvent()
{
throw new UnsupportedOperationException();
}
}
jeromq-0.3.5/src/main/java/zmq/Signaler.java 0000664 0000000 0000000 00000011134 12551504772 0020676 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.io.Closeable;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Pipe;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.concurrent.atomic.AtomicInteger;
// This is a cross-platform equivalent to signal_fd. However, as opposed
// to signal_fd there can be at most one signal in the signaler at any
// given moment. Attempt to send a signal before receiving the previous
// one will result in undefined behaviour.
public class Signaler
implements Closeable
{
// Underlying write & read file descriptor.
private final Pipe.SinkChannel w;
private final Pipe.SourceChannel r;
private final Selector selector;
// Selector.selectNow at every sending message doesn't show enough performance
private final AtomicInteger wcursor = new AtomicInteger(0);
private int rcursor = 0;
public Signaler()
{
// Create the socketpair for signaling.
Pipe pipe;
try {
pipe = Pipe.open();
}
catch (IOException e) {
throw new ZError.IOException(e);
}
r = pipe.source();
w = pipe.sink();
// Set both fds to non-blocking mode.
try {
Utils.unblockSocket(w);
Utils.unblockSocket(r);
}
catch (IOException e) {
throw new ZError.IOException(e);
}
try {
selector = Selector.open();
r.register(selector, SelectionKey.OP_READ);
}
catch (IOException e) {
throw new ZError.IOException(e);
}
}
@Override
public void close() throws IOException
{
IOException exception = null;
try {
r.close();
}
catch (IOException e) {
exception = e;
}
try {
w.close();
}
catch (IOException e) {
exception = e;
}
try {
selector.close();
}
catch (IOException e) {
exception = e;
}
if (exception != null) {
throw exception;
}
}
public SelectableChannel getFd()
{
return r;
}
public void send()
{
int nbytes = 0;
ByteBuffer dummy = ByteBuffer.allocate(1);
while (true) {
try {
Thread.interrupted();
nbytes = w.write(dummy);
}
catch (IOException e) {
throw new ZError.IOException(e);
}
if (nbytes == 0) {
continue;
}
assert (nbytes == 1);
wcursor.incrementAndGet();
break;
}
}
public boolean waitEvent(long timeout)
{
int rc = 0;
try {
if (timeout == 0) {
// waitEvent(0) is called every read/send of SocketBase
// instant readiness is not strictly required
// On the other hand, we can save lots of system call and increase performance
return rcursor < wcursor.get();
}
else if (timeout < 0) {
rc = selector.select(0);
}
else {
rc = selector.select(timeout);
}
}
catch (IOException e) {
throw new ZError.IOException(e);
}
if (rc == 0) {
return false;
}
selector.selectedKeys().clear();
return true;
}
public void recv()
{
int nbytes = 0;
try {
ByteBuffer dummy = ByteBuffer.allocate(1);
nbytes = r.read(dummy);
assert nbytes == 1;
}
catch (IOException e) {
throw new ZError.IOException(e);
}
rcursor++;
}
}
jeromq-0.3.5/src/main/java/zmq/SocketBase.java 0000664 0000000 0000000 00000112747 12551504772 0021171 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.channels.SelectableChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public abstract class SocketBase extends Own
implements IPollEvents, Pipe.IPipeEvents
{
// Map of open endpoints.
private final Map endpoints;
// Map of open inproc endpoints.
private final Map inprocs;
// Used to check whether the object is a socket.
private int tag;
// If true, associated context was already terminated.
private boolean ctxTerminated;
// If true, object should have been already destroyed. However,
// destruction is delayed while we unwind the stack to the point
// where it doesn't intersect the object being destroyed.
private boolean destroyed;
// Socket's mailbox object.
private final Mailbox mailbox;
// List of attached pipes.
private final List pipes;
// Reaper's poller and handle of this socket within it.
private Poller poller;
private SelectableChannel handle;
// Timestamp of when commands were processed the last time.
private long lastTsc;
// Number of messages received since last command processing.
private int ticks;
// True if the last message received had MORE flag set.
private boolean rcvmore;
// Monitor socket
private SocketBase monitorSocket;
// Bitmask of events being monitored
private int monitorEvents;
protected ValueReference errno;
protected SocketBase(Ctx parent, int tid, int sid)
{
super(parent, tid);
tag = 0xbaddecaf;
ctxTerminated = false;
destroyed = false;
lastTsc = 0;
ticks = 0;
rcvmore = false;
monitorSocket = null;
monitorEvents = 0;
options.socketId = sid;
options.linger = parent.get(ZMQ.ZMQ_BLOCKY) != 0 ? -1 : 0;
endpoints = new MultiMap();
inprocs = new MultiMap();
pipes = new ArrayList();
mailbox = new Mailbox("socket-" + sid);
errno = new ValueReference(0);
}
// Concrete algorithms for the x- methods are to be defined by
// individual socket types.
protected abstract void xattachPipe(Pipe pipe, boolean icanhasall);
protected abstract void xpipeTerminated(Pipe pipe);
// Returns false if object is not a socket.
public boolean checkTag()
{
return tag == 0xbaddecaf;
}
// Create a socket of a specified type.
public static SocketBase create(int type, Ctx parent, int tid, int sid)
{
SocketBase s = null;
switch (type) {
case ZMQ.ZMQ_PAIR:
s = new Pair(parent, tid, sid);
break;
case ZMQ.ZMQ_PUB:
s = new Pub(parent, tid, sid);
break;
case ZMQ.ZMQ_SUB:
s = new Sub(parent, tid, sid);
break;
case ZMQ.ZMQ_REQ:
s = new Req(parent, tid, sid);
break;
case ZMQ.ZMQ_REP:
s = new Rep(parent, tid, sid);
break;
case ZMQ.ZMQ_DEALER:
s = new Dealer(parent, tid, sid);
break;
case ZMQ.ZMQ_ROUTER:
s = new Router(parent, tid, sid);
break;
case ZMQ.ZMQ_PULL:
s = new Pull(parent, tid, sid);
break;
case ZMQ.ZMQ_PUSH:
s = new Push(parent, tid, sid);
break;
case ZMQ.ZMQ_XPUB:
s = new XPub(parent, tid, sid);
break;
case ZMQ.ZMQ_XSUB:
s = new XSub(parent, tid, sid);
break;
default:
throw new IllegalArgumentException("type=" + type);
}
return s;
}
public void destroy()
{
try {
mailbox.close();
}
catch (IOException ignore) {
}
stopMonitor();
assert (destroyed);
}
// Returns the mailbox associated with this socket.
public Mailbox getMailbox()
{
return mailbox;
}
// Interrupt blocking call if the socket is stuck in one.
// This function can be called from a different thread!
public void stop()
{
// Called by ctx when it is terminated (zmq_term).
// 'stop' command is sent from the threads that called zmq_term to
// the thread owning the socket. This way, blocking call in the
// owner thread can be interrupted.
sendStop();
}
// Check whether transport protocol, as specified in connect or
// bind, is available and compatible with the socket type.
private void checkProtocol(String protocol)
{
// First check out whether the protcol is something we are aware of.
if (!protocol.equals("inproc") && !protocol.equals("ipc") && !protocol.equals("tcp") /*&&
!protocol.equals("pgm") && !protocol.equals("epgm")*/) {
throw new UnsupportedOperationException(protocol);
}
// Check whether socket type and transport protocol match.
// Specifically, multicast protocols can't be combined with
// bi-directional messaging patterns (socket types).
if ((protocol.equals("pgm") || protocol.equals("epgm")) &&
options.type != ZMQ.ZMQ_PUB && options.type != ZMQ.ZMQ_SUB &&
options.type != ZMQ.ZMQ_XPUB && options.type != ZMQ.ZMQ_XSUB) {
throw new UnsupportedOperationException(protocol + ",type=" + options.type);
}
// Protocol is available.
}
// Register the pipe with this socket.
private void attachPipe(Pipe pipe)
{
attachPipe(pipe, false);
}
private void attachPipe(Pipe pipe, boolean icanhasall)
{
// First, register the pipe so that we can terminate it later on.
pipe.setEventSink(this);
pipes.add(pipe);
// Let the derived socket type know about new pipe.
xattachPipe(pipe, icanhasall);
// If the socket is already being closed, ask any new pipes to terminate
// straight away.
if (isTerminating()) {
registerTermAcks(1);
pipe.terminate(false);
}
}
public void setSocketOpt(int option, Object optval)
{
if (ctxTerminated) {
throw new ZError.CtxTerminatedException();
}
// First, check whether specific socket type overloads the option.
if (xsetsockopt(option, optval)) {
return;
}
// If the socket type doesn't support the option, pass it to
// the generic option parser.
options.setSocketOpt(option, optval);
}
public int getSocketOpt(int option)
{
if (option != ZMQ.ZMQ_EVENTS && ctxTerminated) {
throw new ZError.CtxTerminatedException();
}
// fast track to avoid boxing
if (option == ZMQ.ZMQ_RCVMORE) {
return rcvmore ? 1 : 0;
}
if (option == ZMQ.ZMQ_EVENTS) {
boolean rc = processCommands(0, false);
if (!rc && errno.get() == ZError.ETERM) {
return -1;
}
assert (rc);
int val = 0;
if (hasOut()) {
val |= ZMQ.ZMQ_POLLOUT;
}
if (hasIn()) {
val |= ZMQ.ZMQ_POLLIN;
}
return val;
}
return (Integer) getsockoptx(option);
}
public Object getsockoptx(int option)
{
if (ctxTerminated) {
throw new ZError.CtxTerminatedException();
}
if (option == ZMQ.ZMQ_RCVMORE) {
return rcvmore ? 1 : 0;
}
if (option == ZMQ.ZMQ_FD) {
return mailbox.getFd();
}
if (option == ZMQ.ZMQ_EVENTS) {
boolean rc = processCommands(0, false);
if (!rc && errno.get() == ZError.ETERM) {
return -1;
}
assert (rc);
int val = 0;
if (hasOut()) {
val |= ZMQ.ZMQ_POLLOUT;
}
if (hasIn()) {
val |= ZMQ.ZMQ_POLLIN;
}
return val;
}
// If the socket type doesn't support the option, pass it to
// the generic option parser.
return options.getsockopt(option);
}
public boolean bind(final String addr)
{
if (ctxTerminated) {
throw new ZError.CtxTerminatedException();
}
// Process pending commands, if any.
boolean brc = processCommands(0, false);
if (!brc) {
return false;
}
// Parse addr_ string.
URI uri;
try {
uri = new URI(addr);
}
catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
String protocol = uri.getScheme();
String address = uri.getAuthority();
String path = uri.getPath();
if (address == null) {
address = path;
}
checkProtocol(protocol);
if (protocol.equals("inproc")) {
Ctx.Endpoint endpoint = new Ctx.Endpoint(this, options);
boolean rc = registerEndpoint(addr, endpoint);
if (rc) {
// Save last endpoint URI
options.lastEndpoint = addr;
}
else {
errno.set(ZError.EADDRINUSE);
}
return rc;
}
if (protocol.equals("pgm") || protocol.equals("epgm")) {
// For convenience's sake, bind can be used interchageable with
// connect for PGM and EPGM transports.
return connect(addr);
}
// Remaining trasnports require to be run in an I/O thread, so at this
// point we'll choose one.
IOThread ioThread = chooseIoThread(options.affinity);
if (ioThread == null) {
throw new IllegalStateException("EMTHREAD");
}
if (protocol.equals("tcp")) {
TcpListener listener = new TcpListener(ioThread, this, options);
int rc = listener.setAddress(address);
if (rc != 0) {
listener.destroy();
eventBindFailed(address, rc);
errno.set(rc);
return false;
}
// Save last endpoint URI
options.lastEndpoint = listener.getAddress();
addEndpoint(options.lastEndpoint, listener);
return true;
}
if (protocol.equals("ipc")) {
IpcListener listener = new IpcListener(ioThread, this, options);
int rc = listener.setAddress(address);
if (rc != 0) {
listener.destroy();
eventBindFailed(address, rc);
errno.set(rc);
return false;
}
// Save last endpoint URI
options.lastEndpoint = listener.getAddress();
addEndpoint(addr, listener);
return true;
}
throw new IllegalArgumentException(addr);
}
public boolean connect(String addr)
{
if (ctxTerminated) {
throw new ZError.CtxTerminatedException();
}
// Process pending commands, if any.
boolean brc = processCommands(0, false);
if (!brc) {
return false;
}
// Parse addr_ string.
URI uri;
try {
uri = new URI(addr);
}
catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
String protocol = uri.getScheme();
String address = uri.getAuthority();
String path = uri.getPath();
if (address == null) {
address = path;
}
checkProtocol(protocol);
if (protocol.equals("inproc")) {
// TODO: inproc connect is specific with respect to creating pipes
// as there's no 'reconnect' functionality implemented. Once that
// is in place we should follow generic pipe creation algorithm.
// Find the peer endpoint.
Ctx.Endpoint peer = findEndpoint(addr);
if (peer.socket == null) {
return false;
}
// The total HWM for an inproc connection should be the sum of
// the binder's HWM and the connector's HWM.
int sndhwm = 0;
if (options.sendHwm != 0 && peer.options.recvHwm != 0) {
sndhwm = options.sendHwm + peer.options.recvHwm;
}
int rcvhwm = 0;
if (options.recvHwm != 0 && peer.options.sendHwm != 0) {
rcvhwm = options.recvHwm + peer.options.sendHwm;
}
// Create a bi-directional pipe to connect the peers.
ZObject[] parents = {this, peer.socket};
Pipe[] pipes = {null, null};
int[] hwms = {sndhwm, rcvhwm};
boolean[] delays = {options.delayOnDisconnect, options.delayOnClose};
Pipe.pipepair(parents, pipes, hwms, delays);
// Attach local end of the pipe to this socket object.
attachPipe(pipes[0]);
// If required, send the identity of the peer to the local socket.
if (peer.options.recvIdentity) {
Msg id = new Msg(options.identitySize);
id.put(options.identity, 0 , options.identitySize);
id.setFlags(Msg.IDENTITY);
boolean written = pipes[0].write(id);
assert (written);
pipes[0].flush();
}
// If required, send the identity of the local socket to the peer.
if (options.recvIdentity) {
Msg id = new Msg(peer.options.identitySize);
id.put(peer.options.identity, 0 , peer.options.identitySize);
id.setFlags(Msg.IDENTITY);
boolean written = pipes[1].write(id);
assert (written);
pipes[1].flush();
}
// Attach remote end of the pipe to the peer socket. Note that peer's
// seqnum was incremented in findEndpoint function. We don't need it
// increased here.
sendBind(peer.socket, pipes[1], false);
// Save last endpoint URI
options.lastEndpoint = addr;
// remember inproc connections for disconnect
inprocs.put(addr, pipes[0]);
return true;
}
// Choose the I/O thread to run the session in.
IOThread ioThread = chooseIoThread(options.affinity);
if (ioThread == null) {
throw new IllegalStateException("Empty IO Thread");
}
boolean ipv4only = options.ipv4only != 0;
Address paddr = new Address(protocol, address, ipv4only);
// Resolve address (if needed by the protocol)
paddr.resolve();
// Create session.
SessionBase session = SessionBase.create(ioThread, true, this,
options, paddr);
assert (session != null);
// PGM does not support subscription forwarding; ask for all data to be
// sent to this pipe.
boolean icanhasall = false;
if (protocol.equals("pgm") || protocol.equals("epgm")) {
icanhasall = true;
}
if (options.delayAttachOnConnect != 1 || icanhasall) {
// Create a bi-directional pipe.
ZObject[] parents = {this, session};
Pipe[] pipes = {null, null};
int[] hwms = {options.sendHwm, options.recvHwm};
boolean[] delays = {options.delayOnDisconnect, options.delayOnClose};
Pipe.pipepair(parents, pipes, hwms, delays);
// Attach local end of the pipe to the socket object.
attachPipe(pipes[0], icanhasall);
// Attach remote end of the pipe to the session object later on.
session.attachPipe(pipes[1]);
}
// Save last endpoint URI
options.lastEndpoint = paddr.toString();
addEndpoint(addr, session);
return true;
}
// Creates new endpoint ID and adds the endpoint to the map.
private void addEndpoint(String addr, Own endpoint)
{
// Activate the session. Make it a child of this socket.
launchChild(endpoint);
endpoints.put(addr, endpoint);
}
public boolean termEndpoint(String addr)
{
if (ctxTerminated) {
throw new ZError.CtxTerminatedException();
}
// Check whether endpoint address passed to the function is valid.
if (addr == null) {
throw new IllegalArgumentException();
}
// Process pending commands, if any, since there could be pending unprocessed processOwn()'s
// (from launchChild() for example) we're asked to terminate now.
boolean rc = processCommands(0, false);
if (!rc) {
return false;
}
// Parse addr_ string.
URI uri;
try {
uri = new URI(addr);
}
catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
String protocol = uri.getScheme();
// Disconnect an inproc socket
if (protocol.equals("inproc")) {
if (!inprocs.containsKey(addr)) {
return false;
}
Iterator> it = inprocs.entrySet().iterator();
while (it.hasNext()) {
it.next().getValue().terminate(true);
it.remove();
}
return true;
}
if (!endpoints.containsKey(addr)) {
return false;
}
// Find the endpoints range (if any) corresponding to the addr_ string.
Iterator> it = endpoints.entrySet().iterator();
while (it.hasNext()) {
Entry e = it.next();
if (!e.getKey().equals(addr)) {
continue;
}
termChild(e.getValue());
it.remove();
}
return true;
}
public boolean send(Msg msg, int flags)
{
if (ctxTerminated) {
errno.set(ZError.ETERM);
return false;
}
// Check whether message passed to the function is valid.
if (msg == null) {
throw new IllegalArgumentException();
}
// Process pending commands, if any.
boolean brc = processCommands(0, true);
if (!brc) {
return false;
}
// Clear any user-visible flags that are set on the message.
msg.resetFlags(Msg.MORE);
// At this point we impose the flags on the message.
if ((flags & ZMQ.ZMQ_SNDMORE) > 0) {
msg.setFlags(Msg.MORE);
}
// Try to send the message.
boolean rc = xsend(msg);
if (rc) {
return true;
}
if (errno.get() != ZError.EAGAIN) {
return false;
}
// In case of non-blocking send we'll simply propagate
// the error - including EAGAIN - up the stack.
if ((flags & ZMQ.ZMQ_DONTWAIT) > 0 || options.sendTimeout == 0) {
return false;
}
// Compute the time when the timeout should occur.
// If the timeout is infite, don't care.
int timeout = options.sendTimeout;
long end = timeout < 0 ? 0 : (Clock.nowMS() + timeout);
// Oops, we couldn't send the message. Wait for the next
// command, process it and try to send the message again.
// If timeout is reached in the meantime, return EAGAIN.
while (true) {
if (!processCommands(timeout, false)) {
return false;
}
rc = xsend(msg);
if (rc) {
break;
}
if (errno.get() != ZError.EAGAIN) {
return false;
}
if (timeout > 0) {
timeout = (int) (end - Clock.nowMS());
if (timeout <= 0) {
errno.set(ZError.EAGAIN);
return false;
}
}
}
return true;
}
public Msg recv(int flags)
{
if (ctxTerminated) {
errno.set(ZError.ETERM);
return null;
}
// Once every inbound_poll_rate messages check for signals and process
// incoming commands. This happens only if we are not polling altogether
// because there are messages available all the time. If poll occurs,
// ticks is set to zero and thus we avoid this code.
//
// Note that 'recv' uses different command throttling algorithm (the one
// described above) from the one used by 'send'. This is because counting
// ticks is more efficient than doing RDTSC all the time.
if (++ticks == Config.INBOUND_POLL_RATE.getValue()) {
if (!processCommands(0, false)) {
return null;
}
ticks = 0;
}
// Get the message.
Msg msg = xrecv();
if (msg == null && errno.get() != ZError.EAGAIN) {
return null;
}
// If we have the message, return immediately.
if (msg != null) {
extractFlags(msg);
return msg;
}
// If the message cannot be fetched immediately, there are two scenarios.
// For non-blocking recv, commands are processed in case there's an
// activate_reader command already waiting int a command pipe.
// If it's not, return EAGAIN.
if ((flags & ZMQ.ZMQ_DONTWAIT) > 0 || options.recvTimeout == 0) {
if (!processCommands(0, false)) {
return null;
}
ticks = 0;
msg = xrecv();
if (msg == null) {
return null;
}
extractFlags(msg);
return msg;
}
// Compute the time when the timeout should occur.
// If the timeout is infite, don't care.
int timeout = options.recvTimeout;
long end = timeout < 0 ? 0 : (Clock.nowMS() + timeout);
// In blocking scenario, commands are processed over and over again until
// we are able to fetch a message.
boolean block = (ticks != 0);
while (true) {
if (!processCommands(block ? timeout : 0, false)) {
return null;
}
msg = xrecv();
if (msg != null) {
ticks = 0;
break;
}
if (errno.get() != ZError.EAGAIN) {
return null;
}
block = true;
if (timeout > 0) {
timeout = (int) (end - Clock.nowMS());
if (timeout <= 0) {
errno.set(ZError.EAGAIN);
return null;
}
}
}
extractFlags(msg);
return msg;
}
public void close()
{
// Mark the socket as dead
tag = 0xdeadbeef;
// Transfer the ownership of the socket from this application thread
// to the reaper thread which will take care of the rest of shutdown
// process.
sendReap(this);
}
// These functions are used by the polling mechanism to determine
// which events are to be reported from this socket.
boolean hasIn()
{
return xhasIn();
}
boolean hasOut()
{
return xhasOut();
}
// Using this function reaper thread ask the socket to register with
// its poller.
public void startReaping(Poller poller)
{
// Plug the socket to the reaper thread.
this.poller = poller;
handle = mailbox.getFd();
this.poller.addHandle(handle, this);
this.poller.setPollIn(handle);
// Initialise the termination and check whether it can be deallocated
// immediately.
terminate();
checkDestroy();
}
// Processes commands sent to this socket (if any). If timeout is -1,
// returns only after at least one command was processed.
// If throttle argument is true, commands are processed at most once
// in a predefined time period.
private boolean processCommands(int timeout, boolean throttle)
{
Command cmd;
if (timeout != 0) {
// If we are asked to wait, simply ask mailbox to wait.
cmd = mailbox.recv(timeout);
}
else {
// If we are asked not to wait, check whether we haven't processed
// commands recently, so that we can throttle the new commands.
// Get the CPU's tick counter. If 0, the counter is not available.
long tsc = 0; // save cpu Clock.rdtsc ();
// Optimised version of command processing - it doesn't have to check
// for incoming commands each time. It does so only if certain time
// elapsed since last command processing. Command delay varies
// depending on CPU speed: It's ~1ms on 3GHz CPU, ~2ms on 1.5GHz CPU
// etc. The optimisation makes sense only on platforms where getting
// a timestamp is a very cheap operation (tens of nanoseconds).
if (tsc != 0 && throttle) {
// Check whether TSC haven't jumped backwards (in case of migration
// between CPU cores) and whether certain time have elapsed since
// last command processing. If it didn't do nothing.
if (tsc >= lastTsc && tsc - lastTsc <= Config.MAX_COMMAND_DELAY.getValue()) {
return true;
}
lastTsc = tsc;
}
// Check whether there are any commands pending for this thread.
cmd = mailbox.recv(0);
}
// Process all the commands available at the moment.
while (true) {
if (cmd == null) {
break;
}
cmd.destination().processCommand(cmd);
cmd = mailbox.recv(0);
}
if (ctxTerminated) {
errno.set(ZError.ETERM); // Do not raise exception at the blocked operation
return false;
}
return true;
}
@Override
protected void processStop()
{
// Here, someone have called zmq_term while the socket was still alive.
// We'll remember the fact so that any blocking call is interrupted and any
// further attempt to use the socket will return ETERM. The user is still
// responsible for calling zmq_close on the socket though!
stopMonitor();
ctxTerminated = true;
}
@Override
protected void processBind(Pipe pipe)
{
attachPipe(pipe);
}
@Override
protected void processTerm(int linger)
{
// Unregister all inproc endpoints associated with this socket.
// Doing this we make sure that no new pipes from other sockets (inproc)
// will be initiated.
unregisterEndpoints(this);
// Ask all attached pipes to terminate.
for (int i = 0; i != pipes.size(); ++i) {
pipes.get(i).terminate(false);
}
registerTermAcks(pipes.size());
// Continue the termination process immediately.
super.processTerm(linger);
}
// Delay actual destruction of the socket.
@Override
protected void processDestroy()
{
destroyed = true;
}
// The default implementation assumes there are no specific socket
// options for the particular socket type. If not so, overload this
// method.
protected boolean xsetsockopt(int option, Object optval)
{
return false;
}
protected boolean xhasOut()
{
return false;
}
protected boolean xsend(Msg msg)
{
throw new UnsupportedOperationException("Must Override");
}
protected boolean xhasIn()
{
return false;
}
protected Msg xrecv()
{
throw new UnsupportedOperationException("Must Override");
}
protected void xreadActivated(Pipe pipe)
{
throw new UnsupportedOperationException("Must Override");
}
protected void xwriteActivated(Pipe pipe)
{
throw new UnsupportedOperationException("Must Override");
}
protected void xhiccuped(Pipe pipe)
{
throw new UnsupportedOperationException("Must override");
}
@Override
public void inEvent()
{
// This function is invoked only once the socket is running in the context
// of the reaper thread. Process any commands from other threads/sockets
// that may be available at the moment. Ultimately, the socket will
// be destroyed.
try {
processCommands(0, false);
}
catch (ZError.CtxTerminatedException e) {
}
checkDestroy();
}
@Override
public void outEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void connectEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void acceptEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void timerEvent(int id)
{
throw new UnsupportedOperationException();
}
// To be called after processing commands or invoking any command
// handlers explicitly. If required, it will deallocate the socket.
private void checkDestroy()
{
// If the object was already marked as destroyed, finish the deallocation.
if (destroyed) {
// Remove the socket from the reaper's poller.
poller.removeHandle(handle);
// Remove the socket from the context.
destroySocket(this);
// Notify the reaper about the fact.
sendReaped();
// Deallocate.
super.processDestroy();
}
}
@Override
public void readActivated(Pipe pipe)
{
xreadActivated(pipe);
}
@Override
public void writeActivated(Pipe pipe)
{
xwriteActivated(pipe);
}
@Override
public void hiccuped(Pipe pipe)
{
if (options.delayAttachOnConnect == 1) {
pipe.terminate(false);
}
else {
// Notify derived sockets of the hiccup
xhiccuped(pipe);
}
}
@Override
public void pipeTerminated(Pipe pipe)
{
// Notify the specific socket type about the pipe termination.
xpipeTerminated(pipe);
// Remove pipe from inproc pipes
Iterator> it = inprocs.entrySet().iterator();
while (it.hasNext()) {
if (it.next().getValue() == pipe) {
it.remove();
break;
}
}
// Remove the pipe from the list of attached pipes and confirm its
// termination if we are already shutting down.
pipes.remove(pipe);
if (isTerminating()) {
unregisterTermAck();
}
}
// Moves the flags from the message to local variables,
// to be later retrieved by getSocketOpt.
private void extractFlags(Msg msg)
{
// Test whether IDENTITY flag is valid for this socket type.
if ((msg.flags() & Msg.IDENTITY) > 0) {
assert (options.recvIdentity);
}
// Remove MORE flag.
rcvmore = msg.hasMore();
}
public boolean monitor(final String addr, int events)
{
boolean rc;
if (ctxTerminated) {
throw new ZError.CtxTerminatedException();
}
// Support deregistering monitoring endpoints as well
if (addr == null) {
stopMonitor();
return true;
}
// Parse addr_ string.
URI uri;
try {
uri = new URI(addr);
}
catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
String protocol = uri.getScheme();
String address = uri.getAuthority();
String path = uri.getPath();
if (address == null) {
address = path;
}
checkProtocol(protocol);
// Event notification only supported over inproc://
if (!protocol.equals("inproc")) {
stopMonitor();
throw new IllegalArgumentException("inproc socket required");
}
// Register events to monitor
monitorEvents = events;
monitorSocket = getCtx().createSocket(ZMQ.ZMQ_PAIR);
if (monitorSocket == null) {
return false;
}
// Never block context termination on pending event messages
int linger = 0;
try {
monitorSocket.setSocketOpt(ZMQ.ZMQ_LINGER, linger);
}
catch (IllegalArgumentException e) {
stopMonitor();
throw e;
}
// Spawn the monitor socket endpoint
rc = monitorSocket.bind(addr);
if (!rc) {
stopMonitor();
}
return rc;
}
public void eventConnected(String addr, SelectableChannel ch)
{
if ((monitorEvents & ZMQ.ZMQ_EVENT_CONNECTED) == 0) {
return;
}
monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_CONNECTED, addr, ch));
}
public void eventConnectDelayed(String addr, int errno)
{
if ((monitorEvents & ZMQ.ZMQ_EVENT_CONNECT_DELAYED) == 0) {
return;
}
monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_CONNECT_DELAYED, addr, errno));
}
public void eventConnectRetried(String addr, int interval)
{
if ((monitorEvents & ZMQ.ZMQ_EVENT_CONNECT_RETRIED) == 0) {
return;
}
monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_CONNECT_RETRIED, addr, interval));
}
public void eventListening(String addr, SelectableChannel ch)
{
if ((monitorEvents & ZMQ.ZMQ_EVENT_LISTENING) == 0) {
return;
}
monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_LISTENING, addr, ch));
}
public void eventBindFailed(String addr, int errno)
{
if ((monitorEvents & ZMQ.ZMQ_EVENT_BIND_FAILED) == 0) {
return;
}
monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_BIND_FAILED, addr, errno));
}
public void eventAccepted(String addr, SelectableChannel ch)
{
if ((monitorEvents & ZMQ.ZMQ_EVENT_ACCEPTED) == 0) {
return;
}
monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_ACCEPTED, addr, ch));
}
public void eventAcceptFailed(String addr, int errno)
{
if ((monitorEvents & ZMQ.ZMQ_EVENT_ACCEPT_FAILED) == 0) {
return;
}
monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_ACCEPT_FAILED, addr, errno));
}
public void eventClosed(String addr, SelectableChannel ch)
{
if ((monitorEvents & ZMQ.ZMQ_EVENT_CLOSED) == 0) {
return;
}
monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_CLOSED, addr, ch));
}
public void eventCloseFailed(String addr, int errno)
{
if ((monitorEvents & ZMQ.ZMQ_EVENT_CLOSE_FAILED) == 0) {
return;
}
monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_CLOSE_FAILED, addr, errno));
}
public void eventDisconnected(String addr, SelectableChannel ch)
{
if ((monitorEvents & ZMQ.ZMQ_EVENT_DISCONNECTED) == 0) {
return;
}
monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_DISCONNECTED, addr, ch));
}
protected void monitorEvent(ZMQ.Event event)
{
if (monitorSocket == null) {
return;
}
event.write(monitorSocket);
}
protected void stopMonitor()
{
if (monitorSocket != null) {
if ((monitorEvents & ZMQ.ZMQ_EVENT_MONITOR_STOPPED) != 0) {
monitorEvent(new ZMQ.Event(ZMQ.ZMQ_EVENT_MONITOR_STOPPED, "", 0));
}
monitorSocket.close();
monitorSocket = null;
monitorEvents = 0;
}
}
@Override
public String toString()
{
return super.toString() + "[" + options.socketId + "]";
}
public SelectableChannel getFD()
{
return mailbox.getFd();
}
public String typeString()
{
switch (options.type) {
case ZMQ.ZMQ_PAIR:
return "PAIR";
case ZMQ.ZMQ_PUB:
return "PUB";
case ZMQ.ZMQ_SUB:
return "SUB";
case ZMQ.ZMQ_REQ:
return "REQ";
case ZMQ.ZMQ_REP:
return "REP";
case ZMQ.ZMQ_DEALER:
return "DEALER";
case ZMQ.ZMQ_ROUTER:
return "ROUTER";
case ZMQ.ZMQ_PULL:
return "PULL";
case ZMQ.ZMQ_PUSH:
return "PUSH";
default:
return "UNKOWN";
}
}
public int errno()
{
return errno.get();
}
}
jeromq-0.3.5/src/main/java/zmq/StreamEngine.java 0000664 0000000 0000000 00000046610 12551504772 0021522 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.SocketChannel;
public class StreamEngine implements IEngine, IPollEvents, IMsgSink
{
// Size of the greeting message:
// Preamble (10 bytes) + version (1 byte) + socket type (1 byte).
private static final int GREETING_SIZE = 12;
// True iff we are registered with an I/O poller.
private boolean ioEnabled;
//final private IOObject ioObject;
private SocketChannel handle;
private ByteBuffer inbuf;
private int insize;
private DecoderBase decoder;
private Transfer outbuf;
private int outsize;
private EncoderBase encoder;
// When true, we are still trying to determine whether
// the peer is using versioned protocol, and if so, which
// version. When false, normal message flow has started.
private boolean handshaking;
// The receive buffer holding the greeting message
// that we are receiving from the peer.
private final ByteBuffer greeting;
// The send buffer holding the greeting message
// that we are sending to the peer.
private final ByteBuffer greetingOutputBuffer;
// The session this engine is attached to.
private SessionBase session;
// Detached transient session.
//private SessionBase leftover_session;
private Options options;
// String representation of endpoint
private String endpoint;
private boolean plugged;
// Socket
private SocketBase socket;
private IOObject ioObject;
public StreamEngine(SocketChannel handle, final Options options, final String endpoint)
{
this.handle = handle;
inbuf = null;
insize = 0;
ioEnabled = false;
outbuf = null;
outsize = 0;
handshaking = true;
session = null;
this.options = options;
plugged = false;
this.endpoint = endpoint;
socket = null;
greeting = ByteBuffer.allocate(GREETING_SIZE).order(ByteOrder.BIG_ENDIAN);
greetingOutputBuffer = ByteBuffer.allocate(GREETING_SIZE).order(ByteOrder.BIG_ENDIAN);
encoder = null;
decoder = null;
// Put the socket into non-blocking mode.
try {
Utils.unblockSocket(this.handle);
// Set the socket buffer limits for the underlying socket.
if (this.options.sndbuf != 0) {
this.handle.socket().setSendBufferSize(this.options.sndbuf);
}
if (this.options.rcvbuf != 0) {
this.handle.socket().setReceiveBufferSize(this.options.rcvbuf);
}
}
catch (IOException e) {
throw new ZError.IOException(e);
}
}
private DecoderBase newDecoder(int size, long max, SessionBase session, int version)
{
if (options.decoder == null) {
if (version == V1Protocol.VERSION) {
return new V1Decoder(size, max, session);
}
return new Decoder(size, max);
}
try {
Constructor extends DecoderBase> dcon;
if (version == 0) {
dcon = options.decoder.getConstructor(int.class, long.class);
return dcon.newInstance(size, max);
}
else {
dcon = options.decoder.getConstructor(int.class, long.class, IMsgSink.class, int.class);
return dcon.newInstance(size, max, session, version);
}
}
catch (SecurityException e) {
throw new ZError.InstantiationException(e);
}
catch (NoSuchMethodException e) {
throw new ZError.InstantiationException(e);
}
catch (InvocationTargetException e) {
throw new ZError.InstantiationException(e);
}
catch (IllegalAccessException e) {
throw new ZError.InstantiationException(e);
}
catch (InstantiationException e) {
throw new ZError.InstantiationException(e);
}
}
private EncoderBase newEncoder(int size, SessionBase session, int version)
{
if (options.encoder == null) {
if (version == V1Protocol.VERSION) {
return new V1Encoder(size, session);
}
return new Encoder(size);
}
try {
Constructor extends EncoderBase> econ;
if (version == 0) {
econ = options.encoder.getConstructor(int.class);
return econ.newInstance(size);
}
else {
econ = options.encoder.getConstructor(int.class, IMsgSource.class, int.class);
return econ.newInstance(size, session, version);
}
}
catch (SecurityException e) {
throw new ZError.InstantiationException(e);
}
catch (NoSuchMethodException e) {
throw new ZError.InstantiationException(e);
}
catch (InvocationTargetException e) {
throw new ZError.InstantiationException(e);
}
catch (IllegalAccessException e) {
throw new ZError.InstantiationException(e);
}
catch (InstantiationException e) {
throw new ZError.InstantiationException(e);
}
}
public void destroy()
{
assert (!plugged);
if (handle != null) {
try {
handle.close();
}
catch (IOException e) {
}
handle = null;
}
}
public void plug(IOThread ioThread, SessionBase session)
{
assert (!plugged);
plugged = true;
// Connect to session object.
assert (this.session == null);
assert (session != null);
this.session = session;
socket = this.session.getSocket();
ioObject = new IOObject(null);
ioObject.setHandler(this);
// Connect to I/O threads poller object.
ioObject.plug(ioThread);
ioObject.addHandle(handle);
ioEnabled = true;
// Send the 'length' and 'flags' fields of the identity message.
// The 'length' field is encoded in the long format.
greetingOutputBuffer.put((byte) 0xff);
greetingOutputBuffer.putLong(options.identitySize + 1);
greetingOutputBuffer.put((byte) 0x7f);
ioObject.setPollIn(handle);
// When there's a raw custom encoder, we don't send 10 bytes frame
boolean custom = false;
try {
custom = options.encoder != null && options.encoder.getDeclaredField("RAW_ENCODER") != null;
}
catch (SecurityException e) {
}
catch (NoSuchFieldException e) {
}
if (!custom) {
outsize = greetingOutputBuffer.position();
greetingOutputBuffer.flip();
outbuf = new Transfer.ByteBufferTransfer(greetingOutputBuffer);
ioObject.setPollOut(handle);
}
// Flush all the data that may have been already received downstream.
inEvent();
}
private void unplug()
{
assert (plugged);
plugged = false;
// Cancel all fd subscriptions.
if (ioEnabled) {
ioObject.removeHandle(handle);
ioEnabled = false;
}
// Disconnect from I/O threads poller object.
ioObject.unplug();
// Disconnect from session object.
if (encoder != null) {
encoder.setMsgSource(null);
}
if (decoder != null) {
decoder.setMsgSink(null);
}
session = null;
}
@Override
public void terminate()
{
unplug();
destroy();
}
@Override
public void inEvent()
{
// If still handshaking, receive and process the greeting message.
if (handshaking) {
if (!handshake()) {
return;
}
}
assert (decoder != null);
boolean disconnection = false;
// If there's no data to process in the buffer...
if (insize == 0) {
// Retrieve the buffer and read as much data as possible.
// Note that buffer can be arbitrarily large. However, we assume
// the underlying TCP layer has fixed buffer size and thus the
// number of bytes read will be always limited.
inbuf = decoder.getBuffer();
insize = read(inbuf);
inbuf.flip();
// Check whether the peer has closed the connection.
if (insize == -1) {
insize = 0;
disconnection = true;
}
}
// Push the data to the decoder.
int processed = decoder.processBuffer(inbuf, insize);
if (processed == -1) {
disconnection = true;
}
else {
// Stop polling for input if we got stuck.
if (processed < insize) {
ioObject.resetPollIn(handle);
}
// Adjust the buffer.
insize -= processed;
}
// Flush all messages the decoder may have produced.
session.flush();
// An input error has occurred. If the last decoded message
// has already been accepted, we terminate the engine immediately.
// Otherwise, we stop waiting for socket events and postpone
// the termination until after the message is accepted.
if (disconnection) {
if (decoder.stalled()) {
ioObject.removeHandle(handle);
ioEnabled = false;
}
else {
error();
}
}
}
@Override
public void outEvent()
{
// If write buffer is empty, try to read new data from the encoder.
if (outsize == 0) {
// Even when we stop polling as soon as there is no
// data to send, the poller may invoke outEvent one
// more time due to 'speculative write' optimisation.
if (encoder == null) {
assert (handshaking);
return;
}
outbuf = encoder.getData(null);
outsize = outbuf.remaining();
// If there is no data to send, stop polling for output.
if (outbuf.remaining() == 0) {
ioObject.resetPollOut(handle);
// when we use custom encoder, we might want to close
if (encoder.isError()) {
error();
}
return;
}
}
// If there are any data to write in write buffer, write as much as
// possible to the socket. Note that amount of data to write can be
// arbitratily large. However, we assume that underlying TCP layer has
// limited transmission buffer and thus the actual number of bytes
// written should be reasonably modest.
int nbytes = write(outbuf);
// IO error has occurred. We stop waiting for output events.
// The engine is not terminated until we detect input error;
// this is necessary to prevent losing incomming messages.
if (nbytes == -1) {
ioObject.resetPollOut(handle);
return;
}
outsize -= nbytes;
// If we are still handshaking and there are no data
// to send, stop polling for output.
if (handshaking) {
if (outsize == 0) {
ioObject.resetPollOut(handle);
}
}
// when we use custom encoder, we might want to close after sending a response
if (outsize == 0) {
if (encoder != null && encoder.isError()) {
error();
}
}
}
@Override
public void connectEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void acceptEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void timerEvent(int id)
{
throw new UnsupportedOperationException();
}
@Override
public void activateOut()
{
ioObject.setPollOut(handle);
// Speculative write: The assumption is that at the moment new message
// was sent by the user the socket is probably available for writing.
// Thus we try to write the data to socket avoiding polling for POLLOUT.
// Consequently, the latency should be better in request/reply scenarios.
outEvent();
}
@Override
public void activateIn()
{
if (!ioEnabled) {
// There was an input error but the engine could not
// be terminated (due to the stalled decoder).
// Flush the pending message and terminate the engine now.
decoder.processBuffer(inbuf, 0);
assert (!decoder.stalled());
session.flush();
error();
return;
}
ioObject.setPollIn(handle);
// Speculative read.
ioObject.inEvent();
}
private boolean handshake()
{
assert (handshaking);
// Receive the greeting.
while (greeting.position() < GREETING_SIZE) {
final int n = read(greeting);
if (n == -1) {
error();
return false;
}
if (n == 0) {
return false;
}
// We have received at least one byte from the peer.
// If the first byte is not 0xff, we know that the
// peer is using unversioned protocol.
if ((greeting.get(0) & 0xff) != 0xff) {
break;
}
if (greeting.position() < 10) {
continue;
}
// Inspect the right-most bit of the 10th byte (which coincides
// with the 'flags' field if a regular message was sent).
// Zero indicates this is a header of identity message
// (i.e. the peer is using the unversioned protocol).
if ((greeting.get(9) & 0x01) == 0) {
break;
}
// The peer is using versioned protocol.
// Send the rest of the greeting, if necessary.
if (greetingOutputBuffer.limit() < GREETING_SIZE) {
if (outsize == 0) {
ioObject.setPollOut(handle);
}
int pos = greetingOutputBuffer.position();
greetingOutputBuffer.position(10).limit(GREETING_SIZE);
greetingOutputBuffer.put((byte) 1); // Protocol version
greetingOutputBuffer.put((byte) options.type); // Socket type
greetingOutputBuffer.position(pos);
outsize += 2;
}
}
// Position of the version field in the greeting.
final int versionPos = 10;
// Is the peer using the unversioned protocol?
// If so, we send and receive rests of identity
// messages.
if ((greeting.get(0) & 0xff) != 0xff || (greeting.get(9) & 0x01) == 0) {
encoder = newEncoder(Config.OUT_BATCH_SIZE.getValue(), null, 0);
encoder.setMsgSource(session);
decoder = newDecoder(Config.IN_BATCH_SIZE.getValue(), options.maxMsgSize, null, 0);
decoder.setMsgSink(session);
// We have already sent the message header.
// Since there is no way to tell the encoder to
// skip the message header, we simply throw that
// header data away.
final int headerSize = options.identitySize + 1 >= 255 ? 10 : 2;
ByteBuffer tmp = ByteBuffer.allocate(headerSize);
encoder.getData(tmp);
if (tmp.remaining() != headerSize) {
return false;
}
// Make sure the decoder sees the data we have already received.
inbuf = greeting;
greeting.flip();
insize = greeting.remaining();
// To allow for interoperability with peers that do not forward
// their subscriptions, we inject a phony subsription
// message into the incomming message stream. To put this
// message right after the identity message, we temporarily
// divert the message stream from session to ourselves.
if (options.type == ZMQ.ZMQ_PUB || options.type == ZMQ.ZMQ_XPUB) {
decoder.setMsgSink(this);
}
}
else
if (greeting.get(versionPos) == 0) {
// ZMTP/1.0 framing.
encoder = newEncoder(Config.OUT_BATCH_SIZE.getValue(), null, 0);
encoder.setMsgSource(session);
decoder = newDecoder(Config.IN_BATCH_SIZE.getValue(), options.maxMsgSize, null, 0);
decoder.setMsgSink(session);
}
else {
// v1 framing protocol.
encoder = newEncoder(Config.OUT_BATCH_SIZE.getValue(), session, V1Protocol.VERSION);
decoder = newDecoder(Config.IN_BATCH_SIZE.getValue(), options.maxMsgSize, session, V1Protocol.VERSION);
}
// Start polling for output if necessary.
if (outsize == 0) {
ioObject.setPollOut(handle);
}
// Handshaking was successful.
// Switch into the normal message flow.
handshaking = false;
return true;
}
@Override
public int pushMsg(Msg msg)
{
assert (options.type == ZMQ.ZMQ_PUB || options.type == ZMQ.ZMQ_XPUB);
// The first message is identity.
// Let the session process it.
int rc = session.pushMsg(msg);
assert (rc == 0);
// Inject the subscription message so that the ZMQ 2.x peer
// receives our messages.
msg = new Msg(new byte[] { 1 });
rc = session.pushMsg(msg);
session.flush();
// Once we have injected the subscription message, we can
// Divert the message flow back to the session.
assert (decoder != null);
decoder.setMsgSink(session);
return rc;
}
private void error()
{
assert (session != null);
socket.eventDisconnected(endpoint, handle);
session.detach();
unplug();
destroy();
}
private int write(Transfer buf)
{
int nbytes;
try {
nbytes = buf.transferTo(handle);
}
catch (IOException e) {
return -1;
}
return nbytes;
}
private int read(ByteBuffer buf)
{
int nbytes;
try {
nbytes = handle.read(buf);
}
catch (IOException e) {
return -1;
}
return nbytes;
}
}
jeromq-0.3.5/src/main/java/zmq/Sub.java 0000664 0000000 0000000 00000005132 12551504772 0017664 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
public class Sub extends XSub
{
public static class SubSession extends XSub.XSubSession
{
public SubSession(IOThread ioThread, boolean connect,
SocketBase socket, Options options, Address addr)
{
super(ioThread, connect, socket, options, addr);
}
}
public Sub(Ctx parent, int tid, int sid)
{
super(parent, tid, sid);
options.type = ZMQ.ZMQ_SUB;
// Switch filtering messages on (as opposed to XSUB which where the
// filtering is off).
options.filter = true;
}
@Override
public boolean xsetsockopt(int option, Object optval)
{
if (option != ZMQ.ZMQ_SUBSCRIBE && option != ZMQ.ZMQ_UNSUBSCRIBE) {
return false;
}
byte[] val;
if (optval instanceof String) {
val = ((String) optval).getBytes(ZMQ.CHARSET);
}
else if (optval instanceof byte[]) {
val = (byte[]) optval;
}
else {
throw new IllegalArgumentException();
}
// Create the subscription message.
Msg msg = new Msg(val.length + 1);
if (option == ZMQ.ZMQ_SUBSCRIBE) {
msg.put((byte) 1);
}
else {
// option = ZMQ.ZMQ_UNSUBSCRIBE
msg.put((byte) 0);
}
msg.put(val);
// Pass it further on in the stack.
boolean rc = super.xsend(msg);
if (!rc) {
throw new IllegalStateException("Failed to send subscribe/unsubscribe message");
}
return true;
}
@Override
protected boolean xsend(Msg msg)
{
// Overload the XSUB's send.
throw new UnsupportedOperationException();
}
@Override
protected boolean xhasOut()
{
// Overload the XSUB's send.
return false;
}
}
jeromq-0.3.5/src/main/java/zmq/TcpAddress.java 0000664 0000000 0000000 00000007702 12551504772 0021174 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
public class TcpAddress implements Address.IZAddress
{
public static class TcpAddressMask extends TcpAddress
{
public boolean matchAddress(SocketAddress addr)
{
return address.equals(addr);
}
}
protected InetSocketAddress address;
public TcpAddress(String addr)
{
resolve(addr, false);
}
public TcpAddress()
{
}
@Override
public String toString()
{
if (address == null) {
return "";
}
if (address.getAddress() instanceof Inet6Address) {
return "tcp://[" + address.getAddress().getHostAddress() + "]:" + address.getPort();
}
else {
return "tcp://" + address.getAddress().getHostAddress() + ":" + address.getPort();
}
}
public int getPort()
{
if (address != null) {
return address.getPort();
}
return -1;
}
//Used after binding to ephemeral port to update ephemeral port (0) to actual port
protected void updatePort(int port)
{
address = new InetSocketAddress(address.getAddress(), port);
}
@Override
public void resolve(String name, boolean ipv4only)
{
// Find the ':' at end that separates address from the port number.
int delimiter = name.lastIndexOf(':');
if (delimiter < 0) {
throw new IllegalArgumentException(name);
}
// Separate the address/port.
String addrStr = name.substring(0, delimiter);
String portStr = name.substring(delimiter + 1);
// Remove square brackets around the address, if any.
if (addrStr.length() >= 2 && addrStr.charAt(0) == '[' &&
addrStr.charAt(addrStr.length() - 1) == ']') {
addrStr = addrStr.substring(1, addrStr.length() - 1);
}
int port;
// Allow 0 specifically, to detect invalid port error in atoi if not
if (portStr.equals("*") || portStr.equals("0")) {
// Resolve wildcard to 0 to allow autoselection of port
port = 0;
}
else {
// Parse the port number (0 is not a valid port).
port = Integer.parseInt(portStr);
if (port == 0) {
throw new IllegalArgumentException(name);
}
}
InetAddress addrNet = null;
if (addrStr.equals("*")) {
addrStr = "0.0.0.0";
}
try {
for (InetAddress ia : InetAddress.getAllByName(addrStr)) {
if (ipv4only && (ia instanceof Inet6Address)) {
continue;
}
addrNet = ia;
break;
}
}
catch (UnknownHostException e) {
throw new IllegalArgumentException(e);
}
if (addrNet == null) {
throw new IllegalArgumentException(name);
}
address = new InetSocketAddress(addrNet, port);
}
@Override
public SocketAddress address()
{
return address;
}
}
jeromq-0.3.5/src/main/java/zmq/TcpConnecter.java 0000664 0000000 0000000 00000023546 12551504772 0021533 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.io.IOException;
import java.net.ConnectException;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.nio.channels.SocketChannel;
// If 'delay' is true connecter first waits for a while, then starts
// connection process.
public class TcpConnecter extends Own implements IPollEvents
{
// ID of the timer used to delay the reconnection.
private static final int RECONNECT_TIMER_ID = 1;
private final IOObject ioObject;
// Address to connect to. Owned by session_base_t.
private final Address addr;
// Underlying socket.
private SocketChannel handle;
// If true file descriptor is registered with the poller and 'handle'
// contains valid value.
private boolean handleValid;
// If true, connecter is waiting a while before trying to connect.
private boolean delayedStart;
// True iff a timer has been started.
private boolean timerStarted;
// Reference to the session we belong to.
private SessionBase session;
// Current reconnect ivl, updated for backoff strategy
private int currentReconnectIvl;
// String representation of endpoint to connect to
private Address address;
// Socket
private SocketBase socket;
public TcpConnecter(IOThread ioThread,
SessionBase session, final Options options,
final Address addr, boolean delayedStart)
{
super(ioThread, options);
ioObject = new IOObject(ioThread);
this.addr = addr;
handle = null;
handleValid = false;
this.delayedStart = delayedStart;
timerStarted = false;
this.session = session;
currentReconnectIvl = this.options.reconnectIvl;
assert (this.addr != null);
address = this.addr;
socket = session.getSocket();
}
public void destroy()
{
assert (!timerStarted);
assert (!handleValid);
assert (handle == null);
}
@Override
protected void processPlug()
{
ioObject.setHandler(this);
if (delayedStart) {
addreconnectTimer();
}
else {
startConnecting();
}
}
@Override
public void processTerm(int linger)
{
if (timerStarted) {
ioObject.cancelTimer(RECONNECT_TIMER_ID);
timerStarted = false;
}
if (handleValid) {
ioObject.removeHandle(handle);
handleValid = false;
}
if (handle != null) {
close();
}
super.processTerm(linger);
}
@Override
public void inEvent()
{
// connected but attaching to stream engine is not completed. do nothing
}
@Override
public void outEvent()
{
// connected but attaching to stream engine is not completed. do nothing
}
@Override
public void acceptEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void connectEvent()
{
boolean err = false;
SocketChannel fd = null;
try {
fd = connect();
}
catch (ConnectException e) {
err = true;
}
catch (SocketException e) {
err = true;
}
catch (SocketTimeoutException e) {
err = true;
}
catch (IOException e) {
throw new ZError.IOException(e);
}
ioObject.removeHandle(handle);
handleValid = false;
if (err) {
// Handle the error condition by attempt to reconnect.
close();
addreconnectTimer();
return;
}
handle = null;
try {
Utils.tuneTcpSocket(fd);
Utils.tuneTcpKeepalives(fd, options.tcpKeepAlive, options.tcpKeepAliveCnt, options.tcpKeepAliveIdle, options.tcpKeepAliveIntvl);
}
catch (SocketException e) {
throw new RuntimeException(e);
}
// Create the engine object for this connection.
StreamEngine engine = null;
try {
engine = new StreamEngine(fd, options, address.toString());
}
catch (ZError.InstantiationException e) {
socket.eventConnectDelayed(address.toString(), -1);
return;
}
// Attach the engine to the corresponding session object.
sendAttach(session, engine);
// Shut the connecter down.
terminate();
socket.eventConnected(address.toString(), fd);
}
@Override
public void timerEvent(int id)
{
timerStarted = false;
startConnecting();
}
// Internal function to start the actual connection establishment.
private void startConnecting()
{
// Open the connecting socket.
try {
boolean rc = open();
// Connect may succeed in synchronous manner.
if (rc) {
ioObject.addHandle(handle);
handleValid = true;
ioObject.connectEvent();
}
// Connection establishment may be delayed. Poll for its completion.
else {
ioObject.addHandle(handle);
handleValid = true;
ioObject.setPollConnect(handle);
socket.eventConnectDelayed(address.toString(), -1);
}
}
catch (IOException e) {
// Handle any other error condition by eventual reconnect.
if (handle != null) {
close();
}
addreconnectTimer();
}
}
// Internal function to add a reconnect timer
private void addreconnectTimer()
{
int rcIvl = getNewReconnectIvl();
ioObject.addTimer(rcIvl, RECONNECT_TIMER_ID);
// resolve address again to take into account other addresses
// besides the failing one (e.g. multiple dns entries).
try {
address.resolve();
}
catch (Exception ignored) {
// This will fail if the network goes away and the
// address cannot be resolved for some reason. Try
// not to fail as the event loop will quit
}
socket.eventConnectRetried(address.toString(), rcIvl);
timerStarted = true;
}
// Internal function to return a reconnect backoff delay.
// Will modify the currentReconnectIvl used for next call
// Returns the currently used interval
private int getNewReconnectIvl()
{
// The new interval is the current interval + random value.
int thisInterval = currentReconnectIvl +
(Utils.generateRandom() % options.reconnectIvl);
// Only change the current reconnect interval if the maximum reconnect
// interval was set and if it's larger than the reconnect interval.
if (options.reconnectIvlMax > 0 &&
options.reconnectIvlMax > options.reconnectIvl) {
// Calculate the next interval
currentReconnectIvl = currentReconnectIvl * 2;
if (currentReconnectIvl >= options.reconnectIvlMax) {
currentReconnectIvl = options.reconnectIvlMax;
}
}
return thisInterval;
}
// Open TCP connecting socket. Returns -1 in case of error,
// true if connect was successfull immediately. Returns false with
// if async connect was launched.
private boolean open() throws IOException
{
assert (handle == null);
// Create the socket.
handle = SocketChannel.open();
// Set the socket to non-blocking mode so that we get async connect().
Utils.unblockSocket(handle);
// Connect to the remote peer.
if (addr == null) {
throw new IOException("Null address");
}
Address.IZAddress resolved = addr.resolved();
if (resolved == null) {
throw new IOException("Address not resolved");
}
SocketAddress sa = resolved.address();
if (sa == null) {
throw new IOException("Socket address not resolved");
}
boolean rc = false;
try {
rc = handle.connect(sa);
}
catch (IllegalArgumentException e) {
// this will happen if sa is bad. Address validation is not documented but
// I've found that IAE is thrown in openjdk as well as on android.
throw new IOException(e.getMessage(), e);
}
return rc;
}
// Get the file descriptor of newly created connection. Returns
// retired_fd if the connection was unsuccessfull.
private SocketChannel connect() throws IOException
{
boolean finished = handle.finishConnect();
assert finished;
SocketChannel ret = handle;
return ret;
}
// Close the connecting socket.
private void close()
{
assert (handle != null);
try {
handle.close();
socket.eventClosed(address.toString(), handle);
}
catch (IOException e) {
socket.eventCloseFailed(address.toString(), ZError.exccode(e));
}
handle = null;
}
}
jeromq-0.3.5/src/main/java/zmq/TcpListener.java 0000664 0000000 0000000 00000014420 12551504772 0021367 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.io.IOException;
import java.net.Socket;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
public class TcpListener extends Own implements IPollEvents
{
private static boolean isWindows;
static
{
String os = System.getProperty("os.name").toLowerCase();
isWindows = os.indexOf("win") >= 0;
}
// Address to listen on.
private final TcpAddress address;
// Underlying socket.
private ServerSocketChannel handle;
// Socket the listerner belongs to.
private SocketBase socket;
// String representation of endpoint to bind to
private String endpoint;
private final IOObject ioObject;
public TcpListener(IOThread ioThread, SocketBase socket, final Options options)
{
super(ioThread, options);
ioObject = new IOObject(ioThread);
address = new TcpAddress();
handle = null;
this.socket = socket;
}
@Override
public void destroy()
{
assert (handle == null);
}
@Override
protected void processPlug()
{
// Start polling for incoming connections.
ioObject.setHandler(this);
ioObject.addHandle(handle);
ioObject.setPollAccept(handle);
}
@Override
protected void processTerm(int linger)
{
ioObject.setHandler(this);
ioObject.removeHandle(handle);
close();
super.processTerm(linger);
}
@Override
public void acceptEvent()
{
SocketChannel fd = null;
try {
fd = accept();
Utils.tuneTcpSocket(fd);
Utils.tuneTcpKeepalives(fd, options.tcpKeepAlive, options.tcpKeepAliveCnt, options.tcpKeepAliveIdle, options.tcpKeepAliveIntvl);
}
catch (IOException e) {
// If connection was reset by the peer in the meantime, just ignore it.
// TODO: Handle specific errors like ENFILE/EMFILE etc.
socket.eventAcceptFailed(endpoint, ZError.exccode(e));
return;
}
// Create the engine object for this connection.
StreamEngine engine = null;
try {
engine = new StreamEngine(fd, options, endpoint);
}
catch (ZError.InstantiationException e) {
socket.eventAcceptFailed(endpoint, ZError.EINVAL);
return;
}
// Choose I/O thread to run connecter in. Given that we are already
// running in an I/O thread, there must be at least one available.
IOThread ioThread = chooseIoThread(options.affinity);
// Create and launch a session object.
SessionBase session = SessionBase.create(ioThread, false, socket,
options, new Address(fd.socket().getRemoteSocketAddress()));
session.incSeqnum();
launchChild(session);
sendAttach(session, engine, false);
socket.eventAccepted(endpoint, fd);
}
// Close the listening socket.
private void close()
{
if (handle == null) {
return;
}
try {
handle.close();
socket.eventClosed(endpoint, handle);
}
catch (IOException e) {
socket.eventCloseFailed(endpoint, ZError.exccode(e));
}
handle = null;
}
public String getAddress()
{
return address.toString();
}
// Set address to listen on.
public int setAddress(final String addr)
{
address.resolve(addr, options.ipv4only > 0);
try {
handle = ServerSocketChannel.open();
handle.configureBlocking(false);
if (!isWindows) {
handle.socket().setReuseAddress(true);
}
handle.socket().bind(address.address(), options.backlog);
if (address.getPort() == 0) {
address.updatePort(handle.socket().getLocalPort());
}
}
catch (IOException e) {
close();
return ZError.EADDRINUSE;
}
endpoint = address.toString();
socket.eventListening(endpoint, handle);
return 0;
}
// Accept the new connection. Returns the file descriptor of the
// newly created connection. The function may return retired_fd
// if the connection was dropped while waiting in the listen backlog
// or was denied because of accept filters.
private SocketChannel accept()
{
Socket sock = null;
try {
sock = handle.socket().accept();
}
catch (IOException e) {
return null;
}
if (!options.tcpAcceptFilters.isEmpty()) {
boolean matched = false;
for (TcpAddress.TcpAddressMask am : options.tcpAcceptFilters) {
if (am.matchAddress(address.address())) {
matched = true;
break;
}
}
if (!matched) {
try {
sock.close();
}
catch (IOException e) {
}
return null;
}
}
return sock.getChannel();
}
@Override
public void inEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void outEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void connectEvent()
{
throw new UnsupportedOperationException();
}
@Override
public void timerEvent(int id)
{
throw new UnsupportedOperationException();
}
}
jeromq-0.3.5/src/main/java/zmq/Transfer.java 0000664 0000000 0000000 00000005402 12551504772 0020717 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
public interface Transfer
{
public int transferTo(WritableByteChannel s) throws IOException;
public int remaining();
public static class ByteBufferTransfer implements Transfer
{
private ByteBuffer buf;
public ByteBufferTransfer(ByteBuffer buf)
{
this.buf = buf;
}
@Override
public final int transferTo(WritableByteChannel s) throws IOException
{
return s.write(buf);
}
@Override
public final int remaining()
{
return buf.remaining();
}
}
public static class FileChannelTransfer implements Transfer
{
private Transfer parent;
private FileChannel channel;
private long position;
private long count;
private int remaining;
public FileChannelTransfer(ByteBuffer buf, FileChannel channel, long position, long count)
{
parent = new ByteBufferTransfer(buf);
this.channel = channel;
this.position = position;
this.count = count;
remaining = parent.remaining() + (int) this.count;
}
@Override
public final int transferTo(WritableByteChannel s) throws IOException
{
int sent = 0;
if (parent.remaining() > 0) {
sent = parent.transferTo(s);
}
if (parent.remaining() == 0) {
long fileSent = channel.transferTo(position, count, s);
position += fileSent;
count -= fileSent;
sent += fileSent;
}
remaining -= sent;
if (remaining == 0) {
channel.close();
}
return sent;
}
@Override
public final int remaining()
{
return remaining;
}
}
}
jeromq-0.3.5/src/main/java/zmq/Trie.java 0000664 0000000 0000000 00000022065 12551504772 0020042 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
public class Trie
{
private int refcnt;
private byte min;
private int count;
private int liveNodes;
public interface ITrieHandler
{
void added(byte[] data, int size, Object arg);
}
Trie[] next;
public Trie()
{
min = 0;
count = 0;
liveNodes = 0;
refcnt = 0;
next = null;
}
// Add key to the trie. Returns true if this is a new item in the trie
// rather than a duplicate.
public boolean add(byte[] prefix)
{
return add(prefix, 0);
}
public boolean add(byte[] prefix, int start)
{
// We are at the node corresponding to the prefix. We are done.
if (prefix == null || prefix.length == start) {
++refcnt;
return refcnt == 1;
}
byte c = prefix[start];
if (c < min || c >= min + count) {
// The character is out of range of currently handled
// charcters. We have to extend the table.
if (count == 0) {
min = c;
count = 1;
next = null;
}
else if (count == 1) {
byte oldc = min;
Trie oldp = next[0];
count = (min < c ? c - min : min - c) + 1;
next = new Trie[count];
min = (byte) Math.min(min, c);
next[oldc - min] = oldp;
}
else if (min < c) {
// The new character is above the current character range.
count = c - min + 1;
next = realloc(next, count, true);
}
else {
// The new character is below the current character range.
count = (min + count) - c;
next = realloc(next, count, false);
min = c;
}
}
// If next node does not exist, create one.
if (count == 1) {
if (next == null) {
next = new Trie[1];
next[0] = new Trie();
++liveNodes;
//alloc_assert (next.node);
}
return next[0].add(prefix, start + 1);
}
else {
if (next[c - min] == null) {
next[c - min] = new Trie();
++liveNodes;
//alloc_assert (next.table [c - min]);
}
return next[c - min].add(prefix, start + 1);
}
}
private Trie[] realloc(Trie[] table, int size, boolean ended)
{
return Utils.realloc(Trie.class, table, size, ended);
}
// Remove key from the trie. Returns true if the item is actually
// removed from the trie.
public boolean rm(byte[] prefix, int start)
{
if (prefix == null || prefix.length == start) {
if (refcnt == 0) {
return false;
}
refcnt--;
return refcnt == 0;
}
byte c = prefix[start];
if (count == 0 || c < min || c >= min + count) {
return false;
}
Trie nextNode =
count == 1 ? next[0] : next[c - min];
if (nextNode == null) {
return false;
}
boolean ret = nextNode.rm(prefix , start + 1);
if (nextNode.isRedundant()) {
//delete next_node;
assert (count > 0);
if (count == 1) {
next = null;
count = 0;
--liveNodes;
assert (liveNodes == 0);
}
else {
next[c - min] = null;
assert (liveNodes > 1);
--liveNodes;
// Compact the table if possible
if (liveNodes == 1) {
// If there's only one live node in the table we can
// switch to using the more compact single-node
// representation
Trie node = null;
for (int i = 0; i < count; ++i) {
if (next[i] != null) {
node = next[i];
min = (byte) (i + min);
break;
}
}
assert (node != null);
//free (next.table);
next = null;
next = new Trie[]{node};
count = 1;
}
else if (c == min) {
// We can compact the table "from the left"
byte newMin = min;
for (int i = 1; i < count; ++i) {
if (next[i] != null) {
newMin = (byte) (i + min);
break;
}
}
assert (newMin != min);
assert (newMin > min);
assert (count > newMin - min);
count = count - (newMin - min);
next = realloc(next, count, true);
min = newMin;
}
else if (c == min + count - 1) {
// We can compact the table "from the right"
int newCount = count;
for (int i = 1; i < count; ++i) {
if (next[count - 1 - i] != null) {
newCount = count - i;
break;
}
}
assert (newCount != count);
count = newCount;
next = realloc(next, count, false);
}
}
}
return ret;
}
// Check whether particular key is in the trie.
public boolean check(byte[] data)
{
// This function is on critical path. It deliberately doesn't use
// recursion to get a bit better performance.
Trie current = this;
int start = 0;
while (true) {
// We've found a corresponding subscription!
if (current.refcnt > 0) {
return true;
}
// We've checked all the data and haven't found matching subscription.
if (data.length == start) {
return false;
}
// If there's no corresponding slot for the first character
// of the prefix, the message does not match.
byte c = data[start];
if (c < current.min || c >= current.min + current.count) {
return false;
}
// Move to the next character.
if (current.count == 1) {
current = current.next[0];
}
else {
current = current.next[c - current.min];
if (current == null) {
return false;
}
}
start++;
}
}
// Apply the function supplied to each subscription in the trie.
public void apply(ITrieHandler func, Object arg)
{
applyHelper(null, 0, 0, func, arg);
}
private void applyHelper(byte[] buff, int buffsize, int maxBuffsize, ITrieHandler func,
Object arg)
{
// If this node is a subscription, apply the function.
if (refcnt > 0) {
func.added(buff, buffsize, arg);
}
// Adjust the buffer.
if (buffsize >= maxBuffsize) {
maxBuffsize = buffsize + 256;
buff = Utils.realloc(buff, maxBuffsize);
assert (buff != null);
}
// If there are no subnodes in the trie, return.
if (count == 0) {
return;
}
// If there's one subnode (optimisation).
if (count == 1) {
buff [buffsize] = min;
buffsize++;
next[0].applyHelper(buff, buffsize, maxBuffsize, func, arg);
return;
}
// If there are multiple subnodes.
for (int c = 0; c != count; c++) {
buff [buffsize] = (byte) (min + c);
if (next[c] != null) {
next[c].applyHelper(buff, buffsize + 1, maxBuffsize,
func, arg);
}
}
}
private boolean isRedundant()
{
return refcnt == 0 && liveNodes == 0;
}
}
jeromq-0.3.5/src/main/java/zmq/Utils.java 0000664 0000000 0000000 00000011063 12551504772 0020233 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SocketChannel;
import java.security.SecureRandom;
import java.util.List;
class Utils
{
private Utils()
{
}
private static SecureRandom random = new SecureRandom();
public static int generateRandom()
{
return random.nextInt();
}
public static void tuneTcpSocket(SocketChannel ch) throws SocketException
{
tuneTcpSocket(ch.socket());
}
public static void tuneTcpSocket(Socket fd) throws SocketException
{
// Disable Nagle's algorithm. We are doing data batching on 0MQ level,
// so using Nagle wouldn't improve throughput in anyway, but it would
// hurt latency.
try {
fd.setTcpNoDelay(true);
}
catch (SocketException e) {
}
}
public static void tuneTcpKeepalives(SocketChannel ch, int tcpKeepalive,
int tcpKeepaliveCnt, int tcpKeepaliveIdle,
int tcpKeepaliveIntvl) throws SocketException
{
tuneTcpKeepalives(ch.socket(), tcpKeepalive, tcpKeepaliveCnt,
tcpKeepaliveIdle, tcpKeepaliveIntvl);
}
public static void tuneTcpKeepalives(Socket fd, int tcpKeepalive,
int tcpKeepaliveCnt, int tcpKeepaliveIdle,
int tcpKeepaliveIntvl) throws SocketException
{
if (tcpKeepalive == 1) {
fd.setKeepAlive(true);
}
else if (tcpKeepalive == 0) {
fd.setKeepAlive(false);
}
}
public static void unblockSocket(SelectableChannel s) throws IOException
{
s.configureBlocking(false);
}
@SuppressWarnings("unchecked")
public static T[] realloc(Class klass, T[] src, int size, boolean ended)
{
T[] dest;
if (size > src.length) {
dest = (T[]) Array.newInstance(klass, size);
if (ended) {
System.arraycopy(src, 0, dest, 0, src.length);
}
else {
System.arraycopy(src, 0, dest, size - src.length, src.length);
}
}
else if (size < src.length) {
dest = (T[]) Array.newInstance(klass, size);
if (ended) {
System.arraycopy(src, src.length - size, dest, 0, size);
}
else {
System.arraycopy(src, 0, dest, 0, size);
}
}
else {
dest = src;
}
return dest;
}
public static void swap(List items, int index1, int index2)
{
if (index1 == index2) {
return;
}
T item1 = items.get(index1);
T item2 = items.get(index2);
if (item1 != null) {
items.set(index2, item1);
}
if (item2 != null) {
items.set(index1, item2);
}
}
public static byte[] bytes(ByteBuffer buf)
{
byte[] d = new byte[buf.limit()];
buf.get(d);
return d;
}
public static byte[] realloc(byte[] src, int size)
{
byte[] dest = new byte[size];
if (src != null) {
System.arraycopy(src, 0, dest, 0, src.length);
}
return dest;
}
public static boolean delete(File path)
{
if (!path.exists()) {
return false;
}
boolean ret = true;
if (path.isDirectory()) {
File[] files = path.listFiles();
if (files != null) {
for (File f : files) {
ret = ret && delete(f);
}
}
}
return ret && path.delete();
}
}
jeromq-0.3.5/src/main/java/zmq/V1Decoder.java 0000664 0000000 0000000 00000011655 12551504772 0020716 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.nio.ByteBuffer;
public class V1Decoder extends DecoderBase
{
private static final int ONE_BYTE_SIZE_READY = 0;
private static final int EIGHT_BYTE_SIZE_READY = 1;
private static final int FLAGS_READY = 2;
private static final int MESSAGE_READY = 3;
private final byte[] tmpbuf;
private Msg inProgress;
private IMsgSink msgSink;
private final long maxmsgsize;
private int msgFlags;
public V1Decoder(int bufsize, long maxmsgsize, IMsgSink session)
{
super(bufsize);
this.maxmsgsize = maxmsgsize;
msgSink = session;
tmpbuf = new byte[8];
// At the beginning, read one byte and go to ONE_BYTE_SIZE_READY state.
nextStep(tmpbuf, 1, FLAGS_READY);
}
// Set the receiver of decoded messages.
@Override
public void setMsgSink(IMsgSink msgSink)
{
this.msgSink = msgSink;
}
@Override
protected boolean next()
{
switch(state()) {
case ONE_BYTE_SIZE_READY:
return oneByteSizeReady();
case EIGHT_BYTE_SIZE_READY:
return eightByteSizeReady();
case FLAGS_READY:
return flagsReady();
case MESSAGE_READY:
return messageReady();
default:
return false;
}
}
private boolean oneByteSizeReady()
{
int size = tmpbuf[0];
if (size < 0) {
size = (0xff) & size;
}
// Message size must not exceed the maximum allowed size.
if (maxmsgsize >= 0) {
if (size > maxmsgsize) {
decodingError();
return false;
}
}
// inProgress is initialised at this point so in theory we should
// close it before calling msgInitWithSize, however, it's a 0-byte
// message and thus we can treat it as uninitialised...
inProgress = new Msg(size);
inProgress.setFlags(msgFlags);
nextStep(inProgress.data(), inProgress.size(),
MESSAGE_READY);
return true;
}
private boolean eightByteSizeReady()
{
// The payload size is encoded as 64-bit unsigned integer.
// The most significant byte comes first.
final long msgSize = ByteBuffer.wrap(tmpbuf).getLong();
// Message size must not exceed the maximum allowed size.
if (maxmsgsize >= 0) {
if (msgSize > maxmsgsize) {
decodingError();
return false;
}
}
// Message size must fit within range of size_t data type.
if (msgSize > Integer.MAX_VALUE) {
decodingError();
return false;
}
// inProgress is initialised at this point so in theory we should
// close it before calling init_size, however, it's a 0-byte
// message and thus we can treat it as uninitialised.
inProgress = new Msg((int) msgSize);
inProgress.setFlags(msgFlags);
nextStep(inProgress.data(), inProgress.size(),
MESSAGE_READY);
return true;
}
private boolean flagsReady()
{
// Store the flags from the wire into the message structure.
msgFlags = 0;
int first = tmpbuf[0];
if ((first & V1Protocol.MORE_FLAG) > 0) {
msgFlags |= Msg.MORE;
}
// The payload length is either one or eight bytes,
// depending on whether the 'large' bit is set.
if ((first & V1Protocol.LARGE_FLAG) > 0) {
nextStep(tmpbuf, 8, EIGHT_BYTE_SIZE_READY);
}
else {
nextStep(tmpbuf, 1, ONE_BYTE_SIZE_READY);
}
return true;
}
private boolean messageReady()
{
// Message is completely read. Push it further and start reading
// new message. (inProgress is a 0-byte message after this point.)
if (msgSink == null) {
return false;
}
int rc = msgSink.pushMsg(inProgress);
if (rc != 0) {
if (rc != ZError.EAGAIN) {
decodingError();
}
return false;
}
nextStep(tmpbuf, 1, FLAGS_READY);
return true;
}
}
jeromq-0.3.5/src/main/java/zmq/V1Encoder.java 0000664 0000000 0000000 00000006377 12551504772 0020735 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.nio.ByteBuffer;
// Encoder for 0MQ framing protocol. Converts messages into data stream.
public class V1Encoder extends EncoderBase
{
private static final int SIZE_READY = 0;
private static final int MESSAGE_READY = 1;
private Msg inProgress;
private final byte[] tmpbuf;
private IMsgSource msgSource;
public V1Encoder(int bufsize, IMsgSource session)
{
super(bufsize);
tmpbuf = new byte[9];
msgSource = session;
// Write 0 bytes to the batch and go to messageReady state.
nextStep((byte[]) null, 0, MESSAGE_READY, true);
}
@Override
public void setMsgSource(IMsgSource msgSource)
{
this.msgSource = msgSource;
}
@Override
protected boolean next()
{
switch(state()) {
case SIZE_READY:
return sizeReady();
case MESSAGE_READY:
return messageReady();
default:
return false;
}
}
private boolean sizeReady()
{
// Write message body into the buffer.
nextStep(inProgress.data(), inProgress.size(),
MESSAGE_READY, !inProgress.hasMore());
return true;
}
private boolean messageReady()
{
// Read new message. If there is none, return false.
// Note that new state is set only if write is successful. That way
// unsuccessful write will cause retry on the next state machine
// invocation.
if (msgSource == null) {
return false;
}
inProgress = msgSource.pullMsg();
if (inProgress == null) {
return false;
}
int protocolFlags = 0;
if (inProgress.hasMore()) {
protocolFlags |= V1Protocol.MORE_FLAG;
}
if (inProgress.size() > 255) {
protocolFlags |= V1Protocol.LARGE_FLAG;
}
tmpbuf[0] = (byte) protocolFlags;
// Encode the message length. For messages less then 256 bytes,
// the length is encoded as 8-bit unsigned integer. For larger
// messages, 64-bit unsigned integer in network byte order is used.
final int size = inProgress.size();
if (size > 255) {
ByteBuffer b = ByteBuffer.wrap(tmpbuf);
b.position(1);
b.putLong(size);
nextStep(tmpbuf, 9, SIZE_READY, false);
}
else {
tmpbuf[1] = (byte) (size);
nextStep(tmpbuf, 2, SIZE_READY, false);
}
return true;
}
}
jeromq-0.3.5/src/main/java/zmq/V1Protocol.java 0000664 0000000 0000000 00000001705 12551504772 0021145 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
class V1Protocol
{
private V1Protocol()
{
}
public static final int VERSION = 1;
public static final int MORE_FLAG = 1;
public static final int LARGE_FLAG = 2;
}
jeromq-0.3.5/src/main/java/zmq/ValueReference.java 0000664 0000000 0000000 00000002077 12551504772 0022033 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
public class ValueReference
{
private V value;
public ValueReference(V value)
{
this.value = value;
}
public ValueReference()
{
}
public final V get()
{
return value;
}
public final void set(V value)
{
this.value = value;
}
}
jeromq-0.3.5/src/main/java/zmq/XPub.java 0000664 0000000 0000000 00000015554 12551504772 0020022 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.util.ArrayDeque;
import java.util.Deque;
class XPub extends SocketBase
{
public static class XPubSession extends SessionBase
{
public XPubSession(IOThread ioThread, boolean connect,
SocketBase socket, Options options, Address addr)
{
super(ioThread, connect, socket, options, addr);
}
}
// List of all subscriptions mapped to corresponding pipes.
private final Mtrie subscriptions;
// Distributor of messages holding the list of outbound pipes.
private final Dist dist;
// If true, send all subscription messages upstream, not just
// unique ones
boolean verbose;
// True if we are in the middle of sending a multi-part message.
private boolean more;
// List of pending (un)subscriptions, ie. those that were already
// applied to the trie, but not yet received by the user.
private final Deque pendingData;
private final Deque pendingFlags;
private static Mtrie.IMtrieHandler markAsMatching;
private static Mtrie.IMtrieHandler sendUnsubscription;
static {
markAsMatching = new Mtrie.IMtrieHandler()
{
@Override
public void invoke(Pipe pipe, byte[] data, int size, Object arg)
{
XPub self = (XPub) arg;
self.dist.match(pipe);
}
};
sendUnsubscription = new Mtrie.IMtrieHandler()
{
@Override
public void invoke(Pipe pipe, byte[] data, int size, Object arg)
{
XPub self = (XPub) arg;
if (self.options.type != ZMQ.ZMQ_PUB) {
// Place the unsubscription to the queue of pending (un)sunscriptions
// to be retrived by the user later on.
byte[] unsub = new byte[size + 1];
unsub[0] = 0;
System.arraycopy(data, 0, unsub, 1, size);
self.pendingData.add(Blob.createBlob(unsub, false));
self.pendingFlags.add(0);
}
}
};
}
public XPub(Ctx parent, int tid, int sid)
{
super(parent, tid, sid);
options.type = ZMQ.ZMQ_XPUB;
verbose = false;
more = false;
subscriptions = new Mtrie();
dist = new Dist();
pendingData = new ArrayDeque();
pendingFlags = new ArrayDeque();
}
@Override
protected void xattachPipe(Pipe pipe, boolean icanhasall)
{
assert (pipe != null);
dist.attach(pipe);
// If icanhasall_ is specified, the caller would like to subscribe
// to all data on this pipe, implicitly.
if (icanhasall) {
subscriptions.add(null, pipe);
}
// The pipe is active when attached. Let's read the subscriptions from
// it, if any.
xreadActivated(pipe);
}
@Override
protected void xreadActivated(Pipe pipe)
{
// There are some subscriptions waiting. Let's process them.
Msg sub = null;
while ((sub = pipe.read()) != null) {
// Apply the subscription to the trie
byte[] data = sub.data();
int size = sub.size();
if (size > 0 && (data[0] == 0 || data[0] == 1)) {
boolean unique;
if (data[0] == 0) {
unique = subscriptions.rm(data, 1, pipe);
}
else {
unique = subscriptions.add(data, 1, pipe);
}
// If the subscription is not a duplicate, store it so that it can be
// passed to used on next recv call. (Unsubscribe is not verbose.)
if (options.type == ZMQ.ZMQ_XPUB && (unique || (data[0] == 1 && verbose))) {
pendingData.add(Blob.createBlob(data, true));
pendingFlags.add(0);
}
}
else {
// Process user message coming upstream from xsub socket
pendingData.add(Blob.createBlob(data, true));
pendingFlags.add(sub.flags());
}
}
}
@Override
protected void xwriteActivated(Pipe pipe)
{
dist.activated(pipe);
}
@Override
public boolean xsetsockopt(int option, Object optval)
{
if (option != ZMQ.ZMQ_XPUB_VERBOSE) {
return false;
}
verbose = (Integer) optval == 1;
return true;
}
@Override
protected void xpipeTerminated(Pipe pipe)
{
// Remove the pipe from the trie. If there are topics that nobody
// is interested in anymore, send corresponding unsubscriptions
// upstream.
subscriptions.rm(pipe, sendUnsubscription, this);
dist.terminated(pipe);
}
@Override
protected boolean xsend(Msg msg)
{
boolean msgMore = msg.hasMore();
// For the first part of multi-part message, find the matching pipes.
if (!more) {
subscriptions.match(msg.data(), msg.size(),
markAsMatching, this);
}
// Send the message to all the pipes that were marked as matching
// in the previous step.
boolean rc = dist.sendToMatching(msg);
if (!rc) {
return false;
}
// If we are at the end of multi-part message we can mark all the pipes
// as non-matching.
if (!msgMore) {
dist.unmatch();
}
more = msgMore;
return true;
}
@Override
protected boolean xhasOut()
{
return dist.hasOut();
}
@Override
protected Msg xrecv()
{
// If there is at least one
if (pendingData.isEmpty()) {
errno.set(ZError.EAGAIN);
return null;
}
Blob first = pendingData.pollFirst();
Msg msg = new Msg(first.data());
int flags = pendingFlags.pollFirst();
msg.setFlags(flags);
return msg;
}
@Override
protected boolean xhasIn()
{
return !pendingData.isEmpty();
}
}
jeromq-0.3.5/src/main/java/zmq/XSub.java 0000664 0000000 0000000 00000016423 12551504772 0020021 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
public class XSub extends SocketBase
{
public static class XSubSession extends SessionBase
{
public XSubSession(IOThread ioThread, boolean connect,
SocketBase socket, Options options, Address addr)
{
super(ioThread, connect, socket, options, addr);
}
}
// Fair queueing object for inbound pipes.
private final FQ fq;
// Object for distributing the subscriptions upstream.
private final Dist dist;
// The repository of subscriptions.
private final Trie subscriptions;
// If true, 'message' contains a matching message to return on the
// next recv call.
private boolean hashMessage;
private Msg message;
// If true, part of a multipart message was already received, but
// there are following parts still waiting.
private boolean more;
private static Trie.ITrieHandler sendSubscription;
static {
sendSubscription = new Trie.ITrieHandler()
{
@Override
public void added(byte[] data, int size, Object arg)
{
Pipe pipe = (Pipe) arg;
// Create the subsctription message.
Msg msg = new Msg(size + 1);
msg.put((byte) 1).put(data, 0, size);
// Send it to the pipe.
boolean sent = pipe.write(msg);
// If we reached the SNDHWM, and thus cannot send the subscription, drop
// the subscription message instead. This matches the behaviour of
// setSocketOption(ZMQ_SUBSCRIBE, ...), which also drops subscriptions
// when the SNDHWM is reached.
// if (!sent)
// msg.close ();
}
};
}
public XSub(Ctx parent, int tid, int sid)
{
super(parent, tid, sid);
options.type = ZMQ.ZMQ_XSUB;
hashMessage = false;
more = false;
options.linger = 0;
fq = new FQ();
dist = new Dist();
subscriptions = new Trie();
}
@Override
protected void xattachPipe(Pipe pipe, boolean icanhasall)
{
assert (pipe != null);
fq.attach(pipe);
dist.attach(pipe);
// Send all the cached subscriptions to the new upstream peer.
subscriptions.apply(sendSubscription, pipe);
pipe.flush();
}
@Override
protected void xreadActivated(Pipe pipe)
{
fq.activated(pipe);
}
@Override
protected void xwriteActivated(Pipe pipe)
{
dist.activated(pipe);
}
@Override
protected void xpipeTerminated(Pipe pipe)
{
fq.terminated(pipe);
dist.terminated(pipe);
}
@Override
protected void xhiccuped(Pipe pipe)
{
// Send all the cached subscriptions to the hiccuped pipe.
subscriptions.apply(sendSubscription, pipe);
pipe.flush();
}
@Override
protected boolean xsend(Msg msg)
{
byte[] data = msg.data();
// Malformed subscriptions.
if (data.length < 1 || (data[0] != 0 && data[0] != 1)) {
throw new IllegalArgumentException("subscription flag");
}
// Process the subscription.
if (data[0] == 1) {
// this used to filter out duplicate subscriptions,
// however this is alread done on the XPUB side and
// doing it here as well breaks ZMQ_XPUB_VERBOSE
// when there are forwarding devices involved
//
subscriptions.add(data , 1);
return dist.sendToAll(msg);
}
else {
if (subscriptions.rm(data, 1)) {
return dist.sendToAll(msg);
}
}
return true;
}
@Override
protected boolean xhasOut()
{
// Subscription can be added/removed anytime.
return true;
}
@Override
protected Msg xrecv()
{
Msg msg = null;
// If there's already a message prepared by a previous call to zmq_poll,
// return it straight ahead.
if (hashMessage) {
msg = message;
hashMessage = false;
more = msg.hasMore();
return msg;
}
// TODO: This can result in infinite loop in the case of continuous
// stream of non-matching messages which breaks the non-blocking recv
// semantics.
while (true) {
// Get a message using fair queueing algorithm.
msg = fq.recv(errno);
// If there's no message available, return immediately.
// The same when error occurs.
if (msg == null) {
return null;
}
// Check whether the message matches at least one subscription.
// Non-initial parts of the message are passed
if (more || !options.filter || match(msg)) {
more = msg.hasMore();
return msg;
}
// Message doesn't match. Pop any remaining parts of the message
// from the pipe.
while (msg.hasMore()) {
msg = fq.recv(errno);
assert (msg != null);
}
}
}
@Override
protected boolean xhasIn()
{
// There are subsequent parts of the partly-read message available.
if (more) {
return true;
}
// If there's already a message prepared by a previous call to zmq_poll,
// return straight ahead.
if (hashMessage) {
return true;
}
// TODO: This can result in infinite loop in the case of continuous
// stream of non-matching messages.
while (true) {
// Get a message using fair queueing algorithm.
message = fq.recv(errno);
// If there's no message available, return immediately.
// The same when error occurs.
if (message == null) {
return false;
}
// Check whether the message matches at least one subscription.
if (!options.filter || match(message)) {
hashMessage = true;
return true;
}
// Message doesn't match. Pop any remaining parts of the message
// from the pipe.
while (message.hasMore()) {
message = fq.recv(errno);
assert (message != null);
}
}
}
private boolean match(Msg msg)
{
return subscriptions.check(msg.data());
}
}
jeromq-0.3.5/src/main/java/zmq/YPipe.java 0000664 0000000 0000000 00000012515 12551504772 0020164 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.util.concurrent.atomic.AtomicInteger;
public class YPipe
{
// Allocation-efficient queue to store pipe items.
// Front of the queue points to the first prefetched item, back of
// the pipe points to last un-flushed item. Front is used only by
// reader thread, while back is used only by writer thread.
private final YQueue queue;
// Points to the first un-flushed item. This variable is used
// exclusively by writer thread.
private int w;
// Points to the first un-prefetched item. This variable is used
// exclusively by reader thread.
private int r;
// Points to the first item to be flushed in the future.
private int f;
// The single point of contention between writer and reader thread.
// Points past the last flushed item. If it is NULL,
// reader is asleep. This pointer should be always accessed using
// atomic operations.
private final AtomicInteger c;
public YPipe(int qsize)
{
queue = new YQueue(qsize);
int pos = queue.backPos();
f = pos;
r = pos;
w = pos;
c = new AtomicInteger(queue.backPos());
}
// Write an item to the pipe. Don't flush it yet. If incomplete is
// set to true the item is assumed to be continued by items
// subsequently written to the pipe. Incomplete items are never
// flushed down the stream.
public void write(final T value, boolean incomplete)
{
// Place the value to the queue, add new terminator element.
queue.push(value);
// Move the "flush up to here" poiter.
if (!incomplete) {
f = queue.backPos();
}
}
// Pop an incomplete item from the pipe. Returns true is such
// item exists, false otherwise.
public T unwrite()
{
if (f == queue.backPos()) {
return null;
}
queue.unpush();
return queue.back();
}
// Flush all the completed items into the pipe. Returns false if
// the reader thread is sleeping. In that case, caller is obliged to
// wake the reader up before using the pipe again.
public boolean flush()
{
// If there are no un-flushed items, do nothing.
if (w == f) {
return true;
}
// Try to set 'c' to 'f'.
if (!c.compareAndSet(w, f)) {
// Compare-and-swap was unseccessful because 'c' is NULL.
// This means that the reader is asleep. Therefore we don't
// care about thread-safeness and update c in non-atomic
// manner. We'll return false to let the caller know
// that reader is sleeping.
c.set(f);
w = f;
return false;
}
// Reader is alive. Nothing special to do now. Just move
// the 'first un-flushed item' pointer to 'f'.
w = f;
return true;
}
// Check whether item is available for reading.
public boolean checkRead()
{
// Was the value prefetched already? If so, return.
int h = queue.frontPos();
if (h != r) {
return true;
}
// There's no prefetched value, so let us prefetch more values.
// Prefetching is to simply retrieve the
// pointer from c in atomic fashion. If there are no
// items to prefetch, set c to -1 (using compare-and-swap).
if (c.compareAndSet(h, -1)) {
// nothing to read, h == r must be the same
}
else {
// something to have been written
r = c.get();
}
// If there are no elements prefetched, exit.
// During pipe's lifetime r should never be NULL, however,
// it can happen during pipe shutdown when items
// are being deallocated.
if (h == r || r == -1) {
return false;
}
// There was at least one value prefetched.
return true;
}
// Reads an item from the pipe. Returns false if there is no value.
// available.
public T read()
{
// Try to prefetch a value.
if (!checkRead()) {
return null;
}
// There was at least one value prefetched.
// Return it to the caller.
return queue.pop();
}
// Applies the function fn to the first elemenent in the pipe
// and returns the value returned by the fn.
// The pipe mustn't be empty or the function crashes.
public T probe()
{
boolean rc = checkRead();
assert (rc);
return queue.front();
}
}
jeromq-0.3.5/src/main/java/zmq/YQueue.java 0000664 0000000 0000000 00000011671 12551504772 0020355 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
public class YQueue
{
// Individual memory chunk to hold N elements.
private static class Chunk
{
final T[] values;
final int[] pos;
Chunk prev;
Chunk next;
@SuppressWarnings("unchecked")
public Chunk(int size, int memoryPtr)
{
values = (T[]) new Object[size];
pos = new int[size];
for (int i = 0; i != values.length; i++) {
pos[i] = memoryPtr;
memoryPtr++;
}
}
};
// Back position may point to invalid memory if the queue is empty,
// while begin & end positions are always valid. Begin position is
// accessed exclusively be queue reader (front/pop), while back and
// end positions are accessed exclusively by queue writer (back/push).
private Chunk beginChunk;
private int beginPos;
private Chunk backChunk;
private int backPos;
private Chunk endChunk;
private int endPos;
private volatile Chunk spareChunk;
private final int size;
// People are likely to produce and consume at similar rates. In
// this scenario holding onto the most recently freed chunk saves
// us from having to call malloc/free.
private int memoryPtr;
public YQueue(int size)
{
this.size = size;
memoryPtr = 0;
beginChunk = new Chunk(size, memoryPtr);
memoryPtr += size;
beginPos = 0;
backPos = 0;
backChunk = beginChunk;
spareChunk = beginChunk;
endChunk = beginChunk;
endPos = 1;
}
public int frontPos()
{
return beginChunk.pos[beginPos];
}
// Returns reference to the front element of the queue.
// If the queue is empty, behaviour is undefined.
public T front()
{
return beginChunk.values[beginPos];
}
public int backPos()
{
return backChunk.pos[backPos];
}
// Returns reference to the back element of the queue.
// If the queue is empty, behaviour is undefined.
public T back()
{
return backChunk.values[backPos];
}
public T pop()
{
T val = beginChunk.values[beginPos];
beginChunk.values[beginPos] = null;
beginPos++;
if (beginPos == size) {
beginChunk = beginChunk.next;
beginChunk.prev = null;
beginPos = 0;
}
return val;
}
// Adds an element to the back end of the queue.
public void push(T val)
{
backChunk.values[backPos] = val;
backChunk = endChunk;
backPos = endPos;
endPos++;
if (endPos != size) {
return;
}
Chunk sc = spareChunk;
if (sc != beginChunk) {
spareChunk = spareChunk.next;
endChunk.next = sc;
sc.prev = endChunk;
}
else {
endChunk.next = new Chunk(size, memoryPtr);
memoryPtr += size;
endChunk.next.prev = endChunk;
}
endChunk = endChunk.next;
endPos = 0;
}
// Removes element from the back end of the queue. In other words
// it rollbacks last push to the queue. Take care: Caller is
// responsible for destroying the object being unpushed.
// The caller must also guarantee that the queue isn't empty when
// unpush is called. It cannot be done automatically as the read
// side of the queue can be managed by different, completely
// unsynchronised thread.
public void unpush()
{
// First, move 'back' one position backwards.
if (backPos > 0) {
backPos--;
}
else {
backPos = size - 1;
backChunk = backChunk.prev;
}
// Now, move 'end' position backwards. Note that obsolete end chunk
// is not used as a spare chunk. The analysis shows that doing so
// would require free and atomic operation per chunk deallocated
// instead of a simple free.
if (endPos > 0) {
endPos--;
}
else {
endPos = size - 1;
endChunk = endChunk.prev;
endChunk.next = null;
}
}
}
jeromq-0.3.5/src/main/java/zmq/ZError.java 0000664 0000000 0000000 00000007156 12551504772 0020366 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.net.SocketException;
import java.nio.channels.ClosedChannelException;
public class ZError
{
private ZError()
{
}
public static class CtxTerminatedException extends RuntimeException
{
private static final long serialVersionUID = -4404921838608052956L;
public CtxTerminatedException()
{
super();
}
}
public static class InstantiationException extends RuntimeException
{
private static final long serialVersionUID = -4404921838608052955L;
public InstantiationException(Throwable cause)
{
super(cause);
}
}
public static class IOException extends RuntimeException
{
private static final long serialVersionUID = 9202470691157986262L;
public IOException(java.io.IOException e)
{
super(e);
}
}
public static final int EINTR = 4;
public static final int EACCESS = 13;
public static final int EFAULT = 14;
public static final int EINVAL = 22;
public static final int EAGAIN = 35;
public static final int EINPROGRESS = 36;
public static final int EPROTONOSUPPORT = 43;
public static final int ENOTSUP = 45;
public static final int EADDRINUSE = 48;
public static final int EADDRNOTAVAIL = 49;
public static final int ENETDOWN = 50;
public static final int ENOBUFS = 55;
public static final int EISCONN = 56;
public static final int ENOTCONN = 57;
public static final int ECONNREFUSED = 61;
public static final int EHOSTUNREACH = 65;
private static final int ZMQ_HAUSNUMERO = 156384712;
public static final int ENOTSOCK = ZMQ_HAUSNUMERO + 5;
public static final int EFSM = ZMQ_HAUSNUMERO + 51;
public static final int ENOCOMPATPROTO = ZMQ_HAUSNUMERO + 52;
public static final int ETERM = ZMQ_HAUSNUMERO + 53;
public static final int EMTHREAD = ZMQ_HAUSNUMERO + 54;
public static final int EIOEXC = ZMQ_HAUSNUMERO + 105;
public static final int ESOCKET = ZMQ_HAUSNUMERO + 106;
public static final int EMFILE = ZMQ_HAUSNUMERO + 107;
static int exccode(java.io.IOException e)
{
if (e instanceof SocketException) {
return ESOCKET;
}
else if (e instanceof ClosedChannelException) {
return ENOTCONN;
}
else {
return EIOEXC;
}
}
public static String toString(int code)
{
switch (code) {
case EADDRINUSE:
return "Address already in use";
case EFSM:
return "Operation cannot be accomplished in current state";
case ENOCOMPATPROTO:
return "The protocol is not compatible with the socket type";
case ETERM:
return "Context was terminated";
case EMTHREAD:
return "No thread available";
}
return "";
}
}
jeromq-0.3.5/src/main/java/zmq/ZMQ.java 0000664 0000000 0000000 00000062337 12551504772 0017614 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.charset.Charset;
import java.util.HashMap;
public class ZMQ
{
/******************************************************************************/
/* 0MQ versioning support. */
/******************************************************************************/
/* Version macros for compile-time API version detection */
public static final int ZMQ_VERSION_MAJOR = 3;
public static final int ZMQ_VERSION_MINOR = 2;
public static final int ZMQ_VERSION_PATCH = 5;
/* Context options */
public static final int ZMQ_IO_THREADS = 1;
public static final int ZMQ_MAX_SOCKETS = 2;
/* Default for new contexts */
public static final int ZMQ_IO_THREADS_DFLT = 1;
public static final int ZMQ_MAX_SOCKETS_DFLT = 1024;
/******************************************************************************/
/* 0MQ socket definition. */
/******************************************************************************/
/* Socket types. */
public static final int ZMQ_PAIR = 0;
public static final int ZMQ_PUB = 1;
public static final int ZMQ_SUB = 2;
public static final int ZMQ_REQ = 3;
public static final int ZMQ_REP = 4;
public static final int ZMQ_DEALER = 5;
public static final int ZMQ_ROUTER = 6;
public static final int ZMQ_PULL = 7;
public static final int ZMQ_PUSH = 8;
public static final int ZMQ_XPUB = 9;
public static final int ZMQ_XSUB = 10;
/* Deprecated aliases */
@Deprecated
public static final int ZMQ_XREQ = ZMQ_DEALER;
@Deprecated
public static final int ZMQ_XREP = ZMQ_ROUTER;
/* Socket options. */
public static final int ZMQ_AFFINITY = 4;
public static final int ZMQ_IDENTITY = 5;
public static final int ZMQ_SUBSCRIBE = 6;
public static final int ZMQ_UNSUBSCRIBE = 7;
public static final int ZMQ_RATE = 8;
public static final int ZMQ_RECOVERY_IVL = 9;
public static final int ZMQ_SNDBUF = 11;
public static final int ZMQ_RCVBUF = 12;
public static final int ZMQ_RCVMORE = 13;
public static final int ZMQ_FD = 14;
public static final int ZMQ_EVENTS = 15;
public static final int ZMQ_TYPE = 16;
public static final int ZMQ_LINGER = 17;
public static final int ZMQ_RECONNECT_IVL = 18;
public static final int ZMQ_BACKLOG = 19;
public static final int ZMQ_RECONNECT_IVL_MAX = 21;
public static final int ZMQ_MAXMSGSIZE = 22;
public static final int ZMQ_SNDHWM = 23;
public static final int ZMQ_RCVHWM = 24;
public static final int ZMQ_MULTICAST_HOPS = 25;
public static final int ZMQ_RCVTIMEO = 27;
public static final int ZMQ_SNDTIMEO = 28;
public static final int ZMQ_IPV4ONLY = 31;
public static final int ZMQ_LAST_ENDPOINT = 32;
public static final int ZMQ_ROUTER_MANDATORY = 33;
public static final int ZMQ_TCP_KEEPALIVE = 34;
public static final int ZMQ_TCP_KEEPALIVE_CNT = 35;
public static final int ZMQ_TCP_KEEPALIVE_IDLE = 36;
public static final int ZMQ_TCP_KEEPALIVE_INTVL = 37;
public static final int ZMQ_TCP_ACCEPT_FILTER = 38;
public static final int ZMQ_DELAY_ATTACH_ON_CONNECT = 39;
public static final int ZMQ_XPUB_VERBOSE = 40;
// TODO: more constants
public static final int ZMQ_ROUTER_HANDOVER = 56;
public static final int ZMQ_BLOCKY = 70;
/* Custom options */
public static final int ZMQ_ENCODER = 1001;
public static final int ZMQ_DECODER = 1002;
/* Message options */
public static final int ZMQ_MORE = 1;
/* Send/recv options. */
public static final int ZMQ_DONTWAIT = 1;
public static final int ZMQ_SNDMORE = 2;
/* Deprecated aliases */
public static final int ZMQ_NOBLOCK = ZMQ_DONTWAIT;
public static final int ZMQ_FAIL_UNROUTABLE = ZMQ_ROUTER_MANDATORY;
public static final int ZMQ_ROUTER_BEHAVIOR = ZMQ_ROUTER_MANDATORY;
/******************************************************************************/
/* 0MQ socket events and monitoring */
/******************************************************************************/
/* Socket transport events (tcp and ipc only) */
public static final int ZMQ_EVENT_CONNECTED = 1;
public static final int ZMQ_EVENT_CONNECT_DELAYED = 2;
public static final int ZMQ_EVENT_CONNECT_RETRIED = 4;
public static final int ZMQ_EVENT_LISTENING = 8;
public static final int ZMQ_EVENT_BIND_FAILED = 16;
public static final int ZMQ_EVENT_ACCEPTED = 32;
public static final int ZMQ_EVENT_ACCEPT_FAILED = 64;
public static final int ZMQ_EVENT_CLOSED = 128;
public static final int ZMQ_EVENT_CLOSE_FAILED = 256;
public static final int ZMQ_EVENT_DISCONNECTED = 512;
public static final int ZMQ_EVENT_MONITOR_STOPPED = 1024;
public static final int ZMQ_EVENT_ALL = ZMQ_EVENT_CONNECTED | ZMQ_EVENT_CONNECT_DELAYED |
ZMQ_EVENT_CONNECT_RETRIED | ZMQ_EVENT_LISTENING |
ZMQ_EVENT_BIND_FAILED | ZMQ_EVENT_ACCEPTED |
ZMQ_EVENT_ACCEPT_FAILED | ZMQ_EVENT_CLOSED |
ZMQ_EVENT_CLOSE_FAILED | ZMQ_EVENT_DISCONNECTED | ZMQ_EVENT_MONITOR_STOPPED;
public static final int ZMQ_POLLIN = 1;
public static final int ZMQ_POLLOUT = 2;
public static final int ZMQ_POLLERR = 4;
public static final int ZMQ_STREAMER = 1;
public static final int ZMQ_FORWARDER = 2;
public static final int ZMQ_QUEUE = 3;
public static final byte[] MESSAGE_SEPARATOR = new byte[0];
public static final byte[] SUBSCRIPTION_ALL = new byte[0];
public static final Charset CHARSET = Charset.forName("UTF-8");
public static class Event
{
private static final int VALUE_INTEGER = 1;
private static final int VALUE_CHANNEL = 2;
public final int event;
public final String addr;
public final Object arg;
private final int flag;
public Event(int event, String addr, Object arg)
{
this.event = event;
this.addr = addr;
this.arg = arg;
if (arg instanceof Integer) {
flag = VALUE_INTEGER;
}
else if (arg instanceof SelectableChannel) {
flag = VALUE_CHANNEL;
}
else {
flag = 0;
}
}
public boolean write(SocketBase s)
{
int size = 4 + 1 + addr.length() + 1; // event + len(addr) + addr + flag
if (flag == VALUE_INTEGER) {
size += 4;
}
ByteBuffer buffer = ByteBuffer.allocate(size).order(ByteOrder.BIG_ENDIAN);
buffer.putInt(event);
buffer.put((byte) addr.length());
buffer.put(addr.getBytes(CHARSET));
buffer.put((byte) flag);
if (flag == VALUE_INTEGER) {
buffer.putInt((Integer) arg);
}
buffer.flip();
Msg msg = new Msg(buffer);
return s.send(msg, 0);
}
public static Event read(SocketBase s, int flags)
{
Msg msg = s.recv(flags);
if (msg == null) {
return null;
}
ByteBuffer buffer = msg.buf();
int event = buffer.getInt();
int len = buffer.get();
byte [] addr = new byte [len];
buffer.get(addr);
int flag = buffer.get();
Object arg = null;
if (flag == VALUE_INTEGER) {
arg = buffer.getInt();
}
return new Event(event, new String(addr, CHARSET), arg);
}
public static Event read(SocketBase s)
{
return read(s, 0);
}
}
// New context API
public static Ctx createContext()
{
// Create 0MQ context.
Ctx ctx = new Ctx();
return ctx;
}
private static void destroyContext(Ctx ctx)
{
if (ctx == null || !ctx.checkTag()) {
throw new IllegalStateException();
}
ctx.terminate();
}
public static void setContextOption(Ctx ctx, int option, int optval)
{
if (ctx == null || !ctx.checkTag()) {
throw new IllegalStateException();
}
ctx.set(option, optval);
}
public static int getContextOption(Ctx ctx, int option)
{
if (ctx == null || !ctx.checkTag()) {
throw new IllegalStateException();
}
return ctx.get(option);
}
// Stable/legacy context API
public static Ctx init(int ioThreads)
{
if (ioThreads >= 0) {
Ctx ctx = createContext();
setContextOption(ctx, ZMQ_IO_THREADS, ioThreads);
return ctx;
}
throw new IllegalArgumentException("io_threds must not be negative");
}
public static void term(Ctx ctx)
{
destroyContext(ctx);
}
// Sockets
public static SocketBase socket(Ctx ctx, int type)
{
if (ctx == null || !ctx.checkTag()) {
throw new IllegalStateException();
}
SocketBase s = ctx.createSocket(type);
return s;
}
public static void close(SocketBase s)
{
if (s == null || !s.checkTag()) {
throw new IllegalStateException();
}
s.close();
}
public static void setSocketOption(SocketBase s, int option, Object optval)
{
if (s == null || !s.checkTag()) {
throw new IllegalStateException();
}
s.setSocketOpt(option, optval);
}
public static Object getSocketOptionExt(SocketBase s, int option)
{
if (s == null || !s.checkTag()) {
throw new IllegalStateException();
}
return s.getsockoptx(option);
}
public static int getSocketOption(SocketBase s, int opt)
{
return s.getSocketOpt(opt);
}
public static boolean monitorSocket(SocketBase s, final String addr, int events)
{
if (s == null || !s.checkTag()) {
throw new IllegalStateException();
}
return s.monitor(addr, events);
}
public static boolean bind(SocketBase s, final String addr)
{
if (s == null || !s.checkTag()) {
throw new IllegalStateException();
}
return s.bind(addr);
}
public static boolean connect(SocketBase s, String addr)
{
if (s == null || !s.checkTag()) {
throw new IllegalStateException();
}
return s.connect(addr);
}
public static boolean unbind(SocketBase s, String addr)
{
if (s == null || !s.checkTag()) {
throw new IllegalStateException();
}
return s.termEndpoint(addr);
}
public static boolean disconnect(SocketBase s, String addr)
{
if (s == null || !s.checkTag()) {
throw new IllegalStateException();
}
return s.termEndpoint(addr);
}
// Sending functions.
public static int send(SocketBase s, String str, int flags)
{
byte [] data = str.getBytes(CHARSET);
return send(s, data, data.length, flags);
}
public static int send(SocketBase s, Msg msg, int flags)
{
int rc = sendMsg(s, msg, flags);
if (rc < 0) {
return -1;
}
return rc;
}
public static int send(SocketBase s, byte[] buf, int len, int flags)
{
if (s == null || !s.checkTag()) {
throw new IllegalStateException();
}
Msg msg = new Msg(len);
msg.put(buf, 0, len);
int rc = sendMsg(s, msg, flags);
if (rc < 0) {
return -1;
}
return rc;
}
// Send multiple messages.
//
// If flag bit ZMQ_SNDMORE is set the vector is treated as
// a single multi-part message, i.e. the last message has
// ZMQ_SNDMORE bit switched off.
//
public int sendiov(SocketBase s, byte[][] a, int count, int flags)
{
if (s == null || !s.checkTag()) {
throw new IllegalStateException();
}
int rc = 0;
Msg msg;
for (int i = 0; i < count; ++i) {
msg = new Msg(a[i]);
if (i == count - 1) {
flags = flags & ~ZMQ_SNDMORE;
}
rc = sendMsg(s, msg, flags);
if (rc < 0) {
rc = -1;
break;
}
}
return rc;
}
public static int sendMsg(SocketBase s, Msg msg, int flags)
{
int sz = msgSize(msg);
boolean rc = s.send(msg, flags);
if (!rc) {
return -1;
}
return sz;
}
// Receiving functions.
public static Msg recv(SocketBase s, int flags)
{
if (s == null || !s.checkTag()) {
throw new IllegalStateException();
}
Msg msg = recvMsg(s, flags);
if (msg == null) {
return null;
}
// At the moment an oversized message is silently truncated.
// TODO: Build in a notification mechanism to report the overflows.
//int to_copy = nbytes < len_ ? nbytes : len_;
return msg;
}
// Receive a multi-part message
//
// Receives up to *count_ parts of a multi-part message.
// Sets *count_ to the actual number of parts read.
// ZMQ_RCVMORE is set to indicate if a complete multi-part message was read.
// Returns number of message parts read, or -1 on error.
//
// Note: even if -1 is returned, some parts of the message
// may have been read. Therefore the client must consult
// *count_ to retrieve message parts successfully read,
// even if -1 is returned.
//
// The iov_base* buffers of each iovec *a_ filled in by this
// function may be freed using free().
//
// Implementation note: We assume zmq::msg_t buffer allocated
// by zmq::recvmsg can be freed by free().
// We assume it is safe to steal these buffers by simply
// not closing the zmq::msg_t.
//
public int recviov(SocketBase s, byte[][] a, int count, int flags)
{
if (s == null || !s.checkTag()) {
throw new IllegalStateException();
}
int nread = 0;
boolean recvmore = true;
for (int i = 0; recvmore && i < count; ++i) {
// Cheat! We never close any msg
// because we want to steal the buffer.
Msg msg = recvMsg(s, flags);
if (msg == null) {
nread = -1;
break;
}
// Cheat: acquire zmq_msg buffer.
a[i] = msg.data();
// Assume zmq_socket ZMQ_RVCMORE is properly set.
recvmore = msg.hasMore();
}
return nread;
}
public static Msg recvMsg(SocketBase s, int flags)
{
return s.recv(flags);
}
public static Msg msgInit()
{
return new Msg();
}
public static Msg msgInitWithSize(int messageSize)
{
return new Msg(messageSize);
}
public static int msgSize(Msg msg)
{
return msg.size();
}
public static int getMessageOption(Msg msg, int option)
{
switch (option) {
case ZMQ_MORE:
return msg.hasMore() ? 1 : 0;
default:
throw new IllegalArgumentException();
}
}
public static void sleep(int s)
{
try {
Thread.sleep(s * (1000L));
}
catch (InterruptedException e) {
}
}
// The proxy functionality
public static boolean proxy(SocketBase frontend, SocketBase backend, SocketBase control)
{
if (frontend == null || backend == null) {
throw new IllegalArgumentException();
}
return Proxy.proxy(
frontend,
backend,
control);
}
@Deprecated
public static boolean device(int device, SocketBase insocket,
SocketBase outsocket)
{
return Proxy.proxy(insocket, outsocket, null);
}
/**
* Polling on items. This has very poor performance.
* Try to use zmq_poll with selector
* CAUTION: This could be affected by jdk epoll bug
*
* @param items
* @param timeout
* @return number of events
*/
public static int poll(PollItem[] items, long timeout)
{
return poll(items, items.length, timeout);
}
/**
* Polling on items. This has very poor performance.
* Try to use zmq_poll with selector
* CAUTION: This could be affected by jdk epoll bug
*
* @param items
* @param timeout
* @return number of events
*/
public static int poll(PollItem[] items, int count, long timeout)
{
Selector selector = null;
try {
selector = PollSelector.open();
}
catch (IOException e) {
throw new ZError.IOException(e);
}
int ret = poll(selector, items, count, timeout);
// Do not close selector
return ret;
}
/**
* Polling on items with given selector
* CAUTION: This could be affected by jdk epoll bug
*
* @param selector Open and reuse this selector and do not forget to close when it is not used.
* @param items
* @param timeout
* @return number of events
*/
public static int poll(Selector selector, PollItem[] items, long timeout)
{
return poll(selector, items, items.length, timeout);
}
/**
* Polling on items with given selector
* CAUTION: This could be affected by jdk epoll bug
*
* @param selector Open and reuse this selector and do not forget to close when it is not used.
* @param items
* @param count
* @param timeout
* @return number of events
*/
public static int poll(Selector selector, PollItem[] items, int count, long timeout)
{
if (items == null) {
throw new IllegalArgumentException();
}
if (count == 0) {
if (timeout <= 0) {
return 0;
}
try {
Thread.sleep(timeout);
}
catch (InterruptedException e) {
}
return 0;
}
long now = 0L;
long end = 0L;
HashMap saved = new HashMap();
for (SelectionKey key : selector.keys()) {
if (key.isValid()) {
saved.put(key.channel(), key);
}
}
for (int i = 0; i < count; i++) {
PollItem item = items[i];
if (item == null) {
continue;
}
SelectableChannel ch = item.getChannel(); // mailbox channel if ZMQ socket
SelectionKey key = saved.remove(ch);
if (key != null) {
if (key.interestOps() != item.interestOps()) {
key.interestOps(item.interestOps());
}
key.attach(item);
}
else {
try {
ch.register(selector, item.interestOps(), item);
}
catch (ClosedChannelException e) {
throw new ZError.IOException(e);
}
}
}
if (!saved.isEmpty()) {
for (SelectionKey deprecated : saved.values()) {
deprecated.cancel();
}
}
boolean firstPass = true;
int nevents = 0;
int ready;
while (true) {
// Compute the timeout for the subsequent poll.
long waitMillis;
if (firstPass) {
waitMillis = 0L;
}
else if (timeout < 0L) {
waitMillis = -1L;
}
else {
waitMillis = end - now;
}
// Wait for events.
try {
int rc = 0;
if (waitMillis < 0) {
rc = selector.select(0);
}
else if (waitMillis == 0) {
rc = selector.selectNow();
}
else {
rc = selector.select(waitMillis);
}
for (SelectionKey key : selector.keys()) {
PollItem item = (PollItem) key.attachment();
ready = item.readyOps(key, rc);
if (ready < 0) {
return -1;
}
if (ready > 0) {
nevents++;
}
}
selector.selectedKeys().clear();
}
catch (IOException e) {
throw new ZError.IOException(e);
}
// If timeout is zero, exit immediately whether there are events or not.
if (timeout == 0) {
break;
}
if (nevents > 0) {
break;
}
// At this point we are meant to wait for events but there are none.
// If timeout is infinite we can just loop until we get some events.
if (timeout < 0) {
if (firstPass) {
firstPass = false;
}
continue;
}
// The timeout is finite and there are no events. In the first pass
// we get a timestamp of when the polling have begun. (We assume that
// first pass have taken negligible time). We also compute the time
// when the polling should time out.
if (firstPass) {
now = Clock.nowMS();
end = now + timeout;
if (now == end) {
break;
}
firstPass = false;
continue;
}
// Find out whether timeout have expired.
now = Clock.nowMS();
if (now >= end) {
break;
}
}
return nevents;
}
public static long startStopwatch()
{
return System.nanoTime();
}
public static long stopStopwatch(long watch)
{
return (System.nanoTime() - watch) / 1000;
}
public static int makeVersion(int major, int minor, int patch)
{
return ((major) * 10000 + (minor) * 100 + (patch));
}
public static String strerror(int errno)
{
return "Errno = " + errno;
}
private static final ThreadLocal POLL_SELECTOR = new ThreadLocal();
// GC closes selector handle
private static class PollSelector
{
private Selector selector;
private PollSelector(Selector selector)
{
this.selector = selector;
}
public static Selector open() throws IOException
{
PollSelector polls = POLL_SELECTOR.get();
if (polls == null) {
synchronized (POLL_SELECTOR) {
polls = POLL_SELECTOR.get();
try {
if (polls == null) {
polls = new PollSelector(Selector.open());
POLL_SELECTOR.set(polls);
}
}
catch (IOException e) {
throw new ZError.IOException(e);
}
}
}
return polls.get();
}
public Selector get()
{
assert (selector != null);
assert (selector.isOpen());
return selector;
}
@Override
public void finalize()
{
try {
selector.close();
}
catch (IOException e) {
}
try {
super.finalize();
}
catch (Throwable e) {
}
}
}
}
jeromq-0.3.5/src/main/java/zmq/ZObject.java 0000664 0000000 0000000 00000021177 12551504772 0020502 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package zmq;
// Base class for all objects that participate in inter-thread
// communication.
public abstract class ZObject
{
// Context provides access to the global state.
private final Ctx ctx;
// Thread ID of the thread the object belongs to.
private final int tid;
protected ZObject(Ctx ctx, int tid)
{
this.ctx = ctx;
this.tid = tid;
}
protected ZObject(ZObject parent)
{
this(parent.ctx, parent.tid);
}
protected int getTid()
{
return tid;
}
protected Ctx getCtx()
{
return ctx;
}
protected void processCommand(Command cmd)
{
switch (cmd.type()) {
case ACTIVATE_READ:
processActivateRead();
break;
case ACTIVATE_WRITE:
processActivateWrite((Long) cmd.arg);
break;
case STOP:
processStop();
break;
case PLUG:
processPlug();
processSeqnum();
break;
case OWN:
processOwn((Own) cmd.arg);
processSeqnum();
break;
case ATTACH:
processAttach((IEngine) cmd.arg);
processSeqnum();
break;
case BIND:
processBind((Pipe) cmd.arg);
processSeqnum();
break;
case HICCUP:
processHiccup(cmd.arg);
break;
case PIPE_TERM:
processPipeTerm();
break;
case PIPE_TERM_ACK:
processPipeTermAck();
break;
case TERM_REQ:
processTermReq((Own) cmd.arg);
break;
case TERM:
processTerm((Integer) cmd.arg);
break;
case TERM_ACK:
processTermAck();
break;
case REAP:
processReap((SocketBase) cmd.arg);
break;
case REAPED:
processReaped();
break;
default:
throw new IllegalArgumentException();
}
}
protected boolean registerEndpoint(String addr, Ctx.Endpoint endpoint)
{
return ctx.registerEndpoint(addr, endpoint);
}
protected void unregisterEndpoints(SocketBase socket)
{
ctx.unregisterEndpoints(socket);
}
protected Ctx.Endpoint findEndpoint(String addr)
{
return ctx.findEndpoint(addr);
}
protected void destroySocket(SocketBase socket)
{
ctx.destroySocket(socket);
}
// Chooses least loaded I/O thread.
protected IOThread chooseIoThread(long affinity)
{
return ctx.chooseIoThread(affinity);
}
protected void sendStop()
{
// 'stop' command goes always from administrative thread to
// the current object.
Command cmd = new Command(this, Command.Type.STOP);
ctx.sendCommand(tid, cmd);
}
protected void sendPlug(Own destination)
{
sendPlug(destination, true);
}
protected void sendPlug(Own destination, boolean incSeqnum)
{
if (incSeqnum) {
destination.incSeqnum();
}
Command cmd = new Command(destination, Command.Type.PLUG);
sendCommand(cmd);
}
protected void sendOwn(Own destination, Own object)
{
destination.incSeqnum();
Command cmd = new Command(destination, Command.Type.OWN, object);
sendCommand(cmd);
}
protected void sendAttach(SessionBase destination, IEngine engine)
{
sendAttach(destination, engine, true);
}
protected void sendAttach(SessionBase destination, IEngine engine, boolean incSeqnum)
{
if (incSeqnum) {
destination.incSeqnum();
}
Command cmd = new Command(destination, Command.Type.ATTACH, engine);
sendCommand(cmd);
}
protected void sendBind(Own destination, Pipe pipe)
{
sendBind(destination, pipe, true);
}
protected void sendBind(Own destination, Pipe pipe, boolean incSeqnum)
{
if (incSeqnum) {
destination.incSeqnum();
}
Command cmd = new Command(destination, Command.Type.BIND, pipe);
sendCommand(cmd);
}
protected void sendActivateRead(Pipe destination)
{
Command cmd = new Command(destination, Command.Type.ACTIVATE_READ);
sendCommand(cmd);
}
protected void sendActivateWrite(Pipe destination, long msgsRead)
{
Command cmd = new Command(destination, Command.Type.ACTIVATE_WRITE, msgsRead);
sendCommand(cmd);
}
protected void sendHiccup(Pipe destination, Object pipe)
{
Command cmd = new Command(destination, Command.Type.HICCUP, pipe);
sendCommand(cmd);
}
protected void sendPipeTerm(Pipe destination)
{
Command cmd = new Command(destination, Command.Type.PIPE_TERM);
sendCommand(cmd);
}
protected void sendPipeTermAck(Pipe destination)
{
Command cmd = new Command(destination, Command.Type.PIPE_TERM_ACK);
sendCommand(cmd);
}
protected void sendTermReq(Own destination, Own object)
{
Command cmd = new Command(destination, Command.Type.TERM_REQ, object);
sendCommand(cmd);
}
protected void sendTerm(Own destination, int linger)
{
Command cmd = new Command(destination, Command.Type.TERM, linger);
sendCommand(cmd);
}
protected void sendTermAck(Own destination)
{
Command cmd = new Command(destination, Command.Type.TERM_ACK);
sendCommand(cmd);
}
protected void sendReap(SocketBase socket)
{
Command cmd = new Command(ctx.getReaper(), Command.Type.REAP, socket);
sendCommand(cmd);
}
protected void sendReaped()
{
Command cmd = new Command(ctx.getReaper(), Command.Type.REAPED);
sendCommand(cmd);
}
protected void sendDone()
{
Command cmd = new Command(null, Command.Type.DONE);
ctx.sendCommand(Ctx.TERM_TID, cmd);
}
protected void processStop()
{
throw new UnsupportedOperationException();
}
protected void processPlug()
{
throw new UnsupportedOperationException();
}
protected void processOwn(Own object)
{
throw new UnsupportedOperationException();
}
protected void processAttach(IEngine engine)
{
throw new UnsupportedOperationException();
}
protected void processBind(Pipe pipe)
{
throw new UnsupportedOperationException();
}
protected void processActivateRead()
{
throw new UnsupportedOperationException();
}
protected void processActivateWrite(long msgsRead)
{
throw new UnsupportedOperationException();
}
protected void processHiccup(Object hiccupPipe)
{
throw new UnsupportedOperationException();
}
protected void processPipeTerm()
{
throw new UnsupportedOperationException();
}
protected void processPipeTermAck()
{
throw new UnsupportedOperationException();
}
protected void processTermReq(Own object)
{
throw new UnsupportedOperationException();
}
protected void processTerm(int linger)
{
throw new UnsupportedOperationException();
}
protected void processTermAck()
{
throw new UnsupportedOperationException();
}
protected void processReap(SocketBase socket)
{
throw new UnsupportedOperationException();
}
protected void processReaped()
{
throw new UnsupportedOperationException();
}
// Special handler called after a command that requires a seqnum
// was processed. The implementation should catch up with its counter
// of processed commands here.
protected void processSeqnum()
{
throw new UnsupportedOperationException();
}
private void sendCommand(Command cmd)
{
ctx.sendCommand(cmd.destination().getTid(), cmd);
}
}
jeromq-0.3.5/src/test/ 0000775 0000000 0000000 00000000000 12551504772 0014572 5 ustar 00root root 0000000 0000000 jeromq-0.3.5/src/test/java/ 0000775 0000000 0000000 00000000000 12551504772 0015513 5 ustar 00root root 0000000 0000000 jeromq-0.3.5/src/test/java/guide/ 0000775 0000000 0000000 00000000000 12551504772 0016610 5 ustar 00root root 0000000 0000000 jeromq-0.3.5/src/test/java/guide/MDP.java 0000664 0000000 0000000 00000003242 12551504772 0020074 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.Arrays;
import org.zeromq.ZMQ;
import org.zeromq.ZFrame;
/**
* Majordomo Protocol definitions, Java version
*/
public enum MDP {
/**
* This is the version of MDP/Client we implement
*/
C_CLIENT("MDPC01"),
/**
* This is the version of MDP/Worker we implement
*/
W_WORKER("MDPW01"),
// MDP/Server commands, as byte values
W_READY(1),
W_REQUEST(2),
W_REPLY(3),
W_HEARTBEAT(4),
W_DISCONNECT(5);
private final byte[] data;
MDP(String value) {
this.data = value.getBytes(ZMQ.CHARSET);
}
MDP(int value) { //watch for ints>255, will be truncated
byte b = (byte) (value & 0xFF);
this.data = new byte[] { b };
}
public ZFrame newFrame () {
return new ZFrame(data);
}
public boolean frameEquals (ZFrame frame) {
return Arrays.equals(data, frame.getData());
}
}
jeromq-0.3.5/src/test/java/guide/ZHelper.java 0000664 0000000 0000000 00000004710 12551504772 0021026 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
public class ZHelper
{
private static Random rand = new Random(System.currentTimeMillis ());
/**
* Receives all message parts from socket, prints neatly
*/
public static void dump (Socket sock)
{
System.out.println("----------------------------------------");
while(true) {
byte [] msg = sock.recv (0);
boolean isText = true;
String data = "";
for (int i = 0; i< msg.length; i++) {
if (msg[i] < 32 || msg[i] > 127)
isText = false;
data += String.format ("%02X", msg[i]);
}
if (isText)
data = new String (msg, ZMQ.CHARSET);
System.out.println (String.format ("[%03d] %s", msg.length, data));
if (!sock.hasReceiveMore ())
break;
}
}
public static void setId (Socket sock)
{
String identity = String.format ("%04X-%04X", rand.nextInt (), rand.nextInt ());
sock.setIdentity (identity.getBytes (ZMQ.CHARSET));
}
public static List buildZPipe(Context ctx) {
Socket socket1 = ctx.socket(ZMQ.PAIR);
socket1.setLinger(0);
socket1.setHWM(1);
Socket socket2 = ctx.socket(ZMQ.PAIR);
socket2.setLinger(0);
socket2.setHWM(1);
String iface = "inproc://" + new BigInteger(130, rand).toString(32);
socket1.bind(iface);
socket2.connect(iface);
return Arrays.asList(socket1, socket2);
}
}
jeromq-0.3.5/src/test/java/guide/asyncsrv.java 0000664 0000000 0000000 00000013425 12551504772 0021330 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
import org.zeromq.ZMQ.Poller;
import java.util.Random;
//
//Asynchronous client-to-server (DEALER to ROUTER)
//
//While this example runs in a single process, that is just to make
//it easier to start and stop the example. Each task has its own
//context and conceptually acts as a separate process.
public class asyncsrv
{
//---------------------------------------------------------------------
//This is our client task
//It connects to the server, and then sends a request once per second
//It collects responses as they arrive, and it prints them out. We will
//run several client tasks in parallel, each with a different random ID.
private static Random rand = new Random(System.nanoTime());
private static class client_task implements Runnable {
public void run() {
ZContext ctx = new ZContext();
Socket client = ctx.createSocket(ZMQ.DEALER);
// Set random identity to make tracing easier
String identity = String.format("%04X-%04X", rand.nextInt(), rand.nextInt());
client.setIdentity(identity.getBytes(ZMQ.CHARSET));
client.connect("tcp://localhost:5570");
PollItem[] items = new PollItem[] { new PollItem(client, Poller.POLLIN) };
int requestNbr = 0;
while (!Thread.currentThread().isInterrupted()) {
// Tick once per second, pulling in arriving messages
for (int centitick = 0; centitick < 100; centitick++) {
ZMQ.poll(items, 10);
if (items[0].isReadable()) {
ZMsg msg = ZMsg.recvMsg(client);
msg.getLast().print(identity);
msg.destroy();
}
}
client.send(String.format("request #%d", ++requestNbr), 0);
}
ctx.destroy();
}
}
//This is our server task.
//It uses the multithreaded server model to deal requests out to a pool
//of workers and route replies back to clients. One worker can handle
//one request at a time but one client can talk to multiple workers at
//once.
private static class server_task implements Runnable {
public void run() {
ZContext ctx = new ZContext();
// Frontend socket talks to clients over TCP
Socket frontend = ctx.createSocket(ZMQ.ROUTER);
frontend.bind("tcp://*:5570");
// Backend socket talks to workers over inproc
Socket backend = ctx.createSocket(ZMQ.DEALER);
backend.bind("inproc://backend");
// Launch pool of worker threads, precise number is not critical
for (int threadNbr = 0; threadNbr < 5; threadNbr++)
new Thread(new server_worker(ctx)).start();
// Connect backend to frontend via a proxy
ZMQ.proxy(frontend, backend, null);
ctx.destroy();
}
}
//Each worker task works on one request at a time and sends a random number
//of replies back, with random delays between replies:
private static class server_worker implements Runnable {
private ZContext ctx;
public server_worker(ZContext ctx) {
this.ctx = ctx;
}
public void run() {
Socket worker = ctx.createSocket(ZMQ.DEALER);
worker.connect("inproc://backend");
while (!Thread.currentThread().isInterrupted()) {
// The DEALER socket gives us the address envelope and message
ZMsg msg = ZMsg.recvMsg(worker);
ZFrame address = msg.pop();
ZFrame content = msg.pop();
assert (content != null);
msg.destroy();
// Send 0..4 replies back
int replies = rand.nextInt(5);
for (int reply = 0; reply < replies; reply++) {
// Sleep for some fraction of a second
try {
Thread.sleep(rand.nextInt(1000) + 1);
} catch (InterruptedException e) {
}
address.send(worker, ZFrame.REUSE + ZFrame.MORE);
content.send(worker, ZFrame.REUSE);
}
address.destroy();
content.destroy();
}
ctx.destroy();
}
}
//The main thread simply starts several clients, and a server, and then
//waits for the server to finish.
public static void main(String[] args) throws Exception {
ZContext ctx = new ZContext();
new Thread(new client_task()).start();
new Thread(new client_task()).start();
new Thread(new client_task()).start();
new Thread(new server_task()).start();
// Run for 5 seconds then quit
Thread.sleep(5 * 1000);
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/bstar.java 0000664 0000000 0000000 00000030033 12551504772 0020565 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZLoop;
import org.zeromq.ZLoop.IZLoopHandler;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
// bstar class - Binary Star reactor
public class bstar
{
// States we can be in at any point in time
enum State {
STATE_PRIMARY, // Primary, waiting for peer to connect
STATE_BACKUP, // Backup, waiting for peer to connect
STATE_ACTIVE, // Active - accepting connections
STATE_PASSIVE // Passive - not accepting connections
}
// Events, which start with the states our peer can be in
enum Event {
PEER_PRIMARY, // HA peer is pending primary
PEER_BACKUP, // HA peer is pending backup
PEER_ACTIVE, // HA peer is active
PEER_PASSIVE, // HA peer is passive
CLIENT_REQUEST // Client makes request
}
private ZContext ctx; // Our private context
private ZLoop loop; // Reactor loop
private Socket statepub; // State publisher
private Socket statesub; // State subscriber
private State state; // Current state
private Event event; // Current event
private long peerExpiry; // When peer is considered 'dead'
private ZLoop.IZLoopHandler voterFn; // Voting socket handler
private Object voterArg; // Arguments for voting handler
private ZLoop.IZLoopHandler activeFn; // Call when become active
private Object activeArg; // Arguments for handler
private ZLoop.IZLoopHandler passiveFn; // Call when become passive
private Object passiveArg; // Arguments for handler
// The finite-state machine is the same as in the proof-of-concept server.
// To understand this reactor in detail, first read the ZLoop class.
// .skip
// We send state information this often
// If peer doesn't respond in two heartbeats, it is 'dead'
private final static int BSTAR_HEARTBEAT = 1000; // In msecs
// Binary Star finite state machine (applies event to state)
// Returns false if there was an exception, true if event was valid.
private boolean execute()
{
boolean rc = true;
// Primary server is waiting for peer to connect
// Accepts CLIENT_REQUEST events in this state
if (state == State.STATE_PRIMARY) {
if (event == Event.PEER_BACKUP) {
System.out.printf ("I: connected to backup (passive), ready active\n");
state = State.STATE_ACTIVE;
if (activeFn != null)
activeFn.handle(loop, null, activeArg);
}
else
if (event == Event.PEER_ACTIVE) {
System.out.printf ("I: connected to backup (active), ready passive\n");
state = State.STATE_PASSIVE;
if (passiveFn != null)
passiveFn.handle(loop, null, passiveArg);
}
else
if (event == Event.CLIENT_REQUEST) {
// Allow client requests to turn us into the active if we've
// waited sufficiently long to believe the backup is not
// currently acting as active (i.e., after a failover)
assert (peerExpiry > 0);
if (System.currentTimeMillis() >= peerExpiry) {
System.out.printf ("I: request from client, ready as active\n");
state = State.STATE_ACTIVE;
if (activeFn != null)
activeFn.handle(loop, null, activeArg);
} else
// Don't respond to clients yet - it's possible we're
// performing a failback and the backup is currently active
rc = false;
}
}
else
if (state == State.STATE_BACKUP) {
if (event == Event.PEER_ACTIVE) {
System.out.printf ("I: connected to primary (active), ready passive\n");
state = State.STATE_PASSIVE;
if (passiveFn != null)
passiveFn.handle(loop, null, passiveArg);
}
else
// Reject client connections when acting as backup
if (event == Event.CLIENT_REQUEST)
rc = false;
}
else
// .split active and passive states
// These are the ACTIVE and PASSIVE states:
if (state == State.STATE_ACTIVE) {
if (event == Event.PEER_ACTIVE) {
// Two actives would mean split-brain
System.out.printf ("E: fatal error - dual actives, aborting\n");
rc = false;
}
}
else
// Server is passive
// CLIENT_REQUEST events can trigger failover if peer looks dead
if (state == State.STATE_PASSIVE) {
if (event == Event.PEER_PRIMARY) {
// Peer is restarting - become active, peer will go passive
System.out.printf ("I: primary (passive) is restarting, ready active\n");
state = State.STATE_ACTIVE;
}
else
if (event == Event.PEER_BACKUP) {
// Peer is restarting - become active, peer will go passive
System.out.printf ("I: backup (passive) is restarting, ready active\n");
state = State.STATE_ACTIVE;
}
else
if (event == Event.PEER_PASSIVE) {
// Two passives would mean cluster would be non-responsive
System.out.printf ("E: fatal error - dual passives, aborting\n");
rc = false;
}
else
if (event == Event.CLIENT_REQUEST) {
// Peer becomes active if timeout has passed
// It's the client request that triggers the failover
assert (peerExpiry > 0);
if (System.currentTimeMillis () >= peerExpiry) {
// If peer is dead, switch to the active state
System.out.printf ("I: failover successful, ready active\n");
state = State.STATE_ACTIVE;
}
else
// If peer is alive, reject connections
rc = false;
// Call state change handler if necessary
if (state == State.STATE_ACTIVE && activeFn != null)
activeFn.handle(loop, null, activeArg);
}
}
return rc;
}
private void updatePeerExpiry()
{
peerExpiry = System.currentTimeMillis() + 2 * BSTAR_HEARTBEAT;
}
// Reactor event handlers...
// Publish our state to peer
private static IZLoopHandler SendState = new IZLoopHandler () {
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
bstar self = (bstar) arg;
self.statepub.send(String.format("%d", self.state.ordinal()));
return 0;
}
};
// Receive state from peer, execute finite state machine
private static IZLoopHandler RecvState = new IZLoopHandler () {
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
bstar self = (bstar) arg;
String state = item.getSocket().recvStr();
if (state != null) {
self.event = Event.values()[Integer.parseInt(state)];
self.updatePeerExpiry();
}
return self.execute() ? 0 : -1;
}
};
// Application wants to speak to us, see if it's possible
private static IZLoopHandler VoterReady = new IZLoopHandler () {
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
bstar self = (bstar) arg;
// If server can accept input now, call appl handler
self.event = Event.CLIENT_REQUEST;
if (self.execute())
self.voterFn.handle(loop, item, self.voterArg);
else {
// Destroy waiting message, no-one to read it
ZMsg msg = ZMsg.recvMsg(item.getSocket());
msg.destroy();
}
return 0;
}
};
// .until
// .split constructor
// This is the constructor for our {{bstar}} class. We have to tell it
// whether we're primary or backup server, as well as our local and
// remote endpoints to bind and connect to:
public bstar(boolean primary, String local, String remote) {
// Initialize the Binary Star
ctx = new ZContext();
loop = new ZLoop();
state = primary? State.STATE_PRIMARY: State.STATE_BACKUP;
// Create publisher for state going to peer
statepub = ctx.createSocket(ZMQ.PUB);
statepub.bind(local);
// Create subscriber for state coming from peer
statesub = ctx.createSocket(ZMQ.SUB);
statesub.subscribe(ZMQ.SUBSCRIPTION_ALL);
statesub.connect(remote);
// Set-up basic reactor events
loop.addTimer(BSTAR_HEARTBEAT, 0, SendState, this);
PollItem poller = new PollItem(statesub, ZMQ.Poller.POLLIN);
loop.addPoller(poller, RecvState, this);
}
// .split destructor
// The destructor shuts down the bstar reactor:
public void destroy()
{
loop.destroy();
ctx.destroy();
}
// .split zloop method
// This method returns the underlying zloop reactor, so we can add
// additional timers and readers:
public ZLoop zloop()
{
return loop;
}
// .split voter method
// This method registers a client voter socket. Messages received
// on this socket provide the CLIENT_REQUEST events for the Binary Star
// FSM and are passed to the provided application handler. We require
// exactly one voter per {{bstar}} instance:
public int voter(String endpoint, int type, IZLoopHandler handler, Object arg)
{
// Hold actual handler+arg so we can call this later
Socket socket = ctx.createSocket(type);
socket.bind(endpoint);
voterFn = handler;
voterArg = arg;
PollItem poller = new PollItem(socket, ZMQ.Poller.POLLIN);
return loop.addPoller(poller, VoterReady, this);
}
// .split register state-change handlers
// Register handlers to be called each time there's a state change:
public void newActive(IZLoopHandler handler, Object arg)
{
activeFn = handler;
activeArg = arg;
}
public void newPassive(IZLoopHandler handler, Object arg)
{
passiveFn = handler;
passiveArg = arg;
}
// .split enable/disable tracing
// Enable/disable verbose tracing, for debugging:
public void setVerbose(boolean verbose)
{
loop.verbose(verbose);
}
// .split start the reactor
// Finally, start the configured reactor. It will end if any handler
// returns -1 to the reactor, or if the process receives Interrupt
public int start()
{
assert (voterFn != null);
updatePeerExpiry();
return loop.start();
}
}
jeromq-0.3.5/src/test/java/guide/bstarcli.java 0000664 0000000 0000000 00000007553 12551504772 0021270 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
// Binary Star client proof-of-concept implementation. This client does no
// real work; it just demonstrates the Binary Star failover model.
public class bstarcli
{
private static final long REQUEST_TIMEOUT = 1000; // msecs
private static final long SETTLE_DELAY = 2000; // Before failing over
public static void main(String[] argv) throws Exception
{
ZContext ctx = new ZContext();
String[] server = { "tcp://localhost:5001", "tcp://localhost:5002" };
int serverNbr = 0;
System.out.printf ("I: connecting to server at %s...\n", server [serverNbr]);
Socket client = ctx.createSocket(ZMQ.REQ);
client.connect(server[serverNbr]);
int sequence = 0;
while (!Thread.currentThread().isInterrupted()) {
// We send a request, then we work to get a reply
String request = String.format("%d", ++sequence);
client.send(request);
boolean expectReply = true;
while (expectReply) {
// Poll socket for a reply, with timeout
PollItem items [] = { new PollItem(client, ZMQ.Poller.POLLIN) };
int rc = ZMQ.poll(items, 1, REQUEST_TIMEOUT);
if (rc == -1)
break; // Interrupted
// .split main body of client
// We use a Lazy Pirate strategy in the client. If there's no
// reply within our timeout, we close the socket and try again.
// In Binary Star, it's the client vote that decides which
// server is primary; the client must therefore try to connect
// to each server in turn:
if (items[0].isReadable()) {
// We got a reply from the server, must match getSequence
String reply = client.recvStr();
if (Integer.parseInt(reply) == sequence) {
System.out.printf ("I: server replied OK (%s)\n", reply);
expectReply = false;
Thread.sleep(1000); // One request per second
}
else
System.out.printf ("E: bad reply from server: %s\n", reply);
}
else {
System.out.printf ("W: no response from server, failing over\n");
// Old socket is confused; close it and open a new one
ctx.destroySocket(client);
serverNbr = (serverNbr + 1) % 2;
Thread.sleep(SETTLE_DELAY);
System.out.printf("I: connecting to server at %s...\n",
server[serverNbr]);
client = ctx.createSocket(ZMQ.REQ);
client.connect(server[serverNbr]);
// Send request again, on new socket
client.send(request);
}
}
}
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/bstarsrv.java 0000664 0000000 0000000 00000022425 12551504772 0021326 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
// Binary Star server proof-of-concept implementation. This server does no
// real work; it just demonstrates the Binary Star failover model.
public class bstarsrv
{
// States we can be in at any point in time
enum State {
STATE_PRIMARY, // Primary, waiting for peer to connect
STATE_BACKUP, // Backup, waiting for peer to connect
STATE_ACTIVE, // Active - accepting connections
STATE_PASSIVE // Passive - not accepting connections
}
// Events, which start with the states our peer can be in
enum Event {
PEER_PRIMARY, // HA peer is pending primary
PEER_BACKUP, // HA peer is pending backup
PEER_ACTIVE, // HA peer is active
PEER_PASSIVE, // HA peer is passive
CLIENT_REQUEST // Client makes request
}
// Our finite state machine
private State state; // Current state
private Event event; // Current event
private long peerExpiry; // When peer is considered 'dead'
// We send state information this often
// If peer doesn't respond in two heartbeats, it is 'dead'
private final static long HEARTBEAT = 1000; // In msecs
// .split Binary Star state machine
// The heart of the Binary Star design is its finite-state machine (FSM).
// The FSM runs one event at a time. We apply an event to the current state,
// which checks if the event is accepted, and if so, sets a new state:
private boolean stateMachine()
{
boolean exception = false;
// These are the PRIMARY and BACKUP states; we're waiting to become
// ACTIVE or PASSIVE depending on events we get from our peer:
if (state == State.STATE_PRIMARY) {
if (event == Event.PEER_BACKUP) {
System.out.printf ("I: connected to backup (passive), ready active\n");
state = State.STATE_ACTIVE;
}
else
if (event == Event.PEER_ACTIVE) {
System.out.printf ("I: connected to backup (active), ready passive\n");
state = State.STATE_PASSIVE;
}
// Accept client connections
}
else
if (state == State.STATE_BACKUP) {
if (event == Event.PEER_ACTIVE) {
System.out.printf ("I: connected to primary (active), ready passive\n");
state = State.STATE_PASSIVE;
}
else
// Reject client connections when acting as backup
if (event == Event.CLIENT_REQUEST)
exception = true;
}
else
// .split active and passive states
// These are the ACTIVE and PASSIVE states:
if (state == State.STATE_ACTIVE) {
if (event == Event.PEER_ACTIVE) {
// Two actives would mean split-brain
System.out.printf ("E: fatal error - dual actives, aborting\n");
exception = true;
}
}
else
// Server is passive
// CLIENT_REQUEST events can trigger failover if peer looks dead
if (state == State.STATE_PASSIVE) {
if (event == Event.PEER_PRIMARY) {
// Peer is restarting - become active, peer will go passive
System.out.printf ("I: primary (passive) is restarting, ready active\n");
state = State.STATE_ACTIVE;
}
else
if (event == Event.PEER_BACKUP) {
// Peer is restarting - become active, peer will go passive
System.out.printf ("I: backup (passive) is restarting, ready active\n");
state = State.STATE_ACTIVE;
}
else
if (event == Event.PEER_PASSIVE) {
// Two passives would mean cluster would be non-responsive
System.out.printf ("E: fatal error - dual passives, aborting\n");
exception = true;
}
else
if (event == Event.CLIENT_REQUEST) {
// Peer becomes active if timeout has passed
// It's the client request that triggers the failover
assert (peerExpiry > 0);
if (System.currentTimeMillis () >= peerExpiry) {
// If peer is dead, switch to the active state
System.out.printf ("I: failover successful, ready active\n");
state = State.STATE_ACTIVE;
}
else
// If peer is alive, reject connections
exception = true;
}
}
return exception;
}
// .split main task
// This is our main task. First we bind/connect our sockets with our
// peer and make sure we will get state messages correctly. We use
// three sockets; one to publish state, one to subscribe to state, and
// one for client requests/replies:
public static void main(String[] argv) {
// Arguments can be either of:
// -p primary server, at tcp://localhost:5001
// -b backup server, at tcp://localhost:5002
ZContext ctx = new ZContext();
Socket statepub = ctx.createSocket(ZMQ.PUB);
Socket statesub = ctx.createSocket(ZMQ.SUB);
statesub.subscribe(ZMQ.SUBSCRIPTION_ALL);
Socket frontend = ctx.createSocket(ZMQ.ROUTER);
bstarsrv fsm = new bstarsrv();
if (argv.length == 1 && argv[0].equals("-p")) {
System.out.printf("I: Primary active, waiting for backup (passive)\n");
frontend.bind("tcp://*:5001");
statepub.bind("tcp://*:5003");
statesub.connect("tcp://localhost:5004");
fsm.state = State.STATE_PRIMARY;
}
else
if (argv.length == 1 && argv[0].equals("-b")) {
System.out.printf("I: Backup passive, waiting for primary (active)\n");
frontend.bind("tcp://*:5002");
statepub.bind("tcp://*:5004");
statesub.connect("tcp://localhost:5003");
fsm.state = State.STATE_BACKUP;
}
else {
System.out.printf("Usage: bstarsrv { -p | -b }\n");
ctx.destroy();
System.exit(0);
}
// .split handling socket input
// We now process events on our two input sockets, and process these
// events one at a time via our finite-state machine. Our "work" for
// a client request is simply to echo it back:
// Set timer for next outgoing state message
long sendStateAt = System.currentTimeMillis() + HEARTBEAT;
while (!Thread.currentThread().isInterrupted()) {
PollItem[] items = {
new PollItem(frontend, ZMQ.Poller.POLLIN),
new PollItem(statesub, ZMQ.Poller.POLLIN),
};
int timeLeft = (int) ((sendStateAt - System.currentTimeMillis()));
if (timeLeft < 0)
timeLeft = 0;
int rc = ZMQ.poll(items, 2, timeLeft);
if (rc == -1)
break; // Context has been shut down
if (items[0].isReadable()) {
// Have a client request
ZMsg msg = ZMsg.recvMsg(frontend);
fsm.event = Event.CLIENT_REQUEST;
if (fsm.stateMachine() == false)
// Answer client by echoing request back
msg.send(frontend);
else
msg.destroy();
}
if (items[1].isReadable()) {
// Have state from our peer, execute as event
String message = statesub.recvStr();
fsm.event = Event.values()[Integer.parseInt(message)];
if (fsm.stateMachine())
break; // Error, so exit
fsm.peerExpiry = System.currentTimeMillis() + 2 * HEARTBEAT;
}
// If we timed out, send state to peer
if (System.currentTimeMillis() >= sendStateAt) {
statepub.send(String.valueOf(fsm.state.ordinal()));
sendStateAt = System.currentTimeMillis() + HEARTBEAT;
}
}
if (Thread.currentThread().isInterrupted())
System.out.printf ("W: interrupted\n");
// Shutdown sockets and context
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/bstarsrv2.java 0000664 0000000 0000000 00000004432 12551504772 0021406 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZLoop;
import org.zeromq.ZLoop.IZLoopHandler;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
// Binary Star server, using bstar reactor
public class bstarsrv2
{
private static IZLoopHandler Echo = new IZLoopHandler()
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
ZMsg msg = ZMsg.recvMsg(item.getSocket());
msg.send(item.getSocket());
return 0;
}
};
public static void main(String[] argv) {
// Arguments can be either of:
// -p primary server, at tcp://localhost:5001
// -b backup server, at tcp://localhost:5002
bstar bs = null;
if (argv.length == 1 && argv[0].equals("-p")) {
System.out.printf("I: Primary active, waiting for backup (passive)\n");
bs = new bstar(true, "tcp://*:5003", "tcp://localhost:5004");
bs.voter ("tcp://*:5001", ZMQ.ROUTER, Echo, null);
}
else
if (argv.length == 1 && argv[0].equals("-b")) {
System.out.printf("I: Backup passive, waiting for primary (active)\n");
bs = new bstar(false, "tcp://*:5004", "tcp://localhost:5003");
bs.voter ("tcp://*:5002", ZMQ.ROUTER, Echo, null);
}
else {
System.out.printf("Usage: bstarsrv { -p | -b }\n");
System.exit(0);
}
bs.start();
bs.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/clone.java 0000664 0000000 0000000 00000032555 12551504772 0020565 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Poller;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
import org.zeromq.ZThread;
import org.zeromq.ZThread.IAttachedRunnable;
import java.util.HashMap;
import java.util.Map;
public class clone
{
private ZContext ctx; // Our context wrapper
private Socket pipe; // Pipe through to clone agent
// .split constructor and destructor
// Here are the constructor and destructor for the clone class. Note that
// we create a context specifically for the pipe that connects our
// frontend to the backend agent:
public clone()
{
ctx = new ZContext();
pipe = ZThread.fork(ctx, new CloneAgent());
}
public void destroy()
{
ctx.destroy();
}
// .split subtree method
// Specify subtree for snapshot and updates, which we must do before
// connecting to a server as the subtree specification is sent as the
// first command to the server. Sends a [SUBTREE][subtree] command to
// the agent:
public void subtree(String subtree)
{
ZMsg msg = new ZMsg();
msg.add("SUBTREE");
msg.add(subtree);
msg.send(pipe);
}
// .split connect method
// Connect to a new server endpoint. We can connect to at most two
// servers. Sends [CONNECT][endpoint][service] to the agent:
public void connect(String address, String service)
{
ZMsg msg = new ZMsg();
msg.add("CONNECT");
msg.add(address);
msg.add(service);
msg.send(pipe);
}
// .split set method
// Set a new value in the shared hashmap. Sends a [SET][key][value][ttl]
// command through to the agent which does the actual work:
public void set(String key, String value, int ttl)
{
ZMsg msg = new ZMsg();
msg.add("SET");
msg.add(key);
msg.add(value);
msg.add(String.format("%d", ttl));
msg.send(pipe);
}
// .split get method
// Look up value in distributed hash table. Sends [GET][key] to the agent and
// waits for a value response. If there is no value available, will eventually
// return NULL:
public String get(String key)
{
ZMsg msg = new ZMsg();
msg.add("GET");
msg.add(key);
msg.send(pipe);
ZMsg reply = ZMsg.recvMsg(pipe);
if (reply != null) {
String value = reply.popString();
reply.destroy();
return value;
}
return null;
}
// .split working with servers
// The backend agent manages a set of servers, which we implement using
// our simple class model:
private static class Server {
private String address; // Server address
private int port; // Server port
private Socket snapshot; // Snapshot socket
private Socket subscriber; // Incoming updates
private long expiry; // When server expires
private int requests; // How many snapshot requests made?
protected Server(ZContext ctx, String address, int port, String subtree)
{
System.out.printf("I: adding server %s:%d...\n", address, port);
this.address = address;
this.port = port;
snapshot = ctx.createSocket(ZMQ.DEALER);
snapshot.connect(String.format("%s:%d", address, port));
subscriber = ctx.createSocket(ZMQ.SUB);
subscriber.connect(String.format("%s:%d", address, port + 1));
subscriber.subscribe(subtree.getBytes(ZMQ.CHARSET));
}
protected void destroy()
{
}
}
// .split backend agent class
// Here is the implementation of the backend agent itself:
// Number of servers to which we will talk to
private final static int SERVER_MAX = 2;
// Server considered dead if silent for this long
private final static int SERVER_TTL = 5000; // msecs
// States we can be in
private final static int STATE_INITIAL = 0; // Before asking server for state
private final static int STATE_SYNCING = 1; // Getting state from server
private final static int STATE_ACTIVE = 2; // Getting new updates from server
private static class Agent {
private ZContext ctx; // Context wrapper
private Socket pipe; // Pipe back to application
private Map kvmap; // Actual key/value table
private String subtree; // Subtree specification, if any
private Server[] server;
private int nbrServers; // 0 to SERVER_MAX
private int state; // Current state
private int curServer; // If active, server 0 or 1
private long sequence; // Last kvmsg processed
private Socket publisher; // Outgoing updates
protected Agent (ZContext ctx, Socket pipe)
{
this.ctx = ctx;
this.pipe = pipe;
kvmap = new HashMap();
subtree = "";
state = STATE_INITIAL;
publisher = ctx.createSocket(ZMQ.PUB);
server = new Server[SERVER_MAX];
}
protected void destroy()
{
for (int serverNbr = 0; serverNbr < nbrServers; serverNbr++)
server[serverNbr].destroy();
}
// .split handling a control message
// Here we handle the different control messages from the frontend;
// SUBTREE, CONNECT, SET, and GET:
private boolean controlMessage()
{
ZMsg msg = ZMsg.recvMsg(pipe);
String command = msg.popString();
if (command == null)
return false; // Interrupted
if (command.equals("SUBTREE")) {
subtree = msg.popString();
}
else
if (command.equals("CONNECT")) {
String address = msg.popString();
String service = msg.popString();
if (nbrServers < SERVER_MAX) {
server [nbrServers++] = new Server(
ctx, address, Integer.parseInt(service), subtree);
// We broadcast updates to all known servers
publisher.connect(String.format("%s:%d",
address, Integer.parseInt(service) + 2));
}
else
System.out.printf("E: too many servers (max. %d)\n", SERVER_MAX);
}
else
// .split set and get commands
// When we set a property, we push the new key-value pair onto
// all our connected servers:
if (command.equals("SET")) {
String key = msg.popString();
String value = msg.popString();
String ttl = msg.popString();
kvmap.put(key, value);
// Send key-value pair on to server
kvmsg kvmsg = new kvmsg(0);
kvmsg.setKey(key);
kvmsg.setUUID();
kvmsg.fmtBody("%s", value);
kvmsg.setProp("ttl", ttl);
kvmsg.send(publisher);
kvmsg.destroy();
}
else
if (command.equals("GET")) {
String key = msg.popString();
String value = kvmap.get(key);
if (value != null)
pipe.send(value);
else
pipe.send("");
}
msg.destroy();
return true;
}
}
private static class CloneAgent implements IAttachedRunnable
{
@Override
public void run(Object[] args, ZContext ctx, Socket pipe)
{
Agent self = new Agent(ctx, pipe);
while (!Thread.currentThread().isInterrupted()) {
PollItem[] pollItems = {
new PollItem(pipe, Poller.POLLIN),
null
};
long pollTimer = -1;
int pollSize = 2;
Server server = self.server[self.curServer];
switch (self.state) {
case STATE_INITIAL:
// In this state we ask the server for a snapshot,
// if we have a server to talk to...
if (self.nbrServers > 0) {
System.out.printf("I: waiting for server at %s:%d...\n",
server.address, server.port);
if (server.requests < 2) {
server.snapshot.sendMore("ICANHAZ?");
server.snapshot.send(self.subtree);
server.requests++;
}
server.expiry = System.currentTimeMillis() + SERVER_TTL;
self.state = STATE_SYNCING;
pollItems[1] = new PollItem(server.snapshot, Poller.POLLIN);
}
else
pollSize = 1;
break;
case STATE_SYNCING:
// In this state we read from snapshot and we expect
// the server to respond, else we fail over.
pollItems[1] = new PollItem(server.snapshot, Poller.POLLIN);
break;
case STATE_ACTIVE:
// In this state we read from subscriber and we expect
// the server to give hugz, else we fail over.
pollItems[1] = new PollItem(server.subscriber, Poller.POLLIN);
break;
}
if (server != null) {
pollTimer = server.expiry - System.currentTimeMillis();
if (pollTimer < 0)
pollTimer = 0;
}
// .split client poll loop
// We're ready to process incoming messages; if nothing at all
// comes from our server within the timeout, that means the
// server is dead:
int rc = ZMQ.poll(pollItems, pollSize, pollTimer);
if (rc == -1)
break; // Context has been shut down
if (pollItems[0].isReadable()) {
if (!self.controlMessage())
break; // Interrupted
}
else
if (pollItems[1].isReadable()) {
kvmsg msg = kvmsg.recv(pollItems[1].getSocket());
if (msg == null)
break; // Interrupted
// Anything from server resets its expiry time
server.expiry = System.currentTimeMillis() + SERVER_TTL;
if (self.state == STATE_SYNCING) {
// Store in snapshot until we're finished
server.requests = 0;
if (msg.getKey().equals("KTHXBAI")) {
self.sequence = msg.getSequence();
self.state = STATE_ACTIVE;
System.out.printf("I: received from %s:%d snapshot=%d\n",
server.address, server.port,
self.sequence);
msg.destroy();
}
}
else
if (self.state == STATE_ACTIVE) {
// Discard out-of-sequence updates, incl. hugz
if (msg.getSequence() > self.sequence) {
self.sequence = msg.getSequence();
System.out.printf("I: received from %s:%d update=%d\n",
server.address, server.port,
self.sequence);
}
else
msg.destroy();
}
}
else {
// Server has died, failover to next
System.out.printf("I: server at %s:%d didn't give hugz\n",
server.address, server.port);
self.curServer = (self.curServer + 1) % self.nbrServers;
self.state = STATE_INITIAL;
}
}
self.destroy();
}
}
}
jeromq-0.3.5/src/test/java/guide/clonecli1.java 0000664 0000000 0000000 00000003355 12551504772 0021332 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Socket;
/**
* Clone client model 1
* @author Danish Shrestha
*
*/
public class clonecli1 {
private static Map kvMap = new HashMap();
private static AtomicLong sequence = new AtomicLong();
public void run() {
ZContext ctx = new ZContext();
Socket subscriber = ctx.createSocket(ZMQ.SUB);
subscriber.connect("tcp://localhost:5556");
subscriber.subscribe(ZMQ.SUBSCRIPTION_ALL);
while (true) {
kvsimple kvMsg = kvsimple.recv(subscriber);
if (kvMsg == null)
break;
clonecli1.kvMap.put(kvMsg.getKey(), kvMsg);
System.out.println("receiving " + kvMsg);
sequence.incrementAndGet();
}
ctx.destroy();
}
public static void main(String[] args) {
new clonecli1().run();
}
}
jeromq-0.3.5/src/test/java/guide/clonecli2.java 0000664 0000000 0000000 00000004647 12551504772 0021340 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
/**
* Clone client Model Two
*
* @author Danish Shrestha
*
*/
public class clonecli2 {
private static Map kvMap = new HashMap();
public void run() {
Context ctx = ZMQ.context(1);
Socket snapshot = ctx.socket(ZMQ.DEALER);
snapshot.connect("tcp://localhost:5556");
Socket subscriber = ctx.socket(ZMQ.SUB);
subscriber.connect("tcp://localhost:5557");
subscriber.subscribe(ZMQ.SUBSCRIPTION_ALL);
// get state snapshot
snapshot.send("ICANHAZ?".getBytes(ZMQ.CHARSET), 0);
long sequence = 0;
while (true) {
kvsimple kvMsg = kvsimple.recv(snapshot);
if (kvMsg == null)
break;
sequence = kvMsg.getSequence();
if ("KTHXBAI".equalsIgnoreCase(kvMsg.getKey())) {
System.out.println("Received snapshot = " + kvMsg.getSequence());
break; // done
}
System.out.println("receiving " + kvMsg.getSequence());
clonecli2.kvMap.put(kvMsg.getKey(), kvMsg);
}
// now apply pending updates, discard out-of-getSequence messages
while (true) {
kvsimple kvMsg = kvsimple.recv(subscriber);
if (kvMsg == null)
break;
if (kvMsg.getSequence() > sequence) {
sequence = kvMsg.getSequence();
System.out.println("receiving " + sequence);
clonecli2.kvMap.put(kvMsg.getKey(), kvMsg);
}
}
}
public static void main(String[] args) {
new clonecli2().run();
}
}
jeromq-0.3.5/src/test/java/guide/clonecli3.java 0000664 0000000 0000000 00000006564 12551504772 0021341 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Poller;
import org.zeromq.ZMQ.Socket;
/**
* Clone client Model Three
* @author Danish Shrestha
*
*/
public class clonecli3 {
private static Map kvMap = new HashMap();
public void run() {
ZContext ctx = new ZContext();
Socket snapshot = ctx.createSocket(ZMQ.DEALER);
snapshot.connect("tcp://localhost:5556");
Socket subscriber = ctx.createSocket(ZMQ.SUB);
subscriber.connect("tcp://localhost:5557");
subscriber.subscribe(ZMQ.SUBSCRIPTION_ALL);
Socket push = ctx.createSocket(ZMQ.PUSH);
push.connect("tcp://localhost:5558");
// get state snapshot
long sequence = 0;
snapshot.send("ICANHAZ?".getBytes(ZMQ.CHARSET), 0);
while (true) {
kvsimple kvMsg = kvsimple.recv(snapshot);
if (kvMsg == null)
break; // Interrupted
sequence = kvMsg.getSequence();
if ("KTHXBAI".equalsIgnoreCase(kvMsg.getKey())) {
System.out.println("Received snapshot = " + kvMsg.getSequence());
break; // done
}
System.out.println("receiving " + kvMsg.getSequence());
clonecli3.kvMap.put(kvMsg.getKey(), kvMsg);
}
Poller poller = new ZMQ.Poller(1);
poller.register(subscriber);
Random random = new Random();
// now apply pending updates, discard out-of-getSequence messages
long alarm = System.currentTimeMillis() + 5000;
while (true) {
int rc = poller.poll(Math.max(0, alarm - System.currentTimeMillis()));
if (rc == -1)
break; // Context has been shut down
if (poller.pollin(0)) {
kvsimple kvMsg = kvsimple.recv(subscriber);
if (kvMsg == null)
break; // Interrupted
if (kvMsg.getSequence() > sequence) {
sequence = kvMsg.getSequence();
System.out.println("receiving " + sequence);
clonecli3.kvMap.put(kvMsg.getKey(), kvMsg);
}
}
if (System.currentTimeMillis() >= alarm) {
int key = random.nextInt(10000);
int body = random.nextInt(1000000);
ByteBuffer b = ByteBuffer.allocate(4);
b.asIntBuffer().put(body);
kvsimple kvUpdateMsg = new kvsimple(key + "", 0, b.array());
kvUpdateMsg.send(push);
alarm = System.currentTimeMillis() + 1000;
}
}
ctx.destroy();
}
public static void main(String[] args) {
new clonecli3().run();
}
}
jeromq-0.3.5/src/test/java/guide/clonecli4.java 0000664 0000000 0000000 00000007020 12551504772 0021326 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Poller;
import org.zeromq.ZMQ.Socket;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
/**
* Clone client Model Four
*
*/
public class clonecli4
{
// This client is identical to clonecli3 except for where we
// handles subtrees.
private final static String SUBTREE = "/client/";
private static Map kvMap = new HashMap();
public void run() {
ZContext ctx = new ZContext();
Socket snapshot = ctx.createSocket(ZMQ.DEALER);
snapshot.connect("tcp://localhost:5556");
Socket subscriber = ctx.createSocket(ZMQ.SUB);
subscriber.connect("tcp://localhost:5557");
subscriber.subscribe(SUBTREE.getBytes(ZMQ.CHARSET));
Socket push = ctx.createSocket(ZMQ.PUSH);
push.connect("tcp://localhost:5558");
// get state snapshot
snapshot.sendMore("ICANHAZ?");
snapshot.send(SUBTREE);
long sequence = 0;
while (true) {
kvsimple kvMsg = kvsimple.recv(snapshot);
if (kvMsg == null)
break; // Interrupted
sequence = kvMsg.getSequence();
if ("KTHXBAI".equalsIgnoreCase(kvMsg.getKey())) {
System.out.println("Received snapshot = " + kvMsg.getSequence());
break; // done
}
System.out.println("receiving " + kvMsg.getSequence());
clonecli4.kvMap.put(kvMsg.getKey(), kvMsg);
}
Poller poller = new Poller(1);
poller.register(subscriber);
Random random = new Random();
// now apply pending updates, discard out-of-getSequence messages
long alarm = System.currentTimeMillis() + 5000;
while (true) {
int rc = poller.poll(Math.max(0, alarm - System.currentTimeMillis()));
if (rc == -1)
break; // Context has been shut down
if (poller.pollin(0)) {
kvsimple kvMsg = kvsimple.recv(subscriber);
if (kvMsg == null)
break; // Interrupted
if (kvMsg.getSequence() > sequence) {
sequence = kvMsg.getSequence();
System.out.println("receiving " + sequence);
clonecli4.kvMap.put(kvMsg.getKey(), kvMsg);
}
}
if (System.currentTimeMillis() >= alarm) {
String key = String.format("%s%d", SUBTREE, random.nextInt(10000));
int body = random.nextInt(1000000);
ByteBuffer b = ByteBuffer.allocate(4);
b.asIntBuffer().put(body);
kvsimple kvUpdateMsg = new kvsimple(key, 0, b.array());
kvUpdateMsg.send(push);
alarm = System.currentTimeMillis() + 1000;
}
}
ctx.destroy();
}
public static void main(String[] args) {
new clonecli4().run();
}
}
jeromq-0.3.5/src/test/java/guide/clonecli5.java 0000664 0000000 0000000 00000007026 12551504772 0021335 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Poller;
import org.zeromq.ZMQ.Socket;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* Clone client Model Five
*
*/
public class clonecli5
{
// This client is identical to clonecli3 except for where we
// handles subtrees.
private final static String SUBTREE = "/client/";
public void run() {
ZContext ctx = new ZContext();
Socket snapshot = ctx.createSocket(ZMQ.DEALER);
snapshot.connect("tcp://localhost:5556");
Socket subscriber = ctx.createSocket(ZMQ.SUB);
subscriber.connect("tcp://localhost:5557");
subscriber.subscribe(SUBTREE.getBytes(ZMQ.CHARSET));
Socket publisher = ctx.createSocket(ZMQ.PUSH);
publisher.connect("tcp://localhost:5558");
Map kvMap = new HashMap();
// get state snapshot
snapshot.sendMore("ICANHAZ?");
snapshot.send(SUBTREE);
long sequence = 0;
while (true) {
kvmsg kvMsg = kvmsg.recv(snapshot);
if (kvMsg == null)
break; // Interrupted
sequence = kvMsg.getSequence();
if ("KTHXBAI".equalsIgnoreCase(kvMsg.getKey())) {
System.out.println("Received snapshot = " + kvMsg.getSequence());
kvMsg.destroy();
break; // done
}
System.out.println("receiving " + kvMsg.getSequence());
kvMsg.store(kvMap);
}
Poller poller = new Poller(1);
poller.register(subscriber);
Random random = new Random();
// now apply pending updates, discard out-of-getSequence messages
long alarm = System.currentTimeMillis() + 5000;
while (true) {
int rc = poller.poll(Math.max(0, alarm - System.currentTimeMillis()));
if (rc == -1)
break; // Context has been shut down
if (poller.pollin(0)) {
kvmsg kvMsg = kvmsg.recv(subscriber);
if (kvMsg == null)
break; // Interrupted
if (kvMsg.getSequence() > sequence) {
sequence = kvMsg.getSequence();
System.out.println("receiving " + sequence);
kvMsg.store(kvMap);
} else
kvMsg.destroy();
}
if (System.currentTimeMillis() >= alarm) {
kvmsg kvMsg = new kvmsg(0);
kvMsg.fmtKey("%s%d", SUBTREE, random.nextInt(10000));
kvMsg.fmtBody("%d", random.nextInt(1000000));
kvMsg.setProp("ttl", "%d", random.nextInt(30));
kvMsg.send(publisher);
kvMsg.destroy();
alarm = System.currentTimeMillis() + 1000;
}
}
ctx.destroy();
}
public static void main(String[] args) {
new clonecli5().run();
}
}
jeromq-0.3.5/src/test/java/guide/clonecli6.java 0000664 0000000 0000000 00000003734 12551504772 0021340 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
/**
* Clone client model 6
*/
public class clonecli6
{
private final static String SUBTREE = "/client/";
public void run() {
// Create distributed hash instance
clone clone = new clone();
Random rand = new Random(System.nanoTime());
// Specify configuration
clone.subtree(SUBTREE);
clone.connect("tcp://localhost", "5556");
clone.connect("tcp://localhost", "5566");
// Set random tuples into the distributed hash
while (!Thread.currentThread().isInterrupted()) {
// Set random value, check it was stored
String key = String.format("%s%d", SUBTREE, rand.nextInt(10000));
String value= String.format("%d", rand.nextInt(1000000));
clone.set(key, value, rand.nextInt(30));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
clone.destroy();
}
public static void main(String[] args) {
new clonecli6().run();
}
}
jeromq-0.3.5/src/test/java/guide/clonesrv1.java 0000664 0000000 0000000 00000003503 12551504772 0021370 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.nio.ByteBuffer;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
/**
*
* Clone server model 1
* @author Danish Shrestha
*
*/
public class clonesrv1 {
private static AtomicLong sequence = new AtomicLong();
public void run() {
Context ctx = ZMQ.context(1);
Socket publisher = ctx.socket(ZMQ.PUB);
publisher.bind("tcp://*:5556");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
Random random = new Random();
while (true) {
long currentSequenceNumber = sequence.incrementAndGet();
int key = random.nextInt(10000);
int body = random.nextInt(1000000);
ByteBuffer b = ByteBuffer.allocate(4);
b.asIntBuffer().put(body);
kvsimple kvMsg = new kvsimple(key + "", currentSequenceNumber,
b.array());
kvMsg.send(publisher);
System.out.println("sending " + kvMsg);
}
}
public static void main(String[] args) {
new clonesrv1().run();
}
}
jeromq-0.3.5/src/test/java/guide/clonesrv2.java 0000664 0000000 0000000 00000010775 12551504772 0021402 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicLong;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Poller;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZThread;
import org.zeromq.ZThread.IAttachedRunnable;
/**
* Clone server Model Two
*
* @author Danish Shrestha
*
*/
public class clonesrv2 {
public void run() {
ZContext ctx = new ZContext();
Socket publisher = ctx.createSocket(ZMQ.PUB);
publisher.bind("tcp://*:5557");
Socket updates = ZThread.fork(ctx, new StateManager());
Random random = new Random();
long sequence = 0;
while (!Thread.currentThread().isInterrupted()) {
long currentSequenceNumber = ++sequence;
int key = random.nextInt(10000);
int body = random.nextInt(1000000);
ByteBuffer b = ByteBuffer.allocate(4);
b.asIntBuffer().put(body);
kvsimple kvMsg = new kvsimple(key + "", currentSequenceNumber, b.array());
kvMsg.send(publisher);
kvMsg.send(updates); // send a message to State Manager thead.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
System.out.printf(" Interrupted\n%d messages out\n", sequence);
ctx.destroy();
}
public static class StateManager implements IAttachedRunnable {
private static Map kvMap = new LinkedHashMap();
@Override
public void run(Object[] args, ZContext ctx, Socket pipe) {
pipe.send("READY"); // optional
Socket snapshot = ctx.createSocket(ZMQ.ROUTER);
snapshot.bind("tcp://*:5556");
Poller poller = new ZMQ.Poller(2);
poller.register(pipe, ZMQ.Poller.POLLIN);
poller.register(snapshot, ZMQ.Poller.POLLIN);
long stateSequence = 0;
while (!Thread.currentThread().isInterrupted()) {
if (poller.poll() < 0)
break; // Context has been shut down
// apply state updates from main thread
if (poller.pollin(0)) {
kvsimple kvMsg = kvsimple.recv(pipe);
if (kvMsg == null)
break;
StateManager.kvMap.put(kvMsg.getKey(), kvMsg);
stateSequence = kvMsg.getSequence();
}
// execute state snapshot request
if (poller.pollin(1)) {
byte[] identity = snapshot.recv(0);
if (identity == null)
break;
String request = new String(snapshot.recv(0), ZMQ.CHARSET);
if (!request.equals("ICANHAZ?")) {
System.out.println("E: bad request, aborting");
break;
}
Iterator> iter = kvMap.entrySet().iterator();
while (iter.hasNext()) {
Entry entry = iter.next();
kvsimple msg = entry.getValue();
System.out.println("Sending message " + entry.getValue().getSequence());
this.sendMessage(msg, identity, snapshot);
}
// now send end message with getSequence number
System.out.println("Sending state snapshot = " + stateSequence);
snapshot.send(identity, ZMQ.SNDMORE);
kvsimple message = new kvsimple("KTHXBAI", stateSequence, ZMQ.MESSAGE_SEPARATOR);
message.send(snapshot);
}
}
}
private void sendMessage(kvsimple msg, byte[] identity, Socket snapshot) {
snapshot.send(identity, ZMQ.SNDMORE);
msg.send(snapshot);
}
}
public static void main(String[] args) {
new clonesrv2().run();
}
}
jeromq-0.3.5/src/test/java/guide/clonesrv3.java 0000664 0000000 0000000 00000007475 12551504772 0021406 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Poller;
import org.zeromq.ZMQ.Socket;
/**
* Clone server Model Three
* @author Danish Shrestha
*
*/
public class clonesrv3 {
private static Map kvMap = new LinkedHashMap();
public void run() {
ZContext ctx = new ZContext();
Socket snapshot = ctx.createSocket(ZMQ.ROUTER);
snapshot.bind("tcp://*:5556");
Socket publisher = ctx.createSocket(ZMQ.PUB);
publisher.bind("tcp://*:5557");
Socket collector = ctx.createSocket(ZMQ.PULL);
collector.bind("tcp://*:5558");
Poller poller = new Poller(2);
poller.register(collector, Poller.POLLIN);
poller.register(snapshot, Poller.POLLIN);
long sequence = 0;
while (!Thread.currentThread().isInterrupted()) {
if (poller.poll(1000) < 0)
break; // Context has been shut down
// apply state updates from main thread
if (poller.pollin(0)) {
kvsimple kvMsg = kvsimple.recv(collector);
if (kvMsg == null) // Interrupted
break;
kvMsg.setSequence(++sequence);
kvMsg.send(publisher);
clonesrv3.kvMap.put(kvMsg.getKey(), kvMsg);
System.out.printf("I: publishing update %5d\n", sequence);
}
// execute state snapshot request
if (poller.pollin(1)) {
byte[] identity = snapshot.recv(0);
if (identity == null)
break; // Interrupted
String request = snapshot.recvStr();
if (!request.equals("ICANHAZ?")) {
System.out.println("E: bad request, aborting");
break;
}
Iterator> iter = kvMap.entrySet().iterator();
while (iter.hasNext()) {
Entry entry = iter.next();
kvsimple msg = entry.getValue();
System.out.println("Sending message " + entry.getValue().getSequence());
this.sendMessage(msg, identity, snapshot);
}
// now send end message with getSequence number
System.out.println("Sending state snapshot = " + sequence);
snapshot.send(identity, ZMQ.SNDMORE);
kvsimple message = new kvsimple("KTHXBAI", sequence, ZMQ.SUBSCRIPTION_ALL);
message.send(snapshot);
}
}
System.out.printf (" Interrupted\n%d messages handled\n", sequence);
ctx.destroy();
}
private void sendMessage(kvsimple msg, byte[] identity, Socket snapshot) {
snapshot.send(identity, ZMQ.SNDMORE);
msg.send(snapshot);
}
public static void main(String[] args) {
new clonesrv3().run();
}
}
jeromq-0.3.5/src/test/java/guide/clonesrv4.java 0000664 0000000 0000000 00000007731 12551504772 0021402 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Poller;
import org.zeromq.ZMQ.Socket;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
/**
* Clone server Model Four
*/
public class clonesrv4
{
private static Map kvMap = new LinkedHashMap();
public void run() {
ZContext ctx = new ZContext();
Socket snapshot = ctx.createSocket(ZMQ.ROUTER);
snapshot.bind("tcp://*:5556");
Socket publisher = ctx.createSocket(ZMQ.PUB);
publisher.bind("tcp://*:5557");
Socket collector = ctx.createSocket(ZMQ.PULL);
collector.bind("tcp://*:5558");
Poller poller = new Poller(2);
poller.register(collector, Poller.POLLIN);
poller.register(snapshot, Poller.POLLIN);
long sequence = 0;
while (!Thread.currentThread().isInterrupted()) {
if (poller.poll(1000) < 0)
break; // Context has been shut down
// apply state updates from main thread
if (poller.pollin(0)) {
kvsimple kvMsg = kvsimple.recv(collector);
if (kvMsg == null) // Interrupted
break;
kvMsg.setSequence(++sequence);
kvMsg.send(publisher);
clonesrv4.kvMap.put(kvMsg.getKey(), kvMsg);
System.out.printf("I: publishing update %5d\n", sequence);
}
// execute state snapshot request
if (poller.pollin(1)) {
byte[] identity = snapshot.recv(0);
if (identity == null)
break; // Interrupted
// .until
// Request is in second frame of message
String request = snapshot.recvStr();
if (!request.equals("ICANHAZ?")) {
System.out.println("E: bad request, aborting");
break;
}
String subtree = snapshot.recvStr();
Iterator> iter = kvMap.entrySet().iterator();
while (iter.hasNext()) {
Entry entry = iter.next();
kvsimple msg = entry.getValue();
System.out.println("Sending message " + entry.getValue().getSequence());
this.sendMessage(msg, identity, subtree, snapshot);
}
// now send end message with getSequence number
System.out.println("Sending state snapshot = " + sequence);
snapshot.send(identity, ZMQ.SNDMORE);
kvsimple message = new kvsimple("KTHXBAI", sequence, ZMQ.SUBSCRIPTION_ALL);
message.send(snapshot);
}
}
System.out.printf (" Interrupted\n%d messages handled\n", sequence);
ctx.destroy();
}
private void sendMessage(kvsimple msg, byte[] identity, String subtree, Socket snapshot) {
snapshot.send(identity, ZMQ.SNDMORE);
snapshot.send(subtree, ZMQ.SNDMORE);
msg.send(snapshot);
}
public static void main(String[] args) {
new clonesrv4().run();
}
}
jeromq-0.3.5/src/test/java/guide/clonesrv5.java 0000664 0000000 0000000 00000015415 12551504772 0021401 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZLoop;
import org.zeromq.ZLoop.IZLoopHandler;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
// Clone server - Model Five
public class clonesrv5
{
private ZContext ctx; // Context wrapper
private Map kvmap; // Key-value store
private ZLoop loop; // zloop reactor
private int port; // Main port we're working on
private long sequence; // How many updates we're at
private Socket snapshot; // Handle snapshot requests
private Socket publisher; // Publish updates to clients
private Socket collector; // Collect updates from clients
// .split snapshot handler
// This is the reactor handler for the snapshot socket; it accepts
// just the ICANHAZ? request and replies with a state snapshot ending
// with a KTHXBAI message:
private static class Snapshots implements IZLoopHandler
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
clonesrv5 srv = (clonesrv5) arg;
Socket socket = item.getSocket();
byte[] identity = socket.recv();
if (identity != null) {
// Request is in second frame of message
String request = socket.recvStr();
String subtree = null;
if (request.equals("ICANHAZ?")) {
subtree = socket.recvStr();
}
else
System.out.printf("E: bad request, aborting\n");
if (subtree != null) {
// Send state socket to client
for (Entry entry: srv.kvmap.entrySet()) {
sendSingle(entry.getValue(), identity, subtree, socket);
}
// Now send END message with getSequence number
System.out.printf("I: sending shapshot=%d\n", srv.sequence);
socket.send(identity, ZMQ.SNDMORE);
kvmsg kvmsg = new kvmsg(srv.sequence);
kvmsg.setKey("KTHXBAI");
kvmsg.setBody(subtree.getBytes(ZMQ.CHARSET));
kvmsg.send(socket);
kvmsg.destroy();
}
}
return 0;
}
}
// .split collect updates
// We store each update with a new getSequence number, and if necessary, a
// time-to-live. We publish updates immediately on our publisher socket:
private static class Collector implements IZLoopHandler
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
clonesrv5 srv = (clonesrv5) arg;
Socket socket = item.getSocket();
kvmsg msg = kvmsg.recv(socket);
if (msg != null) {
msg.setSequence(++srv.sequence);
msg.send(srv.publisher);
int ttl = Integer.parseInt(msg.getProp("ttl"));
if (ttl > 0)
msg.setProp("ttl",
"%d", System.currentTimeMillis() + ttl * 1000);
msg.store(srv.kvmap);
System.out.printf("I: publishing update=%d\n", srv.sequence);
}
return 0;
}
}
private static class FlushTTL implements IZLoopHandler
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
clonesrv5 srv = (clonesrv5) arg;
if (srv.kvmap != null) {
for (kvmsg msg: new ArrayList(srv.kvmap.values())) {
srv.flushSingle(msg);
}
}
return 0;
}
}
public clonesrv5 ()
{
port = 5556;
ctx = new ZContext();
kvmap = new HashMap();
loop = new ZLoop();
loop.verbose(false);
// Set up our clone server sockets
snapshot = ctx.createSocket(ZMQ.ROUTER);
snapshot.bind(String.format("tcp://*:%d", port));
publisher = ctx.createSocket(ZMQ.PUB);
publisher.bind(String.format("tcp://*:%d", port + 1));
collector = ctx.createSocket(ZMQ.PULL);
collector.bind(String.format("tcp://*:%d", port + 2));
}
public void run()
{
// Register our handlers with reactor
PollItem poller = new PollItem(snapshot, ZMQ.Poller.POLLIN);
loop.addPoller(poller, new Snapshots(), this);
poller = new PollItem(collector, ZMQ.Poller.POLLIN);
loop.addPoller(poller, new Collector(), this);
loop.addTimer(1000, 0, new FlushTTL(), this);
loop.start();
loop.destroy();
ctx.destroy();
}
// We call this function for each getKey-value pair in our hash table
private static void sendSingle(kvmsg msg, byte[] identity, String subtree, Socket socket)
{
if (msg.getKey().startsWith(subtree)) {
socket.send (identity, // Choose recipient
ZMQ.SNDMORE);
msg.send(socket);
}
}
// .split flush ephemeral values
// At regular intervals, we flush ephemeral values that have expired. This
// could be slow on very large data sets:
// If getKey-value pair has expired, delete it and publish the
// fact to listening clients.
private void flushSingle(kvmsg msg)
{
long ttl = Long.parseLong(msg.getProp("ttl"));
if (ttl > 0 && System.currentTimeMillis() >= ttl) {
msg.setSequence(++sequence);
msg.setBody(ZMQ.MESSAGE_SEPARATOR);
msg.send(publisher);
msg.store(kvmap);
System.out.printf("I: publishing delete=%d\n", sequence);
}
}
public static void main(String[] args)
{
clonesrv5 srv = new clonesrv5();
srv.run();
}
}
jeromq-0.3.5/src/test/java/guide/clonesrv6.java 0000664 0000000 0000000 00000035714 12551504772 0021406 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZLoop;
import org.zeromq.ZLoop.IZLoopHandler;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
// Clone server - Model Six
public class clonesrv6
{
private ZContext ctx; // Context wrapper
private Map kvmap; // Key-value store
private bstar bStar; // Bstar reactor core
private long sequence; // How many updates we're at
private int port; // Main port we're working on
private int peer; // Main port of our peer
private Socket publisher; // Publish updates and hugz
private Socket collector; // Collect updates from clients
private Socket subscriber; // Get updates from peer
private List pending; // Pending updates from clients
private boolean primary; // TRUE if we're primary
private boolean active; // TRUE if we're active
private boolean passive; // TRUE if we're passive
private static class Snapshots implements IZLoopHandler
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
clonesrv6 srv = (clonesrv6) arg;
Socket socket = item.getSocket();
byte[] identity = socket.recv();
if (identity != null) {
// Request is in second frame of message
String request = socket.recvStr();
String subtree = null;
if (request.equals("ICANHAZ?")) {
subtree = socket.recvStr();
}
else
System.out.printf("E: bad request, aborting\n");
if (subtree != null) {
// Send state socket to client
for (Entry entry: srv.kvmap.entrySet()) {
sendSingle(entry.getValue(), identity, subtree, socket);
}
// Now send END message with getSequence number
System.out.printf("I: sending shapshot=%d\n", srv.sequence);
socket.send(identity, ZMQ.SNDMORE);
kvmsg kvmsg = new kvmsg(srv.sequence);
kvmsg.setKey("KTHXBAI");
kvmsg.setBody(subtree.getBytes(ZMQ.CHARSET));
kvmsg.send(socket);
kvmsg.destroy();
}
}
return 0;
}
}
private static class Collector implements IZLoopHandler
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
clonesrv6 srv = (clonesrv6) arg;
Socket socket = item.getSocket();
kvmsg msg = kvmsg.recv(socket);
if (msg != null) {
if(srv.active){
msg.setSequence(++srv.sequence);
msg.send(srv.publisher);
int ttl = Integer.parseInt(msg.getProp("ttl"));
if (ttl > 0)
msg.setProp("ttl",
"%d", System.currentTimeMillis() + ttl * 1000);
msg.store(srv.kvmap);
System.out.printf("I: publishing update=%d\n", srv.sequence);
} else {
// If we already got message from active, drop it, else
// hold on pending list
if (srv.wasPending(msg))
msg.destroy();
else
srv.pending.add(msg);
}
}
return 0;
}
}
// .split heartbeating
// We send a HUGZ message once a second to all subscribers so that they
// can detect if our server dies. They'll then switch over to the backup
// server, which will become active:
private static class SendHugz implements IZLoopHandler
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
clonesrv6 srv = (clonesrv6) arg;
kvmsg msg = new kvmsg(srv.sequence);
msg.setKey("HUGZ");
msg.setBody(ZMQ.MESSAGE_SEPARATOR);
msg.send(srv.publisher);
msg.destroy();
return 0;
}
}
private static class FlushTTL implements IZLoopHandler
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
clonesrv6 srv = (clonesrv6) arg;
if (srv.kvmap != null) {
for (kvmsg msg: new ArrayList(srv.kvmap.values())) {
srv.flushSingle(msg);
}
}
return 0;
}
}
// .split handling state changes
// When we switch from passive to active, we apply our pending list so that
// our kvmap is up-to-date. When we switch to passive, we wipe our kvmap
// and grab a new snapshot from the active server:
private static class NewActive implements IZLoopHandler
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
clonesrv6 srv = (clonesrv6) arg;
srv.active = true;
srv.passive = false;
// Stop subscribing to updates
PollItem poller = new PollItem(srv.subscriber, ZMQ.Poller.POLLIN);
srv.bStar.zloop().removePoller(poller);
// Apply pending list to own hash table
for (kvmsg msg: srv.pending) {
msg.setSequence(++srv.sequence);
msg.send(srv.publisher);
msg.store(srv.kvmap);
System.out.printf("I: publishing pending=%d\n", srv.sequence);
}
return 0;
}
}
private static class NewPassive implements IZLoopHandler
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
clonesrv6 srv = (clonesrv6) arg;
if (srv.kvmap != null) {
for (kvmsg msg: srv.kvmap.values())
msg.destroy();
}
srv.active = false;
srv.passive = true;
// Start subscribing to updates
PollItem poller = new PollItem(srv.subscriber, ZMQ.Poller.POLLIN);
srv.bStar.zloop().addPoller(poller, new Subscriber(), srv);
return 0;
}
}
// .split subscriber handler
// When we get an update, we create a new kvmap if necessary, and then
// add our update to our kvmap. We're always passive in this case:
private static class Subscriber implements IZLoopHandler
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
clonesrv6 srv = (clonesrv6) arg;
Socket socket = item.getSocket();
// Get state snapshot if necessary
if (srv.kvmap == null) {
srv.kvmap = new HashMap();
Socket snapshot = srv.ctx.createSocket(ZMQ.DEALER);
snapshot.connect(String.format("tcp://localhost:%d", srv.peer));
System.out.printf("I: asking for snapshot from: tcp://localhost:%d\n",
srv.peer);
snapshot.sendMore("ICANHAZ?");
snapshot.send(""); // blank subtree to get all
while (true) {
kvmsg msg = kvmsg.recv(snapshot);
if (msg == null)
break; // Interrupted
if (msg.getKey().equals("KTHXBAI")) {
srv.sequence = msg.getSequence();
msg.destroy();
break; // Done
}
msg.store(srv.kvmap);
}
System.out.printf("I: received snapshot=%d\n",srv.sequence);
srv.ctx.destroySocket(snapshot);
}
// Find and remove update off pending list
kvmsg msg = kvmsg.recv(item.getSocket());
if (msg == null)
return 0;
if (!msg.getKey().equals("HUGZ")) {
if (!srv.wasPending(msg)) {
// If active update came before client update, flip it
// around, store active update (with sequence) on pending
// list and use to clear client update when it comes later
srv.pending.add(msg.dup());
}
// If update is more recent than our kvmap, apply it
if (msg.getSequence() > srv.sequence) {
srv.sequence = msg.getSequence();
msg.store(srv.kvmap);
System.out.printf("I: received update=%d\n",srv.sequence);
}
}
msg.destroy();
return 0;
}
}
public clonesrv6(boolean primary)
{
if (primary) {
bStar = new bstar(true, "tcp://*:5003",
"tcp://localhost:5004");
bStar.voter("tcp://*:5556",
ZMQ.ROUTER, new Snapshots(), this);
port = 5556;
peer = 5566;
this.primary = true;
} else {
bStar = new bstar(false, "tcp://*:5004",
"tcp://localhost:5003");
bStar.voter("tcp://*:5566",
ZMQ.ROUTER, new Snapshots(), this);
port = 5566;
peer = 5556;
this.primary = false;
}
// Primary server will become first active
if (primary)
kvmap = new HashMap();
ctx = new ZContext();
pending = new ArrayList();
bStar.setVerbose(true);
// Set up our clone server sockets
publisher = ctx.createSocket(ZMQ.PUB);
collector = ctx.createSocket(ZMQ.SUB);
collector.subscribe(ZMQ.SUBSCRIPTION_ALL);
publisher.bind(String.format("tcp://*:%d", port + 1));
collector.bind(String.format("tcp://*:%d", port+2));
// Set up our own clone client interface to peer
subscriber = ctx.createSocket(ZMQ.SUB);
subscriber.subscribe(ZMQ.SUBSCRIPTION_ALL);
subscriber.connect(String.format("tcp://localhost:%d", peer + 1));
}
// .split main task body
// After we've setup our sockets, we register our binary star
// event handlers, and then start the bstar reactor. This finishes
// when the user presses Ctrl-C or when the process receives a SIGINT
// interrupt:
public void run()
{
// Register state change handlers
bStar.newActive(new NewActive(), this);
bStar.newPassive(new NewPassive(), this);
// Register our other handlers with the bstar reactor
PollItem poller = new PollItem(collector, ZMQ.Poller.POLLIN);
bStar.zloop().addPoller(poller, new Collector(), this);
bStar.zloop().addTimer(1000, 0, new FlushTTL(), this);
bStar.zloop().addTimer(1000, 0, new SendHugz(), this);
// Start the bstar reactor
bStar.start();
// Interrupted, so shut down
for (kvmsg value: pending)
value.destroy();
bStar.destroy();
for (kvmsg value: kvmap.values())
value.destroy();
ctx.destroy();
}
// Send one state snapshot key-value pair to a socket
// Hash item data is our kvmsg object, ready to send
private static void sendSingle(kvmsg msg, byte[] identity, String subtree, Socket socket)
{
if (msg.getKey().startsWith(subtree)) {
socket.send (identity, // Choose recipient
ZMQ.SNDMORE);
msg.send(socket);
}
}
// The collector is more complex than in the clonesrv5 example because the
// way it processes updates depends on whether we're active or passive.
// The active applies them immediately to its kvmap, whereas the passive
// queues them as pending:
// If message was already on pending list, remove it and return TRUE,
// else return FALSE.
boolean wasPending (kvmsg msg)
{
Iterator it = pending.iterator();
while (it.hasNext()) {
if(java.util.Arrays.equals(msg.UUID(), it.next().UUID())){
it.remove();
return true;
}
}
return false;
}
// We purge ephemeral values using exactly the same code as in
// the previous clonesrv5 example.
// .skip
// If key-value pair has expired, delete it and publish the
// fact to listening clients.
private void flushSingle(kvmsg msg)
{
long ttl = Long.parseLong(msg.getProp("ttl"));
if (ttl > 0 && System.currentTimeMillis() >= ttl) {
msg.setSequence(++sequence);
msg.setBody(ZMQ.MESSAGE_SEPARATOR);
msg.send(publisher);
msg.store(kvmap);
System.out.printf("I: publishing delete=%d\n", sequence);
}
}
// .split main task setup
// The main task parses the command line to decide whether to start
// as a primary or backup server. We're using the Binary Star pattern
// for reliability. This interconnects the two servers so they can
// agree on which one is primary and which one is backup. To allow the
// two servers to run on the same box, we use different ports for
// primary and backup. Ports 5003/5004 are used to interconnect the
// servers. Ports 5556/5566 are used to receive voting events (snapshot
// requests in the clone pattern). Ports 5557/5567 are used by the
// publisher, and ports 5558/5568 are used by the collector:
public static void main(String[] args)
{
clonesrv6 srv = null;
if (args.length == 1 && "-p".equals(args[0])) {
srv = new clonesrv6(true);
} else if (args.length == 1 && "-b".equals(args[0])) {
srv = new clonesrv6(false);
} else {
System.out.printf("Usage: clonesrv4 { -p | -b }\n");
System.exit(0);
}
srv.run();
}
}
jeromq-0.3.5/src/test/java/guide/espresso.java 0000664 0000000 0000000 00000010546 12551504772 0021324 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZThread;
import org.zeromq.ZThread.IAttachedRunnable;
import java.util.Random;
// Espresso Pattern
// This shows how to capture data using a pub-sub proxy
public class espresso
{
// The subscriber thread requests messages starting with
// A and B, then reads and counts incoming messages.
private static class Subscriber implements IAttachedRunnable
{
@Override
public void run(Object[] args, ZContext ctx, Socket pipe)
{
// Subscribe to "A" and "B"
Socket subscriber = ctx.createSocket(ZMQ.SUB);
subscriber.connect("tcp://localhost:6001");
subscriber.subscribe("A".getBytes(ZMQ.CHARSET));
subscriber.subscribe("B".getBytes(ZMQ.CHARSET));
int count = 0;
while (count < 5) {
String string = subscriber.recvStr();
if (string == null)
break; // Interrupted
count++;
}
ctx.destroySocket(subscriber);
}
}
// .split publisher thread
// The publisher sends random messages starting with A-J:
private static class Publisher implements IAttachedRunnable
{
@Override
public void run(Object[] args, ZContext ctx, Socket pipe)
{
Socket publisher = ctx.createSocket(ZMQ.PUB);
publisher.bind("tcp://*:6000");
Random rand = new Random(System.currentTimeMillis());
while (!Thread.currentThread().isInterrupted()) {
String string = String.format("%c-%05d", 'A' + rand.nextInt(10), rand.nextInt(100000));
if (!publisher.send(string))
break; // Interrupted
try {
Thread.sleep(100); // Wait for 1/10th second
} catch (InterruptedException e) {
}
}
ctx.destroySocket(publisher);
}
}
// .split listener thread
// The listener receives all messages flowing through the proxy, on its
// pipe. In CZMQ, the pipe is a pair of ZMQ_PAIR sockets that connect
// attached child threads. In other languages your mileage may vary:
private static class Listener implements IAttachedRunnable
{
@Override
public void run(Object[] args, ZContext ctx, Socket pipe)
{
// Print everything that arrives on pipe
while (true) {
ZFrame frame = ZFrame.recvFrame(pipe);
if (frame == null)
break; // Interrupted
frame.print(null);
frame.destroy();
}
}
}
// .split main thread
// The main task starts the subscriber and publisher, and then sets
// itself up as a listening proxy. The listener runs as a child thread:
public static void main(String[] argv)
{
// Start child threads
ZContext ctx = new ZContext();
ZThread.fork(ctx, new Publisher());
ZThread.fork(ctx, new Subscriber());
Socket subscriber = ctx.createSocket(ZMQ.XSUB);
subscriber.connect("tcp://localhost:6000");
Socket publisher = ctx.createSocket(ZMQ.XPUB);
publisher.bind("tcp://*:6001");
Socket listener = ZThread.fork(ctx, new Listener());
ZMQ.proxy (subscriber, publisher, listener);
System.out.println(" interrupted");
// Tell attached threads to exit
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/flcliapi.java 0000664 0000000 0000000 00000027316 12551504772 0021247 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
import org.zeromq.ZThread;
import org.zeromq.ZThread.IAttachedRunnable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
// flcliapi class - Freelance Pattern agent class
// Implements the Freelance Protocol at http://rfc.zeromq.org/spec:10
public class flcliapi
{
// If not a single service replies within this time, give up
private static final int GLOBAL_TIMEOUT = 2500;
// PING interval for servers we think are alive
private static final int PING_INTERVAL = 2000; // msecs
// Server considered dead if silent for this long
private static final int SERVER_TTL = 6000; // msecs
// .split API structure
// This API works in two halves, a common pattern for APIs that need to
// run in the background. One half is an frontend object our application
// creates and works with; the other half is a backend "agent" that runs
// in a background thread. The frontend talks to the backend over an
// inproc pipe socket:
// Structure of our frontend class
private ZContext ctx; // Our context wrapper
private Socket pipe; // Pipe through to flcliapi agent
public flcliapi()
{
ctx = new ZContext();
FreelanceAgent agent = new FreelanceAgent();
pipe = ZThread.fork(ctx, agent);
}
public void destroy()
{
ctx.destroy();
}
// .split connect method
// To implement the connect method, the frontend object sends a multipart
// message to the backend agent. The first part is a string "CONNECT", and
// the second part is the endpoint. It waits 100msec for the connection to
// come up, which isn't pretty, but saves us from sending all requests to a
// single server, at startup time:
public void connect(String endpoint)
{
ZMsg msg = new ZMsg();
msg.add("CONNECT");
msg.add(endpoint);
msg.send(pipe);
try {
Thread.sleep(100); // Allow connection to come up
} catch (InterruptedException e) {
}
}
// .split request method
// To implement the request method, the frontend object sends a message
// to the backend, specifying a command "REQUEST" and the request message:
public ZMsg request(ZMsg request)
{
request.push("REQUEST");
request.send(pipe);
ZMsg reply = ZMsg.recvMsg(pipe);
if (reply != null) {
String status = reply.popString();
if (status.equals("FAILED"))
reply.destroy();
}
return reply;
}
// .split backend agent
// Here we see the backend agent. It runs as an attached thread, talking
// to its parent over a pipe socket. It is a fairly complex piece of work
// so we'll break it down into pieces. First, the agent manages a set of
// servers, using our familiar class approach:
// Simple class for one server we talk to
private static class Server
{
private String endpoint; // Server identity/endpoint
private boolean alive; // 1 if known to be alive
private long pingAt; // Next ping at this time
private long expires; // Expires at this time
protected Server(String endpoint)
{
this.endpoint = endpoint;
alive = false;
pingAt = System.currentTimeMillis() + PING_INTERVAL;
expires = System.currentTimeMillis() + SERVER_TTL;
}
protected void destroy()
{
}
private void ping(Socket socket)
{
if (System.currentTimeMillis() >= pingAt) {
ZMsg ping = new ZMsg();
ping.add(endpoint);
ping.add("PING");
ping.send(socket);
pingAt = System.currentTimeMillis() + PING_INTERVAL;
}
}
private long tickless(long tickless)
{
if (tickless > pingAt)
return pingAt;
return -1;
}
}
// .split backend agent class
// We build the agent as a class that's capable of processing messages
// coming in from its various sockets:
// Simple class for one background agent
private static class Agent
{
private ZContext ctx; // Own context
private Socket pipe; // Socket to talk back to application
private Socket router; // Socket to talk to servers
private Map servers; // Servers we've connected to
private List actives; // Servers we know are alive
private int sequence; // Number of requests ever sent
private ZMsg request; // Current request if any
private ZMsg reply; // Current reply if any
private long expires; // Timeout for request/reply
protected Agent(ZContext ctx, Socket pipe)
{
this.ctx = ctx;
this.pipe = pipe;
router = ctx.createSocket(ZMQ.ROUTER);
servers = new HashMap();
actives = new ArrayList();
}
protected void destroy()
{
for(Server server: servers.values())
server.destroy();
}
// .split control messages
// This method processes one message from our frontend class
// (it's going to be CONNECT or REQUEST):
// Callback when we remove server from agent 'servers' hash table
private void controlMessage()
{
ZMsg msg = ZMsg.recvMsg(pipe);
String command = msg.popString();
if (command.equals("CONNECT")) {
String endpoint = msg.popString();
System.out.printf("I: connecting to %s...\n", endpoint);
router.connect(endpoint);
Server server = new Server(endpoint);
servers.put(endpoint, server);
actives.add(server);
server.pingAt = System.currentTimeMillis() + PING_INTERVAL;
server.expires = System.currentTimeMillis() + SERVER_TTL;
}
else
if (command.equals("REQUEST")) {
assert (request == null); // Strict request-reply cycle
// Prefix request with getSequence number and empty envelope
String sequenceText = String.format("%d", ++sequence);
msg.push(sequenceText);
// Take ownership of request message
request = msg;
msg = null;
// Request expires after global timeout
expires = System.currentTimeMillis() + GLOBAL_TIMEOUT;
}
if (msg != null)
msg.destroy();
}
// .split router messages
// This method processes one message from a connected
// server:
private void routerMessage()
{
ZMsg reply = ZMsg.recvMsg(router);
// Frame 0 is server that replied
String endpoint = reply.popString();
Server server = servers.get(endpoint);
assert (server != null);
if (!server.alive) {
actives.add(server);
server.alive = true;
}
server.pingAt = System.currentTimeMillis() + PING_INTERVAL;
server.expires = System.currentTimeMillis() + SERVER_TTL;
// Frame 1 may be getSequence number for reply
String sequenceStr = reply.popString();
if (Integer.parseInt(sequenceStr) == sequence) {
reply.push("OK");
reply.send(pipe);
request.destroy();
request = null;
}
else
reply.destroy();
}
}
// .split backend agent implementation
// Finally, here's the agent task itself, which polls its two sockets
// and processes incoming messages:
static private class FreelanceAgent implements IAttachedRunnable
{
@Override
public void run(Object[] args, ZContext ctx, Socket pipe)
{
Agent agent = new Agent(ctx, pipe);
PollItem[] items = {
new PollItem(agent.pipe, ZMQ.Poller.POLLIN),
new PollItem(agent.router, ZMQ.Poller.POLLIN)
};
while (!Thread.currentThread().isInterrupted()) {
// Calculate tickless timer, up to 1 hour
long tickless = System.currentTimeMillis() + 1000 * 3600;
if (agent.request != null
&& tickless > agent.expires)
tickless = agent.expires;
for (Server server: agent.servers.values()) {
long newTickless = server.tickless(tickless);
if (newTickless > 0)
tickless = newTickless;
}
int rc = ZMQ.poll(items,
(tickless - System.currentTimeMillis()));
if (rc == -1)
break; // Context has been shut down
if (items[0].isReadable())
agent.controlMessage();
if (items[1].isReadable())
agent.routerMessage();
// If we're processing a request, dispatch to next server
if (agent.request != null) {
if (System.currentTimeMillis() >= agent.expires) {
// Request expired, kill it
agent.pipe.send("FAILED");
agent.request.destroy();
agent.request = null;
}
else {
// Find server to talk to, remove any expired ones
while (!agent.actives.isEmpty()) {
Server server = agent.actives.get(0);
if (System.currentTimeMillis() >= server.expires) {
agent.actives.remove(0);
server.alive = false;
}
else {
ZMsg request = agent.request.duplicate();
request.push(server.endpoint);
request.send(agent.router);
break;
}
}
}
}
// Disconnect and delete any expired servers
// Send heartbeats to idle servers if needed
for (Server server: agent.servers.values())
server.ping(agent.router);
}
agent.destroy();
}
}
}
jeromq-0.3.5/src/test/java/guide/flclient1.java 0000664 0000000 0000000 00000006724 12551504772 0021345 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
// Freelance client - Model 1
// Uses REQ socket to query one or more services
public class flclient1
{
private static final int REQUEST_TIMEOUT = 1000;
private static final int MAX_RETRIES = 3; // Before we abandon
private static ZMsg tryRequest (ZContext ctx, String endpoint, ZMsg request)
{
System.out.printf("I: trying echo service at %s...\n", endpoint);
Socket client = ctx.createSocket(ZMQ.REQ);
client.connect(endpoint);
// Send request, wait safely for reply
ZMsg msg = request.duplicate();
msg.send(client);
PollItem[] items = { new PollItem(client, ZMQ.Poller.POLLIN) };
ZMQ.poll(items, REQUEST_TIMEOUT);
ZMsg reply = null;
if (items[0].isReadable())
reply = ZMsg.recvMsg(client);
// Close socket in any case, we're done with it now
ctx.destroySocket(client);
return reply;
}
// .split client task
// The client uses a Lazy Pirate strategy if it only has one server to talk
// to. If it has two or more servers to talk to, it will try each server just
// once:
public static void main (String[] argv)
{
ZContext ctx = new ZContext();
ZMsg request = new ZMsg();
request.add("Hello world");
ZMsg reply = null;
int endpoints = argv.length;
if (endpoints == 0)
System.out.printf ("I: syntax: flclient1 ...\n");
else
if (endpoints == 1) {
// For one endpoint, we retry N times
int retries;
for (retries = 0; retries < MAX_RETRIES; retries++) {
String endpoint = argv [0];
reply = tryRequest(ctx, endpoint, request);
if (reply != null)
break; // Successful
System.out.printf("W: no response from %s, retrying...\n", endpoint);
}
}
else {
// For multiple endpoints, try each at most once
int endpointNbr;
for (endpointNbr = 0; endpointNbr < endpoints; endpointNbr++) {
String endpoint = argv[endpointNbr];
reply = tryRequest (ctx, endpoint, request);
if (reply != null)
break; // Successful
System.out.printf ("W: no response from %s\n", endpoint);
}
}
if (reply != null) {
System.out.printf ("Service is running OK\n");
reply.destroy();
}
request.destroy();;
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/flclient2.java 0000664 0000000 0000000 00000010553 12551504772 0021341 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
// Freelance client - Model 2
// Uses DEALER socket to blast one or more services
public class flclient2
{
// If not a single service replies within this time, give up
private static final int GLOBAL_TIMEOUT = 2500;
// .split class implementation
// Here is the {{flclient}} class implementation. Each instance has a
// context, a DEALER socket it uses to talk to the servers, a counter
// of how many servers it's connected to, and a request getSequence number:
private ZContext ctx; // Our context wrapper
private Socket socket; // DEALER socket talking to servers
private int servers; // How many servers we have connected to
private int sequence; // Number of requests ever sent
public flclient2()
{
ctx = new ZContext();
socket = ctx.createSocket(ZMQ.DEALER);
}
public void destroy()
{
ctx.destroy();
}
private void connect(String endpoint)
{
socket.connect(endpoint);
servers++;
}
private ZMsg request(ZMsg request)
{
// Prefix request with getSequence number and empty envelope
String sequenceText = String.format("%d", ++sequence);
request.push(sequenceText);
request.push("");
// Blast the request to all connected servers
int server;
for (server = 0; server < servers; server++) {
ZMsg msg = request.duplicate();
msg.send(socket);
}
// Wait for a matching reply to arrive from anywhere
// Since we can poll several times, calculate each one
ZMsg reply = null;
long endtime = System.currentTimeMillis() + GLOBAL_TIMEOUT;
while (System.currentTimeMillis() < endtime) {
PollItem[] items = { new PollItem(socket, ZMQ.Poller.POLLIN) };
ZMQ.poll(items, endtime - System.currentTimeMillis());
if (items[0].isReadable()) {
// Reply is [empty][getSequence][OK]
reply = ZMsg.recvMsg(socket);
assert (reply.size() == 3);
reply.pop();
String sequenceStr = reply.popString();
int sequenceNbr = Integer.parseInt(sequenceStr);
if (sequenceNbr == sequence)
break;
reply.destroy();
}
}
request.destroy();
return reply;
}
public static void main (String[] argv)
{
if (argv.length == 0) {
System.out.printf ("I: syntax: flclient2 ...\n");
System.exit(0);
}
// Create new freelance client object
flclient2 client = new flclient2();
// Connect to each endpoint
int argn;
for (argn = 0; argn < argv.length; argn++)
client.connect(argv[argn]);
// Send a bunch of name resolution 'requests', measure time
int requests = 10000;
long start = System.currentTimeMillis();
while (requests-- > 0) {
ZMsg request = new ZMsg();
request.add("random name");
ZMsg reply = client.request(request);
if (reply == null) {
System.out.printf("E: name service not available, aborting\n");
break;
}
reply.destroy();
}
System.out.printf ("Average round trip cost: %d usec\n",
(int) (System.currentTimeMillis() - start) / 10);
client.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/flclient3.java 0000664 0000000 0000000 00000003746 12551504772 0021350 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
// Freelance client - Model 3
// Uses flcliapi class to encapsulate Freelance pattern
public class flclient3
{
public static void main (String[] argv)
{
// Create new freelance client object
flcliapi client = new flcliapi();
// Connect to several endpoints
client.connect("tcp://localhost:5555");
client.connect("tcp://localhost:5556");
client.connect("tcp://localhost:5557");
// Send a bunch of name resolution 'requests', measure time
int requests = 10000;
long start = System.currentTimeMillis();
while (requests-- > 0) {
ZMsg request = new ZMsg();
request.add("random name");
ZMsg reply = client.request(request);
if (reply == null) {
System.out.printf("E: name service not available, aborting\n");
break;
}
reply.destroy();
}
System.out.printf("Average round trip cost: %d usec\n",
(int) (System.currentTimeMillis() - start) / 10);
client.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/flserver1.java 0000664 0000000 0000000 00000003204 12551504772 0021363 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
// Freelance server - Model 1
// Trivial echo service
public class flserver1
{
public static void main(String[] args)
{
if (args.length < 1) {
System.out.printf("I: syntax: flserver1 \n");
System.exit(0);
}
ZContext ctx = new ZContext();
Socket server = ctx.createSocket(ZMQ.REP);
server.bind(args[0]);
System.out.printf ("I: echo service is ready at %s\n", args[0]);
while (true) {
ZMsg msg = ZMsg.recvMsg(server);
if (msg == null)
break; // Interrupted
msg.send(server);
}
if (Thread.currentThread().isInterrupted())
System.out.printf ("W: interrupted\n");
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/flserver2.java 0000664 0000000 0000000 00000003734 12551504772 0021374 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
// Freelance server - Model 2
// Does some work, replies OK, with message sequencing
public class flserver2
{
public static void main(String[] args)
{
if (args.length < 1) {
System.out.printf("I: syntax: flserver2 \n");
System.exit(0);
}
ZContext ctx = new ZContext();
Socket server = ctx.createSocket(ZMQ.REP);
server.bind(args[0]);
System.out.printf ("I: echo service is ready at %s\n", args[0]);
while (true) {
ZMsg request = ZMsg.recvMsg(server);
if (request == null)
break; // Interrupted
// Fail nastily if run against wrong client
assert (request.size() == 2);
ZFrame identity = request.pop();
request.destroy();
ZMsg reply = new ZMsg();
reply.add(identity);
reply.add("OK");
reply.send(server);
}
if (Thread.currentThread().isInterrupted())
System.out.printf ("W: interrupted\n");
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/flserver3.java 0000664 0000000 0000000 00000005101 12551504772 0021363 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
// Freelance server - Model 3
// Uses an ROUTER/ROUTER socket but just one thread
public class flserver3
{
public static void main(String[] args)
{
boolean verbose = (args.length > 0 && args[0].equals("-v"));
ZContext ctx = new ZContext();
// Prepare server socket with predictable identity
String bindEndpoint = "tcp://*:5555";
String connectEndpoint = "tcp://localhost:5555";
Socket server = ctx.createSocket(ZMQ.ROUTER);
server.setIdentity(connectEndpoint.getBytes(ZMQ.CHARSET));
server.bind(bindEndpoint);
System.out.printf ("I: service is ready at %s\n", bindEndpoint);
while (!Thread.currentThread().isInterrupted()) {
ZMsg request = ZMsg.recvMsg(server);
if (verbose && request != null)
request.dump(System.out);
if (request == null)
break; // Interrupted
// Frame 0: identity of client
// Frame 1: PING, or client control frame
// Frame 2: request body
ZFrame identity = request.pop();
ZFrame control = request.pop();
ZMsg reply = new ZMsg();
if (control.equals(new ZFrame("PING")))
reply.add("PONG");
else {
reply.add(control);
reply.add("OK");
}
request.destroy();
reply.push(identity);
if (verbose && reply != null)
reply.dump(System.out);
reply.send(server);
}
if (Thread.currentThread().isInterrupted())
System.out.printf ("W: interrupted\n");
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/hwclient.java 0000664 0000000 0000000 00000003253 12551504772 0021273 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
//
// Hello World client in Java
// Connects REQ socket to tcp://localhost:5555
// Sends "Hello" to server, expects "World" back
//
import org.zeromq.ZMQ;
public class hwclient{
public static void main (String[] args){
ZMQ.Context context = ZMQ.context(1);
// Socket to talk to server
System.out.println("Connecting to hello world server");
ZMQ.Socket socket = context.socket(ZMQ.REQ);
socket.connect ("tcp://localhost:5555");
for(int requestNbr = 0; requestNbr != 10; requestNbr++) {
String request = "Hello" ;
System.out.println("Sending Hello " + requestNbr );
socket.send(request.getBytes (ZMQ.CHARSET), 0);
byte[] reply = socket.recv(0);
System.out.println("Received " + new String (reply, ZMQ.CHARSET) + " " + requestNbr);
}
socket.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/hwserver.java 0000664 0000000 0000000 00000003236 12551504772 0021324 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
//
// Hello World server in Java
// Binds REP socket to tcp://*:5555
// Expects "Hello" from client, replies with "World"
//
import org.zeromq.ZMQ;
public class hwserver{
public static void main (String[] args) throws Exception{
ZMQ.Context context = ZMQ.context(1);
// Socket to talk to clients
ZMQ.Socket socket = context.socket(ZMQ.REP);
socket.bind ("tcp://*:5555");
while (!Thread.currentThread ().isInterrupted ()) {
byte[] reply = socket.recv(0);
System.out.println("Received " + ": [" + new String(reply, ZMQ.CHARSET) + "]");
// Create a "Hello" message.
String request = "world" ;
// Send the message
socket.send(request.getBytes (ZMQ.CHARSET), 0);
Thread.sleep(1000); // Do some 'work'
}
socket.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/identity.java 0000664 0000000 0000000 00000003471 12551504772 0021311 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
/**
* Demonstrate identities as used by the request-reply pattern.
*/
public class identity {
public static void main (String[] args) throws InterruptedException {
Context context = ZMQ.context(1);
Socket sink = context.socket(ZMQ.ROUTER);
sink.bind("inproc://example");
// First allow 0MQ to set the identity, [00] + random 4byte
Socket anonymous = context.socket(ZMQ.REQ);
anonymous.connect("inproc://example");
anonymous.send ("ROUTER uses a generated UUID",0);
ZHelper.dump (sink);
// Then set the identity ourself
Socket identified = context.socket(ZMQ.REQ);
identified.setIdentity("Hello".getBytes (ZMQ.CHARSET));
identified.connect ("inproc://example");
identified.send("ROUTER socket uses REQ's socket identity", 0);
ZHelper.dump (sink);
sink.close ();
anonymous.close ();
identified.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/interrupt.java 0000664 0000000 0000000 00000003767 12551504772 0021524 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
/*
*
* Interrupt in Java
* Shows how to handle Ctrl-C
*/
import org.zeromq.ZMQ;
import org.zeromq.ZMQException;
public class interrupt {
public static void main (String[] args) {
// Prepare our context and socket
final ZMQ.Context context = ZMQ.context(1);
final Thread zmqThread = new Thread() {
@Override
public void run() {
ZMQ.Socket socket = context.socket(ZMQ.REP);
socket.bind("tcp://*:5555");
while (!Thread.currentThread().isInterrupted()) {
try {
socket.recv (0);
} catch (ZMQException e) {
if (e.getErrorCode () == ZMQ.Error.ETERM.getCode ()) {
break;
}
}
}
socket.close();
}
};
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("W: interrupt received, killing server...");
context.term();
try {
zmqThread.interrupt();
zmqThread.join();
} catch (InterruptedException e) {
}
}
});
zmqThread.start();
}
}
jeromq-0.3.5/src/test/java/guide/kvmsg.java 0000664 0000000 0000000 00000030442 12551504772 0020605 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Socket;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.UUID;
public class kvmsg
{
// Keys are short strings
private static final int KVMSG_KEY_MAX = 255;
// Message is formatted on wire as 4 frames:
// frame 0: getKey (0MQ string)
// frame 1: getSequence (8 bytes, network order)
// frame 2: uuid (blob, 16 bytes)
// frame 3: properties (0MQ string)
// frame 4: body (blob)
private static final int FRAME_KEY = 0;
private static final int FRAME_SEQ = 1;
private static final int FRAME_UUID = 2;
private static final int FRAME_PROPS = 3;
private static final int FRAME_BODY = 4;
private static final int KVMSG_FRAMES = 5;
// Presence indicators for each frame
private boolean[] present = new boolean[KVMSG_FRAMES];
// Corresponding 0MQ message frames, if any
private byte[][] frame = new byte[KVMSG_FRAMES][];
// Key, copied into safe string
private String key;
// List of properties, as name=value strings
private Properties props;
private int props_size;
// .split property encoding
// These two helpers serialize a list of properties to and from a
// message frame:
private void encodeProps()
{
ByteBuffer msg = ByteBuffer.allocate(props_size);
for (Entry o: props.entrySet()) {
String prop = o.getKey().toString() + "=" + o.getValue().toString() + "\n";
msg.put(prop.getBytes(ZMQ.CHARSET));
}
present[FRAME_PROPS] = true;
frame[FRAME_PROPS] = msg.array();
}
private void decodeProps()
{
byte[] msg = frame[FRAME_PROPS];
props_size = msg.length;
props.clear();
if (msg.length == 0)
return;
System.out.println("" + msg.length + " :" + new String(msg, ZMQ.CHARSET));
for (String prop: new String(msg, ZMQ.CHARSET).split("\n")) {
String[] split = prop.split("=");
props.setProperty(split[0], split[1]);
}
}
// .split constructor and destructor
// Here are the constructor and destructor for the class:
// Constructor, takes a getSequence number for the new kvmsg instance:
public kvmsg(long sequence)
{
props = new Properties();
setSequence(sequence);
}
public void destroy()
{
}
// .split recv method
// This method reads a getKey-value message from the socket and returns a
// new {{kvmsg}} instance:
public static kvmsg recv(Socket socket)
{
// This method is almost unchanged from kvsimple
// .skip
assert (socket != null);
kvmsg self = new kvmsg(0);
// Read all frames off the wire, reject if bogus
int frameNbr;
for (frameNbr = 0; frameNbr < KVMSG_FRAMES; frameNbr++) {
//zmq_msg_init (&self->frame [frameNbr]);
self.present[frameNbr] = true;
if ((self.frame[frameNbr] = socket.recv(0)) == null) {
self.destroy();
break;
}
// Verify multipart framing
boolean rcvmore = (frameNbr < KVMSG_FRAMES - 1)? true: false;
if (socket.hasReceiveMore() != rcvmore) {
self.destroy();
break;
}
}
// .until
self.decodeProps();
return self;
}
// Send getKey-value message to socket; any empty frames are sent as such.
public void send(Socket socket)
{
assert (socket != null);
encodeProps();
// The rest of the method is unchanged from kvsimple
// .skip
int frameNbr;
for (frameNbr = 0; frameNbr < KVMSG_FRAMES; frameNbr++) {
byte[] copy = ZMQ.MESSAGE_SEPARATOR;
if (present[frameNbr])
copy = frame[frameNbr];
socket.send(copy, (frameNbr < KVMSG_FRAMES - 1)? ZMQ.SNDMORE: 0);
}
}
// .until
// .split dup method
// This method duplicates a {{kvmsg}} instance, returns the new instance:
public kvmsg dup()
{
kvmsg kvmsg = new kvmsg(0);
int frameNbr;
for (frameNbr = 0; frameNbr < KVMSG_FRAMES; frameNbr++) {
if (present[frameNbr]) {
kvmsg.frame[frameNbr] = new byte[frame[frameNbr].length];
System.arraycopy(frame[frameNbr], 0,
kvmsg.frame[frameNbr], 0, frame[frameNbr].length);
kvmsg.present[frameNbr] = true;
}
}
kvmsg.props_size = props_size;
kvmsg.props.putAll(props);
return kvmsg;
}
// The getKey, getSequence, body, and size methods are the same as in kvsimple.
// .skip
// Return getKey from last read message, if any, else NULL
public String getKey()
{
if (present[FRAME_KEY]) {
if (key == null) {
int size = frame[FRAME_KEY].length;
if (size > KVMSG_KEY_MAX)
size = KVMSG_KEY_MAX;
byte[] buf = new byte[size];
System.arraycopy(frame[FRAME_KEY], 0, buf, 0, size);
key = new String(buf, ZMQ.CHARSET);
}
return key;
}
else
return null;
}
// Set message getKey as provided
public void setKey(String key)
{
byte[] msg = new byte[key.length()];
System.arraycopy(key.getBytes(ZMQ.CHARSET), 0, msg, 0, key.length());
frame[FRAME_KEY] = msg;
present[FRAME_KEY] = true;
}
// Set message getKey using printf format
public void fmtKey(String fmt, Object ... args)
{
setKey(String.format(fmt, args));
}
// Return getSequence nbr from last read message, if any
public long getSequence()
{
if (present[FRAME_SEQ]) {
assert (frame[FRAME_SEQ].length == 8);
ByteBuffer source = ByteBuffer.wrap(frame[FRAME_SEQ]);
return source.getLong();
}
else
return 0;
}
// Set message getSequence number
public void setSequence(long sequence)
{
ByteBuffer msg = ByteBuffer.allocate(8);
msg.putLong(sequence);
present[FRAME_SEQ] = true;
frame[FRAME_SEQ] = msg.array();
}
// Return body from last read message, if any, else NULL
public byte[] body()
{
if (present[FRAME_BODY])
return frame[FRAME_BODY];
else
return null;
}
// Set message body
public void setBody(byte[] body)
{
byte[] msg = new byte[body.length];
System.arraycopy(body, 0, msg, 0, body.length);
frame [FRAME_BODY] = msg;
present[FRAME_BODY] = true;
}
// Set message body using printf format
public void fmtBody(String fmt, Object... args)
{
setBody(String.format(fmt, args).getBytes(ZMQ.CHARSET));
}
// Return body size from last read message, if any, else zero
public int size()
{
if (present[FRAME_BODY])
return frame[FRAME_BODY].length;
else
return 0;
}
// .until
// .split UUID methods
// These methods get and set the UUID for the getKey-value message:
public byte[] UUID()
{
if (present[FRAME_UUID])
return frame[FRAME_UUID];
else
return null;
}
// Sets the UUID to a randomly generated value
public void setUUID()
{
byte[] msg = UUID.randomUUID().toString().getBytes(ZMQ.CHARSET);
present[FRAME_UUID] = true;
frame[FRAME_UUID] = msg;
}
// .split property methods
// These methods get and set a specified message property:
// Get message property, return "" if no such property is defined.
public String getProp(String name)
{
return props.getProperty(name, "");
}
// Set message property. Property name cannot contain '='. Max length of
// value is 255 chars.
public void setProp(String name, String fmt, Object ... args)
{
String value = String.format(fmt, args);
Object old = props.setProperty(name, value);
if (old != null)
props_size -= old.toString().length();
else
props_size += name.length() + 2;
props_size += value.length();
}
// .split store method
// This method stores the getKey-value message into a hash map, unless
// the getKey and value are both null. It nullifies the {{kvmsg}} reference
// so that the object is owned by the hash map, not the caller:
public void store(Map hash)
{
if (size() > 0) {
if (present[FRAME_KEY] && present[FRAME_BODY]) {
hash.put(getKey(), this);
}
} else
hash.remove(getKey());
}
// .split dump method
// This method extends the {{kvsimple}} implementation with support for
// message properties:
public void dump()
{
int size = size();
byte[] body = body();
System.err.printf("[seq:%d]", getSequence());
System.err.printf("[getKey:%s]", getKey());
// .until
System.err.printf("[size:%d] ", size);
System.err.printf("[");
for (String key: props.stringPropertyNames()) {
System.err.printf("%s=%s;", key, props.getProperty(key));
}
System.err.printf("]");
// .skip
for (int charNbr = 0; charNbr < size; charNbr++)
System.err.printf("%02X", body[charNbr]);
System.err.printf("\n");
}
// .until
// .split test method
// This method is the same as in {{kvsimple}} with added support
// for the uuid and property features of {{kvmsg}}:
public void test(boolean verbose)
{
System.out.printf(" * kvmsg: ");
// Prepare our context and sockets
ZContext ctx = new ZContext();
Socket output = ctx.createSocket(ZMQ.DEALER);
output.bind("ipc://kvmsg_selftest.ipc");
Socket input = ctx.createSocket(ZMQ.DEALER);
input.connect("ipc://kvmsg_selftest.ipc");
Map kvmap = new HashMap();
// .until
// Test send and receive of simple message
kvmsg kvmsg = new kvmsg(1);
kvmsg.setKey("getKey");
kvmsg.setUUID();
kvmsg.setBody("body".getBytes(ZMQ.CHARSET));
if (verbose)
kvmsg.dump();
kvmsg.send(output);
kvmsg.store(kvmap);
kvmsg = kvmsg.recv(input);
if (verbose)
kvmsg.dump();
assert (kvmsg.getKey().equals("getKey"));
kvmsg.store(kvmap);
// Test send and receive of message with properties
kvmsg = new kvmsg(2);
kvmsg.setProp("prop1", "value1");
kvmsg.setProp("prop2", "value1");
kvmsg.setProp("prop2", "value2");
kvmsg.setKey("getKey");
kvmsg.setUUID();
kvmsg.setBody("body".getBytes(ZMQ.CHARSET));
assert (kvmsg.getProp("prop2").equals("value2"));
if (verbose)
kvmsg.dump();
kvmsg.send(output);
kvmsg.destroy();
kvmsg = kvmsg.recv(input);
if (verbose)
kvmsg.dump();
assert (kvmsg.key.equals("getKey"));
assert (kvmsg.getProp("prop2").equals("value2"));
kvmsg.destroy();
// .skip
// Shutdown and destroy all objects
ctx.destroy();
System.out.printf("OK\n");
}
// .until
}
jeromq-0.3.5/src/test/java/guide/kvsimple.java 0000664 0000000 0000000 00000006122 12551504772 0021306 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.nio.ByteBuffer;
import java.util.Arrays;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Socket;
/**
*
* A simple getKey value message class
* @author Danish Shrestha
*
*/
public class kvsimple {
private final String key;
private long sequence;
private final byte[] body;
public kvsimple(String key, long sequence, byte[] body) {
this.key = key;
this.sequence = sequence;
this.body = body; // clone if needed
}
public String getKey() {
return key;
}
public long getSequence() {
return sequence;
}
public void setSequence(long sequence)
{
this.sequence = sequence;
}
public byte[] getBody() {
return body;
}
public void send(Socket publisher) {
publisher.send(key.getBytes(ZMQ.CHARSET), ZMQ.SNDMORE);
ByteBuffer bb = ByteBuffer.allocate(8);
bb.asLongBuffer().put(sequence);
publisher.send(bb.array(), ZMQ.SNDMORE);
publisher.send(body, 0);
}
public static kvsimple recv(Socket updates) {
byte [] data = updates.recv(0);
if (data == null || !updates.hasReceiveMore())
return null;
String key = new String(data, ZMQ.CHARSET);
data = updates.recv(0);
if (data == null || !updates.hasReceiveMore())
return null;
Long sequence = ByteBuffer.wrap(data).getLong();
byte[] body = updates.recv(0);
if (body == null || updates.hasReceiveMore())
return null;
return new kvsimple(key, sequence, body);
}
@Override
public String toString() {
return "kvsimple [getKey=" + key + ", getSequence=" + sequence + ", body=" + Arrays.toString(body) + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(body);
result = prime * result + ((key == null) ? 0 : key.hashCode());
result = prime * result + (int) (sequence ^ (sequence >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
kvsimple other = (kvsimple) obj;
if (!Arrays.equals(body, other.body))
return false;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
if (sequence != other.sequence)
return false;
return true;
}
}
jeromq-0.3.5/src/test/java/guide/lbbroker.java 0000664 0000000 0000000 00000015613 12551504772 0021263 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.LinkedList;
import java.util.Queue;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Poller;
import org.zeromq.ZMQ.Socket;
public class lbbroker {
private static final int NBR_CLIENTS = 10;
private static final int NBR_WORKERS = 3;
/**
* Basic request-reply client using REQ socket
*/
private static class ClientTask extends Thread
{
public void run()
{
Context context = ZMQ.context(1);
// Prepare our context and sockets
Socket client = context.socket(ZMQ.REQ);
ZHelper.setId (client); // Set a printable identity
client.connect("ipc://frontend.ipc");
// Send request, get reply
client.send("HELLO");
String reply = client.recvStr ();
System.out.println("Client: " + reply);
client.close();
context.term();
}
}
/**
* While this example runs in a single process, that is just to make
* it easier to start and stop the example. Each thread has its own
* context and conceptually acts as a separate process.
* This is the worker task, using a REQ socket to do load-balancing.
*/
private static class WorkerTask extends Thread
{
public void run()
{
Context context = ZMQ.context(1);
// Prepare our context and sockets
Socket worker = context.socket(ZMQ.REQ);
ZHelper.setId (worker); // Set a printable identity
worker.connect("ipc://backend.ipc");
// Tell backend we're ready for work
worker.send("READY");
while(!Thread.currentThread ().isInterrupted ())
{
String address = worker.recvStr ();
String empty = worker.recvStr ();
assert (empty.length() == 0);
// Get request, send reply
String request = worker.recvStr ();
System.out.println("Worker: " + request);
worker.sendMore (address);
worker.sendMore ("");
worker.send("OK");
}
worker.close ();
context.term ();
}
}
/**
* This is the main task. It starts the clients and workers, and then
* routes requests between the two layers. Workers signal READY when
* they start; after that we treat them as ready when they reply with
* a response back to a client. The load-balancing data structure is
* just a queue of next available workers.
*/
public static void main (String[] args) {
Context context = ZMQ.context(1);
// Prepare our context and sockets
Socket frontend = context.socket(ZMQ.ROUTER);
Socket backend = context.socket(ZMQ.ROUTER);
frontend.bind("ipc://frontend.ipc");
backend.bind("ipc://backend.ipc");
int clientNbr;
for (clientNbr = 0; clientNbr < NBR_CLIENTS; clientNbr++)
new ClientTask().start();
for (int workerNbr = 0; workerNbr < NBR_WORKERS; workerNbr++)
new WorkerTask().start();
// Here is the main loop for the least-recently-used queue. It has two
// sockets; a frontend for clients and a backend for workers. It polls
// the backend in all cases, and polls the frontend only when there are
// one or more workers ready. This is a neat way to use 0MQ's own queues
// to hold messages we're not ready to process yet. When we get a client
// reply, we pop the next available worker, and send the request to it,
// including the originating client identity. When a worker replies, we
// re-queue that worker, and we forward the reply to the original client,
// using the reply envelope.
// Queue of available workers
Queue workerQueue = new LinkedList();
while (!Thread.currentThread().isInterrupted()) {
// Initialize poll set
Poller items = new Poller (2);
//  Always poll for worker activity on backend
items.register(backend, Poller.POLLIN);
//  Poll front-end only if we have available workers
if(workerQueue.size() > 0)
items.register(frontend, Poller.POLLIN);
if (items.poll() < 0)
break; // Interrupted
// Handle worker activity on backend
if (items.pollin(0)) {
// Queue worker address for LRU routing
workerQueue.add (backend.recvStr ());
// Second frame is empty
String empty = backend.recvStr ();
assert (empty.length() == 0);
// Third frame is READY or else a client reply address
String clientAddr = backend.recvStr ();
// If client reply, send rest back to frontend
if (!clientAddr.equals("READY")) {
empty = backend.recvStr ();
assert (empty.length() == 0);
String reply = backend.recvStr ();
frontend.sendMore(clientAddr);
frontend.sendMore("");
frontend.send(reply);
if (--clientNbr == 0)
break;
}
}
if (items.pollin(1)) {
// Now get next client request, route to LRU worker
// Client request is [address][empty][request]
String clientAddr = frontend.recvStr ();
String empty = frontend.recvStr ();
assert (empty.length() == 0);
String request = frontend.recvStr ();
String workerAddr = workerQueue.poll();
backend.sendMore (workerAddr);
backend.sendMore ("");
backend.sendMore (clientAddr );
backend.sendMore ("");
backend.send (request);
}
}
frontend.close();
backend.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/lbbroker2.java 0000664 0000000 0000000 00000013064 12551504772 0021343 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Poller;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
import org.zeromq.ZThread;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
/**
* Load-balancing broker
* Demonstrates use of the high level API
*/
public class lbbroker2
{
private static final int NBR_CLIENTS = 10;
private static final int NBR_WORKERS = 3;
private static byte[] WORKER_READY = { '\001' }; // Signals worker is ready
/**
* Basic request-reply client using REQ socket
*/
private static class ClientTask implements ZThread.IDetachedRunnable
{
@Override
public void run (Object ... args)
{
ZContext context = new ZContext();
// Prepare our context and sockets
Socket client = context.createSocket (ZMQ.REQ);
ZHelper.setId (client); // Set a printable identity
client.connect("ipc://frontend.ipc");
// Send request, get reply
client.send("HELLO");
String reply = client.recvStr ();
System.out.println("Client: " + reply);
context.destroy ();
}
}
/**
* Worker using REQ socket to do load-balancing
*/
private static class WorkerTask implements ZThread.IDetachedRunnable
{
@Override
public void run (Object ... args)
{
ZContext context = new ZContext();
// Prepare our context and sockets
Socket worker = context.createSocket (ZMQ.REQ);
ZHelper.setId (worker); // Set a printable identity
worker.connect("ipc://backend.ipc");
// Tell backend we're ready for work
ZFrame frame = new ZFrame (WORKER_READY);
frame.send (worker, 0);
while(true)
{
ZMsg msg = ZMsg.recvMsg (worker);
if (msg == null)
break;
msg.getLast ().reset ("OK");
msg.send (worker);
}
context.destroy ();
}
}
/**
* This is the main task. This has the identical functionality to
* the previous lbbroker example but uses higher level classes to start child threads
* to hold the list of workers, and to read and send messages:
*/
public static void main (String[] args) {
ZContext context = new ZContext();
// Prepare our context and sockets
Socket frontend = context.createSocket (ZMQ.ROUTER);
Socket backend = context.createSocket (ZMQ.ROUTER);
frontend.bind("ipc://frontend.ipc");
backend.bind("ipc://backend.ipc");
int clientNbr;
for (clientNbr = 0; clientNbr < NBR_CLIENTS; clientNbr++)
ZThread.start (new ClientTask ());
for (int workerNbr = 0; workerNbr < NBR_WORKERS; workerNbr++)
ZThread.start (new WorkerTask ());
// Queue of available workers
Queue workerQueue = new LinkedList ();
// Here is the main loop for the load-balancer. It works the same way
// as the previous example, but is a lot shorter because ZMsg class gives
// us an API that does more with fewer calls:
while (!Thread.currentThread().isInterrupted()) {
// Initialize poll set
Poller items = new Poller (2);
//  Always poll for worker activity on backend
items.register(backend, Poller.POLLIN);
//  Poll front-end only if we have available workers
if(workerQueue.size() > 0)
items.register(frontend, Poller.POLLIN);
if (items.poll() < 0)
break; // Interrupted
// Handle worker activity on backend
if (items.pollin(0)) {
ZMsg msg = ZMsg.recvMsg (backend);
if (msg == null)
break; // Interrupted
ZFrame identity = msg.unwrap ();
// Queue worker address for LRU routing
workerQueue.add (identity);
// Forward message to client if it's not a READY
ZFrame frame = msg.getFirst ();
if (Arrays.equals (frame.getData (), WORKER_READY))
msg.destroy ();
else
msg.send (frontend);
}
if (items.pollin(1)) {
// Get client request, route to first available worker
ZMsg msg = ZMsg.recvMsg (frontend);
if (msg != null) {
msg.wrap (workerQueue.poll ());
msg.send (backend);
}
}
}
context.destroy ();
}
}
jeromq-0.3.5/src/test/java/guide/lbbroker3.java 0000664 0000000 0000000 00000014676 12551504772 0021356 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMsg;
import org.zeromq.ZLoop;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZThread;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
/**
* Load-balancing broker
* Demonstrates use of the ZLoop API and reactor style
*
* The client and worker tasks are identical from the previous example.
*/
public class lbbroker3
{
private static final int NBR_CLIENTS = 10;
private static final int NBR_WORKERS = 3;
private static byte[] WORKER_READY = { '\001' };
/**
* Basic request-reply client using REQ socket
*/
private static class ClientTask implements ZThread.IDetachedRunnable
{
@Override
public void run (Object ... args)
{
ZContext context = new ZContext();
// Prepare our context and sockets
Socket client = context.createSocket (ZMQ.REQ);
ZHelper.setId (client); // Set a printable identity
client.connect("ipc://frontend.ipc");
// Send request, get reply
client.send("HELLO");
String reply = client.recvStr ();
System.out.println("Client: " + reply);
context.destroy ();
}
}
/**
* Worker using REQ socket to do load-balancing
*/
private static class WorkerTask implements ZThread.IDetachedRunnable
{
@Override
public void run (Object ... args)
{
ZContext context = new ZContext();
// Prepare our context and sockets
Socket worker = context.createSocket (ZMQ.REQ);
ZHelper.setId (worker); // Set a printable identity
worker.connect("ipc://backend.ipc");
// Tell backend we're ready for work
ZFrame frame = new ZFrame (WORKER_READY);
frame.send (worker, 0);
while(true)
{
ZMsg msg = ZMsg.recvMsg (worker);
if (msg == null)
break;
msg.getLast ().reset ("OK");
msg.send (worker);
}
context.destroy ();
}
}
//Our load-balancer structure, passed to reactor handlers
private static class LBBroker {
Socket frontend; // Listen to clients
Socket backend; // Listen to workers
Queue workers; // List of ready workers
};
/**
* In the reactor design, each time a message arrives on a socket, the
* reactor passes it to a handler function. We have two handlers; one
* for the frontend, one for the backend:
*/
private static class FrontendHandler implements ZLoop.IZLoopHandler {
@Override
public int handle(ZLoop loop, PollItem item, Object arg_) {
LBBroker arg = (LBBroker)arg_;
ZMsg msg = ZMsg.recvMsg (arg.frontend);
if (msg != null) {
msg.wrap(arg.workers.poll());
msg.send(arg.backend);
// Cancel reader on frontend if we went from 1 to 0 workers
if (arg.workers.size() == 0) {
loop.removePoller (new PollItem (arg.frontend, 0));
}
}
return 0;
}
}
private static class BackendHandler implements ZLoop.IZLoopHandler {
@Override
public int handle(ZLoop loop, PollItem item, Object arg_) {
LBBroker arg = (LBBroker)arg_;
ZMsg msg = ZMsg.recvMsg(arg.backend);
if (msg != null) {
ZFrame address = msg.unwrap();
// Queue worker address for load-balancing
arg.workers.add(address);
// Enable reader on frontend if we went from 0 to 1 workers
if (arg.workers.size() == 1) {
PollItem newItem = new PollItem (arg.frontend, ZMQ.Poller.POLLIN);
loop.addPoller (newItem, frontendHandler, arg);
}
// Forward message to client if it's not a READY
ZFrame frame = msg.getFirst();
if (Arrays.equals (frame.getData(), WORKER_READY))
msg.destroy();
else
msg.send(arg.frontend);
}
return 0;
}
}
private final static FrontendHandler frontendHandler = new FrontendHandler();
private final static BackendHandler backendHandler = new BackendHandler();
/**
* And the main task now sets-up child tasks, then starts its reactor.
* If you press Ctrl-C, the reactor exits and the main task shuts down.
*/
public static void main (String[] args) {
ZContext context = new ZContext();
LBBroker arg = new LBBroker ();
// Prepare our context and sockets
arg.frontend = context.createSocket (ZMQ.ROUTER);
arg.backend = context.createSocket (ZMQ.ROUTER);
arg.frontend.bind("ipc://frontend.ipc");
arg.backend.bind("ipc://backend.ipc");
int clientNbr;
for (clientNbr = 0; clientNbr < NBR_CLIENTS; clientNbr++)
ZThread.start (new ClientTask ());
for (int workerNbr = 0; workerNbr < NBR_WORKERS; workerNbr++)
ZThread.start (new WorkerTask ());
// Queue of available workers
arg.workers = new LinkedList ();
// Prepare reactor and fire it up
ZLoop reactor = new ZLoop ();
PollItem item = new PollItem (arg.backend, ZMQ.Poller.POLLIN);
reactor.addPoller (item, backendHandler, arg);
reactor.start ();
context.destroy ();
}
}
jeromq-0.3.5/src/test/java/guide/lpclient.java 0000664 0000000 0000000 00000007513 12551504772 0021273 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Poller;
import org.zeromq.ZMQ.Socket;
//
// Lazy Pirate client
// Use zmq_poll to do a safe request-reply
// To run, start lpserver and then randomly kill/restart it
//
public class lpclient
{
private final static int REQUEST_TIMEOUT = 2500; // msecs, (> 1000!)
private final static int REQUEST_RETRIES = 3; // Before we abandon
private final static String SERVER_ENDPOINT = "tcp://localhost:5555";
public static void main(String[] argv)
{
ZContext ctx = new ZContext();
System.out.println("I: connecting to server");
Socket client = ctx.createSocket(ZMQ.REQ);
assert (client != null);
client.connect(SERVER_ENDPOINT);
int sequence = 0;
int retriesLeft = REQUEST_RETRIES;
while (retriesLeft > 0 && !Thread.currentThread().isInterrupted()) {
// We send a request, then we work to get a reply
String request = String.format("%d", ++sequence);
client.send(request);
int expect_reply = 1;
while (expect_reply > 0) {
// Poll socket for a reply, with timeout
PollItem items[] = {new PollItem(client, Poller.POLLIN)};
int rc = ZMQ.poll(items, REQUEST_TIMEOUT);
if (rc == -1)
break; // Interrupted
// Here we process a server reply and exit our loop if the
// reply is valid. If we didn't a reply we close the client
// socket and resend the request. We try a number of times
// before finally abandoning:
if (items[0].isReadable()) {
// We got a reply from the server, must match getSequence
String reply = client.recvStr();
if (reply == null)
break; // Interrupted
if (Integer.parseInt(reply) == sequence) {
System.out.printf("I: server replied OK (%s)\n", reply);
retriesLeft = REQUEST_RETRIES;
expect_reply = 0;
} else
System.out.printf("E: malformed reply from server: %s\n",
reply);
} else if (--retriesLeft == 0) {
System.out.println("E: server seems to be offline, abandoning\n");
break;
} else {
System.out.println("W: no response from server, retrying\n");
// Old socket is confused; close it and open a new one
ctx.destroySocket(client);
System.out.println("I: reconnecting to server\n");
client = ctx.createSocket(ZMQ.REQ);
client.connect(SERVER_ENDPOINT);
// Send request again, on new socket
client.send(request);
}
}
}
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/lpserver.java 0000664 0000000 0000000 00000004025 12551504772 0021316 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.Random;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
//
// Lazy Pirate server
// Binds REQ socket to tcp://*:5555
// Like hwserver except:
// - echoes request as-is
// - randomly runs slowly, or exits to simulate a crash.
//
public class lpserver
{
public static void main(String[] argv) throws Exception
{
Random rand = new Random(System.nanoTime());
Context context = ZMQ.context(1);
Socket server = context.socket(ZMQ.REP);
server.bind("tcp://*:5555");
int cycles = 0;
while (true) {
String request = server.recvStr();
cycles++;
// Simulate various problems, after a few cycles
if (cycles > 3 && rand.nextInt(3) == 0) {
System.out.println("I: simulating a crash");
break;
} else if (cycles > 3 && rand.nextInt(3) == 0) {
System.out.println("I: simulating CPU overload");
Thread.sleep(2000);
}
System.out.printf("I: normal request (%s)\n", request);
Thread.sleep(1000); // Do some heavy work
server.send(request);
}
server.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/lruqueue3.java 0000664 0000000 0000000 00000013737 12551504772 0021420 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.LinkedList;
import java.util.Queue;
import org.zeromq.ZLoop;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMsg;
class ClientThread3 extends Thread
{
public void run()
{
ZContext context = new ZContext();
// Prepare our context and sockets
Socket client = context.createSocket(ZMQ.REQ);
// Initialize random number generator
client.connect("ipc://frontend.ipc");
// Send request, get reply
while (true) {
client.send("HELLO".getBytes(ZMQ.CHARSET), 0);
byte[] data = client.recv(0);
if (data == null)
break;
String reply = new String(data, ZMQ.CHARSET);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName() + " Client Sent HELLO");
}
context.destroy();
}
}
class WorkerThread3 extends Thread
{
public void run()
{
ZContext context = new ZContext();
// Prepare our context and sockets
Socket worker = context.createSocket(ZMQ.REQ);
worker.connect("ipc://backend.ipc");
ZFrame frame = new ZFrame(lruqueue3.LRU_READY);
// Tell backend we're ready for work
frame.send(worker, 0);
while (true) {
ZMsg msg = ZMsg.recvMsg(worker);
if (msg == null)
break;
msg.getLast().reset("OK".getBytes(ZMQ.CHARSET));
msg.send(worker);
System.out.println(Thread.currentThread().getName() + " Worker Sent OK");
}
context.destroy();
}
}
//Our LRU queue structure, passed to reactor handlers
class LRUQueueArg
{
Socket frontend; // Listen to clients
Socket backend; // Listen to workers
Queue workers; // List of ready workers
};
//In the reactor design, each time a message arrives on a socket, the
//reactor passes it to a handler function. We have two handlers; one
//for the frontend, one for the backend:
class FrontendHandler implements ZLoop.IZLoopHandler
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg_)
{
LRUQueueArg arg = (LRUQueueArg) arg_;
ZMsg msg = ZMsg.recvMsg(arg.frontend);
if (msg != null) {
msg.wrap(arg.workers.poll());
msg.send(arg.backend);
// Cancel reader on frontend if we went from 1 to 0 workers
if (arg.workers.size() == 0) {
PollItem poller = new PollItem(arg.frontend, ZMQ.Poller.POLLIN);
loop.removePoller(poller);
}
}
return 0;
}
}
class BackendHandler implements ZLoop.IZLoopHandler
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg_)
{
LRUQueueArg arg = (LRUQueueArg) arg_;
ZMsg msg = ZMsg.recvMsg(arg.backend);
if (msg != null) {
ZFrame address = msg.unwrap();
// Queue worker address for LRU routing
arg.workers.add(address);
// Enable reader on frontend if we went from 0 to 1 workers
if (arg.workers.size() == 1) {
PollItem poller = new PollItem(arg.frontend, ZMQ.Poller.POLLIN);
loop.addPoller(poller, lruqueue3.handle_frontend, arg);
}
// Forward message to client if it's not a READY
ZFrame frame = msg.getFirst();
if (new String(frame.getData(), ZMQ.CHARSET).equals(lruqueue3.LRU_READY))
msg.destroy();
else
msg.send(arg.frontend);
}
return 0;
}
}
public class lruqueue3
{
public final static String LRU_READY = "\001";
protected final static FrontendHandler handle_frontend = new FrontendHandler();
protected final static BackendHandler handle_backend = new BackendHandler();
public static void main(String[] args)
{
ZContext context = new ZContext();
LRUQueueArg arg = new LRUQueueArg();
// Prepare our context and sockets
Socket frontend = context.createSocket(ZMQ.ROUTER);
Socket backend = context.createSocket(ZMQ.ROUTER);
arg.frontend = frontend;
arg.backend = backend;
frontend.bind("ipc://frontend.ipc");
backend.bind("ipc://backend.ipc");
int client_nbr;
for (client_nbr = 0; client_nbr < 10; client_nbr++)
new ClientThread3().start();
int worker_nbr;
for (worker_nbr = 0; worker_nbr < 3; worker_nbr++)
new WorkerThread3().start();
// Queue of available workers
arg.workers = new LinkedList();
// Prepare reactor and fire it up
ZLoop reactor = new ZLoop();
reactor.verbose(true);
PollItem poller = new PollItem(arg.backend, ZMQ.Poller.POLLIN);
reactor.addPoller(poller, handle_backend, arg);
reactor.start();
reactor.destroy();
for (ZFrame frame : arg.workers) {
frame.destroy();
}
context.destroy();
System.exit(0);
}
}
jeromq-0.3.5/src/test/java/guide/lvcache.java 0000664 0000000 0000000 00000006521 12551504772 0021064 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
import java.util.HashMap;
import java.util.Map;
// Last value cache
// Uses XPUB subscription messages to re-send data
public class lvcache
{
public static void main(String[] args)
{
ZContext context = new ZContext();
Socket frontend = context.createSocket(ZMQ.SUB);
frontend.bind("tcp://*:5557");
Socket backend = context.createSocket(ZMQ.XPUB);
backend.bind("tcp://*:5558");
// Subscribe to every single topic from publisher
frontend.subscribe(ZMQ.SUBSCRIPTION_ALL);
// Store last instance of each topic in a cache
Map cache = new HashMap();
// .split main poll loop
// We route topic updates from frontend to backend, and
// we handle subscriptions by sending whatever we cached,
// if anything:
while (true) {
PollItem[] items = {
new PollItem(frontend, ZMQ.Poller.POLLIN),
new PollItem(backend, ZMQ.Poller.POLLIN),
};
if (ZMQ.poll(items, 1000) == -1)
break; // Interrupted
// Any new topic data we cache and then forward
if (items[0].isReadable()) {
String topic = frontend.recvStr();
String current = frontend.recvStr();
if (topic == null)
break;
cache.put(topic, current);
backend.sendMore(topic);
backend.send(current);
}
// .split handle subscriptions
// When we get a new subscription, we pull data from the cache:
if (items[1].isReadable()) {
ZFrame frame = ZFrame.recvFrame(backend);
if (frame == null)
break;
// Event is one byte 0=unsub or 1=sub, followed by topic
byte[] event = frame.getData();
if (event [0] == 1) {
String topic = new String(event, 1, event.length -1, ZMQ.CHARSET);
System.out.printf ("Sending cached topic %s\n", topic);
String previous = cache.get(topic);
if (previous != null) {
backend.sendMore(topic);
backend.send(previous);
}
}
frame.destroy();
}
}
context.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/mdbroker.java 0000664 0000000 0000000 00000031766 12551504772 0021275 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMsg;
/**
* Majordomo Protocol broker
* A minimal implementation of http://rfc.zeromq.org/spec:7 and spec:8
*/
public class mdbroker {
// We'd normally pull these from config data
private static final String INTERNAL_SERVICE_PREFIX = "mmi.";
private static final int HEARTBEAT_LIVENESS = 3; // 3-5 is reasonable
private static final int HEARTBEAT_INTERVAL = 2500; // msecs
private static final int HEARTBEAT_EXPIRY = HEARTBEAT_INTERVAL
* HEARTBEAT_LIVENESS;
// ---------------------------------------------------------------------
/**
* This defines a single service.
*/
private static class Service {
public final String name; // Service name
Deque requests; // List of client requests
Deque waiting; // List of waiting workers
public Service(String name) {
this.name = name;
this.requests = new ArrayDeque();
this.waiting = new ArrayDeque();
}
}
/**
* This defines one worker, idle or active.
*/
private static class Worker {
String identity;// Identity of worker
ZFrame address;// Address frame to route to
Service service; // Owning service, if known
long expiry;// Expires at unless heartbeat
public Worker(String identity, ZFrame address) {
this.address = address;
this.identity = identity;
this.expiry = System.currentTimeMillis() + HEARTBEAT_INTERVAL
* HEARTBEAT_LIVENESS;
}
}
// ---------------------------------------------------------------------
private ZContext ctx;// Our context
private ZMQ.Socket socket; // Socket for clients & workers
private long heartbeatAt;// When to send HEARTBEAT
private Map services;// known services
private Map workers;// known workers
private Deque waiting;// idle workers
private boolean verbose = false;// Print activity to stdout
private Formatter log = new Formatter(System.out);
// ---------------------------------------------------------------------
/**
* Main method - create and start new broker.
*/
public static void main(String[] args) {
mdbroker broker = new mdbroker(args.length > 0 && "-v".equals(args[0]));
// Can be called multiple times with different endpoints
broker.bind("tcp://*:5555");
broker.mediate();
}
/**
* Initialize broker state.
*/
public mdbroker(boolean verbose) {
this.verbose = verbose;
this.services = new HashMap();
this.workers = new HashMap();
this.waiting = new ArrayDeque();
this.heartbeatAt = System.currentTimeMillis() + HEARTBEAT_INTERVAL;
this.ctx = new ZContext();
this.socket = ctx.createSocket(ZMQ.ROUTER);
}
// ---------------------------------------------------------------------
/**
* Main broker work happens here
*/
public void mediate() {
while (!Thread.currentThread().isInterrupted()) {
ZMQ.Poller items = new ZMQ.Poller(1);
items.register(socket, ZMQ.Poller.POLLIN);
if (items.poll(HEARTBEAT_INTERVAL) == -1)
break; // Interrupted
if (items.pollin(0)) {
ZMsg msg = ZMsg.recvMsg(socket);
if (msg == null)
break; // Interrupted
if (verbose) {
log.format("I: received message:\n");
msg.dump(log.out());
}
ZFrame sender = msg.pop();
ZFrame empty = msg.pop();
ZFrame header = msg.pop();
if (MDP.C_CLIENT.frameEquals(header)) {
processClient(sender, msg);
} else if (MDP.W_WORKER.frameEquals(header))
processWorker(sender, msg);
else {
log.format("E: invalid message:\n");
msg.dump(log.out());
msg.destroy();
}
sender.destroy();
empty.destroy();
header.destroy();
}
purgeWorkers();
sendHeartbeats();
}
destroy(); // interrupted
}
/**
* Disconnect all workers, destroy context.
*/
private void destroy() {
Worker[] deleteList = workers.entrySet().toArray(new Worker[0]);
for (Worker worker : deleteList) {
deleteWorker(worker, true);
}
ctx.destroy();
}
/**
* Process a request coming from a client.
*/
private void processClient(ZFrame sender, ZMsg msg) {
assert (msg.size() >= 2); // Service name + body
ZFrame serviceFrame = msg.pop();
// Set reply return address to client sender
msg.wrap(sender.duplicate());
if (serviceFrame.toString().startsWith(INTERNAL_SERVICE_PREFIX))
serviceInternal(serviceFrame, msg);
else
dispatch(requireService(serviceFrame), msg);
serviceFrame.destroy();
}
/**
* Process message sent to us by a worker.
*/
private void processWorker(ZFrame sender, ZMsg msg) {
assert (msg.size() >= 1); // At least, command
ZFrame command = msg.pop();
boolean workerReady = workers.containsKey(sender.strhex());
Worker worker = requireWorker(sender);
if (MDP.W_READY.frameEquals(command)) {
// Not first command in session || Reserved service name
if (workerReady
|| sender.toString().startsWith(INTERNAL_SERVICE_PREFIX))
deleteWorker(worker, true);
else {
// Attach worker to service and mark as idle
ZFrame serviceFrame = msg.pop();
worker.service = requireService(serviceFrame);
workerWaiting(worker);
serviceFrame.destroy();
}
} else if (MDP.W_REPLY.frameEquals(command)) {
if (workerReady) {
// Remove & save client return envelope and insert the
// protocol header and service name, then rewrap envelope.
ZFrame client = msg.unwrap();
msg.addFirst(worker.service.name);
msg.addFirst(MDP.C_CLIENT.newFrame());
msg.wrap(client);
msg.send(socket);
workerWaiting(worker);
} else {
deleteWorker(worker, true);
}
} else if (MDP.W_HEARTBEAT.frameEquals(command)) {
if (workerReady) {
worker.expiry = System.currentTimeMillis() + HEARTBEAT_EXPIRY;
} else {
deleteWorker(worker, true);
}
} else if (MDP.W_DISCONNECT.frameEquals(command))
deleteWorker(worker, false);
else {
log.format("E: invalid message:\n");
msg.dump(log.out());
}
msg.destroy();
}
/**
* Deletes worker from all data structures, and destroys worker.
*/
private void deleteWorker(Worker worker, boolean disconnect) {
assert (worker != null);
if (disconnect) {
sendToWorker(worker, MDP.W_DISCONNECT, null, null);
}
if (worker.service != null)
worker.service.waiting.remove(worker);
workers.remove(worker);
worker.address.destroy();
}
/**
* Finds the worker (creates if necessary).
*/
private Worker requireWorker(ZFrame address) {
assert (address != null);
String identity = address.strhex();
Worker worker = workers.get(identity);
if (worker == null) {
worker = new Worker(identity, address.duplicate());
workers.put(identity, worker);
if (verbose)
log.format("I: registering new worker: %s\n", identity);
}
return worker;
}
/**
* Locates the service (creates if necessary).
*/
private Service requireService(ZFrame serviceFrame) {
assert (serviceFrame != null);
String name = serviceFrame.toString();
Service service = services.get(name);
if (service == null) {
service = new Service(name);
services.put(name, service);
}
return service;
}
/**
* Bind broker to endpoint, can call this multiple times. We use a single
* socket for both clients and workers.
*/
private void bind(String endpoint) {
socket.bind(endpoint);
log.format("I: MDP broker/0.1.1 is active at %s\n", endpoint);
}
/**
* Handle internal service according to 8/MMI specification
*/
private void serviceInternal(ZFrame serviceFrame, ZMsg msg) {
String returnCode = "501";
if ("mmi.service".equals(serviceFrame.toString())) {
String name = msg.peekLast().toString();
returnCode = services.containsKey(name) ? "200" : "400";
}
msg.peekLast().reset(returnCode.getBytes(ZMQ.CHARSET));
// Remove & save client return envelope and insert the
// protocol header and service name, then rewrap envelope.
ZFrame client = msg.unwrap();
msg.addFirst(serviceFrame.duplicate());
msg.addFirst(MDP.C_CLIENT.newFrame());
msg.wrap(client);
msg.send(socket);
}
/**
* Send heartbeats to idle workers if it's time
*/
public synchronized void sendHeartbeats() {
// Send heartbeats to idle workers if it's time
if (System.currentTimeMillis() >= heartbeatAt) {
for (Worker worker : waiting) {
sendToWorker(worker, MDP.W_HEARTBEAT, null, null);
}
heartbeatAt = System.currentTimeMillis() + HEARTBEAT_INTERVAL;
}
}
/**
* Look for & kill expired workers. Workers are oldest to most recent, so we
* stop at the first alive worker.
*/
public synchronized void purgeWorkers() {
for (Worker w = waiting.peekFirst(); w != null
&& w.expiry < System.currentTimeMillis(); w = waiting
.peekFirst()) {
log.format("I: deleting expired worker: %s\n", w.identity);
deleteWorker(waiting.pollFirst(), false);
}
}
/**
* This worker is now waiting for work.
*/
public synchronized void workerWaiting(Worker worker) {
// Queue to broker and service waiting lists
waiting.addLast(worker);
worker.service.waiting.addLast(worker);
worker.expiry = System.currentTimeMillis() + HEARTBEAT_EXPIRY;
dispatch(worker.service, null);
}
/**
* Dispatch requests to waiting workers as possible
*/
private void dispatch(Service service, ZMsg msg) {
assert (service != null);
if (msg != null)// Queue message if any
service.requests.offerLast(msg);
purgeWorkers();
while (!service.waiting.isEmpty() && !service.requests.isEmpty()) {
msg = service.requests.pop();
Worker worker = service.waiting.pop();
waiting.remove(worker);
sendToWorker(worker, MDP.W_REQUEST, null, msg);
msg.destroy();
}
}
/**
* Send message to worker. If message is provided, sends that message. Does
* not destroy the message, this is the caller's job.
*/
public void sendToWorker(Worker worker, MDP command, String option,
ZMsg msgp) {
ZMsg msg = msgp == null ? new ZMsg() : msgp.duplicate();
// Stack protocol envelope to start of message
if (option != null)
msg.addFirst(new ZFrame(option));
msg.addFirst(command.newFrame());
msg.addFirst(MDP.W_WORKER.newFrame());
// Stack routing envelope to start of message
msg.wrap(worker.address.duplicate());
if (verbose) {
log.format("I: sending %s to worker\n", command);
msg.dump(log.out());
}
msg.send(socket);
}
}
jeromq-0.3.5/src/test/java/guide/mdcliapi.java 0000664 0000000 0000000 00000010201 12551504772 0021227 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.Formatter;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMsg;
/**
* Majordomo Protocol Client API, Java version Implements the MDP/Worker spec at
* http://rfc.zeromq.org/spec:7.
*
*/
public class mdcliapi {
private String broker;
private ZContext ctx;
private ZMQ.Socket client;
private long timeout = 2500;
private int retries = 3;
private boolean verbose;
private Formatter log = new Formatter(System.out);
public long getTimeout() {
return timeout;
}
public void setTimeout(long timeout) {
this.timeout = timeout;
}
public int getRetries() {
return retries;
}
public void setRetries(int retries) {
this.retries = retries;
}
public mdcliapi(String broker, boolean verbose) {
this.broker = broker;
this.verbose = verbose;
ctx = new ZContext();
reconnectToBroker();
}
/**
* Connect or reconnect to broker
*/
void reconnectToBroker() {
if (client != null) {
ctx.destroySocket(client);
}
client = ctx.createSocket(ZMQ.REQ);
client.connect(broker);
if (verbose)
log.format("I: connecting to broker at %s\n", broker);
}
/**
* Send request to broker and get reply by hook or crook Takes ownership of
* request message and destroys it when sent. Returns the reply message or
* NULL if there was no reply.
*
* @param service
* @param request
* @return
*/
public ZMsg send(String service, ZMsg request) {
request.push(new ZFrame(service));
request.push(MDP.C_CLIENT.newFrame());
if (verbose) {
log.format("I: send request to '%s' service: \n", service);
request.dump(log.out());
}
ZMsg reply = null;
int retriesLeft = retries;
while (retriesLeft > 0 && !Thread.currentThread().isInterrupted()) {
request.duplicate().send(client);
// Poll socket for a reply, with timeout
ZMQ.Poller items = new ZMQ.Poller(1);
items.register(client, ZMQ.Poller.POLLIN);
if (items.poll(timeout) == -1)
break; // Interrupted
if (items.pollin(0)) {
ZMsg msg = ZMsg.recvMsg(client);
if (verbose){
log.format("I: received reply: \n");
msg.dump(log.out());
}
// Don't try to handle errors, just assert noisily
assert (msg.size() >= 3);
ZFrame header = msg.pop();
assert (MDP.C_CLIENT.equals(header.toString()));
header.destroy();
ZFrame replyService = msg.pop();
assert (service.equals(replyService.toString()));
replyService.destroy();
reply = msg;
break;
} else {
items.unregister(client);
if (--retriesLeft == 0) {
log.format("W: permanent error, abandoning\n");
break;
}
log.format("W: no reply, reconnecting\n");
reconnectToBroker();
}
}
request.destroy();
return reply;
}
public void destroy() {
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/mdcliapi2.java 0000664 0000000 0000000 00000007571 12551504772 0021331 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.Formatter;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMsg;
/**
* Majordomo Protocol Client API, asynchronous Java version. Implements the
* MDP/Worker spec at http://rfc.zeromq.org/spec:7.
*/
public class mdcliapi2 {
private String broker;
private ZContext ctx;
private ZMQ.Socket client;
private long timeout = 2500;
private boolean verbose;
private Formatter log = new Formatter(System.out);
public long getTimeout() {
return timeout;
}
public void setTimeout(long timeout) {
this.timeout = timeout;
}
public mdcliapi2(String broker, boolean verbose) {
this.broker = broker;
this.verbose = verbose;
ctx = new ZContext();
reconnectToBroker();
}
/**
* Connect or reconnect to broker
*/
void reconnectToBroker() {
if (client != null) {
ctx.destroySocket(client);
}
client = ctx.createSocket(ZMQ.DEALER);
client.connect(broker);
if (verbose)
log.format("I: connecting to broker at %s...\n", broker);
}
/**
* Returns the reply message or NULL if there was no reply. Does not attempt
* to recover from a broker failure, this is not possible without storing
* all unanswered requests and resending them all…
*/
public ZMsg recv() {
ZMsg reply = null;
// Poll socket for a reply, with timeout
ZMQ.Poller items = new ZMQ.Poller(1);
items.register(client, ZMQ.Poller.POLLIN);
if (items.poll(timeout * 1000) == -1)
return null; // Interrupted
if (items.pollin(0)) {
ZMsg msg = ZMsg.recvMsg(client);
if (verbose) {
log.format("I: received reply: \n");
msg.dump(log.out());
}
// Don't try to handle errors, just assert noisily
assert (msg.size() >= 4);
ZFrame empty = msg.pop();
assert (empty.getData().length == 0);
empty.destroy();
ZFrame header = msg.pop();
assert (MDP.C_CLIENT.equals(header.toString()));
header.destroy();
ZFrame replyService = msg.pop();
replyService.destroy();
reply = msg;
}
return reply;
}
/**
* Send request to broker and get reply by hook or crook Takes ownership of
* request message and destroys it when sent.
*/
public boolean send(String service, ZMsg request) {
assert (request != null);
// Prefix request with protocol frames
// Frame 0: empty (REQ emulation)
// Frame 1: "MDPCxy" (six bytes, MDP/Client x.y)
// Frame 2: Service name (printable string)
request.addFirst(service);
request.addFirst(MDP.C_CLIENT.newFrame());
request.addFirst("");
if (verbose) {
log.format("I: send request to '%s' service: \n", service);
request.dump(log.out());
}
return request.send(client);
}
public void destroy() {
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/mdclient.java 0000664 0000000 0000000 00000003053 12551504772 0021253 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMsg;
/**
* Majordomo Protocol client example. Uses the mdcli API to hide all MDP aspects
*/
public class mdclient {
public static void main(String[] args) {
boolean verbose = (args.length > 0 && "-v".equals(args[0]));
mdcliapi clientSession = new mdcliapi("tcp://localhost:5555", verbose);
int count;
for (count = 0; count < 100000; count++) {
ZMsg request = new ZMsg();
request.addString("Hello world");
ZMsg reply = clientSession.send("echo", request);
if (reply != null)
reply.destroy();
else
break; // Interrupt or failure
}
System.out.printf("%d requests/replies processed\n", count);
clientSession.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/mdclient2.java 0000664 0000000 0000000 00000003241 12551504772 0021334 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMsg;
/**
* Majordomo Protocol client example, asynchronous. Uses the mdcli API to hide
* all MDP aspects
*/
public class mdclient2 {
public static void main(String[] args) {
boolean verbose = (args.length > 0 && "-v".equals(args[0]));
mdcliapi2 clientSession = new mdcliapi2("tcp://localhost:5555", verbose);
int count;
for (count = 0; count < 100000; count++) {
ZMsg request = new ZMsg();
request.addString("Hello world");
clientSession.send("echo", request);
}
for (count = 0; count < 100000; count++) {
ZMsg reply = clientSession.recv();
if (reply != null)
reply.destroy();
else
break; // Interrupt or failure
}
System.out.printf("%d requests/replies processed\n", count);
clientSession.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/mdworker.java 0000664 0000000 0000000 00000002701 12551504772 0021305 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMsg;
/**
* Majordomo Protocol worker example. Uses the mdwrk API to hide all MDP aspects
*
*/
public class mdworker {
/**
* @param args
*/
public static void main(String[] args) {
boolean verbose = (args.length > 0 && "-v".equals(args[0]));
mdwrkapi workerSession = new mdwrkapi("tcp://localhost:5555", "echo", verbose);
ZMsg reply = null;
while (!Thread.currentThread().isInterrupted()) {
ZMsg request = workerSession.receive(reply);
if (request == null)
break; //Interrupted
reply = request; // Echo is complex :-)
}
workerSession.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/mdwrkapi.java 0000664 0000000 0000000 00000015650 12551504772 0021300 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.Formatter;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMsg;
/**
* Majordomo Protocol Client API, Java version Implements the MDP/Worker spec at
* http://rfc.zeromq.org/spec:7.
*/
public class mdwrkapi {
private static final int HEARTBEAT_LIVENESS = 3; // 3-5 is reasonable
private String broker;
private ZContext ctx;
private String service;
private ZMQ.Socket worker; // Socket to broker
private long heartbeatAt;// When to send HEARTBEAT
private int liveness;// How many attempts left
private int heartbeat = 2500;// Heartbeat delay, msecs
private int reconnect = 2500; // Reconnect delay, msecs
// Internal state
private boolean expectReply = false; // false only at start
private long timeout = 2500;
private boolean verbose;// Print activity to stdout
private Formatter log = new Formatter(System.out);
// Return address, if any
private ZFrame replyTo;
public mdwrkapi(String broker, String service, boolean verbose) {
assert (broker != null);
assert (service != null);
this.broker = broker;
this.service = service;
this.verbose = verbose;
ctx = new ZContext();
reconnectToBroker();
}
/**
* Send message to broker If no msg is provided, creates one internally
*
* @param command
* @param option
* @param msg
*/
void sendToBroker(MDP command, String option, ZMsg msg) {
msg = msg != null ? msg.duplicate() : new ZMsg();
// Stack protocol envelope to start of message
if (option != null)
msg.addFirst(new ZFrame(option));
msg.addFirst(command.newFrame());
msg.addFirst(MDP.W_WORKER.newFrame());
msg.addFirst(new ZFrame(ZMQ.MESSAGE_SEPARATOR));
if (verbose) {
log.format("I: sending %s to broker\n", command);
msg.dump(log.out());
}
msg.send(worker);
}
/**
* Connect or reconnect to broker
*/
void reconnectToBroker() {
if (worker != null) {
ctx.destroySocket(worker);
}
worker = ctx.createSocket(ZMQ.DEALER);
worker.connect(broker);
if (verbose)
log.format("I: connecting to broker at %s\n", broker);
// Register service with broker
sendToBroker(MDP.W_READY, service, null);
// If liveness hits zero, queue is considered disconnected
liveness = HEARTBEAT_LIVENESS;
heartbeatAt = System.currentTimeMillis() + heartbeat;
}
/**
* Send reply, if any, to broker and wait for next request.
*/
public ZMsg receive(ZMsg reply) {
// Format and send the reply if we were provided one
assert (reply != null || !expectReply);
if (reply != null) {
assert (replyTo != null);
reply.wrap(replyTo);
sendToBroker(MDP.W_REPLY, null, reply);
reply.destroy();
}
expectReply = true;
while (!Thread.currentThread().isInterrupted()) {
// Poll socket for a reply, with timeout
ZMQ.Poller items = new ZMQ.Poller(1);
items.register(worker, ZMQ.Poller.POLLIN);
if (items.poll(timeout) == -1)
break; // Interrupted
if (items.pollin(0)) {
ZMsg msg = ZMsg.recvMsg(worker);
if (msg == null)
break; // Interrupted
if (verbose) {
log.format("I: received message from broker: \n");
msg.dump(log.out());
}
liveness = HEARTBEAT_LIVENESS;
// Don't try to handle errors, just assert noisily
assert (msg != null && msg.size() >= 3);
ZFrame empty = msg.pop();
assert (empty.getData().length == 0);
empty.destroy();
ZFrame header = msg.pop();
assert (MDP.W_WORKER.frameEquals(header));
header.destroy();
ZFrame command = msg.pop();
if (MDP.W_REQUEST.frameEquals(command)) {
// We should pop and save as many addresses as there are
// up to a null part, but for now, just save one
replyTo = msg.unwrap();
command.destroy();
return msg; // We have a request to process
} else if (MDP.W_HEARTBEAT.frameEquals(command)) {
// Do nothing for heartbeats
} else if (MDP.W_DISCONNECT.frameEquals(command)) {
reconnectToBroker();
} else {
log.format("E: invalid input message: \n");
msg.dump(log.out());
}
command.destroy();
msg.destroy();
} else if (--liveness == 0) {
if (verbose)
log.format("W: disconnected from broker - retrying\n");
try {
Thread.sleep(reconnect);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // Restore the
// interrupted status
break;
}
reconnectToBroker();
}
// Send HEARTBEAT if it's time
if (System.currentTimeMillis() > heartbeatAt) {
sendToBroker(MDP.W_HEARTBEAT, null, null);
heartbeatAt = System.currentTimeMillis() + heartbeat;
}
}
if (Thread.currentThread().isInterrupted())
log.format("W: interrupt received, killing worker\n");
return null;
}
public void destroy() {
ctx.destroy();
}
// ============== getters and setters =================
public int getHeartbeat() {
return heartbeat;
}
public void setHeartbeat(int heartbeat) {
this.heartbeat = heartbeat;
}
public int getReconnect() {
return reconnect;
}
public void setReconnect(int reconnect) {
this.reconnect = reconnect;
}
}
jeromq-0.3.5/src/test/java/guide/mmiecho.java 0000664 0000000 0000000 00000003145 12551504772 0021077 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMsg;
/**
* MMI echo query example
*/
public class mmiecho {
public static void main(String[] args) {
boolean verbose = (args.length > 0 && "-v".equals(args[0]));
mdcliapi clientSession = new mdcliapi("tcp://localhost:5555", verbose);
ZMsg request = new ZMsg();
// This is the service we want to look up
request.addString("echo");
// This is the service we send our request to
ZMsg reply = clientSession.send("mmi.service", request);
if (reply != null) {
String replyCode = reply.getFirst().toString();
System.out.printf("Lookup echo service: %s\n", replyCode);
} else {
System.out
.println("E: no response from broker, make sure it's running");
}
clientSession.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/msgqueue.java 0000664 0000000 0000000 00000003052 12551504772 0021306 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
/**
* Simple message queuing broker
* Same as request-reply broker but using QUEUE device.
*/
public class msgqueue{
public static void main (String[] args) {
// Prepare our context and sockets
Context context = ZMQ.context(1);
// Socket facing clients
Socket frontend = context.socket(ZMQ.ROUTER);
frontend.bind("tcp://*:5559");
// Socket facing services
Socket backend = context.socket(ZMQ.DEALER);
backend.bind("tcp://*:5560");
// Start the proxy
ZMQ.proxy (frontend, backend, null);
// We never get here but clean up anyhow
frontend.close();
backend.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/mspoller.java 0000664 0000000 0000000 00000004037 12551504772 0021314 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
//
// Reading from multiple sockets in Java
// This version uses ZMQ.Poller
//
public class mspoller {
public static void main (String[] args) {
ZMQ.Context context = ZMQ.context(1);
// Connect to task ventilator
ZMQ.Socket receiver = context.socket(ZMQ.PULL);
receiver.connect("tcp://localhost:5557");
// Connect to weather server
ZMQ.Socket subscriber = context.socket(ZMQ.SUB);
subscriber.connect("tcp://localhost:5556");
subscriber.subscribe("10001 ".getBytes(ZMQ.CHARSET));
// Initialize poll set
ZMQ.Poller items = new ZMQ.Poller (2);
items.register(receiver, ZMQ.Poller.POLLIN);
items.register(subscriber, ZMQ.Poller.POLLIN);
// Process messages from both sockets
while (!Thread.currentThread ().isInterrupted ()) {
byte[] message;
items.poll();
if (items.pollin(0)) {
message = receiver.recv(0);
System.out.println("Process task");
}
if (items.pollin(1)) {
message = subscriber.recv(0);
System.out.println("Process weather update");
}
}
receiver.close ();
context.term ();
}
}
jeromq-0.3.5/src/test/java/guide/msreader.java 0000664 0000000 0000000 00000004173 12551504772 0021262 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
//
// Reading from multiple sockets in Java
// This version uses a simple recv loop
//
public class msreader {
public static void main (String[] args) throws Exception {
// Prepare our context and sockets
ZMQ.Context context = ZMQ.context(1);
// Connect to task ventilator
ZMQ.Socket receiver = context.socket(ZMQ.PULL);
receiver.connect("tcp://localhost:5557");
// Connect to weather server
ZMQ.Socket subscriber = context.socket(ZMQ.SUB);
subscriber.connect("tcp://localhost:5556");
subscriber.subscribe("10001 ".getBytes(ZMQ.CHARSET));
// Process messages from both sockets
// We prioritize traffic from the task ventilator
while (!Thread.currentThread ().isInterrupted ()) {
// Process any waiting tasks
byte[] task;
while((task = receiver.recv(ZMQ.DONTWAIT)) != null) {
System.out.println("process task");
}
// Process any waiting weather updates
byte[] update;
while ((update = subscriber.recv(ZMQ.DONTWAIT)) != null) {
System.out.println("process weather update");
}
// No activity, so sleep for 1 msec
Thread.sleep(1000);
}
subscriber.close ();
context.term ();
}
}
jeromq-0.3.5/src/test/java/guide/mtrelay.java 0000664 0000000 0000000 00000005372 12551504772 0021137 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
/**
* Multithreaded relay
*/
public class mtrelay{
private static class Step1 extends Thread
{
private Context context;
private Step1 (Context context)
{
this.context = context;
}
@Override
public void run(){
// Signal downstream to step 2
Socket xmitter = context.socket(ZMQ.PAIR);
xmitter.connect("inproc://step2");
System.out.println ("Step 1 ready, signaling step 2");
xmitter.send("READY", 0);
xmitter.close ();
}
}
private static class Step2 extends Thread
{
private Context context;
private Step2 (Context context)
{
this.context = context;
}
@Override
public void run(){
// Bind to inproc: endpoint, then start upstream thread
Socket receiver = context.socket(ZMQ.PAIR);
receiver.bind("inproc://step2");
Thread step1 = new Step1 (context);
step1.start();
// Wait for signal
receiver.recv(0);
receiver.close ();
// Connect to step3 and tell it we're ready
Socket xmitter = context.socket(ZMQ.PAIR);
xmitter.connect("inproc://step3");
xmitter.send("READY", 0);
xmitter.close ();
}
}
public static void main (String[] args) {
Context context = ZMQ.context(1);
// Bind to inproc: endpoint, then start upstream thread
Socket receiver = context.socket(ZMQ.PAIR);
receiver.bind("inproc://step3");
// Step 2 relays the signal to step 3
Thread step2 = new Step2 (context);
step2.start();
// Wait for signal
receiver.recv(0);
receiver.close ();
System.out.println ("Test successful!");
context.term ();
}
}
jeromq-0.3.5/src/test/java/guide/mtserver.java 0000664 0000000 0000000 00000004705 12551504772 0021330 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
/**
* Multi threaded Hello World server
*/
public class mtserver {
private static class Worker extends Thread
{
private Context context;
private Worker (Context context)
{
this.context = context;
}
@Override
public void run() {
ZMQ.Socket socket = context.socket(ZMQ.REP);
socket.connect ("inproc://workers");
while (true) {
// Wait for next request from client (C string)
String request = socket.recvStr (0);
System.out.println ( Thread.currentThread().getName() + " Received request: [" + request + "]");
// Do some 'work'
try {
Thread.sleep (1000);
} catch (InterruptedException e) {
}
// Send reply back to client (C string)
socket.send("world", 0);
}
}
}
public static void main (String[] args) {
Context context = ZMQ.context(1);
Socket clients = context.socket(ZMQ.ROUTER);
clients.bind ("tcp://*:5555");
Socket workers = context.socket(ZMQ.DEALER);
workers.bind ("inproc://workers");
for(int thread_nbr = 0; thread_nbr < 5; thread_nbr++) {
Thread worker = new Worker (context);
worker.start();
}
// Connect work threads to client threads via a queue
ZMQ.proxy (clients, workers, null);
// We never get here but clean up anyhow
clients.close();
workers.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/pathopub.java 0000664 0000000 0000000 00000003743 12551504772 0021304 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Socket;
import java.util.Random;
// Pathological publisher
// Sends out 1,000 topics and then one random update per second
public class pathopub
{
public static void main(String[] args) throws Exception
{
ZContext context = new ZContext();
Socket publisher = context.createSocket(ZMQ.PUB);
if (args.length == 1)
publisher.connect(args[0]);
else
publisher.bind("tcp://*:5556");
// Ensure subscriber connection has time to complete
Thread.sleep(1000);
// Send out all 1,000 topic messages
int topicNbr;
for (topicNbr = 0; topicNbr < 1000; topicNbr++) {
publisher.send(String.format("%03d", topicNbr), ZMQ.SNDMORE);
publisher.send("Save Roger");
}
// Send one random update per second
Random rand = new Random(System.currentTimeMillis());
while (!Thread.currentThread().isInterrupted()) {
Thread.sleep(1000);
publisher.send(String.format("%03d", rand.nextInt(1000)), ZMQ.SNDMORE);
publisher.send("Off with his head!");
}
context.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/pathosub.java 0000664 0000000 0000000 00000003413 12551504772 0021301 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Socket;
import java.util.Random;
// Pathological subscriber
// Subscribes to one random topic and prints received messages
public class pathosub
{
public static void main(String[] args)
{
ZContext context = new ZContext();
Socket subscriber = context.createSocket(ZMQ.SUB);
if (args.length == 1)
subscriber.connect(args[0]);
else
subscriber.connect("tcp://localhost:5556");
Random rand = new Random(System.currentTimeMillis());
String subscription = String.format("%03d", rand.nextInt(1000));
subscriber.subscribe(subscription.getBytes(ZMQ.CHARSET));
while (true) {
String topic = subscriber.recvStr();
if (topic == null)
break;
String data = subscriber.recvStr();
assert(topic.equals(subscription));
System.out.println(data);
}
context.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/peering1.java 0000664 0000000 0000000 00000006123 12551504772 0021167 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.Random;
import org.zeromq.ZMQ.Poller;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
// Broker peering simulation (part 1)
// Prototypes the state flow
public class peering1
{
public static void main(String[] argv)
{
// First argument is this broker's name
// Other arguments are our peers' names
//
if (argv.length < 1) {
System.out.println("syntax: peering1 me {you}\n");
System.exit(-1);
}
String self = argv[0];
System.out.println(String.format("I: preparing broker at %s\n", self));
Random rand = new Random(System.nanoTime());
ZContext ctx = new ZContext();
// Bind state backend to endpoint
Socket statebe = ctx.createSocket(ZMQ.PUB);
statebe.bind(String.format("ipc://%s-state.ipc", self));
// Connect statefe to all peers
Socket statefe = ctx.createSocket(ZMQ.SUB);
statefe.subscribe(ZMQ.SUBSCRIPTION_ALL);
int argn;
for (argn = 1; argn < argv.length; argn++) {
String peer = argv[argn];
System.out.printf("I: connecting to state backend at '%s'\n", peer);
statefe.connect(String.format("ipc://%s-state.ipc", peer));
}
// The main loop sends out status messages to peers, and collects
// status messages back from peers. The zmq_poll timeout defines
// our own heartbeat:
while (true) {
// Poll for activity, or 1 second timeout
PollItem items[] = {new PollItem(statefe, Poller.POLLIN)};
int rc = ZMQ.poll(items, 1000);
if (rc == -1)
break; // Interrupted
// Handle incoming status messages
if (items[0].isReadable()) {
String peer_name = new String(statefe.recv(0), ZMQ.CHARSET);
String available = new String(statefe.recv(0), ZMQ.CHARSET);
System.out.printf("%s - %s workers free\n", peer_name, available);
} else {
// Send random values for worker availability
statebe.send(self, ZMQ.SNDMORE);
statebe.send(String.format("%d", rand.nextInt(10)), 0);
}
}
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/peering2.java 0000664 0000000 0000000 00000023013 12551504772 0021165 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Poller;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
// Broker peering simulation (part 2)
// Prototypes the request-reply flow
public class peering2
{
private static final int NBR_CLIENTS = 10;
private static final int NBR_WORKERS = 3;
private static final String WORKER_READY = "\001"; // Signals worker is ready
// Our own name; in practice this would be configured per node
private static String self;
// The client task does a request-reply dialog using a standard
// synchronous REQ socket:
private static class client_task extends Thread
{
@Override
public void run()
{
ZContext ctx = new ZContext();
Socket client = ctx.createSocket(ZMQ.REQ);
client.connect(String.format("ipc://%s-localfe.ipc", self));
while (true) {
// Send request, get reply
client.send("HELLO", 0);
String reply = client.recvStr(0);
if (reply == null)
break; // Interrupted
System.out.printf("Client: %s\n", reply);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
ctx.destroy();
}
}
// The worker task plugs into the LRU routing dialog using a REQ
// socket:
private static class worker_task extends Thread
{
@Override
public void run()
{
ZContext ctx = new ZContext();
Socket worker = ctx.createSocket(ZMQ.REQ);
worker.connect(String.format("ipc://%s-localbe.ipc", self));
// Tell broker we're ready for work
ZFrame frame = new ZFrame(WORKER_READY);
frame.send(worker, 0);
while (true) {
// Send request, get reply
ZMsg msg = ZMsg.recvMsg(worker, 0);
if (msg == null)
break; // Interrupted
msg.getLast().print("Worker: ");
msg.getLast().reset("OK");
msg.send(worker);
}
ctx.destroy();
}
}
// The main task begins by setting-up its frontend and backend sockets
// and then starting its client and worker tasks:
public static void main(String[] argv)
{
// First argument is this broker's name
// Other arguments are our peers' names
//
if (argv.length < 1) {
System.out.println("syntax: peering2 me {you}");
System.exit(-1);
}
self = argv[0];
System.out.printf("I: preparing broker at %s\n", self);
Random rand = new Random(System.nanoTime());
ZContext ctx = new ZContext();
// Bind cloud frontend to endpoint
Socket cloudfe = ctx.createSocket(ZMQ.ROUTER);
cloudfe.setIdentity(self.getBytes(ZMQ.CHARSET));
cloudfe.bind(String.format("ipc://%s-cloud.ipc", self));
// Connect cloud backend to all peers
Socket cloudbe = ctx.createSocket(ZMQ.ROUTER);
cloudbe.setIdentity(self.getBytes(ZMQ.CHARSET));
int argn;
for (argn = 1; argn < argv.length; argn++) {
String peer = argv[argn];
System.out.printf("I: connecting to cloud forintend at '%s'\n", peer);
cloudbe.connect(String.format("ipc://%s-cloud.ipc", peer));
}
// Prepare local frontend and backend
Socket localfe = ctx.createSocket(ZMQ.ROUTER);
localfe.bind(String.format("ipc://%s-localfe.ipc", self));
Socket localbe = ctx.createSocket(ZMQ.ROUTER);
localbe.bind(String.format("ipc://%s-localbe.ipc", self));
// Get user to tell us when we can start
System.out.println("Press Enter when all brokers are started: ");
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
// Start local workers
int worker_nbr;
for (worker_nbr = 0; worker_nbr < NBR_WORKERS; worker_nbr++)
new worker_task().start();
// Start local clients
int client_nbr;
for (client_nbr = 0; client_nbr < NBR_CLIENTS; client_nbr++)
new client_task().start();
// Here we handle the request-reply flow. We're using the LRU approach
// to poll workers at all times, and clients only when there are one or
// more workers available.
// Least recently used queue of available workers
int capacity = 0;
ArrayList workers = new ArrayList();
while (true) {
// First, route any waiting replies from workers
PollItem backends[] = {
new PollItem(localbe, Poller.POLLIN),
new PollItem(cloudbe, Poller.POLLIN)
};
// If we have no workers anyhow, wait indefinitely
int rc = ZMQ.poll(backends,
capacity > 0 ? 1000 : -1);
if (rc == -1)
break; // Interrupted
// Handle reply from local worker
ZMsg msg = null;
if (backends[0].isReadable()) {
msg = ZMsg.recvMsg(localbe);
if (msg == null)
break; // Interrupted
ZFrame address = msg.unwrap();
workers.add(address);
capacity++;
// If it's READY, don't route the message any further
ZFrame frame = msg.getFirst();
if (new String(frame.getData(), ZMQ.CHARSET).equals(WORKER_READY)) {
msg.destroy();
msg = null;
}
}
// Or handle reply from peer broker
else if (backends[1].isReadable()) {
msg = ZMsg.recvMsg(cloudbe);
if (msg == null)
break; // Interrupted
// We don't use peer broker address for anything
ZFrame address = msg.unwrap();
address.destroy();
}
// Route reply to cloud if it's addressed to a broker
for (argn = 1; msg != null && argn < argv.length; argn++) {
byte[] data = msg.getFirst().getData();
if (argv[argn].equals(new String(data, ZMQ.CHARSET))) {
msg.send(cloudfe);
msg = null;
}
}
// Route reply to client if we still need to
if (msg != null)
msg.send(localfe);
// Now we route as many client requests as we have worker capacity
// for. We may reroute requests from our local frontend, but not from //
// the cloud frontend. We reroute randomly now, just to test things
// out. In the next version we'll do this properly by calculating
// cloud capacity://
while (capacity > 0) {
PollItem frontends[] = {
new PollItem(localfe, Poller.POLLIN),
new PollItem(cloudfe, Poller.POLLIN)
};
rc = ZMQ.poll(frontends, 0);
assert (rc >= 0);
int reroutable = 0;
// We'll do peer brokers first, to prevent starvation
if (frontends[1].isReadable()) {
msg = ZMsg.recvMsg(cloudfe);
reroutable = 0;
} else if (frontends[0].isReadable()) {
msg = ZMsg.recvMsg(localfe);
reroutable = 1;
} else
break; // No work, go back to backends
// If reroutable, send to cloud 20% of the time
// Here we'd normally use cloud status information
//
if (reroutable != 0 && argv.length > 1 && rand.nextInt(5) == 0) {
// Route to random broker peer
int random_peer = rand.nextInt(argv.length - 1) + 1;
msg.push(argv[random_peer]);
msg.send(cloudbe);
} else {
ZFrame frame = workers.remove(0);
msg.wrap(frame);
msg.send(localbe);
capacity--;
}
}
}
// When we're done, clean up properly
while (workers.size() > 0) {
ZFrame frame = workers.remove(0);
frame.destroy();
}
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/peering3.java 0000664 0000000 0000000 00000031726 12551504772 0021200 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.ArrayList;
import java.util.Random;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Poller;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
// Broker peering simulation (part 3)
// Prototypes the full flow of status and tasks
public class peering3
{
private static final int NBR_CLIENTS = 10;
private static final int NBR_WORKERS = 5;
private static final String WORKER_READY = "\001"; // Signals worker is ready
// Our own name; in practice this would be configured per node
private static String self;
// This is the client task. It issues a burst of requests and then
// sleeps for a few seconds. This simulates sporadic activity; when
// a number of clients are active at once, the local workers should
// be overloaded. The client uses a REQ socket for requests and also
// pushes statistics to the monitor socket:
private static class client_task extends Thread
{
@Override
public void run()
{
ZContext ctx = new ZContext();
Socket client = ctx.createSocket(ZMQ.REQ);
client.connect(String.format("ipc://%s-localfe.ipc", self));
Socket monitor = ctx.createSocket(ZMQ.PUSH);
monitor.connect(String.format("ipc://%s-monitor.ipc", self));
Random rand = new Random(System.nanoTime());
while (true) {
try {
Thread.sleep(rand.nextInt(5) * 1000);
} catch (InterruptedException e1) {
}
int burst = rand.nextInt(15);
while (burst > 0) {
String taskId = String.format("%04X", rand.nextInt(10000));
// Send request, get reply
client.send(taskId, 0);
// Wait max ten seconds for a reply, then complain
PollItem pollSet[] = {new PollItem(client, Poller.POLLIN)};
int rc = ZMQ.poll(pollSet, 10 * 1000);
if (rc == -1)
break; // Interrupted
if (pollSet[0].isReadable()) {
String reply = client.recvStr(0);
if (reply == null)
break; // Interrupted
// Worker is supposed to answer us with our task id
assert (reply.equals(taskId));
monitor.send(String.format("%s", reply), 0);
} else {
monitor.send(
String.format("E: CLIENT EXIT - lost task %s", taskId), 0);
ctx.destroy();
return;
}
burst--;
}
}
}
}
// This is the worker task, which uses a REQ socket to plug into the LRU
// router. It's the same stub worker task you've seen in other examples:
private static class worker_task extends Thread
{
@Override
public void run()
{
Random rand = new Random(System.nanoTime());
ZContext ctx = new ZContext();
Socket worker = ctx.createSocket(ZMQ.REQ);
worker.connect(String.format("ipc://%s-localbe.ipc", self));
// Tell broker we're ready for work
ZFrame frame = new ZFrame(WORKER_READY);
frame.send(worker, 0);
while (true) {
// Send request, get reply
ZMsg msg = ZMsg.recvMsg(worker, 0);
if (msg == null)
break; // Interrupted
// Workers are busy for 0/1 seconds
try {
Thread.sleep(rand.nextInt(2) * 1000);
} catch (InterruptedException e) {
}
msg.send(worker);
}
ctx.destroy();
}
}
// The main task begins by setting-up all its sockets. The local frontend
// talks to clients, and our local backend talks to workers. The cloud
// frontend talks to peer brokers as if they were clients, and the cloud
// backend talks to peer brokers as if they were workers. The state
// backend publishes regular state messages, and the state frontend
// subscribes to all state backends to collect these messages. Finally,
// we use a PULL monitor socket to collect printable messages from tasks:
public static void main(String[] argv)
{
// First argument is this broker's name
// Other arguments are our peers' names
//
if (argv.length < 1) {
System.out.println("syntax: peering3 me {you}");
System.exit(-1);
}
self = argv[0];
System.out.printf("I: preparing broker at %s\n", self);
Random rand = new Random(System.nanoTime());
ZContext ctx = new ZContext();
// Prepare local frontend and backend
Socket localfe = ctx.createSocket(ZMQ.ROUTER);
localfe.bind(String.format("ipc://%s-localfe.ipc", self));
Socket localbe = ctx.createSocket(ZMQ.ROUTER);
localbe.bind(String.format("ipc://%s-localbe.ipc", self));
// Bind cloud frontend to endpoint
Socket cloudfe = ctx.createSocket(ZMQ.ROUTER);
cloudfe.setIdentity(self.getBytes(ZMQ.CHARSET));
cloudfe.bind(String.format("ipc://%s-cloud.ipc", self));
// Connect cloud backend to all peers
Socket cloudbe = ctx.createSocket(ZMQ.ROUTER);
cloudbe.setIdentity(self.getBytes(ZMQ.CHARSET));
int argn;
for (argn = 1; argn < argv.length; argn++) {
String peer = argv[argn];
System.out.printf("I: connecting to cloud forintend at '%s'\n", peer);
cloudbe.connect(String.format("ipc://%s-cloud.ipc", peer));
}
// Bind state backend to endpoint
Socket statebe = ctx.createSocket(ZMQ.PUB);
statebe.bind(String.format("ipc://%s-state.ipc", self));
// Connect statefe to all peers
Socket statefe = ctx.createSocket(ZMQ.SUB);
statefe.subscribe(ZMQ.SUBSCRIPTION_ALL);
for (argn = 1; argn < argv.length; argn++) {
String peer = argv[argn];
System.out.printf("I: connecting to state backend at '%s'\n", peer);
statefe.connect(String.format("ipc://%s-state.ipc", peer));
}
// Prepare monitor socket
Socket monitor = ctx.createSocket(ZMQ.PULL);
monitor.bind(String.format("ipc://%s-monitor.ipc", self));
// Start local workers
int worker_nbr;
for (worker_nbr = 0; worker_nbr < NBR_WORKERS; worker_nbr++)
new worker_task().start();
// Start local clients
int client_nbr;
for (client_nbr = 0; client_nbr < NBR_CLIENTS; client_nbr++)
new client_task().start();
// Queue of available workers
int localCapacity = 0;
int cloudCapacity = 0;
ArrayList workers = new ArrayList();
// The main loop has two parts. First we poll workers and our two service
// sockets (statefe and monitor), in any case. If we have no ready workers,
// there's no point in looking at incoming requests. These can remain on
// their internal 0MQ queues:
while (true) {
// First, route any waiting replies from workers
PollItem primary[] = {
new PollItem(localbe, Poller.POLLIN),
new PollItem(cloudbe, Poller.POLLIN),
new PollItem(statefe, Poller.POLLIN),
new PollItem(monitor, Poller.POLLIN)
};
// If we have no workers anyhow, wait indefinitely
int rc = ZMQ.poll(primary,
localCapacity > 0 ? 1000 : -1);
if (rc == -1)
break; // Interrupted
// Track if capacity changes during this iteration
int previous = localCapacity;
// Handle reply from local worker
ZMsg msg = null;
if (primary[0].isReadable()) {
msg = ZMsg.recvMsg(localbe);
if (msg == null)
break; // Interrupted
ZFrame address = msg.unwrap();
workers.add(address);
localCapacity++;
// If it's READY, don't route the message any further
ZFrame frame = msg.getFirst();
if (new String(frame.getData(), ZMQ.CHARSET).equals(WORKER_READY)) {
msg.destroy();
msg = null;
}
}
// Or handle reply from peer broker
else if (primary[1].isReadable()) {
msg = ZMsg.recvMsg(cloudbe);
if (msg == null)
break; // Interrupted
// We don't use peer broker address for anything
ZFrame address = msg.unwrap();
address.destroy();
}
// Route reply to cloud if it's addressed to a broker
for (argn = 1; msg != null && argn < argv.length; argn++) {
byte[] data = msg.getFirst().getData();
if (argv[argn].equals(new String(data, ZMQ.CHARSET))) {
msg.send(cloudfe);
msg = null;
}
}
// Route reply to client if we still need to
if (msg != null)
msg.send(localfe);
// If we have input messages on our statefe or monitor sockets we
// can process these immediately:
if (primary[2].isReadable()) {
String peer = statefe.recvStr();
String status = statefe.recvStr();
cloudCapacity = Integer.parseInt(status);
}
if (primary[3].isReadable()) {
String status = monitor.recvStr();
System.out.println(status);
}
// Now we route as many client requests as we have worker capacity
// for. We may reroute requests from our local frontend, but not from //
// the cloud frontend. We reroute randomly now, just to test things
// out. In the next version we'll do this properly by calculating
// cloud capacity://
while (localCapacity + cloudCapacity > 0) {
PollItem secondary[] = {
new PollItem(localfe, Poller.POLLIN),
new PollItem(cloudfe, Poller.POLLIN)
};
if (localCapacity > 0)
rc = ZMQ.poll(secondary, 2, 0);
else
rc = ZMQ.poll(secondary, 1, 0);
assert (rc >= 0);
if (secondary[0].isReadable()) {
msg = ZMsg.recvMsg(localfe);
} else if (secondary[1].isReadable()) {
msg = ZMsg.recvMsg(cloudfe);
} else
break; // No work, go back to backends
if (localCapacity > 0) {
ZFrame frame = workers.remove(0);
msg.wrap(frame);
msg.send(localbe);
localCapacity--;
} else {
// Route to random broker peer
int random_peer = rand.nextInt(argv.length - 1) + 1;
msg.push(argv[random_peer]);
msg.send(cloudbe);
}
}
// We broadcast capacity messages to other peers; to reduce chatter
// we do this only if our capacity changed.
if (localCapacity != previous) {
// We stick our own address onto the envelope
statebe.sendMore(self);
// Broadcast new capacity
statebe.send(String.format("%d", localCapacity), 0);
}
}
// When we're done, clean up properly
while (workers.size() > 0) {
ZFrame frame = workers.remove(0);
frame.destroy();
}
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/ppqueue.java 0000664 0000000 0000000 00000015243 12551504772 0021144 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.ArrayList;
import java.util.Iterator;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
//
// Paranoid Pirate queue
//
public class ppqueue {
private final static int HEARTBEAT_LIVENESS = 3; // 3-5 is reasonable
private final static int HEARTBEAT_INTERVAL = 1000; // msecs
// Paranoid Pirate Protocol constants
private final static String PPP_READY = "\001"; // Signals worker is ready
private final static String PPP_HEARTBEAT = "\002"; // Signals worker heartbeat
// Here we define the worker class; a structure and a set of functions that
// as constructor, destructor, and methods on worker objects:
private static class Worker {
ZFrame address; // Address of worker
String identity; // Printable identity
long expiry; // Expires at this time
protected Worker(ZFrame address) {
this.address = address;
identity = new String(address.getData(), ZMQ.CHARSET);
expiry = System.currentTimeMillis() + HEARTBEAT_INTERVAL * HEARTBEAT_LIVENESS;
}
// The ready method puts a worker to the end of the ready list:
protected void ready(ArrayList workers) {
Iterator it = workers.iterator();
while (it.hasNext()) {
Worker worker = it.next();
if (identity.equals(worker.identity)) {
it.remove();
break;
}
}
workers.add(this);
}
// The next method returns the next available worker address:
protected static ZFrame next(ArrayList workers) {
Worker worker = workers.remove(0);
assert (worker != null);
ZFrame frame = worker.address;
return frame;
}
// The purge method looks for and kills expired workers. We hold workers
// from oldest to most recent, so we stop at the first alive worker:
protected static void purge(ArrayList workers) {
Iterator it = workers.iterator();
while (it.hasNext()) {
Worker worker = it.next();
if (System.currentTimeMillis() < worker.expiry) {
break;
}
it.remove();
}
}
};
// The main task is an LRU queue with heartbeating on workers so we can
// detect crashed or blocked worker tasks:
public static void main(String[] args) {
ZContext ctx = new ZContext ();
Socket frontend = ctx.createSocket(ZMQ.ROUTER);
Socket backend = ctx.createSocket(ZMQ.ROUTER);
frontend.bind( "tcp://*:5555"); // For clients
backend.bind( "tcp://*:5556"); // For workers
// List of available workers
ArrayList workers = new ArrayList ();
// Send out heartbeats at regular intervals
long heartbeat_at = System.currentTimeMillis() + HEARTBEAT_INTERVAL;
while (true) {
PollItem items [] = {
new PollItem( backend, ZMQ.Poller.POLLIN ),
new PollItem( frontend, ZMQ.Poller.POLLIN )
};
// Poll frontend only if we have available workers
int rc = ZMQ.poll (items, workers.size() > 0 ? 2:1,
HEARTBEAT_INTERVAL );
if (rc == -1)
break; // Interrupted
// Handle worker activity on backend
if (items [0].isReadable()) {
// Use worker address for LRU routing
ZMsg msg = ZMsg.recvMsg (backend);
if (msg == null)
break; // Interrupted
// Any sign of life from worker means it's ready
ZFrame address = msg.unwrap();
Worker worker = new Worker(address);
worker.ready(workers);
// Validate control message, or return reply to client
if (msg.size() == 1) {
ZFrame frame = msg.getFirst();
String data = new String(frame.getData(), ZMQ.CHARSET);
if (!data.equals(PPP_READY)
&& !data.equals( PPP_HEARTBEAT)) {
System.out.println ("E: invalid message from worker");
msg.dump(System.out);
}
msg.destroy();
}
else
msg.send(frontend);
}
if (items [1].isReadable()) {
// Now get next client request, route to next worker
ZMsg msg = ZMsg.recvMsg (frontend);
if (msg == null)
break; // Interrupted
msg.push(Worker.next(workers));
msg.send( backend);
}
// We handle heartbeating after any socket activity. First we send
// heartbeats to any idle workers if it's time. Then we purge any
// dead workers:
if (System.currentTimeMillis() >= heartbeat_at) {
for (Worker worker: workers) {
worker.address.send(backend,
ZFrame.REUSE + ZFrame.MORE);
ZFrame frame = new ZFrame (PPP_HEARTBEAT);
frame.send(backend, 0);
}
heartbeat_at = System.currentTimeMillis() + HEARTBEAT_INTERVAL;
}
Worker.purge (workers);
}
// When we're done, clean up properly
while ( workers.size() > 0) {
Worker worker = workers.remove(0);
}
workers.clear();
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/ppworker.java 0000664 0000000 0000000 00000015341 12551504772 0021330 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.Random;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
//
// Paranoid Pirate worker
//
public class ppworker
{
private final static int HEARTBEAT_LIVENESS = 3; // 3-5 is reasonable
private final static int HEARTBEAT_INTERVAL = 1000; // msecs
private final static int INTERVAL_INIT = 1000; // Initial reconnect
private final static int INTERVAL_MAX = 32000; // After exponential backoff
// Paranoid Pirate Protocol constants
private final static String PPP_READY = "\001"; // Signals worker is ready
private final static String PPP_HEARTBEAT = "\002"; // Signals worker heartbeat
// Helper function that returns a new configured socket
// connected to the Paranoid Pirate queue
private static Socket worker_socket(ZContext ctx)
{
Socket worker = ctx.createSocket(ZMQ.DEALER);
worker.connect("tcp://localhost:5556");
// Tell queue we're ready for work
System.out.println("I: worker ready\n");
ZFrame frame = new ZFrame(PPP_READY);
frame.send(worker, 0);
return worker;
}
// We have a single task, which implements the worker side of the
// Paranoid Pirate Protocol (PPP). The interesting parts here are
// the heartbeating, which lets the worker detect if the queue has
// died, and vice-versa:
public static void main(String[] args)
{
ZContext ctx = new ZContext();
Socket worker = worker_socket(ctx);
// If liveness hits zero, queue is considered disconnected
int liveness = HEARTBEAT_LIVENESS;
int interval = INTERVAL_INIT;
// Send out heartbeats at regular intervals
long heartbeat_at = System.currentTimeMillis() + HEARTBEAT_INTERVAL;
Random rand = new Random(System.nanoTime());
int cycles = 0;
while (true) {
PollItem items[] = {new PollItem(worker, ZMQ.Poller.POLLIN)};
int rc = ZMQ.poll(items, HEARTBEAT_INTERVAL);
if (rc == -1)
break; // Interrupted
if (items[0].isReadable()) {
// Get message
// - 3-part envelope + content -> request
// - 1-part HEARTBEAT -> heartbeat
ZMsg msg = ZMsg.recvMsg(worker);
if (msg == null)
break; // Interrupted
// To test the robustness of the queue implementation we //
// simulate various typical problems, such as the worker
// crashing, or running very slowly. We do this after a few
// cycles so that the architecture can get up and running
// first:
if (msg.size() == 3) {
cycles++;
if (cycles > 3 && rand.nextInt(5) == 0) {
System.out.println("I: simulating a crash\n");
msg.destroy();
msg = null;
break;
} else if (cycles > 3 && rand.nextInt(5) == 0) {
System.out.println("I: simulating CPU overload\n");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
break;
}
}
System.out.println("I: normal reply\n");
msg.send(worker);
liveness = HEARTBEAT_LIVENESS;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
} // Do some heavy work
} else
// When we get a heartbeat message from the queue, it means the
// queue was (recently) alive, so reset our liveness indicator:
if (msg.size() == 1) {
ZFrame frame = msg.getFirst();
if (PPP_HEARTBEAT.equals(new String(frame.getData(), ZMQ.CHARSET)))
liveness = HEARTBEAT_LIVENESS;
else {
System.out.println("E: invalid message\n");
msg.dump(System.out);
}
msg.destroy();
} else {
System.out.println("E: invalid message\n");
msg.dump(System.out);
}
interval = INTERVAL_INIT;
} else
// If the queue hasn't sent us heartbeats in a while, destroy the
// socket and reconnect. This is the simplest most brutal way of
// discarding any messages we might have sent in the meantime://
if (--liveness == 0) {
System.out.println("W: heartbeat failure, can't reach queue\n");
System.out.printf("W: reconnecting in %sd msec\n", interval);
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (interval < INTERVAL_MAX)
interval *= 2;
ctx.destroySocket(worker);
worker = worker_socket(ctx);
liveness = HEARTBEAT_LIVENESS;
}
// Send heartbeat to queue if it's time
if (System.currentTimeMillis() > heartbeat_at) {
heartbeat_at = System.currentTimeMillis() + HEARTBEAT_INTERVAL;
System.out.println("I: worker heartbeat\n");
ZFrame frame = new ZFrame(PPP_HEARTBEAT);
frame.send(worker, 0);
}
}
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/psenvpub.java 0000664 0000000 0000000 00000003032 12551504772 0021313 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
/**
* Pubsub envelope publisher
*/
public class psenvpub {
public static void main (String[] args) throws Exception {
// Prepare our context and publisher
Context context = ZMQ.context(1);
Socket publisher = context.socket(ZMQ.PUB);
publisher.bind("tcp://*:5563");
while (!Thread.currentThread ().isInterrupted ()) {
// Write two messages, each with an envelope and content
publisher.sendMore ("A");
publisher.send ("We don't want to see this");
publisher.sendMore ("B");
publisher.send("We would like to see this");
}
publisher.close ();
context.term ();
}
}
jeromq-0.3.5/src/test/java/guide/psenvsub.java 0000664 0000000 0000000 00000003103 12551504772 0021315 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
/**
* Pubsub envelope subscriber
*/
public class psenvsub {
public static void main (String[] args) {
// Prepare our context and subscriber
Context context = ZMQ.context(1);
Socket subscriber = context.socket(ZMQ.SUB);
subscriber.connect("tcp://localhost:5563");
subscriber.subscribe("B".getBytes(ZMQ.CHARSET));
while (!Thread.currentThread ().isInterrupted ()) {
// Read envelope with address
String address = subscriber.recvStr ();
// Read message contents
String contents = subscriber.recvStr ();
System.out.println(address + " : " + contents);
}
subscriber.close ();
context.term ();
}
}
jeromq-0.3.5/src/test/java/guide/rrbroker.java 0000664 0000000 0000000 00000005271 12551504772 0021310 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Poller;
import org.zeromq.ZMQ.Socket;
/**
* Simple request-reply broker
*
*/
public class rrbroker{
public static void main (String[] args) {
// Prepare our context and sockets
Context context = ZMQ.context(1);
Socket frontend = context.socket(ZMQ.ROUTER);
Socket backend = context.socket(ZMQ.DEALER);
frontend.bind("tcp://*:5559");
backend.bind("tcp://*:5560");
System.out.println("launch and connect broker.");
// Initialize poll set
Poller items = new Poller (2);
items.register(frontend, Poller.POLLIN);
items.register(backend, Poller.POLLIN);
boolean more = false;
byte[] message;
// Switch messages between sockets
while (!Thread.currentThread().isInterrupted()) {
// poll and memorize multipart detection
items.poll();
if (items.pollin(0)) {
while (true) {
// receive message
message = frontend.recv(0);
more = frontend.hasReceiveMore();
// Broker it
backend.send(message, more ? ZMQ.SNDMORE : 0);
if(!more){
break;
}
}
}
if (items.pollin(1)) {
while (true) {
// receive message
message = backend.recv(0);
more = backend.hasReceiveMore();
// Broker it
frontend.send(message, more ? ZMQ.SNDMORE : 0);
if(!more){
break;
}
}
}
}
// We never get here but clean up anyhow
frontend.close();
backend.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/rrclient.java 0000664 0000000 0000000 00000003221 12551504772 0021273 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
/**
* Hello World client
* Connects REQ socket to tcp://localhost:5559
* Sends "Hello" to server, expects "World" back
*/
public class rrclient{
public static void main (String[] args) {
Context context = ZMQ.context(1);
// Socket to talk to server
Socket requester = context.socket(ZMQ.REQ);
requester.connect("tcp://localhost:5559");
System.out.println("launch and connect client.");
for (int request_nbr = 0; request_nbr < 10; request_nbr++) {
requester.send("Hello", 0);
String reply = requester.recvStr (0);
System.out.println("Received reply " + request_nbr + " [" + reply + "]");
}
// We never get here but clean up anyhow
requester.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/rrworker.java 0000664 0000000 0000000 00000003327 12551504772 0021335 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
// Hello World worker
// Connects REP socket to tcp://*:5560
// Expects "Hello" from client, replies with "World"
public class rrworker
{
public static void main (String[] args) throws Exception {
Context context = ZMQ.context (1);
// Socket to talk to server
Socket responder = context.socket (ZMQ.REP);
responder.connect ("tcp://localhost:5560");
while (!Thread.currentThread ().isInterrupted ()) {
// Wait for next request from client
String string = responder.recvStr (0);
System.out.printf ("Received request: [%s]\n", string);
// Do some 'work'
Thread.sleep (1000);
// Send reply back to client
responder.send ("World");
}
// We never get here but clean up anyhow
responder.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/rtdealer.java 0000664 0000000 0000000 00000007140 12551504772 0021257 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
import java.util.Random;
/**
* ROUTER-TO-REQ example
*/
public class rtdealer
{
private static Random rand = new Random();
private static final int NBR_WORKERS = 10;
private static class Worker extends Thread {
@Override
public void run() {
Context context = ZMQ.context(1);
Socket worker = context.socket(ZMQ.DEALER);
ZHelper.setId (worker); // Set a printable identity
worker.connect("tcp://localhost:5671");
int total = 0;
while (true) {
// Tell the broker we're ready for work
worker.sendMore ("");
worker.send ("Hi Boss");
// Get workload from broker, until finished
worker.recvStr (); // Envelope delimiter
String workload = worker.recvStr ();
boolean finished = workload.equals ("Fired!");
if (finished) {
System.out.printf ("Completed: %d tasks\n", total);
break;
}
total++;
// Do some random work
try {
Thread.sleep (rand.nextInt (500) + 1);
} catch (InterruptedException e) {
}
}
worker.close();
context.term();
}
}
/**
* While this example runs in a single process, that is just to make
* it easier to start and stop the example. Each thread has its own
* context and conceptually acts as a separate process.
*/
public static void main (String[] args) throws Exception {
Context context = ZMQ.context(1);
Socket broker = context.socket(ZMQ.ROUTER);
broker.bind("tcp://*:5671");
for (int workerNbr = 0; workerNbr < NBR_WORKERS; workerNbr++)
{
Thread worker = new Worker ();
worker.start ();
}
// Run for five seconds and then tell workers to end
long endTime = System.currentTimeMillis () + 5000;
int workersFired = 0;
while (true) {
// Next message gives us least recently used worker
String identity = broker.recvStr ();
broker.sendMore (identity);
broker.recv (0); // Envelope delimiter
broker.recv (0); // Response from worker
broker.sendMore ("");
// Encourage workers until it's time to fire them
if (System.currentTimeMillis () < endTime)
broker.send ("Work harder");
else {
broker.send ("Fired!");
if (++workersFired == NBR_WORKERS)
break;
}
}
broker.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/rtmama.java 0000664 0000000 0000000 00000006025 12551504772 0020737 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
//
//Custom routing Router to Mama (ROUTER to REQ)
//
public class rtmama {
private static final int NBR_WORKERS =10;
public static class Worker implements Runnable {
private final byte[] END = "END".getBytes(ZMQ.CHARSET);
public void run() {
ZMQ.Context context = ZMQ.context(1);
ZMQ.Socket worker = context.socket(ZMQ.REQ);
// worker.setIdentity(); will set a random id automatically
worker.connect("ipc://routing.ipc");
int total = 0;
while (true) {
worker.send("ready", 0);
byte[] workerload = worker.recv(0);
if (new String(workerload, ZMQ.CHARSET).equals("END")) {
System.out.println(
String.format(
"Processs %d tasks.", total
)
);
break;
}
total += 1;
}
worker.close();
context.term();
}
}
public static void main(String[] args) {
ZMQ.Context context = ZMQ.context(1);
ZMQ.Socket client = context.socket(ZMQ.ROUTER);
client.bind("ipc://routing.ipc");
for (int i = 0 ; i != NBR_WORKERS; i++) {
new Thread(new Worker()).start();
}
for (int i = 0 ; i != NBR_WORKERS; i++) {
// LRU worker is next waiting in queue
byte[] address = client.recv(0);
byte[] empty = client.recv(0);
byte[] ready = client.recv(0);
client.send(address, ZMQ.SNDMORE);
client.send("", ZMQ.SNDMORE);
client.send("This is the workload", 0);
}
for (int i = 0 ; i != NBR_WORKERS; i++) {
// LRU worker is next waiting in queue
byte[] address = client.recv(0);
byte[] empty = client.recv(0);
byte[] ready = client.recv(0);
client.send(address, ZMQ.SNDMORE);
client.send("", ZMQ.SNDMORE);
client.send("END", 0);
}
// Now ask mamas to shut down and report their results
client.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/rtpapa.java 0000664 0000000 0000000 00000004432 12551504772 0020745 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
//
//Custom routing Router to Papa (ROUTER to REP)
//
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
public class rtpapa
{
// We will do this all in one thread to emphasize the getSequence
// of events
public static void main(String[] args)
{
Context context = ZMQ.context(1);
Socket client = context.socket(ZMQ.ROUTER);
client.bind("ipc://routing.ipc");
Socket worker = context.socket(ZMQ.REP);
worker.setIdentity("A".getBytes(ZMQ.CHARSET));
worker.connect("ipc://routing.ipc");
// Wait for the worker to connect so that when we send a message
// with routing envelope, it will actually match the worker
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Send papa address, address stack, empty part, and request
client.send("A", ZMQ.SNDMORE);
client.send("address 3", ZMQ.SNDMORE);
client.send("address 2", ZMQ.SNDMORE);
client.send("address 1", ZMQ.SNDMORE);
client.send("", ZMQ.SNDMORE);
client.send("This is the workload", 0);
// Worker should get just the workload
ZHelper.dump(worker);
// We don't play with envelopes in the worker
worker.send("This is the reply", 0);
// Now dump what we got off the ROUTER socket
ZHelper.dump(client);
client.close();
worker.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/rtreq.java 0000664 0000000 0000000 00000006774 12551504772 0020626 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
import java.util.Random;
/**
* ROUTER-TO-REQ example
*/
public class rtreq
{
private static Random rand = new Random();
private static final int NBR_WORKERS = 10;
private static class Worker extends Thread {
@Override
public void run() {
Context context = ZMQ.context(1);
Socket worker = context.socket(ZMQ.REQ);
ZHelper.setId (worker); // Set a printable identity
worker.connect("tcp://localhost:5671");
int total = 0;
while (true) {
// Tell the broker we're ready for work
worker.send ("Hi Boss");
// Get workload from broker, until finished
String workload = worker.recvStr ();
boolean finished = workload.equals ("Fired!");
if (finished) {
System.out.printf ("Completed: %d tasks\n", total);
break;
}
total++;
// Do some random work
try {
Thread.sleep (rand.nextInt (500) + 1);
} catch (InterruptedException e) {
}
}
worker.close();
context.term();
}
}
/**
* While this example runs in a single process, that is just to make
* it easier to start and stop the example. Each thread has its own
* context and conceptually acts as a separate process.
*/
public static void main (String[] args) throws Exception {
Context context = ZMQ.context(1);
Socket broker = context.socket(ZMQ.ROUTER);
broker.bind("tcp://*:5671");
for (int workerNbr = 0; workerNbr < NBR_WORKERS; workerNbr++)
{
Thread worker = new Worker ();
worker.start ();
}
// Run for five seconds and then tell workers to end
long endTime = System.currentTimeMillis () + 5000;
int workersFired = 0;
while (true) {
// Next message gives us least recently used worker
String identity = broker.recvStr ();
broker.sendMore (identity);
broker.recvStr (); // Envelope delimiter
broker.recvStr (); // Response from worker
broker.sendMore ("");
// Encourage workers until it's time to fire them
if (System.currentTimeMillis () < endTime)
broker.send ("Work harder");
else {
broker.send ("Fired!");
if (++workersFired == NBR_WORKERS)
break;
}
}
broker.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/spqueue.java 0000664 0000000 0000000 00000006515 12551504772 0021151 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.ArrayList;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Poller;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
//
// Simple Pirate queue
// This is identical to load-balancing pattern, with no reliability mechanisms
// at all. It depends on the client for recovery. Runs forever.
//
public class spqueue
{
private final static String WORKER_READY = "\001"; // Signals worker is ready
public static void main(String[] args)
{
ZContext ctx = new ZContext();
Socket frontend = ctx.createSocket(ZMQ.ROUTER);
Socket backend = ctx.createSocket(ZMQ.ROUTER);
frontend.bind("tcp://*:5555"); // For clients
backend.bind("tcp://*:5556"); // For workers
// Queue of available workers
ArrayList workers = new ArrayList();
// The body of this example is exactly the same as lruqueue2.
while (true) {
PollItem items[] = {
new PollItem(backend, Poller.POLLIN),
new PollItem(frontend, Poller.POLLIN)
};
int rc = ZMQ.poll(items, workers.size() > 0 ? 2 : 1, -1);
// Poll frontend only if we have available workers
if (rc == -1)
break; // Interrupted
// Handle worker activity on backend
if (items[0].isReadable()) {
// Use worker address for LRU routing
ZMsg msg = ZMsg.recvMsg(backend);
if (msg == null)
break; // Interrupted
ZFrame address = msg.unwrap();
workers.add(address);
// Forward message to client if it's not a READY
ZFrame frame = msg.getFirst();
if (new String(frame.getData(), ZMQ.CHARSET).equals(WORKER_READY))
msg.destroy();
else
msg.send(frontend);
}
if (items[1].isReadable()) {
// Get client request, route to first available worker
ZMsg msg = ZMsg.recvMsg(frontend);
if (msg != null) {
msg.wrap(workers.remove(0));
msg.send(backend);
}
}
}
// When we're done, clean up properly
while (workers.size() > 0) {
ZFrame frame = workers.remove(0);
frame.destroy();
}
workers.clear();
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/spworker.java 0000664 0000000 0000000 00000005153 12551504772 0021333 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.Random;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
//
// Simple Pirate worker
// Connects REQ socket to tcp://*:5556
// Implements worker part of load-balancing queueing
//
public class spworker
{
private final static String WORKER_READY = "\001"; // Signals worker is ready
public static void main(String[] args) throws Exception
{
ZContext ctx = new ZContext();
Socket worker = ctx.createSocket(ZMQ.REQ);
// Set random identity to make tracing easier
Random rand = new Random(System.nanoTime());
String identity = String.format("%04X-%04X", rand.nextInt(0x10000), rand.nextInt(0x10000));
worker.setIdentity(identity.getBytes(ZMQ.CHARSET));
worker.connect("tcp://localhost:5556");
// Tell broker we're ready for work
System.out.printf("I: (%s) worker ready\n", identity);
ZFrame frame = new ZFrame(WORKER_READY);
frame.send(worker, 0);
int cycles = 0;
while (true) {
ZMsg msg = ZMsg.recvMsg(worker);
if (msg == null)
break; // Interrupted
// Simulate various problems, after a few cycles
cycles++;
if (cycles > 3 && rand.nextInt(5) == 0) {
System.out.printf("I: (%s) simulating a crash\n", identity);
msg.destroy();
break;
} else if (cycles > 3 && rand.nextInt(5) == 0) {
System.out.printf("I: (%s) simulating CPU overload\n", identity);
Thread.sleep(3000);
}
System.out.printf("I: (%s) normal reply\n", identity);
Thread.sleep(1000); // Do some heavy work
msg.send(worker);
}
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/suisnail.java 0000664 0000000 0000000 00000007656 12551504772 0021320 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
// Suicidal Snail
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZThread;
import org.zeromq.ZThread.IAttachedRunnable;
import java.util.Random;
public class suisnail
{
private static final long MAX_ALLOWED_DELAY = 1000; // msecs
private static Random rand = new Random(System.currentTimeMillis());
// This is our subscriber. It connects to the publisher and subscribes
// to everything. It sleeps for a short time between messages to
// simulate doing too much work. If a message is more than one second
// late, it croaks.
private static class Subscriber implements IAttachedRunnable
{
@Override
public void run(Object[] args, ZContext ctx, Socket pipe)
{
// Subscribe to everything
Socket subscriber = ctx.createSocket(ZMQ.SUB);
subscriber.subscribe(ZMQ.SUBSCRIPTION_ALL);
subscriber.connect("tcp://localhost:5556");
// Get and process messages
while (true) {
String string = subscriber.recvStr();
System.out.printf("%s\n", string);
long clock = Long.parseLong(string);
// Suicide snail logic
if (System.currentTimeMillis() - clock > MAX_ALLOWED_DELAY) {
System.err.println("E: subscriber cannot keep up, aborting");
break;
}
// Work for 1 msec plus some random additional time
try {
Thread.sleep(1000 + rand.nextInt(2000));
} catch (InterruptedException e) {
break;
}
}
pipe.send("gone and died");
}
}
// .split publisher task
// This is our publisher task. It publishes a time-stamped message to its
// PUB socket every millisecond:
private static class Publisher implements IAttachedRunnable
{
@Override
public void run(Object[] args, ZContext ctx, Socket pipe)
{
// Prepare publisher
Socket publisher = ctx.createSocket(ZMQ.PUB);
publisher.bind("tcp://*:5556");
while (true) {
// Send current clock (msecs) to subscribers
String string = String.format("%d", System.currentTimeMillis());
publisher.send(string);
String signal = pipe.recvStr(ZMQ.DONTWAIT);
if (signal != null) {
break;
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
}
}
}
// .split main task
// The main task simply starts a client and a server, and then
// waits for the client to signal that it has died:
public static void main (String[] args) throws Exception
{
ZContext ctx = new ZContext();
Socket pubpipe = ZThread.fork(ctx, new Publisher());
Socket subpipe = ZThread.fork(ctx, new Subscriber());
subpipe.recvStr();
pubpipe.send("break");
Thread.sleep(100);
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/syncpub.java 0000664 0000000 0000000 00000004437 12551504772 0021146 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
/**
* Synchronized publisher.
*/
public class syncpub{
/**
* We wait for 10 subscribers
*/
protected static int SUBSCRIBERS_EXPECTED = 10;
public static void main (String[] args) {
Context context = ZMQ.context(1);
// Socket to talk to clients
Socket publisher = context.socket(ZMQ.PUB);
publisher.setLinger(5000);
// In 0MQ 3.x pub socket could drop messages if sub can follow the generation of pub messages
publisher.setSndHWM(0);
publisher.bind("tcp://*:5561");
// Socket to receive signals
Socket syncservice = context.socket(ZMQ.REP);
syncservice.bind("tcp://*:5562");
System.out.println("Waiting subscribers");
// Get synchronization from subscribers
int subscribers = 0;
while (subscribers < SUBSCRIBERS_EXPECTED) {
// - wait for synchronization request
syncservice.recv(0);
// - send synchronization reply
syncservice.send("", 0);
subscribers++;
}
// Now broadcast exactly 1M updates followed by END
System.out.println ("Broadcasting messages");
int update_nbr;
for (update_nbr = 0; update_nbr < 1000000; update_nbr++){
publisher.send("Rhubarb", 0);
}
publisher.send("END", 0);
// clean up
publisher.close();
syncservice.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/syncsub.java 0000664 0000000 0000000 00000003670 12551504772 0021147 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
/**
* Synchronized subscriber.
*/
public class syncsub{
public static void main (String[] args) {
Context context = ZMQ.context(1);
// First, connect our subscriber socket
Socket subscriber = context.socket(ZMQ.SUB);
subscriber.connect("tcp://localhost:5561");
subscriber.subscribe(ZMQ.SUBSCRIPTION_ALL);
// Second, synchronize with publisher
Socket syncclient = context.socket(ZMQ.REQ);
syncclient.connect("tcp://localhost:5562");
// - send a synchronization request
syncclient.send(ZMQ.MESSAGE_SEPARATOR, 0);
// - wait for synchronization reply
syncclient.recv(0);
// Third, get our updates and report how many we got
int update_nbr = 0;
while (true) {
String string = subscriber.recvStr(0);
if (string.equals("END")) {
break;
}
update_nbr++;
}
System.out.println("Received " + update_nbr + " updates.");
subscriber.close();
syncclient.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/tasksink.java 0000664 0000000 0000000 00000004013 12551504772 0021300 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
//
// Task sink in Java
// Binds PULL socket to tcp://localhost:5558
// Collects results from workers via that socket
//
public class tasksink {
public static void main (String[] args) throws Exception {
// Prepare our context and socket
ZMQ.Context context = ZMQ.context(1);
ZMQ.Socket receiver = context.socket(ZMQ.PULL);
receiver.bind("tcp://*:5558");
// Wait for start of batch
String string = new String(receiver.recv(0), ZMQ.CHARSET);
// Start our clock now
long tstart = System.currentTimeMillis();
// Process 100 confirmations
int task_nbr;
int total_msec = 0; // Total calculated cost in msecs
for (task_nbr = 0; task_nbr < 100; task_nbr++) {
string = new String(receiver.recv(0), ZMQ.CHARSET).trim();
if ((task_nbr / 10) * 10 == task_nbr) {
System.out.print(":");
} else {
System.out.print(".");
}
}
// Calculate and report duration of batch
long tend = System.currentTimeMillis();
System.out.println("\nTotal elapsed time: " + (tend - tstart) + " msec");
receiver.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/tasksink2.java 0000664 0000000 0000000 00000004322 12551504772 0021365 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
/**
* Task sink - design 2
* Adds pub-sub flow to send kill signal to workers
*/
public class tasksink2 {
public static void main (String[] args) throws Exception {
// Prepare our context and socket
ZMQ.Context context = ZMQ.context(1);
ZMQ.Socket receiver = context.socket(ZMQ.PULL);
receiver.bind("tcp://*:5558");
// Socket for worker control
ZMQ.Socket controller = context.socket(ZMQ.PUB);
controller.bind("tcp://*:5559");
// Wait for start of batch
receiver.recv(0);
// Start our clock now
long tstart = System.currentTimeMillis();
// Process 100 confirmations
int task_nbr;
for (task_nbr = 0; task_nbr < 100; task_nbr++) {
receiver.recv(0);
if ((task_nbr / 10) * 10 == task_nbr) {
System.out.print(":");
} else {
System.out.print(".");
}
System.out.flush();
}
// Calculate and report duration of batch
long tend = System.currentTimeMillis();
System.out.println("Total elapsed time: " + (tend - tstart) + " msec");
// Send the kill signal to the workers
controller.send("KILL", 0);
// Give it some time to deliver
Thread.sleep(1);
receiver.close();
controller.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/taskvent.java 0000664 0000000 0000000 00000004604 12551504772 0021316 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.Random;
import org.zeromq.ZMQ;
//
// Task ventilator in Java
// Binds PUSH socket to tcp://localhost:5557
// Sends batch of tasks to workers via that socket
//
public class taskvent {
public static void main (String[] args) throws Exception {
ZMQ.Context context = ZMQ.context(1);
// Socket to send messages on
ZMQ.Socket sender = context.socket(ZMQ.PUSH);
sender.bind("tcp://*:5557");
// Socket to send messages on
ZMQ.Socket sink = context.socket(ZMQ.PUSH);
sink.connect("tcp://localhost:5558");
System.out.println("Press Enter when the workers are ready: ");
System.in.read();
System.out.println("Sending tasks to workers\n");
// The first message is "0" and signals start of batch
sink.send("0", 0);
// Initialize random number generator
Random srandom = new Random(System.currentTimeMillis());
// Send 100 tasks
int task_nbr;
int total_msec = 0; // Total expected cost in msecs
for (task_nbr = 0; task_nbr < 100; task_nbr++) {
int workload;
// Random workload from 1 to 100msecs
workload = srandom.nextInt(100) + 1;
total_msec += workload;
System.out.print(workload + ".");
String string = String.format("%d", workload);
sender.send(string, 0);
}
System.out.println("Total expected cost: " + total_msec + " msec");
Thread.sleep(1000); // Give 0MQ time to deliver
sink.close();
sender.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/taskwork.java 0000664 0000000 0000000 00000004002 12551504772 0021314 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
//
// Task worker in Java
// Connects PULL socket to tcp://localhost:5557
// Collects workloads from ventilator via that socket
// Connects PUSH socket to tcp://localhost:5558
// Sends results to sink via that socket
//
public class taskwork {
public static void main (String[] args) throws Exception {
ZMQ.Context context = ZMQ.context(1);
// Socket to receive messages on
ZMQ.Socket receiver = context.socket(ZMQ.PULL);
receiver.connect("tcp://localhost:5557");
// Socket to send messages to
ZMQ.Socket sender = context.socket(ZMQ.PUSH);
sender.connect("tcp://localhost:5558");
// Process tasks forever
while (!Thread.currentThread ().isInterrupted ()) {
String string = new String(receiver.recv(0), ZMQ.CHARSET).trim();
long msec = Long.parseLong(string);
// Simple progress indicator for the viewer
System.out.flush();
System.out.print(string + '.');
// Do the work
Thread.sleep(msec);
// Send results to sink
sender.send(ZMQ.MESSAGE_SEPARATOR, 0);
}
sender.close();
receiver.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/taskwork2.java 0000664 0000000 0000000 00000004556 12551504772 0021414 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
/**
* Task worker - design 2
* Adds pub-sub flow to receive and respond to kill signal
*/
public class taskwork2 {
public static void main (String[] args) throws InterruptedException {
ZMQ.Context context = ZMQ.context(1);
ZMQ.Socket receiver = context.socket(ZMQ.PULL);
receiver.connect("tcp://localhost:5557");
ZMQ.Socket sender = context.socket(ZMQ.PUSH);
sender.connect("tcp://localhost:5558");
ZMQ.Socket controller = context.socket(ZMQ.SUB);
controller.connect("tcp://localhost:5559");
controller.subscribe(ZMQ.SUBSCRIPTION_ALL);
ZMQ.Poller items = new ZMQ.Poller (2);
items.register(receiver, ZMQ.Poller.POLLIN);
items.register(controller, ZMQ.Poller.POLLIN);
while (true) {
items.poll();
if (items.pollin(0)) {
String message = receiver.recvStr (0);
long nsec = Long.parseLong(message);
// Simple progress indicator for the viewer
System.out.print(message + '.');
System.out.flush();
// Do the work
Thread.sleep(nsec);
// Send results to sink
sender.send("", 0);
}
// Any waiting controller command acts as 'KILL'
if (items.pollin(1)) {
break; // Exit loop
}
}
// Finished
receiver.close();
sender.close();
controller.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/ticlient.java 0000664 0000000 0000000 00000006445 12551504772 0021277 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
// Titanic client example
// Implements client side of http://rfc.zeromq.org/spec:9
// Calls a TSP service
// Returns response if successful (status code 200 OK), else NULL
//
import org.zeromq.ZFrame;
import org.zeromq.ZMsg;
public class ticlient
{
static ZMsg
serviceCall (mdcliapi session, String service, ZMsg request)
{
ZMsg reply = session.send(service, request);
if (reply != null) {
ZFrame status = reply.pop();
if (status.streq("200")) {
status.destroy();
return reply;
}
else if (status.streq("400")) {
System.out.println("E: client fatal error, aborting");
}
else
if (status.streq("500")) {
System.out.println("E: server fatal error, aborting");
}
reply.destroy();
}
return null; // Didn't succeed; don't care why not
}
public static void main (String[] args) throws Exception
{
boolean verbose = (args.length > 0 && args[0].equals("-v"));
mdcliapi session = new mdcliapi("tcp://localhost:5555", verbose);
// 1. Send 'echo' request to Titanic
ZMsg request = new ZMsg();
request.add("echo");
request.add("Hello world");
ZMsg reply = serviceCall(
session, "titanic.request", request);
ZFrame uuid = null;
if (reply != null) {
uuid = reply.pop();
reply.destroy();
uuid.print("I: request UUID ");
}
// 2. Wait until we get a reply
while (!Thread.currentThread().isInterrupted()) {
Thread.sleep(100);
request = new ZMsg();
request.add(uuid.duplicate());
reply = serviceCall(
session, "titanic.reply", request);
if (reply != null) {
String replyString = reply.getLast().toString();
System.out.printf ("Reply: %s\n", replyString);
reply.destroy();
// 3. Close request
request = new ZMsg();
request.add(uuid.duplicate());
reply = serviceCall(session, "titanic.close", request);
reply.destroy();
break;
}
else {
System.out.println("I: no reply yet, trying again...");
Thread.sleep (5000); // Try again in 5 seconds
}
}
uuid.destroy();
session.destroy();
}
}
jeromq-0.3.5/src/test/java/guide/titanic.java 0000664 0000000 0000000 00000032350 12551504772 0021111 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
import org.zeromq.ZThread;
import org.zeromq.ZThread.IAttachedRunnable;
import org.zeromq.ZThread.IDetachedRunnable;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.UUID;
public class titanic
{
// Return a new UUID as a printable character string
// Caller must free returned string when finished with it
static String generateUUID()
{
return UUID.randomUUID().toString();
}
private static final String TITANIC_DIR = ".titanic";
// Returns freshly allocated request filename for given UUID
private static String requestFilename(String uuid) {
String filename = String.format("%s/%s.req", TITANIC_DIR, uuid);
return filename;
}
// Returns freshly allocated reply filename for given UUID
private static String replyFilename(String uuid) {
String filename = String.format("%s/%s.rep", TITANIC_DIR, uuid);
return filename;
}
// .split Titanic request service
// The {{titanic.request}} task waits for requests to this service. It writes
// each request to disk and returns a UUID to the client. The client picks
// up the reply asynchronously using the {{titanic.reply}} service:
static class TitanicRequest implements IAttachedRunnable
{
@Override
public void run(Object[] args, ZContext ctx, Socket pipe)
{
mdwrkapi worker = new mdwrkapi(
"tcp://localhost:5555", "titanic.request", false);
ZMsg reply = null;
while (true) {
// Send reply if it's not null
// And then get next request from broker
ZMsg request = worker.receive(reply);
if (request == null)
break; // Interrupted, exit
// Ensure message directory exists
new File(TITANIC_DIR).mkdirs();
// Generate UUID and save message to disk
String uuid = generateUUID();
String filename = requestFilename(uuid);
DataOutputStream file = null;
try {
file = new DataOutputStream(new FileOutputStream(filename));
ZMsg.save(request, file);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (file != null)
file.close();
} catch (IOException e) {
}
}
request.destroy();
// Send UUID through to message queue
reply = new ZMsg();
reply.add(uuid);
reply.send(pipe);
// Now send UUID back to client
// Done by the mdwrk_recv() at the top of the loop
reply = new ZMsg();
reply.add("200");
reply.add(uuid);
}
worker.destroy();
}
}
// .split Titanic reply service
// The {{titanic.reply}} task checks if there's a reply for the specified
// request (by UUID), and returns a 200 (OK), 300 (Pending), or 400
// (Unknown) accordingly:
static class TitanicReply implements IDetachedRunnable
{
@Override
public void run(Object[] args)
{
mdwrkapi worker = new mdwrkapi(
"tcp://localhost:5555", "titanic.reply", false);
ZMsg reply = null;
while (true) {
ZMsg request = worker.receive(reply);
if (request == null)
break; // Interrupted, exit
String uuid = request.popString();
String reqFilename = requestFilename(uuid);
String repFilename = replyFilename(uuid);
if (new File(repFilename).exists()) {
DataInputStream file = null;
try {
file = new DataInputStream(new FileInputStream(repFilename));
reply = ZMsg.load(file);
reply.push("200");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (file != null)
file.close();
} catch (IOException e) {
}
}
}
else {
reply = new ZMsg();
if (new File(reqFilename).exists())
reply.push("300"); //Pending
else
reply.push("400"); //Unknown
}
request.destroy();
}
worker.destroy();
}
}
// .split Titanic close task
// The {{titanic.close}} task removes any waiting replies for the request
// (specified by UUID). It's idempotent, so it is safe to call more than
// once in a row:
static class TitanicClose implements IDetachedRunnable
{
@Override
public void run(Object[] args)
{
mdwrkapi worker = new mdwrkapi(
"tcp://localhost:5555", "titanic.close", false);
ZMsg reply = null;
while (true) {
ZMsg request = worker.receive(reply);
if (request == null)
break; // Interrupted, exit
String uuid = request.popString();
String req_filename = requestFilename(uuid);
String rep_filename = replyFilename(uuid);
new File(rep_filename).delete();
new File(req_filename).delete();
request.destroy();
reply = new ZMsg();
reply.add("200");
}
worker.destroy();
}
}
// .split worker task
// This is the main thread for the Titanic worker. It starts three child
// threads; for the request, reply, and close services. It then dispatches
// requests to workers using a simple brute force disk queue. It receives
// request UUIDs from the {{titanic.request}} service, saves these to a disk
// file, and then throws each request at MDP workers until it gets a
// response.
public static void main(String[] args)
{
boolean verbose = (args.length > 0 && "-v".equals(args[0]));
ZContext ctx = new ZContext();
Socket requestPipe = ZThread.fork(ctx, new TitanicRequest());
ZThread.start(new TitanicReply());
ZThread.start(new TitanicClose());
// Main dispatcher loop
while (true) {
// We'll dispatch once per second, if there's no activity
PollItem items [] = { new PollItem(requestPipe, ZMQ.Poller.POLLIN) };
int rc = ZMQ.poll(items, 1, 1000);
if (rc == -1)
break; // Interrupted
if (items [0].isReadable()) {
// Ensure message directory exists
new File(TITANIC_DIR).mkdirs();
// Append UUID to queue, prefixed with '-' for pending
ZMsg msg = ZMsg.recvMsg(requestPipe);
if (msg == null)
break; // Interrupted
String uuid = msg.popString();
BufferedWriter wfile = null;
try {
wfile = new BufferedWriter(new FileWriter(TITANIC_DIR + "/queue", true));
wfile.write("-" + uuid + "\n");
} catch (IOException e) {
e.printStackTrace();
break;
} finally {
try {
if (wfile != null)
wfile.close();
} catch (IOException e) {
}
}
msg.destroy();
}
// Brute force dispatcher
byte[] entry = new byte[37]; //"?........:....:....:....:............:";
RandomAccessFile file = null;
try {
file = new RandomAccessFile(TITANIC_DIR + "/queue", "rw");
while (file.read(entry) > 0) {
// UUID is prefixed with '-' if still waiting
if (entry[0] == '-') {
if (verbose)
System.out.printf("I: processing request %s\n", new String(entry, 1, entry.length -1, ZMQ.CHARSET));
if (serviceSuccess(new String(entry, 1, entry.length -1, ZMQ.CHARSET))) {
// Mark queue entry as processed
file.seek(file.getFilePointer() - 37);
file.writeBytes("+");
file.seek(file.getFilePointer() + 36);
}
}
// Skip end of line, LF or CRLF
if (file.readByte() == '\r')
file.readByte();
if (Thread.currentThread().isInterrupted())
break;
}
} catch (FileNotFoundException e) {
} catch (IOException e) {
e.printStackTrace();
} finally {
if (file != null) {
try {
file.close();
} catch (IOException e) {
}
}
}
}
}
// .split try to call a service
// Here, we first check if the requested MDP service is defined or not,
// using a MMI lookup to the Majordomo broker. If the service exists,
// we send a request and wait for a reply using the conventional MDP
// client API. This is not meant to be fast, just very simple:
static boolean serviceSuccess(String uuid)
{
// Load request message, service will be first frame
String filename = requestFilename(uuid);
// If the client already closed request, treat as successful
if (!new File(filename).exists())
return true;
DataInputStream file = null;
ZMsg request;
try {
file = new DataInputStream(new FileInputStream(filename));
request = ZMsg.load(file);
} catch (IOException e) {
e.printStackTrace();
return true;
} finally {
try {
if (file != null)
file.close();
} catch (IOException e) {
}
}
ZFrame service = request.pop();
String serviceName = service.toString();
// Create MDP client session with short timeout
mdcliapi client = new mdcliapi("tcp://localhost:5555", false);
client.setTimeout(1000); // 1 sec
client.setRetries(1); // only 1 retry
// Use MMI protocol to check if service is available
ZMsg mmiRequest = new ZMsg();
mmiRequest.add(service);
ZMsg mmiReply = client.send("mmi.service", mmiRequest);
boolean serviceOK = (mmiReply != null
&& mmiReply.getFirst().toString().equals("200"));
mmiReply.destroy();
boolean result = false;
if (serviceOK) {
ZMsg reply = client.send(serviceName, request);
if (reply != null) {
filename = replyFilename(uuid);
DataOutputStream ofile = null;
try {
ofile = new DataOutputStream(new FileOutputStream(filename));
ZMsg.save(reply, ofile);
} catch (IOException e) {
e.printStackTrace();
return true;
} finally {
try {
if (file != null)
file.close();
} catch (IOException e) {
}
}
result = true;
}
reply.destroy();;
}
else
request.destroy();
client.destroy();
return result;
}
}
jeromq-0.3.5/src/test/java/guide/tripping.java 0000664 0000000 0000000 00000013041 12551504772 0021306 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZContext;
import org.zeromq.ZFrame;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMsg;
/**
* Round-trip demonstrator. Broker, Worker and Client are mocked as separate
* threads.
*/
public class tripping {
static class Broker implements Runnable {
@Override
public void run() {
ZContext ctx = new ZContext();
Socket frontend = ctx.createSocket(ZMQ.ROUTER);
Socket backend = ctx.createSocket(ZMQ.ROUTER);
frontend.setHWM (0);
backend.setHWM (0);
frontend.bind("tcp://*:5555");
backend.bind("tcp://*:5556");
while (!Thread.currentThread().isInterrupted()) {
ZMQ.Poller items = new ZMQ.Poller(2);
items.register(frontend, ZMQ.Poller.POLLIN);
items.register(backend, ZMQ.Poller.POLLIN);
if (items.poll() == -1)
break; // Interrupted
if (items.pollin(0)) {
ZMsg msg = ZMsg.recvMsg(frontend);
if (msg == null)
break; // Interrupted
ZFrame address = msg.pop();
address.destroy();
msg.addFirst(new ZFrame("W"));
msg.send(backend);
}
if (items.pollin(1)) {
ZMsg msg = ZMsg.recvMsg(backend);
if (msg == null)
break; // Interrupted
ZFrame address = msg.pop();
address.destroy();
msg.addFirst(new ZFrame("C"));
msg.send(frontend);
}
}
ctx.destroy();
}
}
static class Worker implements Runnable {
@Override
public void run() {
ZContext ctx = new ZContext();
Socket worker = ctx.createSocket(ZMQ.DEALER);
worker.setHWM (0);
worker.setIdentity("W".getBytes(ZMQ.CHARSET));
worker.connect("tcp://localhost:5556");
while (!Thread.currentThread().isInterrupted()) {
ZMsg msg = ZMsg.recvMsg(worker);
msg.send(worker);
}
ctx.destroy();
}
}
static class Client implements Runnable {
private static int SAMPLE_SIZE = 10000;
@Override
public void run() {
ZContext ctx = new ZContext();
Socket client = ctx.createSocket(ZMQ.DEALER);
client.setHWM (0);
client.setIdentity("C".getBytes(ZMQ.CHARSET));
client.connect("tcp://localhost:5555");
System.out.println("Setting up test");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
int requests;
long start;
System.out.println("Synchronous round-trip test");
start = System.currentTimeMillis();
for (requests = 0; requests < SAMPLE_SIZE; requests++) {
ZMsg req = new ZMsg();
req.addString("hello");
req.send(client);
ZMsg.recvMsg(client).destroy();
}
System.out.printf(" %d calls/second\n",
(1000 * SAMPLE_SIZE) / (System.currentTimeMillis() - start));
System.out.println("Asynchronous round-trip test");
start = System.currentTimeMillis();
for (requests = 0; requests < SAMPLE_SIZE; requests++) {
ZMsg req = new ZMsg();
req.addString("hello");
req.send(client);
}
for (requests = 0; requests < SAMPLE_SIZE
&& !Thread.currentThread().isInterrupted(); requests++) {
ZMsg.recvMsg(client).destroy();
}
System.out.printf(" %d calls/second\n",
(1000 * SAMPLE_SIZE) / (System.currentTimeMillis() - start));
ctx.destroy();
}
}
public static void main(String[] args) {
if (args.length==1)
Client.SAMPLE_SIZE = Integer.parseInt(args[0]);
Thread brokerThread = new Thread(new Broker());
Thread workerThread = new Thread(new Worker());
Thread clientThread = new Thread(new Client());
brokerThread.setDaemon(true);
workerThread.setDaemon(true);
brokerThread.start();
workerThread.start();
clientThread.start();
try {
clientThread.join();
workerThread.interrupt();
brokerThread.interrupt();
Thread.sleep(200);// give them some time
} catch (InterruptedException e) {
}
}
}
jeromq-0.3.5/src/test/java/guide/version.java 0000664 0000000 0000000 00000002052 12551504772 0021137 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
// Report 0MQ version
public class version {
public static void main (String[] args) {
System.out.println(String.format("Version string: %s, Version int: %d",
ZMQ.getVersionString(),
ZMQ.getFullVersion()));
}
}
jeromq-0.3.5/src/test/java/guide/wuclient.java 0000664 0000000 0000000 00000004364 12551504772 0021314 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.StringTokenizer;
import org.zeromq.ZMQ;
//
// Weather update client in Java
// Connects SUB socket to tcp://localhost:5556
// Collects weather updates and finds avg temp in zipcode
//
public class wuclient {
public static void main (String[] args) {
ZMQ.Context context = ZMQ.context(1);
// Socket to talk to server
System.out.println("Collecting updates from weather server");
ZMQ.Socket subscriber = context.socket(ZMQ.SUB);
subscriber.connect("tcp://localhost:5556");
// Subscribe to zipcode, default is NYC, 10001
String filter = (args.length > 0) ? args[0] : "10001 ";
subscriber.subscribe(filter.getBytes(ZMQ.CHARSET));
// Process 100 updates
int update_nbr;
long total_temp = 0;
for (update_nbr = 0; update_nbr < 100; update_nbr++) {
// Use trim to remove the tailing '0' character
String string = subscriber.recvStr(0).trim();
StringTokenizer sscanf = new StringTokenizer(string, " ");
int zipcode = Integer.valueOf(sscanf.nextToken());
int temperature = Integer.valueOf(sscanf.nextToken());
int relhumidity = Integer.valueOf(sscanf.nextToken());
total_temp += temperature;
}
System.out.println("Average temperature for zipcode '"
+ filter + "' was " + (int) (total_temp / update_nbr));
subscriber.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/wuproxy.java 0000664 0000000 0000000 00000003142 12551504772 0021210 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import org.zeromq.ZMQ;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
/**
* Weather proxy device.
*/
public class wuproxy{
public static void main (String[] args) {
// Prepare our context and sockets
Context context = ZMQ.context(1);
// This is where the weather server sits
Socket frontend = context.socket(ZMQ.SUB);
frontend.connect("tcp://192.168.55.210:5556");
// This is our public endpoint for subscribers
Socket backend = context.socket(ZMQ.PUB);
backend.bind("tcp://10.1.1.0:8100");
// Subscribe on everything
frontend.subscribe(ZMQ.SUBSCRIPTION_ALL);
// Run the proxy until the user interrupts us
ZMQ.proxy (frontend, backend, null);
frontend.close();
backend.close();
context.term();
}
}
jeromq-0.3.5/src/test/java/guide/wuserver.java 0000664 0000000 0000000 00000003644 12551504772 0021344 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package guide;
import java.util.Random;
import org.zeromq.ZMQ;
//
// Weather update server in Java
// Binds PUB socket to tcp://*:5556
// Publishes random weather updates
//
public class wuserver {
public static void main (String[] args) throws Exception {
// Prepare our context and publisher
ZMQ.Context context = ZMQ.context(1);
ZMQ.Socket publisher = context.socket(ZMQ.PUB);
publisher.bind("tcp://*:5556");
publisher.bind("ipc://weather");
// Initialize random number generator
Random srandom = new Random(System.currentTimeMillis());
while (!Thread.currentThread ().isInterrupted ()) {
// Get values that will fool the boss
int zipcode, temperature, relhumidity;
zipcode = 10000 + srandom.nextInt(10000) ;
temperature = srandom.nextInt(215) - 80 + 1;
relhumidity = srandom.nextInt(50) + 10 + 1;
// Send message to all subscribers
String update = String.format("%05d %d %d", zipcode, temperature, relhumidity);
publisher.send(update, 0);
}
publisher.close ();
context.term ();
}
}
jeromq-0.3.5/src/test/java/org/ 0000775 0000000 0000000 00000000000 12551504772 0016302 5 ustar 00root root 0000000 0000000 jeromq-0.3.5/src/test/java/org/zeromq/ 0000775 0000000 0000000 00000000000 12551504772 0017617 5 ustar 00root root 0000000 0000000 jeromq-0.3.5/src/test/java/org/zeromq/TestProxy.java 0000664 0000000 0000000 00000010173 12551504772 0022445 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package org.zeromq;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
import org.junit.Test;
import static org.junit.Assert.assertNotNull;
public class TestProxy
{
static class Client extends Thread
{
private Socket s = null;
private String name = null;
public Client(Context ctx, String name)
{
s = ctx.socket(ZMQ.REQ);
this.name = name;
s.setIdentity(name.getBytes(ZMQ.CHARSET));
}
@Override
public void run()
{
s.connect("tcp://127.0.0.1:6660");
s.send("hello", 0);
String msg = s.recvStr(0);
s.send("world", 0);
msg = s.recvStr(0);
s.close();
}
}
static class Dealer extends Thread
{
private Socket s = null;
private String name = null;
public Dealer(Context ctx, String name)
{
s = ctx.socket(ZMQ.DEALER);
this.name = name;
s.setIdentity(name.getBytes(ZMQ.CHARSET));
}
@Override
public void run()
{
System.out.println("Start dealer " + name);
s.connect("tcp://127.0.0.1:6661");
int count = 0;
while (count < 2) {
String msg = s.recvStr(0);
if (msg == null) {
throw new RuntimeException();
}
String identity = msg;
System.out.println(name + " received client identity " + identity);
msg = s.recvStr(0);
if (msg == null) {
throw new RuntimeException();
}
System.out.println(name + " received bottom " + msg);
msg = s.recvStr(0);
if (msg == null) {
throw new RuntimeException();
}
String data = msg;
System.out.println(name + " received data " + msg + " " + data);
s.send(identity, ZMQ.SNDMORE);
s.send((byte[]) null, ZMQ.SNDMORE);
String response = "OK " + data;
s.send(response, 0);
count++;
}
s.close();
System.out.println("Stop dealer " + name);
}
}
static class Main extends Thread
{
Context ctx;
Main(Context ctx)
{
this.ctx = ctx;
}
@Override
public void run()
{
Socket frontend = ctx.socket(ZMQ.ROUTER);
assertNotNull(frontend);
frontend.bind("tcp://127.0.0.1:6660");
Socket backend = ctx.socket(ZMQ.DEALER);
assertNotNull(backend);
backend.bind("tcp://127.0.0.1:6661");
ZMQ.proxy(frontend, backend, null);
frontend.close();
backend.close();
assert true;
}
}
@Test
public void testProxy() throws Exception
{
Context ctx = ZMQ.context(1);
assert (ctx != null);
Main mt = new Main(ctx);
mt.start();
new Dealer(ctx, "AA").start();
new Dealer(ctx, "BB").start();
Thread.sleep(1000);
Thread c1 = new Client(ctx, "X");
c1.start();
Thread c2 = new Client(ctx, "Y");
c2.start();
c1.join();
c2.join();
ctx.term();
}
}
jeromq-0.3.5/src/test/java/org/zeromq/TestReqRouterThreadedTcp.java 0000664 0000000 0000000 00000012577 12551504772 0025376 0 ustar 00root root 0000000 0000000 package org.zeromq;
/*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Test;
import org.zeromq.ZMQ.Socket;
/**
* Tests a REQ-ROUTER dialog with several methods,
* each component being on a separate thread.
* @author fred
*
*/
public class TestReqRouterThreadedTcp
{
private static final long REQUEST_TIMEOUT = 1000; // msecs
/**
* A very simple server for one reply only.
* @author fred
*
*/
private class Server extends Thread
{
private final int port;
/**
* Creates a new server.
* @param port the port to which to connect.
*/
public Server(int port)
{
this.port = port;
}
@Override
public void run()
{
ZContext ctx = new ZContext();
ZMQ.Socket server = ctx.createSocket(ZMQ.ROUTER);
server.bind("tcp://localhost:" + port);
ZMsg msg = ZMsg.recvMsg(server);
// only one echo message for this server
msg.send(server);
msg.destroy();
// Clean up.
ctx.destroySocket(server);
ctx.close();
}
}
private class Client extends Thread
{
private final int port;
final AtomicBoolean finished = new AtomicBoolean();
/**
* Creates a new client.
* @param port the port to which to connect.
*/
public Client(int port)
{
this.port = port;
}
@Override
public void run()
{
ZContext ctx = new ZContext();
ZMQ.Socket client = ctx.createSocket(ZMQ.REQ);
client.connect("tcp://localhost:" + port);
client.send("DATA");
inBetween(client);
String reply = client.recvStr();
assertThat(reply, notNullValue());
assertThat(reply, is("DATA"));
// Clean up.
ctx.destroySocket(client);
ctx.close();
finished.set(true);
}
/**
* Called between the request-reply cycle.
* @param client the socket participating to the cycle of request-reply
*/
protected void inBetween(Socket client)
{
// to be overriden
}
}
private class ClientPoll extends Client
{
public ClientPoll(int port)
{
super(port);
}
// same results
// @Override
// protected void inBetween(Socket client) {
// // Poll socket for a reply, with timeout
// PollItem items[] = { new PollItem(client, ZMQ.Poller.POLLIN) };
// int rc = ZMQ.poll(items, 1, REQUEST_TIMEOUT);
// assertThat(rc, is(1));
// boolean readable = items[0].isReadable();
// assertThat(readable, is(true));
// }
/**
* Here we use a poller to check for readability of the message.
* This should activate the prefetching mechanism.
*/
@Override
protected void inBetween(Socket client)
{
// Poll socket for a reply, with timeout
ZMQ.Poller poller = new ZMQ.Poller(1);
poller.register(client, ZMQ.Poller.POLLIN);
int rc = poller.poll(REQUEST_TIMEOUT);
assertThat(rc, is(1));
boolean readable = poller.pollin(0);
assertThat(readable, is(true));
// now a message should have been prefetched
}
}
/**
* Test dialog directly.
* @throws Exception if something bad occurs.
*/
@Test
public void testReqRouterTcp() throws Exception
{
int port = 5962;
Server server = new Server(port);
server.start();
Client client = new Client(port);
client.start();
server.join();
client.join();
boolean finished = client.finished.get();
assertThat(finished, is(true));
}
/**
* Test dialog with a polling access in between request-reply.
* This should activate the prefetching mechanism.
* @throws Exception if something bad occurs.
*/
@Test
public void testReqRouterTcpPoll() throws Exception
{
int port = 5963;
Server server = new Server(port);
server.start();
ClientPoll client = new ClientPoll(port);
client.start();
server.join();
client.join();
boolean finished = client.finished.get();
assertThat(finished, is(true));
}
}
jeromq-0.3.5/src/test/java/org/zeromq/TestZActor.java 0000664 0000000 0000000 00000011217 12551504772 0022526 0 ustar 00root root 0000000 0000000 package org.zeromq;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import org.junit.Assert;
import org.junit.Test;
import org.zeromq.ZActor.Actor;
import org.zeromq.ZMQ.Socket;
import zmq.ZError;
public class TestZActor
{
private class MiniActor extends ZActor.SimpleActor
{
}
@Test
public void testMinimalistic()
{
Actor acting = new ZActor.SimpleActor()
{
@Override
public List createSockets(ZContext ctx, Object[] args)
{
assert ("TEST".equals(args[0]));
return Arrays.asList(ctx.createSocket(ZMQ.PUB));
}
@Override
public boolean backstage(Socket pipe, ZPoller poller, int events)
{
String string = pipe.recvStr();
if ("HELLO".equals(string)) {
pipe.send("WORLD");
return false;
}
return true;
}
};
ZActor actor = new ZActor(acting, "LOCK", Arrays.asList("TEST").toArray());
Socket pipe = actor.pipe();
boolean rc = pipe.send("HELLO");
Assert.assertTrue("Unable to send a message through pipe", rc);
ZMsg msg = actor.recv();
String world = msg.popString();
Assert.assertEquals("No matching response from actor", "WORLD", world);
msg = actor.recv();
Assert.assertNull("Able te receive a message from a locked actor", msg);
rc = actor.sign();
Assert.assertFalse("Locked actor is still here", rc);
rc = actor.send("whatever");
Assert.assertFalse("Able to send a message to a locked actor", rc);
try {
rc = pipe.send("boom ?!");
Assert.assertTrue("actor pipe was closed pretty fast", rc);
}
catch (ZMQException e) {
int errno = e.getErrorCode();
Assert.assertEquals("Expected exception has the wrong code", ZError.ETERM, errno);
}
System.out.println(".");
}
@Test
public void testRecreateAgent()
{
MiniActor acting = new MiniActor()
{
private int counter = 0;
@Override
public List createSockets(ZContext ctx, Object[] args)
{
++counter;
System.out.print(".Acting Ready for a hello world.");
assert ("TEST".equals(args[0]));
return super.createSockets(ctx, args);
}
@Override
public boolean backstage(Socket pipe, ZPoller poller, int events)
{
String string = pipe.recvStr();
if ("HELLO".equals(string)) {
System.out.print("Hi! ");
pipe.send("WORLD", ZMQ.SNDMORE);
pipe.send(Integer.toString(counter));
return false;
}
return true;
}
public boolean destroyed(Socket pipe, ZPoller poller)
{
if (counter == 2) {
System.out.print(".Acting Finished.");
return false;
}
// recreate a new agent
return true;
}
};
ZActor actor = new ZActor(acting, UUID.randomUUID().toString(), Arrays.asList("TEST").toArray());
ZAgent agent = actor.agent();
agent = actor;
agent = actor.agent();
Socket pipe = agent.pipe();
boolean rc = pipe.send("HELLO");
assert (rc);
ZMsg msg = actor.recv();
String world = msg.popString();
String counter = msg.popString();
assert ("WORLD".equals(world));
assert ("1".equals(counter));
rc = actor.send("HELLO");
assert (rc);
msg = agent.recv();
world = msg.popString();
counter = msg.popString();
assert (msg != null);
assert ("WORLD".equals(world));
assert ("2".equals(counter));
msg = agent.recv();
Assert.assertNull("Able te receive a message from a locked actor", msg);
rc = agent.sign();
Assert.assertFalse("Locked actor is still here", rc);
rc = agent.send("whatever");
Assert.assertFalse("Able to send a message to a locked actor", rc);
try {
rc = pipe.send("boom ?!");
Assert.assertTrue("actor pipe was closed pretty fast", rc);
}
catch (ZMQException e) {
int errno = e.getErrorCode();
Assert.assertEquals("Expected exception has the wrong code", ZError.ETERM, errno);
}
System.out.println();
}
}
jeromq-0.3.5/src/test/java/org/zeromq/TestZContext.java 0000664 0000000 0000000 00000003133 12551504772 0023100 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package org.zeromq;
import org.junit.Assert;
import org.junit.Test;
import org.zeromq.ZMQ.Socket;
public class TestZContext
{
@Test
public void testZContext()
{
ZContext ctx = new ZContext();
Socket s1 = ctx.createSocket(ZMQ.PAIR);
Socket s2 = ctx.createSocket(ZMQ.XREQ);
Socket s3 = ctx.createSocket(ZMQ.REQ);
Socket s4 = ctx.createSocket(ZMQ.REP);
Socket s5 = ctx.createSocket(ZMQ.PUB);
Socket s6 = ctx.createSocket(ZMQ.SUB);
ctx.close();
Assert.assertEquals(0, ctx.getSockets().size());
}
@Test
public void testZContextSocketCloseBeforeContextClose()
{
ZContext ctx = new ZContext();
Socket s1 = ctx.createSocket(ZMQ.PUSH);
Socket s2 = ctx.createSocket(ZMQ.PULL);
s1.close();
s2.close();
ctx.close();
}
}
jeromq-0.3.5/src/test/java/org/zeromq/TestZLoop.java 0000664 0000000 0000000 00000017624 12551504772 0022377 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package org.zeromq;
import org.junit.After;
import org.junit.Assert;
import org.zeromq.ZMQ.Poller;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZMQ.PollItem;
import org.junit.Test;
import org.junit.Before;
public class TestZLoop
{
private String received;
private ZContext ctx;
private Socket input;
private Socket output;
@Before
public void setUp()
{
ctx = new ZContext();
assert (ctx != null);
output = ctx.createSocket(ZMQ.PAIR);
assert (output != null);
output.bind("inproc://zloop.test");
input = ctx.createSocket(ZMQ.PAIR);
assert (input != null);
input.connect("inproc://zloop.test");
received = "FAILED";
}
@After
public void tearDown()
{
ctx.destroy();
}
@Test
public void testZLoop()
{
int rc = 0;
ZLoop loop = new ZLoop();
assert (loop != null);
ZLoop.IZLoopHandler timerEvent = new ZLoop.IZLoopHandler()
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
((Socket) arg).send("PING", 0);
return 0;
}
};
ZLoop.IZLoopHandler socketEvent = new ZLoop.IZLoopHandler()
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
received = ((Socket) arg).recvStr(0);
// Just end the reactor
return -1;
}
};
// After 10 msecs, send a ping message to output
loop.addTimer(10, 1, timerEvent, input);
// When we get the ping message, end the reactor
PollItem pollInput = new PollItem(output, Poller.POLLIN);
rc = loop.addPoller(pollInput, socketEvent, output);
Assert.assertEquals(0, rc);
loop.start();
loop.removePoller(pollInput);
Assert.assertEquals("PING", received);
}
@Test
public void testZLoopAddTimerFromTimer()
{
int rc = 0;
ZLoop loop = new ZLoop();
assert (loop != null);
ZLoop.IZLoopHandler timerEvent = new ZLoop.IZLoopHandler()
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
final long now = System.currentTimeMillis();
ZLoop.IZLoopHandler timerEvent2 = new ZLoop.IZLoopHandler()
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
final long now2 = System.currentTimeMillis();
assert (now2 >= now + 10);
((Socket) arg).send("PING", 0);
return 0;
}
};
loop.addTimer(10, 1, timerEvent2, arg);
return 0;
}
};
ZLoop.IZLoopHandler socketEvent = new ZLoop.IZLoopHandler()
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
received = ((Socket) arg).recvStr(0);
// Just end the reactor
return -1;
}
};
// After 10 msecs, fire a timer that registers
// another timer that sends the ping message
loop.addTimer(10, 1, timerEvent, input);
// When we get the ping message, end the reactor
PollItem pollInput = new PollItem(output, Poller.POLLIN);
rc = loop.addPoller(pollInput, socketEvent, output);
Assert.assertEquals(0, rc);
loop.start();
loop.removePoller(pollInput);
Assert.assertEquals("PING", received);
}
@Test(timeout = 1000)
public void testZLoopAddTimerFromSocketHandler()
{
int rc = 0;
ZLoop loop = new ZLoop();
assert (loop != null);
ZLoop.IZLoopHandler timerEvent = new ZLoop.IZLoopHandler()
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
((Socket) arg).send("PING", 0);
return 0;
}
};
ZLoop.IZLoopHandler socketEvent = new ZLoop.IZLoopHandler()
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
final long now = System.currentTimeMillis();
ZLoop.IZLoopHandler timerEvent2 = new ZLoop.IZLoopHandler()
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
final long now2 = System.currentTimeMillis();
Assert.assertTrue(now2 >= now + 10);
received = ((Socket) arg).recvStr(0);
// Just end the reactor
return -1;
}
};
// After 10 msec fire a timer that ends the reactor
loop.addTimer(10, 1, timerEvent2, arg);
return 0;
}
};
// Fire a timer that sends the ping message
loop.addTimer(0, 1, timerEvent, input);
// When we get the ping message, end the reactor
PollItem pollInput = new PollItem(output, Poller.POLLIN);
rc = loop.addPoller(pollInput, socketEvent, output);
Assert.assertEquals(0, rc);
loop.start();
loop.removePoller(pollInput);
Assert.assertEquals("PING", received);
}
@Test(timeout = 1000)
public void testZLoopEndReactorFromTimer()
{
int rc = 0;
ZLoop loop = new ZLoop();
assert (loop != null);
ZLoop.IZLoopHandler timerEvent = new ZLoop.IZLoopHandler()
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
((Socket) arg).send("PING", 0);
return 0;
}
};
ZLoop.IZLoopHandler socketEvent = new ZLoop.IZLoopHandler()
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
// After 10 msecs, fire an event that ends the reactor
ZLoop.IZLoopHandler shutdownEvent = new ZLoop.IZLoopHandler()
{
@Override
public int handle(ZLoop loop, PollItem item, Object arg)
{
received = ((Socket) arg).recvStr(0);
// Just end the reactor
return -1;
}
};
loop.addTimer(10, 1, shutdownEvent, arg);
return 0;
}
};
// Fire event that sends a ping message to output
loop.addTimer(0, 1, timerEvent, input);
// When we get the ping message, end the reactor
PollItem pollInput = new PollItem(output, Poller.POLLIN);
rc = loop.addPoller(pollInput, socketEvent, output);
Assert.assertEquals(0, rc);
loop.start();
loop.removePoller(pollInput);
Assert.assertEquals("PING", received);
}
}
jeromq-0.3.5/src/test/java/org/zeromq/TestZMQ.java 0000664 0000000 0000000 00000034043 12551504772 0021775 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package org.zeromq;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.CharacterCodingException;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.Socket;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class TestZMQ
{
static class Client extends Thread
{
private Socket s = null;
public Client(Context ctx)
{
s = ctx.socket(ZMQ.PULL);
}
@Override
public void run()
{
System.out.println("Start client thread ");
s.connect("tcp://127.0.0.1:6669");
s.recv(0);
s.close();
System.out.println("Stop client thread ");
}
}
@Test
public void testPollerPollout() throws Exception
{
ZMQ.Context context = ZMQ.context(1);
Client client = new Client(context);
// Socket to send messages to
ZMQ.Socket sender = context.socket(ZMQ.PUSH);
sender.bind("tcp://127.0.0.1:6669");
ZMQ.Poller outItems;
outItems = context.poller();
outItems.register(sender, ZMQ.Poller.POLLOUT);
while (!Thread.currentThread().isInterrupted()) {
outItems.poll(1000);
if (outItems.pollout(0)) {
sender.send("OK", 0);
System.out.println("ok");
break;
}
else {
System.out.println("not writable");
client.start();
}
}
client.join();
sender.close();
context.term();
}
@Test
public void testByteBufferSend() throws InterruptedException
{
ZMQ.Context context = ZMQ.context(1);
ByteBuffer bb = ByteBuffer.allocate(4).order(ByteOrder.nativeOrder());
ZMQ.Socket push = null;
ZMQ.Socket pull = null;
try {
push = context.socket(ZMQ.PUSH);
pull = context.socket(ZMQ.PULL);
pull.bind("tcp://*:12344");
push.connect("tcp://localhost:12344");
bb.put("PING".getBytes(ZMQ.CHARSET));
bb.flip();
push.sendByteBuffer(bb, 0);
String actual = new String(pull.recv(), ZMQ.CHARSET);
assertEquals("PING", actual);
}
finally {
try {
push.close();
}
catch (Exception ignore) {
}
try {
pull.close();
}
catch (Exception ignore) {
}
try {
context.term();
}
catch (Exception ignore) {
}
}
}
@Test
public void testByteBufferRecv() throws InterruptedException, CharacterCodingException
{
ZMQ.Context context = ZMQ.context(1);
ByteBuffer bb = ByteBuffer.allocate(6).order(ByteOrder.nativeOrder());
ZMQ.Socket push = null;
ZMQ.Socket pull = null;
try {
push = context.socket(ZMQ.PUSH);
pull = context.socket(ZMQ.PULL);
pull.bind("tcp://*:12345");
push.connect("tcp://localhost:12345");
push.send("PING".getBytes(ZMQ.CHARSET), 0);
pull.recvByteBuffer(bb, 0);
bb.flip();
byte[] b = new byte[bb.remaining()];
bb.duplicate().get(b);
assertEquals("PING", new String(b, ZMQ.CHARSET));
}
finally {
try {
push.close();
}
catch (Exception ignore) {
ignore.printStackTrace();
}
try {
pull.close();
}
catch (Exception ignore) {
ignore.printStackTrace();
}
try {
context.term();
}
catch (Exception ignore) {
ignore.printStackTrace();
}
}
}
@Test(expected = ZMQException.class)
public void testBindSameAddress()
{
ZMQ.Context context = ZMQ.context(1);
ZMQ.Socket socket1 = context.socket(ZMQ.REQ);
ZMQ.Socket socket2 = context.socket(ZMQ.REQ);
socket1.bind("tcp://*:12346");
try {
socket2.bind("tcp://*:12346");
fail("Exception not thrown");
}
catch (ZMQException e) {
assertEquals(e.getErrorCode(), ZMQ.Error.EADDRINUSE.getCode());
throw e;
}
finally {
socket1.close();
socket2.close();
context.term();
}
}
@Test(expected = ZMQException.class)
public void testBindInprocSameAddress()
{
ZMQ.Context context = ZMQ.context(1);
ZMQ.Socket socket1 = context.socket(ZMQ.REQ);
ZMQ.Socket socket2 = context.socket(ZMQ.REQ);
socket1.bind("inproc://address.already.in.use");
try {
socket2.bind("inproc://address.already.in.use");
fail("Exception not thrown");
}
catch (ZMQException e) {
assertEquals(e.getErrorCode(), ZMQ.Error.EADDRINUSE.getCode());
throw e;
}
finally {
socket1.close();
socket2.close();
context.term();
}
}
@Test
public void testEventConnected()
{
Context context = ZMQ.context(1);
ZMQ.Event event;
Socket helper = context.socket(ZMQ.REQ);
int port = helper.bindToRandomPort("tcp://127.0.0.1");
Socket socket = context.socket(ZMQ.REP);
Socket monitor = context.socket(ZMQ.PAIR);
monitor.setReceiveTimeOut(100);
assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_CONNECTED));
monitor.connect("inproc://monitor.socket");
socket.connect("tcp://127.0.0.1:" + port);
event = ZMQ.Event.recv(monitor);
assertNotNull("No event was received", event);
assertEquals(ZMQ.EVENT_CONNECTED, event.getEvent());
helper.close();
socket.close();
monitor.close();
context.term();
}
@Test
public void testEventConnectDelayed()
{
Context context = ZMQ.context(1);
ZMQ.Event event;
Socket socket = context.socket(ZMQ.REP);
Socket monitor = context.socket(ZMQ.PAIR);
monitor.setReceiveTimeOut(100);
assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_CONNECT_DELAYED));
monitor.connect("inproc://monitor.socket");
socket.connect("tcp://127.0.0.1:6751");
event = ZMQ.Event.recv(monitor);
assertNotNull("No event was received", event);
assertEquals(ZMQ.EVENT_CONNECT_DELAYED, event.getEvent());
socket.close();
monitor.close();
context.term();
}
@Test
public void testEventConnectRetried()
{
Context context = ZMQ.context(1);
ZMQ.Event event;
Socket socket = context.socket(ZMQ.REP);
Socket monitor = context.socket(ZMQ.PAIR);
monitor.setReceiveTimeOut(100);
assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_CONNECT_RETRIED));
monitor.connect("inproc://monitor.socket");
socket.connect("tcp://127.0.0.1:6752");
event = ZMQ.Event.recv(monitor);
assertNotNull("No event was received", event);
assertEquals(ZMQ.EVENT_CONNECT_RETRIED, event.getEvent());
socket.close();
monitor.close();
context.term();
}
@Test
public void testEventListening()
{
Context context = ZMQ.context(1);
ZMQ.Event event;
Socket socket = context.socket(ZMQ.REP);
Socket monitor = context.socket(ZMQ.PAIR);
monitor.setReceiveTimeOut(100);
assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_LISTENING));
monitor.connect("inproc://monitor.socket");
socket.bindToRandomPort("tcp://127.0.0.1");
event = ZMQ.Event.recv(monitor);
assertNotNull("No event was received", event);
assertEquals(ZMQ.EVENT_LISTENING, event.getEvent());
socket.close();
monitor.close();
context.term();
}
@Test
public void testEventBindFailed()
{
Context context = ZMQ.context(1);
ZMQ.Event event;
Socket helper = context.socket(ZMQ.REP);
int port = helper.bindToRandomPort("tcp://127.0.0.1");
Socket socket = context.socket(ZMQ.REP);
Socket monitor = context.socket(ZMQ.PAIR);
monitor.setReceiveTimeOut(100);
assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_BIND_FAILED));
monitor.connect("inproc://monitor.socket");
try {
socket.bind("tcp://127.0.0.1:" + port);
}
catch (ZMQException ex) {
}
event = ZMQ.Event.recv(monitor);
assertNotNull("No event was received", event);
assertEquals(ZMQ.EVENT_BIND_FAILED, event.getEvent());
helper.close();
socket.close();
monitor.close();
context.term();
}
@Test
public void testEventAccepted()
{
Context context = ZMQ.context(1);
ZMQ.Event event;
Socket socket = context.socket(ZMQ.REP);
Socket monitor = context.socket(ZMQ.PAIR);
Socket helper = context.socket(ZMQ.REQ);
monitor.setReceiveTimeOut(100);
assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_ACCEPTED));
monitor.connect("inproc://monitor.socket");
int port = socket.bindToRandomPort("tcp://127.0.0.1");
helper.connect("tcp://127.0.0.1:" + port);
event = ZMQ.Event.recv(monitor);
assertNotNull("No event was received", event);
assertEquals(ZMQ.EVENT_ACCEPTED, event.getEvent());
helper.close();
socket.close();
monitor.close();
context.term();
}
@Test
public void testEventClosed()
{
Context context = ZMQ.context(1);
ZMQ.Event event;
Socket socket = context.socket(ZMQ.REP);
Socket monitor = context.socket(ZMQ.PAIR);
monitor.setReceiveTimeOut(100);
socket.bindToRandomPort("tcp://127.0.0.1");
assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_CLOSED));
monitor.connect("inproc://monitor.socket");
socket.close();
event = ZMQ.Event.recv(monitor);
assertNotNull("No event was received", event);
assertEquals(ZMQ.EVENT_CLOSED, event.getEvent());
monitor.close();
context.term();
}
@Test
public void testEventDisconnected()
{
Context context = ZMQ.context(1);
ZMQ.Event event;
Socket socket = context.socket(ZMQ.REP);
Socket monitor = context.socket(ZMQ.PAIR);
Socket helper = context.socket(ZMQ.REQ);
monitor.setReceiveTimeOut(100);
int port = socket.bindToRandomPort("tcp://127.0.0.1");
helper.connect("tcp://127.0.0.1:" + port);
assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_DISCONNECTED));
monitor.connect("inproc://monitor.socket");
helper.close();
event = ZMQ.Event.recv(monitor);
assertNotNull("No event was received", event);
assertEquals(ZMQ.EVENT_DISCONNECTED, event.getEvent());
socket.close();
monitor.close();
context.term();
}
@Test
public void testEventMonitorStopped()
{
Context context = ZMQ.context(1);
ZMQ.Event event;
Socket socket = context.socket(ZMQ.REP);
Socket monitor = context.socket(ZMQ.PAIR);
monitor.setReceiveTimeOut(100);
assertTrue(socket.monitor("inproc://monitor.socket", ZMQ.EVENT_MONITOR_STOPPED));
monitor.connect("inproc://monitor.socket");
socket.monitor(null, 0);
event = ZMQ.Event.recv(monitor);
assertNotNull("No event was received", event);
assertEquals(ZMQ.EVENT_MONITOR_STOPPED, event.getEvent());
socket.close();
monitor.close();
context.term();
}
@Test
public void testSocketUnbind()
{
Context context = ZMQ.context(1);
Socket push = context.socket(ZMQ.PUSH);
Socket pull = context.socket(ZMQ.PULL);
pull.setReceiveTimeOut(50);
int port = pull.bindToRandomPort("tcp://127.0.0.1");
push.connect("tcp://127.0.0.1:" + port);
byte[] data = "ABC".getBytes();
push.send(data);
assertArrayEquals(data, pull.recv());
pull.unbind("tcp://127.0.0.1:" + port);
push.send(data);
assertNull(pull.recv());
push.close();
pull.close();
context.term();
}
@Test
public void testContextBlocky()
{
Context ctx = ZMQ.context(1);
Socket router = ctx.socket(ZMQ.ROUTER);
long rc = router.getLinger();
assertEquals(-1, rc);
router.close();
ctx.setBlocky(false);
router = ctx.socket(ZMQ.ROUTER);
rc = router.getLinger();
assertEquals(0, rc);
router.close();
ctx.term();
}
@Test(timeout = 1000)
public void testSocketDoubleClose()
{
Context ctx = ZMQ.context(1);
Socket socket = ctx.socket(ZMQ.PUSH);
socket.close();
socket.close();
}
}
jeromq-0.3.5/src/test/java/org/zeromq/TestZPoller.java 0000664 0000000 0000000 00000004020 12551504772 0022705 0 ustar 00root root 0000000 0000000 package org.zeromq;
import java.io.IOException;
import java.nio.channels.SelectableChannel;
import org.junit.Assert;
import org.junit.Test;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZPoller.EventsHandler;
public class TestZPoller
{
@Test
public void testUseNull() throws IOException
{
ZContext ctx = null; //new ZContext();
ZPoller poller = new ZPoller(new ZStar.VerySimpleSelectorCreator().create());
SelectableChannel channel = null;
Socket socket = null; //ctx.createSocket(ZMQ.SUB);
boolean rc = false;
rc = poller.register(socket, ZPoller.IN);
Assert.assertFalse("Registering a null socket was successful", rc);
rc = poller.register(channel, ZPoller.OUT);
Assert.assertFalse("Registering a null channel was successful", rc);
int events = poller.poll(10);
Assert.assertEquals("reading event on without sockets", 0, events);
rc = poller.isReadable(socket);
Assert.assertFalse("checking read event on a null socket was successful", rc);
rc = poller.writable(socket);
Assert.assertFalse("checking write event on a null socket was successful", rc);
rc = poller.readable(channel);
Assert.assertFalse("checking read event on a null channel was successful", rc);
rc = poller.isWritable(channel);
Assert.assertFalse("checking write event on a null channel was successful", rc);
EventsHandler global = null;
poller.setGlobalHandler(global);
EventsHandler handler = null;
rc = poller.register(socket, handler, ZPoller.ERR);
Assert.assertFalse("Register with handler on a null socket was successful", rc);
rc = poller.register(channel, ZPoller.ERR);
Assert.assertFalse("Register with handler on a null channel was successful", rc);
events = poller.poll(10);
Assert.assertEquals("reading event with events handlers without sockets", 0, events);
poller.close();
System.out.println();
}
}
jeromq-0.3.5/src/test/java/org/zeromq/TestZProxy.java 0000664 0000000 0000000 00000007427 12551504772 0022607 0 ustar 00root root 0000000 0000000 package org.zeromq;
import java.util.Arrays;
import org.junit.Assert;
import org.junit.Test;
import org.zeromq.ZMQ.Socket;
public class TestZProxy
{
@Test
public void testAllOptions()
{
final ZProxy.Proxy provider = new ZProxy.Proxy.SimpleProxy()
{
public Socket create(ZContext ctx, ZProxy.Plug place, Object[] extraArgs)
{
Socket socket = null;
if (place == ZProxy.Plug.FRONT) {
socket = ctx.createSocket(ZMQ.ROUTER);
}
if (place == ZProxy.Plug.BACK) {
socket = ctx.createSocket(ZMQ.DEALER);
}
return socket;
}
public void configure(Socket socket, ZProxy.Plug place, Object[] extrArgs)
{
if (place == ZProxy.Plug.FRONT) {
socket.bind("tcp://127.0.0.1:6660");
}
if (place == ZProxy.Plug.BACK) {
socket.bind("tcp://127.0.0.1:6661");
}
if (place == ZProxy.Plug.CAPTURE && socket != null) {
socket.bind("tcp://127.0.0.1:4263");
}
}
@Override
public boolean restart(ZMsg cfg, Socket socket, ZProxy.Plug place, Object[] extraArgs)
{
if (place == ZProxy.Plug.FRONT) {
socket.unbind("tcp://127.0.0.1:6660");
socket.bind("tcp://127.0.0.1:6660");
}
if (place == ZProxy.Plug.BACK) {
socket.unbind("tcp://127.0.0.1:6661");
socket.bind("tcp://127.0.0.1:6661");
}
if (place == ZProxy.Plug.CAPTURE && socket != null) {
socket.unbind("tcp://127.0.0.1:4263");
socket.bind("tcp://127.0.0.1:5347");
}
return false;
}
@Override
public boolean configure(Socket pipe, ZMsg cfg, Socket frontend, Socket backend, Socket capture, Object[] args)
{
assert (cfg.popString().equals("TEST-CONFIG"));
ZMsg msg = new ZMsg();
msg.add("TODO");
msg.send(pipe);
return true;
}
@Override
public boolean custom(Socket pipe, String cmd, Socket frontend,
Socket backend, Socket capture, Object[] args)
{
// TODO test custom commands
return super.custom(pipe, cmd, frontend, backend, capture, args);
}
};
ZProxy proxy = ZProxy.newProxy(null, "ProxyOne", provider, "ABRACADABRA", Arrays.asList("TEST"));
final boolean async = false;
final boolean sync = true;
String status = null;
status = proxy.status(async);
Assert.assertEquals("async status before any operation is not good!", ZProxy.ALIVE, status);
status = proxy.start(async);
Assert.assertEquals("Start async status is not good!", ZProxy.STOPPED, status);
status = proxy.pause(async);
Assert.assertEquals("Pause async status is not good!", ZProxy.STARTED, status);
status = proxy.stop(async);
Assert.assertEquals("Stop async status is not good!", ZProxy.PAUSED, status);
status = proxy.status(async);
Assert.assertEquals("async status is not good!", ZProxy.STOPPED, status);
ZMsg msg = new ZMsg();
msg.add("TEST-CONFIG");
ZMsg recvd = proxy.configure(msg);
Assert.assertEquals("TODO", recvd.popString());
System.out.println("Received config");
proxy.exit(async);
// rc = pipe.send("boom ?!");
// assert (!rc);
System.out.println();
}
}
jeromq-0.3.5/src/test/java/org/zeromq/TestZStar.java 0000664 0000000 0000000 00000005572 12551504772 0022376 0 ustar 00root root 0000000 0000000 package org.zeromq;
import java.nio.channels.Selector;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import org.junit.Assert;
import org.junit.Test;
import org.zeromq.ZMQ.Socket;
import org.zeromq.ZStar.Fortune;
public class TestZStar
{
private final class BlackHole implements ZStar.Fortune
{
@Override
public String premiere(Socket mic, Object[] args)
{
return "Test " + Arrays.toString(args);
}
@Override
public ZStar.Star create(ZContext ctx, Socket pipe, Selector sel, int count,
ZStar.Star previous, Object[] args)
{
return new NoNo();
}
@Override
public boolean interview(Socket mic)
{
System.out.print("Fortune is not here anymore ...");
// tell that star is not here anymore
return true;
}
@Override
public void party(ZContext ctx)
{
// do nothing
System.out.print(" Cleaning the remains.. ");
}
}
private final class NoNo implements ZStar.Star
{
@Override
public void prepare()
{
// do nothing
}
@Override
public int breathe()
{
return -1;
}
@Override
public boolean act(int events)
{
return false;
}
@Override
public boolean entract()
{
return false;
}
@Override
public boolean renews()
{
return false;
}
}
@Test
public void testNoStar()
{
System.out.print("No star: ");
ZStar.Fortune fortune = new BlackHole();
ZStar.Entourage entourage = new ZStar.Entourage()
{
@Override
public void breakaleg(ZContext ctx, Fortune fortune, Socket phone,
Object[] bags)
{
// Crepi il lupo!
}
@Override
public void party(ZContext ctx)
{
// right now there are some random closing issues
ZStar.party(30, TimeUnit.MILLISECONDS);
// waited a bit here seems to arrange that.
// no user penalty cost, the show is over.
}
};
ZStar star = new ZStar(fortune, "motdelafin", Arrays.asList("TEST", entourage).toArray());
ZMsg msg = star.recv();
Assert.assertNull("Able to receive a message from a black hole", msg);
boolean rc = star.sign();
Assert.assertFalse("Able to detect the presence of a black hole", rc);
rc = star.send("whatever");
Assert.assertFalse("Able to send a command to a black hole", rc);
// don't try it
// rc = star.pipe().send("boom ?!");
// star.retire();
System.out.println(".");
}
}
jeromq-0.3.5/src/test/java/org/zeromq/TestZThread.java 0000664 0000000 0000000 00000004145 12551504772 0022667 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package org.zeromq;
import org.zeromq.ZMQ.Socket;
import org.junit.Assert;
import org.junit.Test;
public class TestZThread
{
@Test
public void testDetached()
{
ZThread.IDetachedRunnable detached = new ZThread.IDetachedRunnable()
{
@Override
public void run(Object[] args)
{
ZContext ctx = new ZContext();
assert (ctx != null);
Socket push = ctx.createSocket(ZMQ.PUSH);
assert (push != null);
ctx.destroy();
}
};
ZThread.start(detached);
}
@Test
public void testFork()
{
ZContext ctx = new ZContext();
ZThread.IAttachedRunnable attached = new ZThread.IAttachedRunnable()
{
@Override
public void run(Object[] args, ZContext ctx, Socket pipe)
{
// Create a socket to check it'll be automatically deleted
ctx.createSocket(ZMQ.PUSH);
pipe.recvStr();
pipe.send("pong");
}
};
Socket pipe = ZThread.fork(ctx, attached);
assert (pipe != null);
pipe.send("ping");
String pong = pipe.recvStr();
Assert.assertEquals(pong, "pong");
// Everything should be cleanly closed now
ctx.destroy();
}
}
jeromq-0.3.5/src/test/java/org/zeromq/ZBeaconTest.java 0000664 0000000 0000000 00000003372 12551504772 0022650 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package org.zeromq;
import java.net.InetAddress;
import org.junit.Test;
import org.zeromq.ZBeacon.Listener;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
public class ZBeaconTest
{
@Test
public void test() throws InterruptedException
{
final CountDownLatch latch = new CountDownLatch(1);
byte[] beacon = new byte[] { 'H', 'Y', 'D', 'R', 'A', 0x01, 0x12, 0x34 };
byte[] prefix = new byte[] { 'H', 'Y', 'D', 'R', 'A', 0x01 };
ZBeacon zbeacon = new ZBeacon("255.255.255.255", 5670, beacon, false);
zbeacon.setPrefix(prefix);
zbeacon.setListener(new Listener()
{
@Override
public void onBeacon(InetAddress sender, byte[] beacon)
{
latch.countDown();
}
});
zbeacon.start();
latch.await(20, TimeUnit.SECONDS);
assertEquals(latch.getCount(), 0);
zbeacon.stop();
}
}
jeromq-0.3.5/src/test/java/org/zeromq/ZMsgTest.java 0000664 0000000 0000000 00000003760 12551504772 0022210 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package org.zeromq;
import org.junit.Assert;
import org.junit.Test;
/**
* Created by hartmann on 3/21/14.
*/
public class ZMsgTest
{
@Test
public void testRecvFrame() throws Exception
{
ZMQ.Context ctx = ZMQ.context(0);
ZMQ.Socket socket = ctx.socket(ZMQ.PULL);
ZFrame f = ZFrame.recvFrame(socket, ZMQ.NOBLOCK);
Assert.assertNull(f);
socket.close();
ctx.close();
}
@Test
public void testRecvMsg() throws Exception
{
ZMQ.Context ctx = ZMQ.context(0);
ZMQ.Socket socket = ctx.socket(ZMQ.PULL);
ZMsg msg = ZMsg.recvMsg(socket, ZMQ.NOBLOCK);
Assert.assertNull(msg);
socket.close();
ctx.close();
}
@Test
public void testRecvNullByteMsg() throws Exception
{
ZMQ.Context ctx = ZMQ.context(0);
ZMQ.Socket sender = ctx.socket(ZMQ.PUSH);
ZMQ.Socket receiver = ctx.socket(ZMQ.PULL);
receiver.bind("inproc://" + this.hashCode());
sender.connect("inproc://" + this.hashCode());
sender.send(new byte[0]);
ZMsg msg = ZMsg.recvMsg(receiver, ZMQ.NOBLOCK);
Assert.assertNotNull(msg);
sender.close();
receiver.close();
ctx.close();
}
}
jeromq-0.3.5/src/test/java/perf/ 0000775 0000000 0000000 00000000000 12551504772 0016447 5 ustar 00root root 0000000 0000000 jeromq-0.3.5/src/test/java/perf/InprocLat.java 0000664 0000000 0000000 00000010352 12551504772 0021206 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package perf;
import zmq.Ctx;
import zmq.Msg;
import zmq.SocketBase;
import zmq.ZMQ;
public class InprocLat
{
private InprocLat()
{
}
static class Worker implements Runnable
{
private Ctx ctx;
private int roundtripCount;
Worker(Ctx ctx, int roundtripCount)
{
this.ctx = ctx;
this.roundtripCount = roundtripCount;
}
@Override
public void run()
{
SocketBase s = ZMQ.socket(ctx, ZMQ.ZMQ_REP);
if (s == null) {
printf("error in socket: %s\n");
exit(1);
}
boolean rc = ZMQ.connect(s, "inproc://lat_test");
if (!rc) {
printf("error in connect: %s\n");
exit(1);
}
Msg msg;
for (int i = 0; i != roundtripCount; i++) {
msg = ZMQ.recvMsg(s, 0);
if (msg == null) {
printf("error in recvmsg: %s\n");
exit(1);
}
int r = ZMQ.sendMsg(s, msg, 0);
if (r < 0) {
printf("error in sendmsg: %s\n");
exit(1);
}
}
ZMQ.close(s);
}
private void exit(int i)
{
// TODO Auto-generated method stub
}
}
public static void main(String[] argv) throws Exception
{
if (argv.length != 2) {
printf("usage: inproc_lat \n");
return;
}
int messageSize = atoi(argv [0]);
int roundtripCount = atoi(argv [1]);
Ctx ctx = ZMQ.init(1);
if (ctx == null) {
printf("error in init:");
return;
}
SocketBase s = ZMQ.socket(ctx, ZMQ.ZMQ_REQ);
if (s == null) {
printf("error in socket: ");
return;
}
boolean rc = ZMQ.bind(s, "inproc://lat_test");
if (!rc) {
printf("error in bind: ");
return;
}
Thread localThread = new Thread(new Worker(ctx, roundtripCount));
localThread.start();
Msg smsg = ZMQ.msgInitWithSize(messageSize);
printf("message size: %d [B]\n", (int) messageSize);
printf("roundtrip count: %d\n", (int) roundtripCount);
long watch = ZMQ.startStopwatch();
for (int i = 0; i != roundtripCount; i++) {
int r = ZMQ.sendMsg(s, smsg, 0);
if (r < 0) {
printf("error in sendmsg: %s\n");
return;
}
Msg msg = ZMQ.recvMsg(s, 0);
if (msg == null) {
printf("error in recvmsg: %s\n");
return;
}
if (ZMQ.msgSize(msg) != messageSize) {
printf("message of incorrect size received\n");
return;
}
}
long elapsed = ZMQ.stopStopwatch(watch);
double latency = (double) elapsed / (roundtripCount * 2);
localThread.join();
printf("average latency: %.3f [us]\n", (double) latency);
ZMQ.close(s);
ZMQ.term(ctx);
}
private static int atoi(String string)
{
return Integer.parseInt(string);
}
private static void printf(String string)
{
System.out.println(string);
}
private static void printf(String string, Object ... args)
{
System.out.println(String.format(string, args));
}
}
jeromq-0.3.5/src/test/java/perf/LocalLat.java 0000664 0000000 0000000 00000005431 12551504772 0021010 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package perf;
import zmq.Ctx;
import zmq.Msg;
import zmq.SocketBase;
import zmq.ZMQ;
public class LocalLat
{
private LocalLat()
{
}
public static void main(String[] args)
{
String bindTo;
int roundtripCount;
int messageSize;
Ctx ctx;
SocketBase s;
boolean rc;
int n;
int i;
Msg msg;
if (args.length != 3) {
printf("usage: local_lat "
+ "\n");
return;
}
bindTo = args [0];
messageSize = atoi(args [1]);
roundtripCount = atoi(args [2]);
ctx = ZMQ.init(1);
if (ctx == null) {
printf("error in init: %s\n");
return;
}
s = ZMQ.socket(ctx, ZMQ.ZMQ_REP);
if (s == null) {
printf("error in socket: %s\n", ZMQ.strerror(s.errno()));
return;
}
rc = ZMQ.bind(s, bindTo);
if (!rc) {
printf("error in bind: %s\n", ZMQ.strerror(s.errno()));
return;
}
for (i = 0; i != roundtripCount; i++) {
msg = ZMQ.recvMsg(s, 0);
if (msg == null) {
printf("error in recvmsg: %s\n", ZMQ.strerror(s.errno()));
return;
}
if (ZMQ.msgSize(msg) != messageSize) {
printf("message of incorrect size received\n");
return;
}
n = ZMQ.sendMsg(s, msg, 0);
if (n < 0) {
printf("error in sendmsg: %s\n", ZMQ.strerror(s.errno()));
return;
}
}
ZMQ.sleep(1000);
ZMQ.close(s);
ZMQ.term(ctx);
}
private static int atoi(String string)
{
return Integer.parseInt(string);
}
private static void printf(String string)
{
System.out.println(string);
}
private static void printf(String string, Object ... args)
{
System.out.println(String.format(string, args));
}
}
jeromq-0.3.5/src/test/java/perf/LocalThr.java 0000664 0000000 0000000 00000007071 12551504772 0021027 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package perf;
import zmq.Ctx;
import zmq.Msg;
import zmq.SocketBase;
import zmq.ZMQ;
public class LocalThr
{
private LocalThr()
{
}
public static void main(String[] argv)
{
String bindTo;
long messageCount;
int messageSize;
Ctx ctx;
SocketBase s;
boolean rc;
long i;
Msg msg;
long watch;
long elapsed;
long throughput;
double megabits;
if (argv.length != 3) {
printf("usage: local_thr \n");
return;
}
bindTo = argv [0];
messageSize = atoi(argv [1]);
messageCount = atol(argv [2]);
ctx = ZMQ.init(1);
if (ctx == null) {
printf("error in init");
return;
}
s = ZMQ.socket(ctx, ZMQ.ZMQ_PULL);
if (s == null) {
printf("error in socket");
}
// Add your socket options here.
// For example ZMQ_RATE, ZMQ_RECOVERY_IVL and ZMQ_MCAST_LOOP for PGM.
rc = ZMQ.bind(s, bindTo);
if (!rc) {
printf("error in bind: %s\n");
return;
}
msg = ZMQ.recvMsg(s, 0);
if (msg == null) {
printf("error in recvmsg: %s\n");
return;
}
watch = ZMQ.startStopwatch();
for (i = 0; i != messageCount - 1; i++) {
msg = ZMQ.recvMsg(s, 0);
if (msg == null) {
printf("error in recvmsg: %s\n");
return;
}
if (ZMQ.msgSize(msg) != messageSize) {
printf("message of incorrect size received " + ZMQ.msgSize(msg));
return;
}
}
elapsed = ZMQ.stopStopwatch(watch);
if (elapsed == 0) {
elapsed = 1;
}
throughput = (long)
((double) messageCount / (double) elapsed * 1000000L);
megabits = (double) (throughput * messageSize * 8) / 1000000;
printf("message elapsed: %.3f \n", (double) elapsed / 1000000L);
printf("message size: %d [B]\n", (int) messageSize);
printf("message count: %d\n", (int) messageCount);
printf("mean throughput: %d [msg/s]\n", (int) throughput);
printf("mean throughput: %.3f [Mb/s]\n", (double) megabits);
ZMQ.close(s);
ZMQ.term(ctx);
}
private static void printf(String str, Object ... args)
{
// TODO Auto-generated method stub
System.out.println(String.format(str, args));
}
private static int atoi(String string)
{
return Integer.valueOf(string);
}
private static long atol(String string)
{
return Long.valueOf(string);
}
private static void printf(String string)
{
System.out.println(string);
}
}
jeromq-0.3.5/src/test/java/perf/RemoteThr.java 0000664 0000000 0000000 00000005065 12551504772 0021231 0 ustar 00root root 0000000 0000000 /*
Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
package perf;
import zmq.Ctx;
import zmq.Msg;
import zmq.SocketBase;
import zmq.ZMQ;
public class RemoteThr
{
private RemoteThr()
{
}
public static void main(String[] argv)
{
String connectTo;
long messageCount;
int messageSize;
Ctx ctx;
SocketBase s;
boolean rc;
long i;
Msg msg;
if (argv.length != 3) {
printf("usage: remote_thr