SuperPeer.java Source code

Java tutorial

Introduction

Here is the source code for SuperPeer.java

Source

/**
 * @authors Bala Subrahmanyam Kambala, Daniel William DaCosta
 * @license GPLv3 (http://www.gnu.org/copyleft/gpl.html)
 * @descriptrion Implements the Super Peer Interface.
 */

import java.rmi.*;
import java.rmi.server.*;
import java.util.logging.Level;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.OptionGroup;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;

import java.util.Collections;
import java.util.TreeSet;
import java.util.Collection;
import java.util.Iterator;
import java.security.SecureRandom;
import java.security.NoSuchAlgorithmException;
import java.lang.Math.*;
import java.lang.Thread;
import java.util.concurrent.locks.*;

public class SuperPeer extends UnicastRemoteObject implements SuperPeerInterface {
    /**
     * Logger for SuperPeer.
     */
    private Logger lg;

    /**
     * We would like node ID's to be unique. This table will be used to ensure
     * this.
     */
    private TreeSet<PeerInfo> peertable;

    /**
     * Random number generator for Node IDs.
     */
    private SecureRandom prng;

    /**
     * SHA1 Hasher.
     */
    private HasherInterface hasher;

    /**
     * Used to lock the critical section on peer startup.
     */
    private boolean lock;

    /**
     * The m-bits
     */
    private int mbits;

    /**
     * SuperPeer Constructor. It takes the number of bits in the key.
     */
    SuperPeer(int _mbits) throws RemoteException, NoSuchAlgorithmException {
        lock = false;
        lg = new Logger("SuperPeer");
        mbits = _mbits;
        peertable = new TreeSet<PeerInfo>(new PeerInfoComparator());
        prng = SecureRandom.getInstance("SHA1PRNG");
        hasher = new SHA1Hasher(mbits);
        lg.log(Level.FINER, "SuperPeer started.");
    }

    @Override
    public void lock() throws Exception {
        lg.log(Level.FINEST, "SuperPeer lock engaged.");
        while (lock) {
            Thread.sleep(1000);
        }
        lock = true;
    }

    @Override
    public synchronized void unlock() throws Exception {
        lock = false;
        lg.log(Level.FINEST, "SuperPeer lock disengaged.");
    }

    @Override
    public synchronized Key getSuccessor(Key nodeid) throws Exception {
        lg.log(Level.FINEST, "getSuccessor Entry.");
        Iterator<PeerInfo> it = peertable.iterator();
        PeerInfo fe = null;

        // Find the first peer key greater than the provided one.
        while (it.hasNext()) {
            fe = it.next();
            if (fe.getNodeId().compare(nodeid) > 0)
                break;
            fe = null;
        }

        // This means that either the peertable is empty or
        // nodeid provided is higher than all other peers.
        if (fe == null) {
            lg.log(Level.FINER, "getSuccessor - Highest nodeid or peertable empty try the first entry.");
            it = peertable.iterator();
            if (it.hasNext()) {
                fe = it.next();
                if (fe.getNodeId().compare(nodeid) == 0)
                    fe = null;
            }
        }
        Key rv = null;
        if (fe != null)
            rv = fe.getNodeId();
        else
            lg.log(Level.FINER, "getSuccessor - No successor found, table must be empty..");
        lg.log(Level.FINEST, "getSuccessor Exit.");
        return rv;
    }

    @Override
    public synchronized Key getPredecessor(Key nodeid) throws Exception {
        lg.log(Level.FINEST, "getPredecessor Entry.");
        Iterator<PeerInfo> it = peertable.iterator();
        Iterator<PeerInfo> it2 = peertable.iterator();
        PeerInfo fe = null;
        PeerInfo pfe = it2.next();

        while (it.hasNext()) {
            fe = it.next();
            if (fe.getNodeId().compare(nodeid) >= 0)
                break;
            pfe = fe;
            fe = null;
        }
        Key rv = pfe.getNodeId();
        lg.log(Level.FINEST, "getPredecessor Exit.");
        if (pfe.getNodeId().equals(nodeid))
            return peertable.last().getNodeId();
        else
            return rv;
    }

    @Override
    public synchronized Key join() throws Exception {
        lg.log(Level.FINEST, "join Entry.");
        Key rv;
        String ip = RemoteServer.getClientHost();
        // XXX: ID collisions need to be detected using peertable!
        rv = hasher.getHash(new Integer(prng.nextInt()).toString());
        PeerInfo pi = new PeerInfo(rv, ip);
        while (peertable.contains(pi)) {
            rv = hasher.getHash(new Integer(prng.nextInt()).toString());
            pi = new PeerInfo(rv, ip);
            lg.log(Level.WARNING, " Random Peer Key Collision, is your key space big enough?");
        }
        peertable.add(pi);
        lg.log(Level.INFO, "!!!! Allocating Node ID " + rv + " to client at " + ip + " !!!!");
        lg.log(Level.FINEST, "join Exit.");
        return rv;
    }

    @Override
    public synchronized HasherInterface getHasher() throws Exception {
        lg.log(Level.FINEST, "getHasher Entry.");
        lg.log(Level.FINEST, "getHasher Exit.");
        return new SHA1Hasher(mbits);
    }

    @Override
    public synchronized String getAddress(Key id) throws Exception {
        lg.log(Level.FINEST, "getAddress Entry.");
        PeerInfo fe = null;
        Iterator<PeerInfo> it = peertable.iterator();
        while (it.hasNext()) {
            fe = it.next();
            lg.log(Level.FINER, "getAddress - Checking " + fe.getNodeId().toString() + " for match ...");
            if (fe.getNodeId().equals(id)) {
                lg.log(Level.FINER, "getAddress - match found.");
                lg.log(Level.FINEST, "getAddress Exit.");
                return fe.getIP();
            }
        }

        lg.log(Level.WARNING, "getAddress failed on " + id.toString() + ", returning null!");
        lg.log(Level.FINEST, "getAddress Entry.");
        return null;
    }

    @Override
    public synchronized String[][] getPeers() throws Exception {
        String[][] rv = new String[peertable.size()][2];
        PeerInfo fe = null;
        Iterator<PeerInfo> it = peertable.iterator();
        int i = 0;
        while (it.hasNext()) {
            fe = it.next();
            rv[i][0] = fe.getNodeId().toString();
            rv[i][1] = fe.getIP();
            i++;
        }
        return rv;
    }

    /**
     * The good stuff.
     */
    public static void main(String[] argv) {
        int mbits = 5;
        ArgumentHandler cli = new ArgumentHandler("SuperPeer [-h]",
                "Run a DHT SuperPeer and attached to the specified superpeer.",
                "Bala Subrahmanyam Kambala, Daniel William DaCosta - GPLv3 (http://www.gnu.org/copyleft/gpl.html)");
        cli.addOption("h", "help", false, "Print this usage information.");
        cli.addOption("m", "mbits", true,
                "The maximum number of unique keys in terms of 2^m (Default is " + Integer.toString(mbits) + ").");

        CommandLine commandLine = cli.parse(argv);
        if (commandLine.hasOption('h')) {
            cli.usage("");
            System.exit(0);
        }
        if (commandLine.hasOption('m')) {
            //XXX:uncaught exception!
            mbits = Integer.parseInt((commandLine.getOptionValue('m')));
        }
        try {
            Naming.rebind("SuperPeer", new SuperPeer(mbits));
        } catch (Exception e) {
            System.out.println("SuperPeer failed: " + e);
        }
    }
}