/*
* Pool.java
* Copyright (C) 2011,2012 Wannes De Smet
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.xenmaster.pool;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import net.wgr.rmi.Remote;
import org.apache.log4j.Logger;
import org.jgroups.JChannel;
import org.jgroups.protocols.BPING;
import org.jgroups.protocols.MERGE2;
import org.jgroups.protocols.UDP;
import org.jgroups.stack.ProtocolStack;
/**
*
* @created Oct 23, 2011
* @author double-u
*/
public class Pool {
protected HashMap<InetAddress, Worker> workers;
protected HashMap<InetAddress, Remote> remotes;
// Pool Orchestrating Protocol
protected DatagramSocket popSocket;
protected ServerSocket rmiSocket;
protected Thread rmi;
protected boolean run, master;
protected Worker local;
protected JChannel channel;
// The port number is completely random ... or is it?
public final static int PORT = 24515;
private volatile static Pool instance;
private Pool() {
workers = new HashMap<>();
rmi = new Thread(new RMIListener(), "Pool RMI");
//channel = buildChannel();
}
public static Pool get() {
if (instance == null) {
instance = new Pool();
}
return instance;
}
protected JChannel buildChannel() {
JChannel jc = new JChannel(false);
ProtocolStack stack = new ProtocolStack();
jc.setProtocolStack(stack);
// Transport
UDP udp = new UDP();
udp.setBindPort(PORT);
stack.addProtocol(udp);
// Discovery
BPING ping = new BPING();
stack.addProtocol(ping);
// Group merge
MERGE2 merge = new MERGE2();
stack.addProtocol(merge);
try {
stack.init();
} catch (Exception ex) {
Logger.getLogger(getClass()).error("Failed to connect to cluster", ex);
}
return jc;
}
public JChannel getChannel() {
return channel;
}
public Map<InetAddress, Worker> getWorkers() {
return workers;
}
public void boot() throws SocketException, UnknownHostException, IOException {
//popSocket = new DatagramSocket(PORT);
//rmiSocket = new ServerSocket(PORT);
run = true;
//wpop.start();
//rmi.start();
//GlobalExecutorService.get().scheduleAtFixedRate(new AliveBroadcaster(), 0, 1, TimeUnit.SECONDS);
}
public void stop() {
// Send "going down" msg to pool master or to friend if this is the master
run = false;
}
protected class AliveBroadcaster implements Runnable {
protected DatagramSocket sock;
protected AliveBroadcaster() throws SocketException, UnknownHostException {
sock = new DatagramSocket();
sock.connect(InetAddress.getByName("255.255.255.255"), PORT);
sock.setBroadcast(true);
}
@Override
public void run() {
try {
XMPacket xmp = new XMPacket();
xmp.alive = true;
xmp.master = master;
byte[] data = xmp.getContents();
DatagramPacket packet = new DatagramPacket(data, data.length);
try {
sock.send(packet);
} catch (IOException ex) {
Logger.getLogger(getClass()).error("Failed to broadcast alive packet", ex);
}
} catch (Exception ex) {
Logger.getLogger(getClass()).error("Exception", ex);
}
}
}
protected class RMIListener implements Runnable {
@Override
public void run() {
while (run) {
try {
Socket sock = rmiSocket.accept();
Remote r = new Remote();
r.boot(sock);
r.getReceiver().addInvocationTarget(local);
} catch (IOException ex) {
Logger.getLogger(getClass()).warn("Accepting RMI connection failed", ex);
}
}
}
}
public static boolean isMasterActive() {
boolean masterDetected = false;
for (Worker w : Pool.get().getWorkers().values()) {
if (w instanceof Master) {
masterDetected = true;
break;
}
}
if (masterDetected) {
return true;
}
Logger.getLogger(Pool.class).info("Waiting for 2 seconds for any master to come online");
try {
Thread.sleep(2000);
for (Worker w : Pool.get().getWorkers().values()) {
if (w instanceof Master) {
masterDetected = true;
break;
}
}
} catch (InterruptedException ex) {
Logger.getLogger(Pool.class).error("Waiting for master failed", ex);
}
if (masterDetected) {
return true;
} else {
return false;
}
}
}