private void driveClientIO() throws IOException, GearmanException {
   for (GearmanJobServerSession sess : sessionsMap.values()) {
     int interestOps = SelectionKey.OP_READ;
     if (sess.sessionHasDataToWrite()) {
       interestOps |= SelectionKey.OP_WRITE;
     }
     try {
       sess.getSelectionKey().interestOps(interestOps);
     } catch (IllegalStateException ise) {
       LOG.warn("Unable to drive IO for session " + sess + "," + " skipping.", ise);
       continue;
     }
   }
   ioAvailable.selectNow();
   Set<SelectionKey> keys = ioAvailable.selectedKeys();
   LOG.trace(
       "Driving IO for client "
           + this
           + ". "
           + keys.size()
           + " session(s) currently available for IO");
   Iterator<SelectionKey> iter = keys.iterator();
   while (iter.hasNext()) {
     SelectionKey key = iter.next();
     GearmanJobServerSession s = sessionsMap.get(key);
     s.driveSessionIO();
   }
 }
  public void work() {
    if (!state.equals(State.IDLE)) {
      throw new IllegalStateException(
          "Can not call work while worker " + "is running or shutting down");
    }

    state = State.RUNNING;
    // a map keeping track of sessions with connection errors
    // (to avoid printing an error about them in every reconnect attempt)
    Map<GearmanJobServerSession, Boolean> havingConnectionError =
        new HashMap<GearmanJobServerSession, Boolean>();

    while (isRunning()) {

      // look for sessions which have been disconnected and attempt to reconnect.
      for (Iterator<GearmanJobServerSession> iter = sessionMap.values().iterator();
          iter.hasNext(); ) {
        GearmanJobServerSession sess = iter.next();
        if (!sess.isInitialized()) {
          try {

            // reconnect, unregister old selection key and register new one
            SelectionKey oldKey = sess.isInitialized() ? sess.getSelectionKey() : null;
            sess.initSession(ioAvailable, this);
            if (oldKey != null) {
              iter.remove();
            }
            sessionMap.put(sess.getSelectionKey(), sess);

            // register all functions with the newly reconnected server
            for (FunctionDefinition d : functionMap.values()) {
              GearmanTask gsr = new GearmanTask(null, generateCanDoPacket(d));
              sess.submitTask(gsr);
            }

            GearmanPacket p =
                new GearmanPacketImpl(
                    GearmanPacketMagic.REQ,
                    GearmanPacketType.SET_CLIENT_ID,
                    ByteUtils.toUTF8Bytes(id));
            sess.submitTask(new GearmanTask(p));

            GearmanTask sessTask =
                new GearmanTask(
                    new GrabJobEventHandler(sess),
                    new GearmanPacketImpl(
                        GearmanPacketMagic.REQ, getGrabJobPacketType(), new byte[0]));
            sess.submitTask(sessTask);
            sess.driveSessionIO();

            // log reconnection message
            if (havingConnectionError.get(sess)) {
              LOG.info("Re-established connection to " + sess.getConnection().toString());
            }
            havingConnectionError.put(sess, false);
          } catch (IOException e) {
            if (!havingConnectionError.get(sess)) {
              LOG.warn("Error connecting to " + sess + ", will keep trying..");
            }

            havingConnectionError.put(sess, true);

            try {
              Thread.sleep(50);
            } catch (InterruptedException e1) {
            }
          }
        } else {
          havingConnectionError.put(sess, false);
        }
      }

      for (GearmanJobServerSession sess : sessionMap.values()) {
        // if still disconnected, skip
        if (!sess.isInitialized()) {
          continue;
        }
        int interestOps = SelectionKey.OP_READ;
        if (sess.sessionHasDataToWrite()) {
          interestOps |= SelectionKey.OP_WRITE;
        }
        sess.getSelectionKey().interestOps(interestOps);
      }
      try {
        ioAvailable.select(1);
      } catch (IOException io) {
        LOG.warn("Receieved IOException while" + " selecting for IO", io);
      }

      for (SelectionKey key : ioAvailable.selectedKeys()) {
        GearmanJobServerSession sess = sessionMap.get(key);
        if (sess == null) {
          LOG.warn("Worker does not have " + "session for key " + key);
          continue;
        }
        if (!sess.isInitialized()) {
          continue;
        }
        try {
          GearmanTask sessTask = taskMap.get(sess);
          if (sessTask == null) {
            sessTask =
                new GearmanTask( // NOPMD
                    new GrabJobEventHandler(sess),
                    new GearmanPacketImpl(
                        GearmanPacketMagic.REQ, getGrabJobPacketType(), new byte[0]));
            taskMap.put(sess, sessTask);
            sess.submitTask(sessTask);
            LOG.debug(
                "Worker: "
                    + this
                    + " submitted a "
                    + sessTask.getRequestPacket().getPacketType()
                    + " to session: "
                    + sess);
          }
          sess.driveSessionIO();
          // For the time being we will execute the jobs synchronously
          // in the future, I expect to change this.
          if (!functionList.isEmpty()) {
            GearmanFunction fun = functionList.remove();
            submitFunction(fun);
            statistics();
          }

        } catch (IOException ioe) {
          LOG.warn("Received IOException while driving" + " IO on session " + sess, ioe);
          sess.closeSession();
          continue;
        }
      }
    }

    shutDownWorker(true);
  }