Hooks and scripting architecture Overview
The scripting subsystem bridges Java and GraalVM JavaScript through the following core components:
ScriptCore: The runtime environment manager. It handles script parsing, context creation, and hook dispatching across loaded modules.LuwrainObj: The central API gateway exposed to the script context as the globalLuwrainobject.ScriptExtension: A base class allowing Java developers to package scripts as standard LUWRAIN extensions.- GraalVM Polyglot: Handles the automatic marshaling of types (handled explicitly via
ScriptUtils) and asynchronous Promises (AsyncFunction).
The Hook System
Hooks allow scripts to intercept and react to system events.
Hooks are dispatched from the Java core and handled by JavaScript callbacks registered via Luwrain.addHook().
A hook is a set of handlers registered as lambda expressions with the hook name. Multiple handlers can be registered for the same hook name. How they will be executed is determined by the strategy of calling the hook, which is described below.
There are some system-defined hooks, but any application can additionally define its own. Here are some examples of system hooks:
luwrain.startup: Triggered when the system finishes booting.luwrain.announcement: Triggered on system announcements.luwrain.clipboard.copy.all: Triggered when a area copy operation is requested.luwrain.edit.inputandluwrain.text.input: Triggered on text input events.luwrain.url.open: Triggered before a URL is opened.
Hook Execution Strategies (Java Side)
Platform developers dispatch hooks using specific strategies defined in Hooks.java:
- Notification: Broadcasts the event to all registered handlers. Return values are ignored.
- Chain of Responsibility: Handlers are executed in order. If a handler returns
true, the chain breaks, and subsequent handlers are skipped. - Permission: All handlers must return
truefor the action to be permitted. - Provider: Returns the first non-null value provided by a handler.
- Transformer: Passes an argument through a sequence of handlers, allowing each to modify and return the data.
- Collector: Aggregates the return values of all handlers into an array.
A JavaScript file can register a hook with the code like in this example:
Luwrain.addHook('luwrain.startup', function() {
//Any custom actions the user wants to run on startup
});
Asynchronous JavaScript Integration
LUWRAIN seamlessly bridges Java CompletableFuture with JavaScript promise objects via the AsyncFunction interface.
When a script calls an asynchronous method like Luwrain.fetchUrl(), the Java engine executes the network request on a background thread.
Once complete, it invokes the GraalVM Polyglot context to resolve or reject the JS Promise on the synchronized script object.
For JavaScript users it looks like usual using of promises. Below is an example:
Luwrain.fetchUrl("https://api.example.com/data")
.then(function(response) {
Luwrain.speak("Data downloaded successfully.");
})
.catch(function(error) {
Luwrain.speak("Failed to download data.");
});
The keywords async and await for using promises are also supported.
This mechanism is very important because the code of the hook handlers is executed in the main thread of the system.
Performing I/O operations that take time to complete
will cause the system to "freeze".
Using asynchronous functions avoids this effect.
The approach is very similar to the one used in modern browsers.
The Global Luwrain Object API
When writing scripts, the Luwrain object is globally available.
It provides access to speech, system I/O, UI popups, and extensibility mechanisms.
3.1. Speech and Audio
-
Luwrain.speak(text: String, [sound: String]): BooleanSpeaks the provided text using the active TTS engine. Optionally plays a predefined sound before speaking. -
Luwrain.playSound(soundName: String): BooleanPlays a system sound defined in the LUWRAIN constants. -
Luwrain.message(text: String, [messageType: String]): BooleanDisplays and speaks a system message.messageTypecan alter the priority or presentation of the message. -
Luwrain.addHook(hookName: String, callback: Function): BooleanRegisters a callback function to a system hook (see Section 4: The Hook System). -
Luwrain.addCommand(commandName: String, executable: Function): BooleanRegisters a new system-wide command that the user can invoke by name. -
Luwrain.addShortcut(shortcutName: String, executable: Function): BooleanBinds a function to a system shortcut. -
Luwrain.addWorker(name: String, firstLaunchDelay: Number, launchPeriod: Number, callback: Function): BooleanRegisters a background worker that executes periodically. Delays are in milliseconds.
3.3. File System and Network
Luwrain.readTextFile(filePath: String): Array<String>Reads a file encoded in UTF-8 and returns an array of strings (lines).Luwrain.writeTextFile(filePath: String, lines: Array<String>): BooleanWrites an array of strings to a file in UTF-8 encoding.Luwrain.deleteFile(filePath: String): BooleanDeletes the specified file.Luwrain.urlGet(url: String): StringPerforms a synchronous HTTP GET request and returns the response body as a string.Luwrain.fetchUrl(url: String): Promise<String>Performs an asynchronous HTTP GET request. Returns a standard JavaScriptPromisethat resolves with the response text.
3.4. System Execution and Concurrency
Luwrain.launchApp(appNameOrFunction: String | Function, [args: Array<String>]): BooleanLaunches a LUWRAIN application by its registered name or directly executes an application function.Luwrain.executeBkg(callback: Function): BooleanExecutes the provided function in a background JavaFutureTask, preventing UI thread blocking.Luwrain.newJob(name: String, args: Array<String>, dir: String, onFinished: Function): JobInstanceObjSpawns a system job/process with the specified arguments and working directory. TheonFinishedcallback receives(isSuccess: Boolean, exitCode: Number).Luwrain.quit(): BooleanTerminates the LUWRAIN environment.
3.5. Utilities and UI
Luwrain.parseXml(xmlString: String, [baseUri: String]): JSoupDocObjParses an XML/HTML string using JSoup and returns a traversable document object.Luwrain.createWizardArea(options: Object): WizardAreaObjCreates a wizard UI component. Ifoptions.inputis provided, it acts as the input handler.Luwrain.openUrl(url: String): BooleanOpens the specified URL in the host OS's default web browser safely on the UI thread.- String utilities:
Luwrain.isDigit(char),Luwrain.isLetter(char),Luwrain.isLetterOrDigit(char),Luwrain.isSpace(char).