private ControlMessage processControlMessage(ControlMessage ctrlmsg) throws IOException {
    NetworkMessage netmsg = new NetworkMessage(ControlMessage.marshal(ctrlmsg));

    netmsg.writeTo(this.output_stream);
    netmsg = NetworkMessage.readFrom(this.input_stream);

    try {
      ctrlmsg = ControlMessage.unmarshal(netmsg.getData());
    } catch (ParseException ex) {
      throw new IOException(
          "Received an invalid message from remote server '"
              + this.server_address
              + "': "
              + ex.getMessage()
              + ".");
    }

    if (ctrlmsg.getType() != ControlMessage.ControlType.SUCCESS
        && ctrlmsg.getType() != ControlMessage.ControlType.FAILURE) {
      throw new IOException(
          "Remote server '" + this.server_address + "' does not follow the protocol.");
    }

    return ctrlmsg;
  }
  public void initialize(ServiceMetaData meta_data, Level log_level) throws IOException {
    // Launch server via ssh
    List<String> launch_command = new ArrayList<String>();

    launch_command.add("ssh");
    launch_command.add("-n");
    launch_command.add(this.server_address.getAddress());
    launch_command.add("nohup");
    launch_command.add("java");
    launch_command.add("-jar");
    launch_command.add(this.path_to_jar);
    launch_command.add("-l");
    launch_command.add(log_level.toString());
    launch_command.add(Integer.toString(this.server_address.getPort()));
    launch_command.add("&");

    logger.info("Launching a remote server at '" + this.server_address + "'.");
    new ProcessBuilder(launch_command).start();

    try {
      // Connect to server
      try {
        Thread.sleep(1000);
      } catch (InterruptedException ex) {
      }
      this.socket = new Socket(this.server_address.getAddress(), this.server_address.getPort());
      this.input_stream = this.socket.getInputStream();
      this.output_stream = this.socket.getOutputStream();
      this.connected = true;

      // Send metadata to server
      ControlMessage ctrlmsg =
          new ControlMessage(
              ControlMessage.ControlType.INIT, this.server_address.toString(), meta_data);

      ctrlmsg = this.processControlMessage(ctrlmsg);

      if (ctrlmsg.getType() == ControlMessage.ControlType.FAILURE) {
        throw new IOException(
            "Remote server '"
                + this.server_address
                + "' failed to initialize: "
                + ctrlmsg.getDescription()
                + ".");
      }

    } catch (IOException ex) {
      this.shutDown();
      throw ex;
    }
    logger.info("Remote server at '" + this.server_address + "' launched successfully.");
  }
 public void unlockWrite() throws IOException {
   ControlMessage ctrlmsg = new ControlMessage(ControlMessage.ControlType.UNLOCK_WRITE);
   ctrlmsg = this.processControlMessage(ctrlmsg);
   if (ctrlmsg.getType() == ControlMessage.ControlType.FAILURE) {
     throw new IOException(
         "Remote server '"
             + this.server_address
             + "' failed to unlock write operations: "
             + ctrlmsg.getDescription()
             + ".");
   }
   logger.info("Unlocked write operations on remote server '" + this.server_address + "'.");
 }
 public void stop() throws IOException {
   ControlMessage ctrlmsg = new ControlMessage(ControlMessage.ControlType.STOP);
   ctrlmsg = this.processControlMessage(ctrlmsg);
   if (ctrlmsg.getType() == ControlMessage.ControlType.FAILURE) {
     throw new IOException(
         "Remote server '"
             + this.server_address
             + "' failed to stop: "
             + ctrlmsg.getDescription()
             + ".");
   }
   logger.info("Stopped remote server '" + this.server_address + "'.");
 }
 public void updateMetaData(ServiceMetaData meta_data) throws IOException {
   ControlMessage ctrlmsg = new ControlMessage(ControlMessage.ControlType.UPDATE, meta_data);
   ctrlmsg = this.processControlMessage(ctrlmsg);
   if (ctrlmsg.getType() == ControlMessage.ControlType.FAILURE) {
     throw new IOException(
         "Remote server '"
             + this.server_address
             + "' failed to update metadata: "
             + ctrlmsg.getDescription()
             + ".");
   }
   logger.info("Updated metadata on remote server '" + this.server_address + "'.");
 }
 public void deleteData(HashValue range_begin, HashValue range_end) throws IOException {
   DataTransferRequest dt_request =
       new DataTransferRequest(range_begin, range_end, this.server_address);
   ControlMessage ctrlmsg = new ControlMessage(ControlMessage.ControlType.DELETE_DATA, dt_request);
   ctrlmsg = this.processControlMessage(ctrlmsg);
   if (ctrlmsg.getType() == ControlMessage.ControlType.FAILURE) {
     throw new IOException(
         "Remote server '"
             + this.server_address
             + "' failed to delete data: "
             + ctrlmsg.getDescription()
             + ".");
   }
   logger.info("Deleted data on server '" + this.server_address + "'.");
 }
 public void shutDown() throws IOException {
   try {
     if (this.connected && !this.socket.isOutputShutdown()) {
       ControlMessage ctrlmsg = new ControlMessage(ControlMessage.ControlType.SHUTDOWN);
       NetworkMessage netmsg = new NetworkMessage(ControlMessage.marshal(ctrlmsg));
       netmsg.writeTo(this.output_stream);
     }
     if (this.input_stream != null) {
       this.input_stream.close();
     }
     if (this.output_stream != null) {
       this.output_stream.close();
     }
     if (this.socket != null && !this.socket.isClosed()) {
       this.socket.close();
     }
   } catch (IOException ex) {
     logger.warn(
         "Warning! Unable to tear down connection to server ("
             + this.server_address
             + "): "
             + ex.getMessage());
   }
   this.connected = false;
   logger.info("Remote server at '" + this.server_address + "' shut down.");
 }
 public void moveData(HashValue range_begin, HashValue range_end, ServerAddress target)
     throws IOException {
   DataTransferRequest dt_request = new DataTransferRequest(range_begin, range_end, target);
   ControlMessage ctrlmsg = new ControlMessage(ControlMessage.ControlType.MOVE_DATA, dt_request);
   ctrlmsg = this.processControlMessage(ctrlmsg);
   if (ctrlmsg.getType() == ControlMessage.ControlType.FAILURE) {
     throw new IOException(
         "Remote server '"
             + this.server_address
             + "' failed to transfer data to '"
             + target
             + "': "
             + ctrlmsg.getDescription()
             + ".");
   }
   logger.info("Moved data from server '" + this.server_address + "' to server '" + target + "'.");
 }