Skip to main content

ri/java/classes/
hooks.rs

1//! Copyright © 2025-2026 Wenze Wei. All Rights Reserved.
2//!
3//! This file is part of Ri.
4//! The Ri project belongs to the Dunimd Team.
5//!
6//! Licensed under the Apache License, Version 2.0 (the "License");
7//! You may not use this file except in compliance with the License.
8//! You may obtain a copy of the License at
9//!
10//!     http://www.apache.org/licenses/LICENSE-2.0
11//!
12//! Unless required by applicable law or agreed to in writing, software
13//! distributed under the License is distributed on an "AS IS" BASIS,
14//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15//! See the License for the specific language governing permissions and
16//! limitations under the License.
17
18//! # Hooks Module JNI Bindings
19//!
20//! JNI bindings for Ri hooks classes.
21
22use jni::JNIEnv;
23use jni::objects::{JClass, JString};
24use jni::sys::{jlong, jint, jstring};
25use crate::hooks::{RiHookBus, RiHookEvent, RiHookKind, RiModulePhase};
26use crate::java::exception::check_not_null;
27use std::sync::Arc;
28
29// =============================================================================
30// RiHookBus JNI Bindings
31// =============================================================================
32
33#[no_mangle]
34pub extern "system" fn Java_com_dunimd_ri_hooks_RiHookBus_new0(
35    _env: JNIEnv,
36    _class: JClass,
37) -> jlong {
38    // Arc semantics: `hooks0` on RiServiceContext hands out pointers into an Arc
39    // owned by the context, so free0 must use Arc::from_raw to stay compatible.
40    Arc::into_raw(Arc::new(RiHookBus::new())) as jlong
41}
42
43#[no_mangle]
44pub extern "system" fn Java_com_dunimd_ri_hooks_RiHookBus_free0(
45    _env: JNIEnv,
46    _class: JClass,
47    ptr: jlong,
48) {
49    if ptr != 0 {
50        // Drop one Arc reference. If the pointer came from RiServiceContext::hooks0,
51        // the context still holds its own reference and keeps the bus alive.
52        unsafe {
53            let _ = Arc::from_raw(ptr as *const RiHookBus);
54        }
55    }
56}
57
58#[no_mangle]
59pub extern "system" fn Java_com_dunimd_ri_hooks_RiHookBus_emit0(
60    mut env: JNIEnv,
61    _class: JClass,
62    ptr: jlong,
63    kind_ordinal: jint,
64    module: JString,
65    phase_ordinal: jint,
66) {
67    if !check_not_null(&mut env, ptr, "RiHookBus") {
68        return;
69    }
70    
71    let bus = unsafe { &*(ptr as *const RiHookBus) };
72    
73    let kind = match kind_ordinal {
74        0 => RiHookKind::Startup,
75        1 => RiHookKind::Shutdown,
76        2 => RiHookKind::BeforeModulesInit,
77        3 => RiHookKind::AfterModulesInit,
78        4 => RiHookKind::BeforeModulesStart,
79        5 => RiHookKind::AfterModulesStart,
80        6 => RiHookKind::BeforeModulesShutdown,
81        7 => RiHookKind::AfterModulesShutdown,
82        8 => RiHookKind::ConfigReload,
83        _ => RiHookKind::Startup,
84    };
85    
86    let module_str: Option<String> = if module.is_null() {
87        None
88    } else {
89        match env.get_string(&module) {
90            Ok(s) => Some(s.into()),
91            Err(_) => None,
92        }
93    };
94    
95    let phase = if phase_ordinal < 0 {
96        None
97    } else {
98        Some(match phase_ordinal {
99            0 => RiModulePhase::Init,
100            1 => RiModulePhase::BeforeStart,
101            2 => RiModulePhase::Start,
102            3 => RiModulePhase::AfterStart,
103            4 => RiModulePhase::BeforeShutdown,
104            5 => RiModulePhase::Shutdown,
105            6 => RiModulePhase::AfterShutdown,
106            7 => RiModulePhase::AsyncInit,
107            8 => RiModulePhase::AsyncBeforeStart,
108            9 => RiModulePhase::AsyncStart,
109            10 => RiModulePhase::AsyncAfterStart,
110            11 => RiModulePhase::AsyncBeforeShutdown,
111            12 => RiModulePhase::AsyncShutdown,
112            13 => RiModulePhase::AsyncAfterShutdown,
113            _ => RiModulePhase::Init,
114        })
115    };
116    
117    let _ = bus.emit_simple(&kind, module_str.as_deref(), phase);
118}
119
120#[no_mangle]
121pub extern "system" fn Java_com_dunimd_ri_hooks_RiHookBus_hasHandlers0(
122    mut env: JNIEnv,
123    _class: JClass,
124    ptr: jlong,
125    kind_ordinal: jint,
126) -> jni::sys::jboolean {
127    if !check_not_null(&mut env, ptr, "RiHookBus") {
128        return 0;
129    }
130    
131    let bus = unsafe { &*(ptr as *const RiHookBus) };
132    
133    let kind = match kind_ordinal {
134        0 => RiHookKind::Startup,
135        1 => RiHookKind::Shutdown,
136        2 => RiHookKind::BeforeModulesInit,
137        3 => RiHookKind::AfterModulesInit,
138        4 => RiHookKind::BeforeModulesStart,
139        5 => RiHookKind::AfterModulesStart,
140        6 => RiHookKind::BeforeModulesShutdown,
141        7 => RiHookKind::AfterModulesShutdown,
142        8 => RiHookKind::ConfigReload,
143        _ => RiHookKind::Startup,
144    };
145    
146    if bus.has_handlers(&kind) { 1 } else { 0 }
147}
148
149// =============================================================================
150// RiHookEvent JNI Bindings
151// =============================================================================
152
153#[no_mangle]
154pub extern "system" fn Java_com_dunimd_ri_hooks_RiHookEvent_new0(
155    mut env: JNIEnv,
156    _class: JClass,
157    kind_ordinal: jint,
158    module: JString,
159    phase_ordinal: jint,
160) -> jlong {
161    let kind = match kind_ordinal {
162        0 => RiHookKind::Startup,
163        1 => RiHookKind::Shutdown,
164        2 => RiHookKind::BeforeModulesInit,
165        3 => RiHookKind::AfterModulesInit,
166        4 => RiHookKind::BeforeModulesStart,
167        5 => RiHookKind::AfterModulesStart,
168        6 => RiHookKind::BeforeModulesShutdown,
169        7 => RiHookKind::AfterModulesShutdown,
170        8 => RiHookKind::ConfigReload,
171        _ => RiHookKind::Startup,
172    };
173    
174    let module_str: Option<String> = if module.is_null() {
175        None
176    } else {
177        env.get_string(&module).ok().map(|s| s.into())
178    };
179    
180    let phase = if phase_ordinal < 0 {
181        None
182    } else {
183        Some(match phase_ordinal {
184            0 => RiModulePhase::Init,
185            1 => RiModulePhase::BeforeStart,
186            2 => RiModulePhase::Start,
187            3 => RiModulePhase::AfterStart,
188            4 => RiModulePhase::BeforeShutdown,
189            5 => RiModulePhase::Shutdown,
190            6 => RiModulePhase::AfterShutdown,
191            7 => RiModulePhase::AsyncInit,
192            8 => RiModulePhase::AsyncBeforeStart,
193            9 => RiModulePhase::AsyncStart,
194            10 => RiModulePhase::AsyncAfterStart,
195            11 => RiModulePhase::AsyncBeforeShutdown,
196            12 => RiModulePhase::AsyncShutdown,
197            13 => RiModulePhase::AsyncAfterShutdown,
198            _ => RiModulePhase::Init,
199        })
200    };
201    
202    let event = Box::new(RiHookEvent::new(kind, module_str, phase));
203    Box::into_raw(event) as jlong
204}
205
206#[no_mangle]
207pub extern "system" fn Java_com_dunimd_ri_hooks_RiHookEvent_getKind0(
208    mut env: JNIEnv,
209    _class: JClass,
210    ptr: jlong,
211) -> jint {
212    if !check_not_null(&mut env, ptr, "RiHookEvent") {
213        return 0;
214    }
215    
216    let event = unsafe { &*(ptr as *const RiHookEvent) };
217    match event.kind {
218        RiHookKind::Startup => 0,
219        RiHookKind::Shutdown => 1,
220        RiHookKind::BeforeModulesInit => 2,
221        RiHookKind::AfterModulesInit => 3,
222        RiHookKind::BeforeModulesStart => 4,
223        RiHookKind::AfterModulesStart => 5,
224        RiHookKind::BeforeModulesShutdown => 6,
225        RiHookKind::AfterModulesShutdown => 7,
226        RiHookKind::ConfigReload => 8,
227    }
228}
229
230#[no_mangle]
231pub extern "system" fn Java_com_dunimd_ri_hooks_RiHookEvent_getModule0(
232    mut env: JNIEnv,
233    _class: JClass,
234    ptr: jlong,
235) -> jstring {
236    if !check_not_null(&mut env, ptr, "RiHookEvent") {
237        return std::ptr::null_mut();
238    }
239    
240    let event = unsafe { &*(ptr as *const RiHookEvent) };
241    match &event.module {
242        Some(module) => match env.new_string(module) {
243            Ok(s) => s.into_raw(),
244            Err(_) => std::ptr::null_mut(),
245        },
246        None => std::ptr::null_mut(),
247    }
248}
249
250#[no_mangle]
251pub extern "system" fn Java_com_dunimd_ri_hooks_RiHookEvent_getPhase0(
252    mut env: JNIEnv,
253    _class: JClass,
254    ptr: jlong,
255) -> jint {
256    if !check_not_null(&mut env, ptr, "RiHookEvent") {
257        return -1;
258    }
259    
260    let event = unsafe { &*(ptr as *const RiHookEvent) };
261    match &event.phase {
262        Some(phase) => match phase {
263            RiModulePhase::Init => 0,
264            RiModulePhase::BeforeStart => 1,
265            RiModulePhase::Start => 2,
266            RiModulePhase::AfterStart => 3,
267            RiModulePhase::BeforeShutdown => 4,
268            RiModulePhase::Shutdown => 5,
269            RiModulePhase::AfterShutdown => 6,
270            RiModulePhase::AsyncInit => 7,
271            RiModulePhase::AsyncBeforeStart => 8,
272            RiModulePhase::AsyncStart => 9,
273            RiModulePhase::AsyncAfterStart => 10,
274            RiModulePhase::AsyncBeforeShutdown => 11,
275            RiModulePhase::AsyncShutdown => 12,
276            RiModulePhase::AsyncAfterShutdown => 13,
277        },
278        None => -1,
279    }
280}
281
282#[no_mangle]
283pub extern "system" fn Java_com_dunimd_ri_hooks_RiHookEvent_free0(
284    _env: JNIEnv,
285    _class: JClass,
286    ptr: jlong,
287) {
288    if ptr != 0 {
289        unsafe {
290            let _ = Box::from_raw(ptr as *mut RiHookEvent);
291        }
292    }
293}