private void announceConnectionDown() {

    if (client.getLogger() != null)
      client.getLogger().log(Level.INFO, "Announcing connection down...");

    try {

      if (socket != null) {

        try {

          socket.close();

        } catch (Exception ex) {

        }
      }

      if (input != null) {

        try {

          input.close();

        } catch (Exception ex) {

        }
      }

      if (output != null) {

        try {

          output.close();

        } catch (Exception ex) {

        }
      }

    } catch (Exception ex) {

    }

    if (this.client != null) {

      this.client.setDisconnected();
    }

    this.stopActivity();
    killBufferBridgeThread();
  }
  private synchronized void bufferBytes(byte[] b) throws Exception {

    if (b == null) {

      return;
    }

    if (this.buffer != null) {

      if (client.getLogger() != null)
        client.getLogger().log(Level.INFO, "Buffering " + b.length + " bytes");

      this.buffer.buffer(b);

    } else {

      if (client.getLogger() != null) client.getLogger().log(Level.INFO, "Buffer is null.");
    }
  }
  @Override
  public void write(byte[] toWrite) {

    if (this.output != null) {

      try {

        this.output.write(toWrite);
        totalSentBytes += toWrite.length;

      } catch (IOException ex) {

        if (client.getLogger() != null)
          client
              .getLogger()
              .log(Level.SEVERE, "Could not write data to client's output stream", ex);

        this.announceConnectionDown();
      }
    }
  }
  private void startReading() {

    if (this.input == null) {

      return;
    }

    final long totalBytesReceivedEver = 0;

    Runnable readJob =
        new Runnable() {

          @Override
          public void run() {

            while (true) {

              try {

                // Block and wait for one byte
                if (client.getLogger() != null)
                  client.getLogger().log(Level.INFO, "Blocked reading (waiting for bytes)...");

                int b = input.read();

                if (client.getLogger() != null)
                  client.getLogger().log(Level.INFO, ":) UnBlocked reading");

                // Connection closed
                if (b == -1) {

                  announceConnectionDown();
                  break;
                }

                // Read all available data on the stream
                int available = input.available();
                byte[] data = new byte[available + 1];
                data[0] = (byte) b;
                int totalBytesRead = input.read(data, 1, available);
                final byte[] all_bytes = Arrays.copyOf(data, totalBytesRead + 1);

                totalBytesRead += all_bytes.length;

                if (client.getLogger() != null)
                  client
                      .getLogger()
                      .log(
                          Level.INFO,
                          totalBytesRead + " bytes read. Total available was " + available);

                // Send the data to the buffer and keep reading
                Runnable bufferWork =
                    new Runnable() {

                      int wIndex = workIndex;

                      @Override
                      public void run() {

                        if (client.getLogger() != null)
                          client
                              .getLogger()
                              .log(Level.INFO, "Work [" + wIndex + "]  Buffering on work queue...");

                        bufferBytes(all_bytes);
                      }
                    };

                workIndex++;
                queueItUp(bufferWork);

              } catch (IOException ex) {

                if (client.getLogger() != null)
                  client.getLogger().log(Level.INFO, "Connection lost");

                try {

                  input.close();

                } catch (Exception ex_) {

                }

                try {

                  output.close();

                } catch (Exception ex_) {

                }

                try {

                  socket.close();

                } catch (Exception ex_) {

                }

                announceConnectionDown();
                break;
              }
            }
          }
        };

    client.getExecutorService().submit(readJob);
    if (client.getLogger() != null) client.getLogger().log(Level.INFO, "ReadingThread started...");
  }
  @Override
  public void startActivity() throws Exception {

    this.socket = client.getSocket();
    this.input = socket.getInputStream();
    this.output = socket.getOutputStream();

    client
        .getExecutorService()
        .submit(
            new SuicideRunnable() {

              @Override
              public boolean suicideMyself() {

                if (socket == null) return true;

                return socket.isClosed();
              }

              private void attemptThreadsPoolShutdown() {

                if (client.isServerSide()) {

                  if (client.getLogger() != null)
                    client.getLogger().log(Level.WARNING, "Shutdown the Threads pool");

                  client.getExecutorService().shutdownNow();
                  client.shutdown();

                } else {

                  if (!client.isReconnectEnabled()) {

                    if (client.getLogger() != null)
                      client
                          .getLogger()
                          .log(Level.WARNING, "Reconnect disabled. Shutdown the Threads pool.");

                    client.getExecutorService().shutdownNow();
                    client.shutdown();
                  }
                }
              }

              @Override
              public void run() {

                while (true) {

                  synchronized (queue) {
                    while (queue.isEmpty()) {

                      try {

                        queue.wait();

                      } catch (Exception ex) {

                      }

                      if (suicideMyself()) {

                        if (client.getLogger() != null)
                          client.getLogger().log(Level.WARNING, "Killing buffering Bridge thread");

                        attemptThreadsPoolShutdown();
                        return;
                      }
                    }

                    Runnable runnable = queue.poll();
                    runnable.run();

                    if (suicideMyself()) {

                      if (client.getLogger() != null)
                        client
                            .getLogger()
                            .log(
                                Level.WARNING,
                                "Killing buffering Bridge thread after its last Job");

                      attemptThreadsPoolShutdown();
                      return;
                    }
                  }
                }
              }
            });

    startReading();
  }