package org.apache.solr.common.cloud;

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

import java.io.IOException;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

import org.apache.zookeeper.ClientCnxn;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;

// we use this class to expose nasty stuff for tests
public class SolrZooKeeper extends ZooKeeper {
  List<Thread> spawnedThreads = new CopyOnWriteArrayList<Thread>();
  
  // for test debug
  //static Map<SolrZooKeeper,Exception> clients = new ConcurrentHashMap<SolrZooKeeper,Exception>();

  public SolrZooKeeper(String connectString, int sessionTimeout,
      Watcher watcher) throws IOException {
    super(connectString, sessionTimeout, watcher);
    //clients.put(this, new RuntimeException());
  }
  
  public ClientCnxn getConnection() {
    return cnxn;
  }
  
  /**
   * Cause this ZooKeeper object to stop receiving from the ZooKeeperServer
   * for the given number of milliseconds.
   * @param ms the number of milliseconds to pause.
   */
  public void pauseCnxn(final long ms) {
    Thread t = new Thread() {
      public void run() {
        try {
          synchronized (cnxn) {
            try {
              // nocommit: reflect me, move me somewehre else as static method,
              // something. i am only used by tests! the rest of this file is clean.
              ((SocketChannel) cnxn.sendThread.sockKey.channel()).socket()
                  .close();
            } catch (Exception e) {
            }
            Thread.sleep(ms);
          }

          // Wait a long while to make sure we properly clean up these threads.
          Thread.sleep(500000);
        } catch (InterruptedException e) {}
      }
    };
    t.start();
    spawnedThreads.add(t);
  }

  @Override
  public synchronized void close() throws InterruptedException {
    //clients.remove(this);
    for (Thread t : spawnedThreads) {
      t.interrupt();
    }
    super.close();
  }
  
//  public static void assertCloses() {
//    if (clients.size() > 0) {
//      Iterator<Exception> stacktraces = clients.values().iterator();
//      Exception cause = null;
//      cause = stacktraces.next();
//      throw new RuntimeException("Found a bad one!", cause);
//    }
//  }
  
}

@@ -879,34 +879,26 @@
 ava.
-nio.channels.SocketChann
+lang.reflect.Fi
 el
+d
 ;%0Aim
@@ -911,113 +911,100 @@
 ava.
-util.Iterator;%0Aimport java.util.List;%0Aimport java.util.Map;%0Aimport java.util.concurrent.ConcurrentHashMap
+nio.channels.SelectableChannel;%0Aimport java.nio.channels.SelectionKey;%0Aimport java.util.List
 ;%0Aim
@@ -1739,16 +1739,475 @@
 %0A  %7D%0A  %0A
+  SelectableChannel getSendThreadChannel() throws Exception %7B%0A    final Field sendThreadFld = cnxn.getClass().getDeclaredField(%22sendThread%22);%0A    sendThreadFld.setAccessible(true);%0A    Object sendThread = sendThreadFld.get(cnxn);%0A    final Field sockKeyFld = sendThread.getClass().getDeclaredField(%22sockKey%22);%0A    sockKeyFld.setAccessible(true);%0A    final SelectionKey sockKey = (SelectionKey) sockKeyFld.get(sendThread);%0A    return sockKey.channel();%0A  %7D%0A  %0A
   /**%0A  
@@ -2560,339 +2560,159 @@
     
-// nocommit: reflect me, move me somewehre else as static method,%0A              // something. i am only used by tests! the rest of this file is clean.%0A              ((SocketChannel) cnxn.sendThread.sockKey.channel()).socket()%0A                  .close();%0A            %7D catch (Exception e) %7B%0A            %7D%0A            Thread.sleep(ms
+getSendThreadChannel().close();%0A            %7D catch (Exception e) %7B%0A              throw new RuntimeException(%22Closing zookeper send channel failed.%22, e
 );%0A 
@@ -2720,18 +2720,19 @@
         
+ 
+ 
 %7D
-%0A
 %0A       
@@ -2738,109 +2738,39 @@
     
-// Wait a long while to make sure we properly clean up these threads.%0A          Thread.sleep(500000);
+  Thread.sleep(ms);%0A          %7D
 %0A   
@@ -2953,36 +2953,8 @@
 n %7B%0A
-    //clients.remove(this);%0A
     
@@ -2992,16 +2992,33 @@
  %7B%0A     
+ if (t.isAlive())
  t.inter

Fix crazy zookeeper test-only stuff by reflection.