-
-
Notifications
You must be signed in to change notification settings - Fork 99
/
Jvm.kt
171 lines (140 loc) · 6.61 KB
/
Jvm.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package com.hexagonkt.core
import com.hexagonkt.core.text.SNAKE_CASE
import com.hexagonkt.core.text.parseOrNull
import java.io.Console
import java.net.InetAddress
import java.nio.charset.Charset
import java.time.ZoneId
import java.util.*
import kotlin.reflect.KClass
/**
* Object with utilities to gather information about the running JVM.
*/
object Jvm {
private val systemSettingPattern: Regex by lazy { SNAKE_CASE }
/** Operating system name ('os.name' property). If `null` throws an exception. */
val os: String by lazy { os() }
/** Operating system type. */
val osKind: OsKind by lazy { osKind() }
/**
* JVM Console, if the program don't have a console (i.e.: input or output redirected), an
* exception is thrown.
*/
val console: Console by lazy {
System.console() ?: error("Program doesn't have a console (I/O may be redirected)")
}
/** True if the program has a console (terminal, TTY, PTY...), false if I/O is piped. */
val isConsole: Boolean by lazy { System.console() != null }
/** Current JVM runtime. */
val runtime: Runtime by lazy { Runtime.getRuntime() }
/** Default timezone. */
val timeZone: TimeZone by lazy { TimeZone.getDefault() }
/** Default zone ID. */
val zoneId: ZoneId by lazy { timeZone.toZoneId() }
/** Default character set. */
val charset: Charset by lazy { Charset.defaultCharset() }
/** Default locale for this instance of the Java Virtual Machine. */
val locale: Locale by lazy { Locale.getDefault() }
/** The host name of the machine running this program. */
val hostName: String by lazy { InetAddress.getLocalHost().hostName }
/** The IP address of the machine running this program. */
val ip: String by lazy { InetAddress.getLocalHost().hostAddress }
/** Name of the JVM running this program. For example: OpenJDK 64-Bit Server VM. */
val name: String by lazy { System.getProperty("java.vm.name", "N/A") }
/** Java version aka language level. For example: 11 */
val version: String by lazy { System.getProperty("java.vm.specification.version", "N/A") }
/** Number of processors available to the Java virtual machine. */
val cpuCount: Int by lazy { runtime.availableProcessors() }
/** User locale consist of 2-letter language code, 2-letter country code and file encoding. */
val localeCode: String by lazy {
"%s_%s.%s".format(locale.language, locale.country, charset.name())
}
/**
* Amount of memory in kilobytes available to the JVM.
*
* @return Total amount of memory in kilobytes.
*/
fun totalMemory(): String =
runtime.totalMemory().let { "%,d".format(it / 1024) }
/**
* Amount of used memory in kilobytes.
*
* @return Used memory in kilobytes.
*/
fun usedMemory(): String =
(runtime.totalMemory() - runtime.freeMemory()).let { "%,d".format(it / 1024) }
/**
* Add a map to system properties, optionally overriding them.
*
* @param settings Data to be added to system properties.
* @param overwrite If true, overwrite existing entries with supplied data.
*/
fun loadSystemSettings(settings: Map<String, String>, overwrite: Boolean = false) {
settings.keys.forEach {
check(it.matches(systemSettingPattern)) {
"Property name must match $systemSettingPattern ($it)"
}
}
val systemProperties = System.getProperties()
val properties =
if (overwrite) settings.entries
else settings.entries.filter { !systemProperties.containsKey(it.key) }
properties.forEach { (k, v) -> System.setProperty(k, v) }
}
/**
* Retrieve a setting by name by looking in OS environment variables first and in the JVM system
* properties if not found.
*
* @param type Type of the requested parameter. Supported types are: boolean, int, long, float,
* double and string, throw an error if other type is supplied.
* @param name Name of the searched parameter, can not be blank.
* @return Value of the searched parameter in the requested type, `null` if the parameter is not
* found on the OS environment variables or in JVM system properties.
*/
fun <T: Any> systemSettingOrNull(type: KClass<T>, name: String): T? =
systemSettingRaw(name).let { it.parseOrNull(type) }
fun <T: Any> systemSetting(type: KClass<T>, name: String): T =
systemSettingOrNull(type, name)
?: error("Required '${type.simpleName}' system setting '$name' not found")
/**
* Retrieve a flag (boolean parameter) by name by looking in OS environment variables first and
* in the JVM system properties if not found.
*
* @param name Name of the searched parameter, can not be blank.
* @return True if the parameter is found and its value is exactly 'true', false otherwise.
*/
fun systemFlag(name: String): Boolean =
systemSettingOrNull(Boolean::class, name) ?: false
/**
* Utility method for retrieving a system setting, check [systemSettingOrNull] for details.
*
* @param T Type of the requested parameter. Supported types are: boolean, int, long, float,
* double and string, throw an error if other type is supplied.
* @param name Name of the searched parameter, can not be blank.
* @return Value of the searched parameter in the requested type, `null` if the parameter is not
* found on the OS environment variables or in JVM system properties.
*/
inline fun <reified T: Any> systemSettingOrNull(name: String): T? =
systemSettingOrNull(T::class, name)
inline fun <reified T: Any> systemSetting(name: String): T =
systemSetting(T::class, name)
private fun systemSettingRaw(name: String): String? {
val correctName = name.matches(systemSettingPattern)
require(correctName) { "Setting name must match $systemSettingPattern" }
return System.getenv(name) ?: System.getenv(name.uppercase()) ?: System.getProperty(name)
}
/** Operating system name ('os.name' property). If `null` throws an exception. */
internal fun os(): String =
System.getProperty("os.name") ?: error("OS property ('os.name') not found")
/** Operating system type. */
internal fun osKind(): OsKind =
os().lowercase().let {
when {
it.contains("win") -> OsKind.WINDOWS
it.contains("mac") -> OsKind.MACOS
it.contains("nux") -> OsKind.LINUX
it.contains("nix") || it.contains("aix") -> OsKind.UNIX
else -> error("Unsupported OS: ${os()}")
}
}
}