/*
* Copyright 2014 University of Southern California
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package edu.usc.pgroup.zmq;
import edu.usc.pgroup.floe.container.FlakeControlCommand;
import edu.usc.pgroup.floe.utils.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zeromq.ZMQ;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
/**
* @author kumbhare
*/
public class TestZMQ {
/**
* Logger.
*/
private static final Logger LOGGER =
LoggerFactory.getLogger(TestZMQ.class);
private static class Flake {
private final String fid;
private final boolean source;
private Integer[] listeningPorts;
List<Pellet> pellets;
ZMQ.Context context;
public Flake(String fid, Integer[] listeningPorts, boolean source) {
this.source = source;
pellets = new ArrayList<>();
this.fid = fid;
this.listeningPorts = listeningPorts;
this.context = ZMQ.context(3);
}
public void run() {
LOGGER.info("Starting flake:"+fid);
startSender();
startReceiver();
}
void startSender() {
new FlakeSender(context, listeningPorts).start();
}
void startReceiver() {
new FlakeReceiver(context).start();
}
public void createPellet(String pid, boolean source) {
Pellet p = new Pellet(context, fid, pid, source);
p.start();
}
private class FlakeSender extends Thread {
private final ZMQ.Context context;
private final Integer[] listeningPorts;
public FlakeSender(ZMQ.Context context, Integer[] listeningPorts) {
this.context = context;
this.listeningPorts = listeningPorts;
}
public void run() {
new MiddleEnd().start();
/*ZMQ.Socket middleendreceiver = context.socket(ZMQ.SUB);
middleendreceiver.connect("inproc://sender-middleend-"+ fid);
middleendreceiver.subscribe("".getBytes()); //dummy topic.*/
//ZMQ.Socket backend = context.socket(ZMQ.PUSH);
for(Integer port: listeningPorts) {
//backend.bind("tcp://*:" + port);
new BackEnd(port).start();
}
/*for(int i = 0; ; i++) {
backend.send(String.valueOf(i));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}*/
//ZMQ.proxy(middleendreceiver, backend, null);
}
private class BackEnd extends Thread {
private final int port;
public BackEnd(int port) {
this.port = port;
}
public void run() {
ZMQ.Socket middleendreceiver = context.socket(ZMQ.SUB);
middleendreceiver.connect("inproc://sender-middleend-"+ fid);
middleendreceiver.subscribe("".getBytes()); //dummy topic.
ZMQ.Socket backend = context.socket(ZMQ.PUSH);
backend.bind("tcp://*:" + port);
ZMQ.proxy(middleendreceiver, backend, null);
}
}
private class MiddleEnd extends Thread {
public void run() {
ZMQ.Socket frontend = context.socket(ZMQ.PULL);
frontend.bind("inproc://sender-frontend-"+ fid);
ZMQ.Socket middleend = context.socket(ZMQ.PUB);
middleend.bind("inproc://sender-middleend-"+ fid);
ZMQ.proxy(frontend, middleend, null);
}
}
}
private class FlakeReceiver extends Thread {
private final ZMQ.Context context;
public FlakeReceiver(ZMQ.Context context) {
this.context = context;
}
public void run() {
ZMQ.Socket frontend = context.socket(ZMQ.PULL);
/*for(Integer port: connectPorts) {
frontend.connect("tcp://localhost:" + port);
}*/
ZMQ.Socket backend = context.socket(ZMQ.PUSH);
backend.bind("inproc://receiver-backend-" + fid);
ZMQ.Socket controlSocket = context.socket(ZMQ.REP);
controlSocket.bind("ipc://flake-control-" + fid);
ZMQ.Poller pollerItems = new ZMQ.Poller(2);
pollerItems.register(frontend, ZMQ.Poller.POLLIN);
pollerItems.register(controlSocket, ZMQ.Poller.POLLIN);
while (!Thread.currentThread().isInterrupted()) {
byte[] message;
pollerItems.poll();
if (pollerItems.pollin(0)) {
//forward to the backend.
message = frontend.recv();
backend.send(message, 0);
} else if (pollerItems.pollin(1)) {
message = controlSocket.recv();
//process control message.
FlakeControlCommand command
= (FlakeControlCommand) Utils.deserialize(
message);
/*FlakeCommandExecutor.execute(command);*/
switch (command.getCommand()) {
case CONNECT_PRED:
String connectstr = (String) command.getData();
LOGGER.info("Connecting to: " + connectstr);
frontend.connect(connectstr);
break;
case INCREMENT_PELLET:
String pid = (String) command.getData();
LOGGER.info("CREATING PELLET: " + pid + " on "
+ fid);
createPellet(pid, source);
break;
case DECREMENT_PELLET:
break;
}
byte result[] = new byte[1];
controlSocket.send(result,0);
}
}
//ZMQ.proxy(frontend, backend, null);
/*for(int i = 0; ; i++) {
String recv = frontend.recvStr(Charset.defaultCharset());
System.out.println(fid + " " + i +" : " +recv);
}*/
}
}
}
private static class Pellet extends Thread{
private final String pid;
private final String fid;
private final boolean source;
private final ZMQ.Context context;
public Pellet(ZMQ.Context context, String fid, String pid,
boolean source) {
this.pid = pid;
this.fid = fid;
this.source = source;
this.context = context;
}
public void run() {
// Prepare our context and sockets
ZMQ.Socket clientsender = context.socket(ZMQ.PUSH);
clientsender.connect("inproc://sender-frontend-"+ fid);
ZMQ.Socket clientreceiver = null;
clientreceiver = context.socket(ZMQ.PULL);
clientreceiver.connect("inproc://receiver-backend-" + fid);
int i = 0;
while(true) {
String data = String.valueOf(i++);
if(!source) {
data = clientreceiver.recvStr(Charset.defaultCharset());
System.out.println(fid + " : " + pid + " : " + data);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
clientsender.send("from:" + pid + "=" + data);
}
// Send request, get reply
}
}
public static void main(String[] args) {
//NUMBER OF LISTENING PORTS IS FIXED BY THE TOPOLOGY. ONE FOR EACH
// LOGICAL EDGE.
Flake c1f1 = new Flake("f1", new Integer[]{5009}, true);
Flake c1f2 = new Flake("f2", new Integer[]{5011}, false);
/*Flake c2f4 = new Flake("f4", new Integer[]{5009, 5010},
new Integer[]{5009, 5010});*/
c1f1.run();
c1f2.run();
//"ipc://flake-control-" + fid
ZMQ.Context ctx = ZMQ.context(1);
ZMQ.Socket f1control = ctx.socket(ZMQ.REQ);
f1control.connect("ipc://flake-control-f1");
ZMQ.Socket f2control = ctx.socket(ZMQ.REQ);
f2control.connect("ipc://flake-control-f2");
byte[] results;
//command 1 : increment pellet f1
FlakeControlCommand command = new FlakeControlCommand(
FlakeControlCommand.Command.INCREMENT_PELLET, "p1");
f1control.send(Utils.serialize(command), 0);
results = f1control.recv();
//command 2 : increment pellet f2
FlakeControlCommand command2 = new FlakeControlCommand(
FlakeControlCommand.Command.INCREMENT_PELLET, "p2");
f2control.send(Utils.serialize(command2), 0);
results = f2control.recv();
//command 3 : connect f2 to f1
FlakeControlCommand command3 = new FlakeControlCommand(
FlakeControlCommand.Command.CONNECT_PRED,
"tcp://localhost:5009");
f2control.send(Utils.serialize(command3), 0);
results = f2control.recv();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//command 4 : increment pellet f2
FlakeControlCommand command4 = new FlakeControlCommand(
FlakeControlCommand.Command.INCREMENT_PELLET, "p3");
f2control.send(Utils.serialize(command4), 0);
results = f2control.recv();
/*Flake c2f3 = new Flake("f3", new Integer[]{5012},
new Integer[]{5010});
c2f3.run();
c2f3.createPellet("p3", false);
c2f3.createPellet("p4", false);*/
//c2f4.createPellet("p4", false);
}
}