package com.proofpoint.zookeeper;

import ch.qos.logback.classic.Level;
import com.proofpoint.io.TempLocalDirectory;
import com.proofpoint.log.Logger;
import org.apache.zookeeper.ClientCnxn;
import org.apache.zookeeper.server.FinalRequestProcessor;
import org.apache.zookeeper.server.NIOServerCnxn;
import org.apache.zookeeper.server.ZooKeeperServer;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.net.BindException;
import java.net.InetSocketAddress;

/**
 * manages an internally running ZooKeeper server and clients to that server.
 * FOR TESTING PURPOSES ONLY
 */
public class ZookeeperTestServerInstance
{
    private static final Logger log = Logger.get(ZookeeperTestServerInstance.class);

    static {
        ((ch.qos.logback.classic.Logger) LoggerFactory.getLogger(FinalRequestProcessor.class)).setLevel(Level.ERROR);
        ((ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ClientCnxn.class)).setLevel(Level.ERROR);
        ((ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ZookeeperEvent.class)).setLevel(Level.ERROR);
    }

    private final ZooKeeperServer server;
    private final int port;
    private final NIOServerCnxn.Factory factory;
    private final TempLocalDirectory tempLocalDirectory;

    private static final int TIME_IN_MS = 2000;

    /**
     * Create the server using a default port
     *
     * @throws Exception errors
     */
    public ZookeeperTestServerInstance()
            throws Exception
    {
        // TODO: choose random port
        this(4534);
    }

    /**
     * Create the server using the given port
     *
     * @param port the port
     * @throws Exception errors
     */
    public ZookeeperTestServerInstance(int port)
            throws Exception
    {
        this.port = port;

        tempLocalDirectory = new TempLocalDirectory();
        tempLocalDirectory.cleanupPrevious();
        File tempDirectory = tempLocalDirectory.newDirectory();

        log.info("Test Zookeeper port: %d path: %s", port, tempDirectory);

        File logDir = new File(tempDirectory, "log");
        File dataDir = new File(tempDirectory, "data");

        try {
            server = new ZooKeeperServer(dataDir, logDir, TIME_IN_MS);
            factory = new NIOServerCnxn.Factory(new InetSocketAddress(port));
            factory.startup(server);
        }
        catch (BindException e) {
            log.debug("Address is in use: %d", port);
            throw e;
        }
    }

    /**
     * Close the server and any open clients
     *
     * @throws InterruptedException thread interruption
     */
    public void close()
            throws InterruptedException
    {
        try {
            server.shutdown();
            factory.shutdown();
        }
        finally {
            tempLocalDirectory.cleanup();
        }
    }

    /**
     * Returns the temp directory instance
     *
     * @return temp directory
     */
    public TempLocalDirectory getTempDirectory()
    {
        return tempLocalDirectory;
    }

    /**
     * Returns the connection string to use
     *
     * @return connection string
     */
    public String getConnectString()
    {
        return "localhost:" + port;
    }
}

@@ -398,16 +398,44 @@
 o.File;%0A
+import java.io.IOException;%0A
 import j
@@ -491,16 +491,46 @@
 Address;
+%0Aimport java.net.ServerSocket;
 %0A%0A/**%0A *
@@ -604,19 +604,16 @@
  server.
-%0A *
  FOR TES
@@ -774,16 +774,20 @@
   static
+%0A   
  %7B%0A     
@@ -1539,55 +1539,551 @@
     
-// TODO: choose random port%0A        this(4534);
+this(getRandomPort());%0A    %7D%0A%0A    private static int getRandomPort()%0A    %7B%0A        ServerSocket server = null;%0A        try %7B%0A            server = new ServerSocket(0);%0A            return server.getLocalPort();%0A        %7D%0A        catch ( IOException e ) %7B%0A            throw new Error(e);%0A        %7D%0A        finally %7B%0A            if ( server != null ) %7B%0A                try %7B%0A                    server.close();%0A                %7D%0A                catch ( IOException ignore ) %7B%0A                    // ignore%0A                %7D%0A            %7D%0A        %7D
 %0A   
@@ -2171,24 +2171,31 @@
 rt the port%0A
+     *%0A
      * @thro
@@ -2689,32 +2689,40 @@
 %22);%0A%0A        try
+%0A       
  %7B%0A            s
@@ -2919,16 +2919,17 @@
  catch (
+ 
 BindExce
@@ -2935,17 +2935,26 @@
 eption e
-)
+ )%0A       
  %7B%0A     
@@ -3237,32 +3237,40 @@
    %7B%0A        try
+%0A       
  %7B%0A            s
@@ -3336,32 +3336,40 @@
 %0A        finally
+%0A       
  %7B%0A            t

Use random port