/**
   * Creates new HTTP requests handler.
   *
   * @param hnd Handler.
   * @param authChecker Authentication checking closure.
   * @param log Logger.
   */
  GridJettyRestHandler(
      GridRestProtocolHandler hnd, GridClosure<String, Boolean> authChecker, GridLogger log) {
    assert hnd != null;
    assert log != null;

    this.hnd = hnd;
    this.log = log;
    this.authChecker = authChecker;

    // Init default page and favicon.
    try {
      initDefaultPage();

      if (log.isDebugEnabled()) log.debug("Initialized default page.");
    } catch (IOException e) {
      U.warn(log, "Failed to initialize default page: " + e.getMessage());
    }

    try {
      initFavicon();

      if (log.isDebugEnabled())
        log.debug(
            favicon != null ? "Initialized favicon, size: " + favicon.length : "Favicon is null.");
    } catch (IOException e) {
      U.warn(log, "Failed to initialize favicon: " + e.getMessage());
    }
  }
  private static void performCopy(
      @NotNull File fromFile, @NotNull File toFile, final boolean syncTimestamp)
      throws IOException {
    final FileOutputStream fos;
    try {
      fos = openOutputStream(toFile);
    } catch (IOException e) {
      if (SystemInfo.isWindows
          && e.getMessage() != null
          && e.getMessage().contains("denied")
          && WinUACTemporaryFix.nativeCopy(fromFile, toFile, syncTimestamp)) {
        return;
      }
      throw e;
    }

    try {
      final FileInputStream fis = new FileInputStream(fromFile);
      try {
        copy(fis, fos);
      } finally {
        fis.close();
      }
    } finally {
      fos.close();
    }

    if (syncTimestamp) {
      final long timeStamp = fromFile.lastModified();
      if (timeStamp < 0) {
        LOG.warn("Invalid timestamp " + timeStamp + " of '" + fromFile + "'");
      } else if (!toFile.setLastModified(timeStamp)) {
        LOG.warn("Unable to set timestamp " + timeStamp + " to '" + toFile + "'");
      }
    }

    if (SystemInfo.isUnix && fromFile.canExecute()) {
      FileSystemUtil.clonePermissions(fromFile.getPath(), toFile.getPath());
    }
  }
  /** {@inheritDoc} */
  @SuppressWarnings("BusyWait")
  @Override
  public void start(final GridRestProtocolHandler hnd) throws GridException {
    assert hnd != null;

    GridConfiguration cfg = ctx.config();

    GridNioServerListener<GridClientMessage> lsnr = new GridTcpRestNioListener(log, hnd);

    GridNioParser parser = new GridTcpRestParser(log);

    try {
      host = resolveRestTcpHost(cfg);

      SSLContext sslCtx = null;

      if (cfg.isRestTcpSslEnabled()) {
        GridSslContextFactory factory = cfg.getRestTcpSslContextFactory();

        if (factory == null)
          // Thrown SSL exception instead of GridException for writing correct warning message into
          // log.
          throw new SSLException("SSL is enabled, but SSL context factory is not specified.");

        sslCtx = factory.createSslContext();
      }

      int lastPort = cfg.getRestTcpPort() + cfg.getRestPortRange() - 1;

      for (port = cfg.getRestTcpPort(); port <= lastPort; port++) {
        if (startTcpServer(host, port, lsnr, parser, sslCtx, cfg)) {
          if (log.isInfoEnabled()) log.info(startInfo());

          return;
        }
      }

      U.warn(
          log,
          "Failed to start TCP binary REST server (possibly all ports in range are in use) "
              + "[firstPort="
              + cfg.getRestTcpPort()
              + ", lastPort="
              + lastPort
              + ", host="
              + host
              + ']');
    } catch (SSLException e) {
      U.warn(
          log,
          "Failed to start " + name() + " protocol on port " + port + ": " + e.getMessage(),
          "Failed to start "
              + name()
              + " protocol on port "
              + port
              + ". Check if SSL context factory is "
              + "properly configured.");
    } catch (IOException e) {
      U.warn(
          log,
          "Failed to start " + name() + " protocol on port " + port + ": " + e.getMessage(),
          "Failed to start "
              + name()
              + " protocol on port "
              + port
              + ". "
              + "Check restTcpHost configuration property.");
    }
  }
  /** {@inheritDoc} */
  @SuppressWarnings("ErrorNotRethrown")
  @Override
  public IpcEndpoint accept() throws IgniteCheckedException {
    while (!Thread.currentThread().isInterrupted()) {
      Socket sock = null;

      boolean accepted = false;

      try {
        sock = srvSock.accept();

        accepted = true;

        InputStream inputStream = sock.getInputStream();
        ObjectInputStream in = new ObjectInputStream(inputStream);

        ObjectOutputStream out = new ObjectOutputStream(sock.getOutputStream());

        IpcSharedMemorySpace inSpace = null;

        IpcSharedMemorySpace outSpace = null;

        boolean err = true;

        try {
          IpcSharedMemoryInitRequest req = (IpcSharedMemoryInitRequest) in.readObject();

          if (log.isDebugEnabled()) log.debug("Processing request: " + req);

          IgnitePair<String> p = inOutToken(req.pid(), size);

          String file1 = p.get1();
          String file2 = p.get2();

          assert file1 != null;
          assert file2 != null;

          // Create tokens.
          new File(file1).createNewFile();
          new File(file2).createNewFile();

          if (log.isDebugEnabled()) log.debug("Created token files: " + p);

          inSpace = new IpcSharedMemorySpace(file1, req.pid(), pid, size, true, log);

          outSpace = new IpcSharedMemorySpace(file2, pid, req.pid(), size, false, log);

          IpcSharedMemoryClientEndpoint ret =
              new IpcSharedMemoryClientEndpoint(inSpace, outSpace, log);

          out.writeObject(
              new IpcSharedMemoryInitResponse(
                  file2, outSpace.sharedMemoryId(), file1, inSpace.sharedMemoryId(), pid, size));

          err = !in.readBoolean();

          endpoints.add(ret);

          return ret;
        } catch (UnsatisfiedLinkError e) {
          throw IpcSharedMemoryUtils.linkError(e);
        } catch (IOException e) {
          if (log.isDebugEnabled())
            log.debug(
                "Failed to process incoming connection "
                    + "(was connection closed by another party):"
                    + e.getMessage());
        } catch (ClassNotFoundException e) {
          U.error(log, "Failed to process incoming connection.", e);
        } catch (ClassCastException e) {
          String msg =
              "Failed to process incoming connection (most probably, shared memory "
                  + "rest endpoint has been configured by mistake).";

          LT.warn(log, null, msg);

          sendErrorResponse(out, e);
        } catch (IpcOutOfSystemResourcesException e) {
          if (!omitOutOfResourcesWarn) LT.warn(log, null, OUT_OF_RESOURCES_MSG);

          sendErrorResponse(out, e);
        } catch (IgniteCheckedException e) {
          LT.error(log, e, "Failed to process incoming shared memory connection.");

          sendErrorResponse(out, e);
        } finally {
          // Exception has been thrown, need to free system resources.
          if (err) {
            if (inSpace != null) inSpace.forceClose();

            // Safety.
            if (outSpace != null) outSpace.forceClose();
          }
        }
      } catch (IOException e) {
        if (!Thread.currentThread().isInterrupted() && !accepted)
          throw new IgniteCheckedException("Failed to accept incoming connection.", e);

        if (!closed)
          LT.error(
              log, null, "Failed to process incoming shared memory connection: " + e.getMessage());
      } finally {
        U.closeQuiet(sock);
      }
    } // while

    throw new IgniteInterruptedCheckedException("Socket accept was interrupted.");
  }