fun execute()

in src/main/kotlin/com/compiler/server/executor/JavaExecutor.kt [22:80]


  fun execute(args: List<String>): ProgramOutput {
    return Runtime.getRuntime().exec(args.toTypedArray()).use {
      outputStream.close()

      val standardOut = InputStreamReader(this.inputStream).buffered()
      val standardError = InputStreamReader(this.errorStream).buffered()

      val standardOutput = asyncBufferedOutput(standardOut, limit = MAX_OUTPUT_SIZE)
      val errorOutput = asyncBufferedOutput(standardError, limit = MAX_OUTPUT_SIZE)

      try {
        val currTime = System.currentTimeMillis()
        val futuresList = Executors.newFixedThreadPool(2) // one thread per output
          .invokeAll(listOf(standardOutput, errorOutput), EXECUTION_TIMEOUT, TimeUnit.MILLISECONDS)
        // we do not wait for process to end, while either time-limit or output-limit triggered
        // program itself will be destroyed right after we'll leave this method
        println("Script execution time in millis: " + (System.currentTimeMillis() - currTime))

        val outputResults = futuresList.map {
          try {
            it.get()
          } catch (_: Exception) {
            ""
          }
        }

        val (standardText, _) = outputResults

        when {
          futuresList.any { it.isCancelled } -> {
            // execution timeout. Both Future objects must be in 'done' state, to say that process finished
            ProgramOutput(restriction = ExecutorMessages.TIMEOUT_MESSAGE)
          }

          outputResults.any { it.length >= MAX_OUTPUT_SIZE } -> {
            // log-limit exceeded
            ProgramOutput(restriction = ExecutorMessages.TOO_LONG_OUTPUT_MESSAGE)
          }

          else -> {
            // normal exit
            ProgramOutput(standardText)
          }
        }
      } catch (any: Exception) {
        // all sort of things may happen, so we better be aware
        ProgramOutput(exception = any)
      } finally {
        try {
          // don't need this process any more. It will not allow to close IO handlers if not destroyed or finished
          this.destroy()
          standardOut.close()
          standardError.close()
        } catch (_: IOException) {
          // don't care
        }
      }
    }
  }