package net.varkhan.serv.p2p.util;
import net.varkhan.base.containers.array.Arrays;
import net.varkhan.base.management.report.JMXAverageMonitorReport;
import net.varkhan.serv.p2p.PeerHub;
import net.varkhan.serv.p2p.message.dispatch.MesgSender;
import net.varkhan.serv.p2p.network.P2PGroup;
import net.varkhan.serv.p2p.connect.*;
import net.varkhan.serv.p2p.message.dispatch.MesgDispatcher;
import net.varkhan.serv.p2p.message.MesgPayload;
import net.varkhan.serv.p2p.message.dispatch.MesgReceiver;
import net.varkhan.serv.p2p.message.dispatch.SingleReceiver;
import net.varkhan.serv.p2p.message.protocol.BinaryPayload;
import net.varkhan.serv.p2p.message.dispatch.AsyncDispatcher;
import net.varkhan.serv.p2p.network.P2PHub;
import net.varkhan.serv.p2p.connect.config.MapProperties;
import java.io.*;
import java.nio.charset.Charset;
import java.util.List;
import java.util.ArrayList;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
/**
* <b>A peering monitoring and testing shell that gives command-line access to the basic operations of this protocol.</b>
* <p/>
* This class implements a command shell, that creates a peer hub (set up according to parameters
* specified as arguments), and interactively prompts for commands, that give access to administrative
* operations on the node, monitoring and reporting tools, and communication primitives to other nodes
* or groups.
* <p/>
* A peer is a <i>Host</i>, that advertises an availability status and <i>Group</i> memberships (a set of group
* names and properties). Communication between peers can be one-to-one or one-to-many, based on the definition
* of named groups (in this case, a multicast group specified by a name, and address and port number). The global
* set of nodes (the <i>Hub</i>) is represented by the <b>*</b> group, that all nodes must join in order to participate.
* In addition, each group (that has at least one member in the hub) may use several multicast addresses and ports
* to reach its members. A distributed set of shared variables (String to String mapping) is maintained across the hub.
* <p/>
* Each node maintains a view of the state of all other nodes in the hub, updated as other nodes advertise
* their state changes, including status and group membership. The <<u>return</u>> key on the command
* line, and the <u>info</u> command give respectively a concise and verbose report of this view. The <u>join</u>
* and leave commands can be used to manipulate the group memberships of the local node.
* <p/>
* A node also maintains a local cache of the distributed set of variables, updated as other nodes request changes
* in those bindings. The var command can be used to query or update the global consensus on this set of variables.
* <p/>
* In addition, the send and call commands can be used to communicate with individual nodes (identified by their
* node ID) or groups (identified by their group name). send does not expect a reply, while call will display the
* response received from the target node or nodes (in case of a group call).
* <p/>
* <h3>Startup arguments</h3>
* <p/>
* <div><b>PeerClient</b>
* [<b>-n</b> <i>node_name</i>]
* [<b>-b</b> <i>bind_addr</i>]
* [<b>-a</b> <i>hub_addr</i>]
* [<b>-c</b> <i>hub_port</i>]
* [<i>target_ID</i>] | [<b>send</b>|<b>call</b> <i>target_ID</i> <i>service_ID</i> <i>message</i>]</div>
* <p/>
* <table>
* <tr><td><b>-n</b> <i>node_name</i>
* </td><td> specify the name to be advertised by the local peer
* </td></tr>
* <tr><td><b>-b</b> <i>bind_addr</i>
* </td><td> specify the local address this node binds to
* </td></tr>
* <tr><td><b>-a</b> <i>hub_addr</i>
* </td><td> specify the multicast address used by the hub
* </td></tr>
* <tr><td><b>-c</b> <i>hub_port</i>
* </td><td> specify the multicast port used by the hub
* </td></tr>
* <tr><td><i>name</i>
* </td><td> the name of a specific peer or group to monitor
* </td></tr>
* <tr><td><b>call</b> <i>name</i> <i>service_ID</i> <i>message</i>
* </td><td> transmits a CALL message to a named peer, wait for the reply, then exits
* </td></tr>
* <tr><td><b>send</b> <i>name</i> <i>service_ID</i> <i>message</i>
* </td><td> transmits a SEND message to a named peer, then exits
* </td></tr>
* </table>
* <p/>
* <h3>Shell commands</h3>
* <table>
* <tr><td><b>help</b>
* </td><td> this help
* </td></tr>
* <tr><td><b>exit</b>
* </td><td> terminates this shell
* </td></tr>
* <tr><td><b><none></b> (the <return> key)
* </td><td> displays abbreviated node and group information for the local hub
* </td></tr>
* <tr><td><b>info</b>
* </td><td> displays detailed node and group information for the local hub
* </td></tr>
* <tr><td><b>join</b> <i>group_name</i> <i>port_number</i>
* </td><td> joins a group, with the specified multicast port
* </td></tr>
* <tr><td><b>leave</b> <i>group_name</i>
* </td><td> leaves a group
* </td></tr>
* <tr><td><b>call</b> <i>target_ID</i> <i>service_ID</i> <i>message</i>
* </td><td> transmits a CALL message to a target, and wait for the reply
* </td></tr>
* <tr><td><b>send</b> <i>target_ID</i> <i>service_ID</i> <i>message</i>
* </td><td> transmits a SEND message to a target
* </td></tr>
* <tr><td><b>var</b> <i>name</i> [<i>value</i>]
* </td><td> gets (or sets, if a value is provided) a shared variable value
* </td></tr>
* </table>
* <p/>
* @author varkhan
* @date 2/24/11
* @time 9:32 PM
*/
public class P2PClient {
private static void makePing(PeerHub hub, String name) {
System.out.println("PING");
System.out.println("--------------------------------------------------");
System.out.println("To: @"+(name==null?"*":name));
ping(hub, name);
}
private static void ping(PeerHub hub, String name) {
PeerAddress node=hub.resolve(name);
hub.ping(node);
}
private static void makeCall(PeerHub hub, String name, String method, String message) {
System.out.println("CALL");
System.out.println("--------------------------------------------------");
System.out.println("To: @"+name+"/"+method);
System.out.println(message);
MesgReceiver rh = new MesgReceiver() {
private long time = System.currentTimeMillis();
public void receive(PeerAddress src, PeerAddress dst, String method, MesgPayload message) {
System.out.println("--------------------------------------------------");
System.out.println("From: "+src.name());
try {
System.out.println(new String(message.getDataAsArray(),"UTF-8"));
} catch (IOException e) {
// ignore
}
System.out.println("--------------------------------------------------");
System.out.println("Time: "+(System.currentTimeMillis()-time)+"ms");
System.out.println();
}
public void release() {
}
public boolean finished() {
return System.currentTimeMillis()-time>getMaxDelay();
}
public long getMaxDelay() {
// Expires in 10s
return 10000;
}
public long getMaxCount() {
return Integer.MAX_VALUE;
}
};
call(hub, name, method, message, rh);
}
private static void waitCall(PeerHub hub, String name, String method, String message) {
System.out.println("CALL");
System.out.println("--------------------------------------------------");
System.out.println("To: @"+name+"/"+method);
System.out.println(message);
System.out.println("--------------------------------------------------");
SingleReceiver rh = new SingleReceiver(300000);
long time = System.currentTimeMillis();
call(hub,name,method, message, rh);
if(!rh.isReceived()) {
System.out.println("Call failed");
return;
}
System.out.println("From: "+rh.getSrc().name());
try {
System.out.println(new String(rh.getMessage().getDataAsArray()));
} catch (IOException e) {
// ignore
}
System.out.println("--------------------------------------------------");
System.out.println("Time: "+(System.currentTimeMillis()-time)+"ms");
}
private static void call(PeerHub hub, final String pointName, final String method, String message, final MesgReceiver hdlr) {
if(pointName==null) return;
final BinaryPayload msg=new BinaryPayload();
msg.setData(Charset.forName("UTF-8").encode(message));
final PeerNode node = hub.resolve(pointName).as(PeerNode.class);
if(node!=null) try {
node.call(method, msg, hdlr);
} catch (IOException e) {
// Ignore exceptions
}
else {
hub.world().addListener(new PeerGroup.GroupListener() {
private volatile boolean sent=false;
public void release() {
}
public boolean finished() {
return sent;
}
public void update(PeerGroup group) {
// Nothing there
}
public void addHost(PeerGroup group, PeerHost point) {
PeerNode addr=point.as(PeerNode.class);
if(!sent&&addr!=null&&pointName.equals(point.name())) {
waitPointHeartBeat(point);
try {
addr.call(method, msg, hdlr);
}
catch(IOException e) {
// Ignore exception
}
sent=true;
}
}
public void delHost(PeerGroup group, PeerHost point) {
// Nothing there
}
});
}
}
private static void makeSend(PeerHub hub, final String name, String method, String message) {
System.out.println("SEND");
System.out.println("--------------------------------------------------");
System.out.println("To: @"+name+"/"+method);
System.out.println(message);
send(hub,name,method, message);
}
private static void send(PeerHub hub, final String name, final String method, String message) {
if(name==null) return;
final BinaryPayload msg=new BinaryPayload();
msg.setData(Charset.forName("UTF-8").encode(message));
final PeerNode node = hub.resolve(name).as(PeerNode.class);
if(node!=null) try {
node.call(method, msg, null);
} catch (IOException e) {
// Ignore exceptions
}
else {
hub.world().addListener(new PeerGroup.GroupListener() {
private volatile boolean sent=false;
public void release() {
}
public boolean finished() {
return sent;
}
public void update(PeerGroup group) {
// Nothing there
}
public void addHost(PeerGroup group, PeerHost point) {
PeerNode addr=point.as(PeerNode.class);
if(!sent&&addr!=null&&name.equals(point.name())) {
waitPointHeartBeat(point);
try {
addr.call(method, msg, null);
}
catch(IOException e) {
// Ignore exception
}
sent=true;
}
}
public void delHost(PeerGroup group, PeerHost point) {
// Nothing there
}
});
}
}
private static void makeInfo(PeerHub hub, String name) {
PeerAddress peer = hub.resolve(name);
if(peer!=null) {
if(peer instanceof PeerHub) {
printHubDetail("", (PeerHub) peer);
}
else if(peer instanceof PeerGroup) {
printGroupDetail("", (PeerGroup) peer);
}
else if(peer instanceof PeerHost) {
printHostDetail("", (PeerHost) peer);
}
else {
System.out.println("Peer "+name+" not a recognized type");
}
}
else System.out.println("Peer "+name+" not found");
}
private static void printHubDetail(String t, PeerHub w) {
System.out.println(t+w.name()+" [");
for(PeerGroup g: w.world().groups()) {
printGroupDetail(t+"\t", g);
System.out.println();
}
System.out.println(t+"]");
System.out.println(t+"\t"+w.toString().replace("\n", "\n"+t+"\t"));
}
private static void printGroupInfo(String t, PeerGroup g) {
System.out.println(t+g.name()+"\t"+g.state());
}
private static void printGroupDetail(String t, PeerGroup g) {
System.out.println(t+g.name()+" {");
for(PeerAddress n: g.hosts()) {
if(n instanceof PeerGroup) printGroupInfo(t+"\t", (PeerGroup) n);
else if(n instanceof PeerHost) printHostInfo(t+"\t", (PeerHost) n);
}
System.out.println(t+"}");
System.out.println(t+"\t"+g.toString().replace("\n", "\n"+t+"\t"));
}
private static void printHostInfo(String t, PeerHost h) {
System.out.println(t+h.name()+"\t"+h.state());
}
private static void printHostDetail(String t, PeerHost h) {
System.out.println(t+h.name()+"\t"+h.state()+" [");
for(PeerGroup g: h.groups()) {
printGroupDetail(t+"\t", g);
}
System.out.println(t+"]");
System.out.println(t+"\t"+h.toString().replace("\n", "\n"+t+"\t"));
}
private static void waitPointHeartBeat(PeerAddress point) {
long delay = 0;
PeerHost host = point.as(PeerHost.class);
if(host!=null) delay = host.getHeartBeat();
else {
PeerGroup group = point.as(PeerGroup.class);
if(group!=null) for(PeerAddress p: group.hosts()) {
host = p.as(PeerHost.class);
if(host!=null && host.getHeartBeat()>delay) delay = host.getHeartBeat();
}
}
if(delay>0) try {
Thread.sleep(delay);
}
catch(InterruptedException e) {
// ignore
}
}
private static void makeCons(final PeerHub hub, final String key, final String value) {
Thread t = new Thread() {
public void run() {
if(value==null) System.out.println(hub.get(key));
else System.out.println(hub.set(key, value));
}
};
t.start();
}
private static String getStatus(PeerHub hub) {
if(hub==null) return "ERROR[no hub]";
StringBuilder buf = new StringBuilder();
PeerNode localNode = hub.local();
buf.append("<ServerStatus name=\"").append(localNode.name()).append("\" state=\"").append(localNode.state().name()).append("\">\n");
buf.append("\t").append("<Nodes>\n");
for(PeerAddress n: hub.world().hosts()) {
if(n instanceof PeerHost) buf.append("\t\t").append("<Node name=\"").append(n.name()).append("\" state=\"").append(((PeerHost) n).state().name()).append("\"/>\n");
}
buf.append("\t").append("</Nodes>\n");
buf.append("\t").append("<Groups>\n");
for(PeerAddress g: hub.world().hosts()) {
buf.append("\t\t").append("<Group name=\"").append(g.name()).append("\">\n");
if(g instanceof PeerGroup) {
for(PeerAddress n: ((PeerGroup) g).hosts()) {
if(n instanceof PeerHost) buf.append("\t\t\t").append("<Node name=\"").append(n.name()).append("\" state=\"").append(((PeerHost) n).state().name()).append("\"/>\n");
}
}
buf.append("\t\t").append("</Group>\n");
}
buf.append("\t").append("</Groups>\n");
buf.append("</ServerStatus>\n");
return buf.toString();
}
private static interface PointReporter {
public void report(String why, PeerAddress point);
public boolean isMute();
public void setMute(boolean mute);
}
private static PointGroupListener report(PeerHub hub, final String targetId, final PointReporter tr) {
if(targetId!=null) {
PointGroupListener ul = new PointGroupListener(targetId, tr);
hub.world().addListener(ul);
return ul;
}
return null;
}
private static final PointReporter stdoutTR=new PointReporter() {
public boolean mute=true;
public void report(String why, PeerAddress target) {
if(mute) return;
if(target instanceof PeerHost)
System.out.append(why).append("\t").append(target.name()).append(": ").println(target.toString());
else if(target instanceof PeerGroup) {
System.out.append(why).append("\t").append(target.name()).println(" {");
for(PeerAddress node : ((PeerGroup) target).hosts())
if(node instanceof PeerHost)
System.out.append("\t").append(node.name()).append(": ").println(((PeerHost) node).state());
System.out.println("}");
}
}
public boolean isMute() {
return mute;
}
public void setMute(boolean mute) {
this.mute=mute;
}
};
private static void shorthelp(PrintStream pr) {
pr.append("Usage: ").append(P2PClient.class.getSimpleName())
.append(" [-n local_name] [-b bind_addr] [-a hub_addr] [-c hub_port] [name] | [send|call name method message] ").println();
pr.println();
}
private static void inlinehelp(PrintStream pr) {
pr.append(P2PClient.class.getSimpleName()).append(" commands:").println();
pr.append("help ").append("\t- ").append("this help").println();
pr.append("exit ").append("\t- ").append("terminates this shell").println();
pr.append("<none> (<return>) ").append("\t- ").append("displays abbreviated node and group information for the local hub").println();
pr.append("info ").append("\t- ").append("displays detailed node and group information for the local hub").println();
pr.append("join group_name port_number").append("\t- ").append("joins a group, with the specified multicast port").println();
pr.append("leave group_name ").append("\t- ").append("leaves a group").println();
pr.append("call name method message ").append("\t- ").append("transmits a CALL message to a named peer, and wait for the reply").println();
pr.append("send name method message ").append("\t- ").append("transmits a SEND message to a named peer").println();
pr.append("var name [value] ").append("\t- ").append("gets (or sets, if a value is provided) a shared variable value").println();
pr.println();
}
private static void longhelp(PrintStream pr) {
pr.append(P2PClient.class.getSimpleName()).append(" options:").println();
pr.append("-n local_name ").append("\t- ").append("specify the name to be advertised by this node").println();
pr.append("-b bind_addr ").append("\t- ").append("specify the local address this node binds to").println();
pr.append("-a hub_addr ").append("\t- ").append("specify the multicast address used by the hub").println();
pr.append("-c hub_port ").append("\t- ").append("specify the multicast port used by the hub").println();
pr.append("name ").append("\t- ").append("the name of a specific peer to monitor").println();
pr.append("call name method message ").append("\t- ").append("transmit a CALL message to a named peer, wait for the reply, then exits").println();
pr.append("send name method message ").append("\t- ").append("transmit a SEND message to a named peer, then exits").println();
pr.println();
}
public static void main(String[] args) throws Exception {
String cname="admin";
String sname="PeerHubReport";
InetAddress gaddr=InetAddress.getByName("225.6.7.8");
InetAddress laddr=null;
int gport=1337;
int lport=8001;
long hearbeat=10000;
int verb=0;
List<String> al=new ArrayList<String>();
int a=0;
while(a<args.length) {
if("-h".equals(args[a])||"--help".equals(args[a])) {
shorthelp(System.out);
longhelp(System.out);
System.exit(0);
}
else if("-n".equals(args[a])||"--name".equals(args[a])) {
a++;
if(a>=args.length) {
shorthelp(System.err);
System.err.println("Node name not specified");
System.exit(5);
}
sname=args[a++];
}
else if("-c".equals(args[a])||"--hub-port".equals(args[a])) {
a++;
if(a>=args.length) {
shorthelp(System.err);
System.err.println("PeerHub port not specified");
System.exit(5);
}
try {
lport=Integer.parseInt(args[a]);
}
catch(NumberFormatException e) {
shorthelp(System.err);
System.err.println("Invalid hub port: "+args[a]);
System.exit(5);
}
a++;
}
else if("-a".equals(args[a])||"--hub-addr".equals(args[a])) {
a++;
if(a>=args.length) {
shorthelp(System.err);
System.err.println("PeerHub address not specified");
System.exit(5);
}
try {
gaddr=InetAddress.getByName(args[a]);
}
catch(UnknownHostException e) {
shorthelp(System.err);
System.err.println("Invalid hub address: "+args[a]);
System.exit(5);
}
a++;
}
else if("-b".equals(args[a])||"--bind".equals(args[a])) {
a++;
if(a>=args.length) {
shorthelp(System.err);
System.err.println("Local address not specified");
System.exit(5);
}
try {
laddr=InetAddress.getByName(args[a]);
}
catch(UnknownHostException e) {
shorthelp(System.err);
System.err.println("Invalid local address: "+args[a]);
System.exit(5);
}
// try {
// if(NetworkInterface.getByInetAddress(laddr)==null) {
// shorthelp(System.err);
// System.err.println("No such local address: "+args[a]);
// System.exit(5);
// }
// }
// catch(SocketException e) {
// shorthelp(System.err);
// System.err.println("Local address unavailable: "+args[a]);
// e.printStackTrace(System.err);
// System.exit(5);
// }
a++;
}
else if("-v".equals(args[a])||"--verbose".equals(args[a])) {
a++;
verb++;
}
else {
al.add(args[a++]);
}
}
String tname=cname+'.'+sname+'-'+Long.toHexString(System.nanoTime()).toUpperCase();
final P2PHub hub;
try {
ThreadPoolExecutor exec=new ThreadPoolExecutor(5, 10, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(100));
MesgDispatcher disp=new AsyncDispatcher(exec, new JMXAverageMonitorReport(10, "Peer", "dispatch", tname), 10);
TraceMessageExecutor trace=new TraceMessageExecutor(sname, disp);
hub=new P2PHub(tname, trace, laddr, lport, gaddr, gport, hearbeat);
trace.setHub(hub);
}
catch(IOException e) {
System.err.println("IO error creating "+tname+":");
e.printStackTrace();
System.exit(2);
return;
}
hub.start();
// hub.join(cname, new MapProperties());
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
hub.stop();
}
});
// hub.start();
if(al.size()>3) {
final String type=al.get(0);
final String targetId=al.get(1);
final String serviceId=al.get(2);
final String message=al.get(3);
if("call".equalsIgnoreCase(type)) waitCall(hub, targetId, serviceId, message);
else if("send".equalsIgnoreCase(type)) makeSend(hub, targetId, serviceId, message);
else {
shorthelp(System.err);
System.err.println("Invalid call type: "+type);
System.exit(5);
}
System.exit(0);
}
if(al.size()>0) report(hub, al.get(0), stdoutTR);
PushbackInputStream ins=new PushbackInputStream(System.in);
BufferedReader inr=new BufferedReader(new InputStreamReader(ins));
System.out.flush();
System.err.flush();
System.out.print("> ");
System.out.flush();
for(;;) {
try {
synchronized(System.in) {
System.in.wait(100);
}
}
catch(InterruptedException e) {
// Ignore
}
// try {
// if(ins.available()==0) continue;
// int b = ins.read();
// // Exit if we reached EOF or the user typed Ctrl-D (EOT=004)
// if(b<0 || b==4) break;
// ins.unread(b);
// }
// catch(IOException e) {
// continue;
// }
String line;
try {
line=inr.readLine();
}
catch(IOException e) {
line=null;
}
if(line!=null) {
String[] cmdargs=Command.splitCmd(line.trim());
if(verb>2) System.err.println("CMD: \""+Arrays.join("\" \"", cmdargs)+"\"");
if(cmdargs.length>0&&cmdargs[0].length()>0) try {
final String cmd=cmdargs[0];
if(cmd.equalsIgnoreCase("exit")) System.exit(0);
else if(cmd.equalsIgnoreCase("help")||cmd.equalsIgnoreCase("h")||cmd.equalsIgnoreCase("?"))
inlinehelp(System.out);
else if(cmd.equalsIgnoreCase("info")) {
if(cmdargs.length<2) makeInfo(hub, null);
else makeInfo(hub, cmdargs[1]);
}
else if(cmd.equalsIgnoreCase("verb")) {
if(cmdargs.length<2) {
inlinehelp(System.err);
System.err.println("Too few arguments for command "+cmd);
}
else {
if(cmdargs[1].equals("0")||cmdargs[1].equalsIgnoreCase("false")) stdoutTR.setMute(true);
else if(cmdargs[1].equals("1")||cmdargs[1].equalsIgnoreCase("true"))
stdoutTR.setMute(false);
}
}
else if(cmd.equalsIgnoreCase("ping")) {
if(cmdargs.length<2) {
makePing(hub, null);
}
else {
makePing(hub, cmdargs[1]);
}
// Wait half a second to get reply before showing prompt again
try {
Thread.sleep(250);
}
catch(InterruptedException e) {
// ignore
}
}
else if(cmd.equalsIgnoreCase("call")) {
if(cmdargs.length<4) {
inlinehelp(System.err);
System.err.println("Too few arguments for command "+cmd);
}
else {
makeCall(hub, cmdargs[1], cmdargs[2], cmdargs[3]);
// Wait half a second to get reply before showing prompt again
try {
Thread.sleep(250);
}
catch(InterruptedException e) {
// ignore
}
}
}
else if(cmd.equalsIgnoreCase("send")) {
if(cmdargs.length<4) {
inlinehelp(System.err);
System.err.println("Too few arguments for command "+cmd);
}
else makeSend(hub, cmdargs[1], cmdargs[2], cmdargs[3]);
}
else if(cmd.equalsIgnoreCase("join")) {
if(cmdargs.length<4) {
inlinehelp(System.err);
System.err.println("Too few arguments for command "+cmd);
}
else try {
String groupName=cmdargs[1];
InetAddress groupAddr="-".equals(cmdargs[2]) ? gaddr : InetAddress.getByName(cmdargs[2]);
int groupPort=Integer.parseInt(cmdargs[3]);
hub.join(groupName, P2PGroup.getProperties(new MapProperties(), groupName, groupAddr, groupPort));
}
catch(NumberFormatException e) {
inlinehelp(System.err);
System.err.println("Invalid port number for "+cmd);
}
}
else if(cmd.equalsIgnoreCase("leave")) {
if(cmdargs.length<2) {
inlinehelp(System.err);
System.err.println("Too few arguments for command "+cmd);
}
else {
hub.leave(cmdargs[1]);
}
}
else if(cmd.equalsIgnoreCase("var")) {
if(cmdargs.length<2) {
inlinehelp(System.err);
System.err.println("Too few arguments for command "+cmd);
}
else {
makeCons(hub, cmdargs[1], cmdargs.length>2 ? cmdargs[2] : null);
}
// Wait half a second to get reply before showing prompt again
try {
Thread.sleep(250);
}
catch(InterruptedException e) {
// ignore
}
}
else if(cmd.equalsIgnoreCase("exit")) System.exit(0);
else {
System.err.println("Unknown command "+cmd);
System.err.println("Type 'help' for a listing of available commands");
}
}
catch(Throwable t) {
System.err.println("Command "+cmdargs[0]+" failed");
t.printStackTrace(System.err);
}
else {
System.out.println("--------------------------------------------------");
// FIXME add printout
// hub.showClusters(System.out);
// System.out.println();
// hub.showNodes(System.out);
System.out.println();
}
System.out.flush();
System.err.flush();
System.out.print("> ");
System.out.flush();
}
}
}
private static class TraceMessageExecutor implements MesgDispatcher {
private final String hdr;
private PeerHub hub;
private boolean mute=false;
public synchronized boolean isMute() {
return mute;
}
public synchronized void setMute(boolean mute) {
this.mute=mute;
}
public TraceMessageExecutor(String hdr, MesgDispatcher disp) {
this.hdr=hdr;
}
public PeerHub getHub() {
return hub;
}
public void setHub(PeerHub hub) {
this.hub=hub;
}
public void repl(PeerAddress src, PeerAddress dst, String method, MesgPayload repl, long sequence) {
synchronized(this) { if(mute) return; }
try {
System.err.println(hdr+" REPL "
+dst.name()+":"+method
+" from "+src.name()+": \""
+new String(repl.getDataAsArray(), Charset.forName("UTF-8")).replace("\"", "\\\"")+"\"");
}
catch(IOException e) {
System.err.println(hdr+" REPL "+dst.name()+":"+method+" from "+src.name()+" >> ERROR "+e);
}
}
@Override
public void call(PeerAddress src, PeerAddress dst, String method, MesgPayload call, MesgPayload repl, long sequence, MesgSender send) {
if("getStatus".equals(method)) {
if(repl instanceof BinaryPayload)
((BinaryPayload) repl).setData(getStatus(hub).getBytes(Charset.forName("UTF-8")));
return;
}
synchronized(this) { if(mute) return; }
try {
System.err.println(hdr+" CALL "
+dst.name()+":"+method
+" from "+src.name()+": \""
+new String(repl.getDataAsArray(), Charset.forName("UTF-8")).replace("\"", "\\\"")+"\"");
if(repl instanceof BinaryPayload) {
String ans="> "+new String(repl.getDataAsArray(), Charset.forName("UTF-8"));
((BinaryPayload) repl).setData(ans.getBytes(Charset.forName("UTF-8")));
}
}
catch(IOException e) {
System.err.println(hdr+" CALL "+dst.name()+":"+method+" from "+src.name()+" >> ERROR "+e);
}
}
private final AtomicLong nextSequence=new AtomicLong(0);
public long register(MesgReceiver handler) {
long sequence=nextSequence.incrementAndGet();
// registry.put(sequence, handler);
return sequence;
}
public void unregister(long sequence) {
// CommReceiver receiver = registry.remove(sequence);
// if(receiver!=null) receiver.release();
}
}
private static class PointGroupListener implements PeerGroup.GroupListener {
private final String targetId;
private final PointReporter tr;
private boolean end=false;
public PointGroupListener(String targetId, PointReporter tr) {
this.targetId=targetId;
this.tr=tr;
}
@Override
public void update(PeerGroup target) {
if(targetId.equals(target.name())) tr.report("UPD", target);
}
@Override
public void addHost(PeerGroup target, PeerHost point) {
if(targetId.equals(target.name())) {
tr.report("ADD", target);
target.addListener(this);
}
}
@Override
public void delHost(PeerGroup target, PeerHost point) {
if(targetId.equals(target.name())) {
tr.report("DEL", target);
end=true;
}
}
@Override
public void release() { }
@Override
public boolean finished() {
return end;
}
}
}