com.jetbrains.plugin.structure.base.utils.LanguageUtils.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of structure-base Show documentation
Show all versions of structure-base Show documentation
Base library for parsing JetBrains plugins. Used by other JetBrains Plugins structure libraries.
/*
* Copyright 2000-2020 JetBrains s.r.o. and other contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
*/
package com.jetbrains.plugin.structure.base.utils
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.Closeable
import java.io.IOException
import java.io.PrintWriter
import java.io.StringWriter
import java.util.concurrent.ExecutorService
import java.util.concurrent.TimeUnit
private val logger: Logger = LoggerFactory.getLogger("LanguageUtils")
/**
* Checks whether the current thread has been interrupted.
* Clears the *interrupted status* and throws [InterruptedException]
* if it is the case.
*/
@Throws(InterruptedException::class)
fun checkIfInterrupted() {
if (Thread.interrupted()) {
throw InterruptedException()
}
}
/**
* Checks whether the current thread has been interrupted.
* Clears the *interrupted status*, invokes the [action],
* and throws [InterruptedException] if it is the case.
*/
@Throws(InterruptedException::class)
fun checkIfInterrupted(action: () -> Unit) {
if (Thread.interrupted()) {
try {
action()
} finally {
throw InterruptedException()
}
}
}
/**
* Throws [InterruptedException] if [this] is interrupted exception.
* Otherwise checks the current thread's interrupted flag and
* throws [InterruptedException] if it is set.
*/
fun Throwable.rethrowIfInterrupted() {
if (this is InterruptedException) {
throw this
}
checkIfInterrupted()
}
fun T.closeLogged() {
try {
this?.close()
} catch (ie: InterruptedException) {
Thread.currentThread().interrupt()
logger.info("Cannot close because of interruption: $this")
} catch (e: Exception) {
logger.error("Unable to close $this", e)
}
}
inline fun T.closeOnException(block: (T) -> R): R {
try {
return block(this)
} catch (e: Throwable) {
this?.closeLogged()
throw e
}
}
inline fun List.closeOnException(block: (List) -> R): R {
try {
return block(this)
} catch (e: Throwable) {
this.forEach { t: T -> t?.closeLogged() }
throw e
}
}
/**
* Closes multiple resources and throws an exception with all failed-to-close causes
* set as suppressed exceptions, if any.
*/
fun List.closeAll() {
val exceptions = mapNotNull {
try {
it.close()
null
} catch (ie: InterruptedException) {
Thread.currentThread().interrupt()
null
} catch (e: Exception) {
e
}
}
checkIfInterrupted()
if (exceptions.isNotEmpty()) {
val closeException = IOException("Exceptions while closing multiple resources")
exceptions.forEach { closeException.addSuppressed(it) }
throw closeException
}
}
fun Iterator.toList() = asSequence().toList()
fun Iterator.toSet() = asSequence().toSet()
fun Throwable.getStackTraceAsString(): String {
val sw = StringWriter()
val pw = PrintWriter(sw, true)
printStackTrace(pw)
return sw.buffer.toString()
}
fun Throwable.getShortExceptionMessage(): String =
buildString {
append([email protected])
val eMessage = message
if (eMessage != null) {
append(" ($eMessage)")
}
var cause = [email protected]
while (cause != null) {
append(" caused by ").append(cause.javaClass.name)
val causeMessage = cause.message
if (causeMessage != null) {
append(" ($causeMessage)")
}
cause = cause.cause
}
}
fun ExecutorService.shutdownAndAwaitTermination(timeout: Long, timeUnit: TimeUnit) {
// Disable new tasks from being submitted
shutdown()
try {
// Wait a while for existing tasks to terminate
if (!awaitTermination(timeout, timeUnit)) {
// Cancel currently executing tasks
shutdownNow()
// Wait a while for tasks to respond to being cancelled
if (!awaitTermination(timeout, timeUnit)) {
throw RuntimeException("Executor didn't terminate")
}
}
} catch (ie: InterruptedException) {
// (Re-) Cancel if current thread also interrupted
shutdownNow()
// Preserve interrupt status
Thread.currentThread().interrupt()
}
}