Skip to main content

ri/java/classes/
cache.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//! # Cache Module JNI Bindings
19//!
20//! JNI bindings for Ri cache classes.
21
22use jni::JNIEnv;
23use jni::objects::{JClass, JString};
24use jni::sys::{jlong, jboolean, jint, jstring};
25use crate::cache::{RiCacheModule, RiCacheConfig, RiCacheBackendType, RiCacheStats, RiCachePolicy, RiCachedValue, RiCacheManager};
26use crate::java::exception::check_not_null;
27
28// =============================================================================
29// RiCacheModule JNI Bindings
30// =============================================================================
31
32#[no_mangle]
33pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheModule_new0(
34    mut env: JNIEnv,
35    _class: JClass,
36    config_ptr: jlong,
37) -> jlong {
38    if !check_not_null(&mut env, config_ptr, "RiCacheConfig") {
39        return 0;
40    }
41    
42    let config = unsafe { &*(config_ptr as *const RiCacheConfig) };
43    let module = Box::new(RiCacheModule::new(config.clone()));
44    Box::into_raw(module) as jlong
45}
46
47#[no_mangle]
48pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheModule_set(
49    mut env: JNIEnv,
50    _class: JClass,
51    ptr: jlong,
52    key: JString,
53    value: JString,
54    _ttl_secs: jlong,
55) {
56    if !check_not_null(&mut env, ptr, "RiCacheModule") {
57        return;
58    }
59    
60    let _module = unsafe { &*(ptr as *const RiCacheModule) };
61    let _key_str: String = env.get_string(&key)
62        .expect("Failed to get key")
63        .into();
64    let _value_str: String = env.get_string(&value)
65        .expect("Failed to get value")
66        .into();
67}
68
69#[no_mangle]
70pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheModule_get(
71    mut env: JNIEnv,
72    _class: JClass,
73    ptr: jlong,
74    key: JString,
75) -> jstring {
76    if !check_not_null(&mut env, ptr, "RiCacheModule") {
77        return std::ptr::null_mut();
78    }
79    
80    let _module = unsafe { &*(ptr as *const RiCacheModule) };
81    let _key_str: String = env.get_string(&key)
82        .expect("Failed to get key")
83        .into();
84    
85    std::ptr::null_mut()
86}
87
88#[no_mangle]
89pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheModule_delete(
90    mut env: JNIEnv,
91    _class: JClass,
92    ptr: jlong,
93    key: JString,
94) {
95    if !check_not_null(&mut env, ptr, "RiCacheModule") {
96        return;
97    }
98    
99    let _module = unsafe { &*(ptr as *const RiCacheModule) };
100    let _key_str: String = env.get_string(&key)
101        .expect("Failed to get key")
102        .into();
103}
104
105#[no_mangle]
106pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheModule_exists(
107    mut env: JNIEnv,
108    _class: JClass,
109    ptr: jlong,
110    key: JString,
111) -> jboolean {
112    if !check_not_null(&mut env, ptr, "RiCacheModule") {
113        return 0;
114    }
115    
116    let _module = unsafe { &*(ptr as *const RiCacheModule) };
117    let _key_str: String = env.get_string(&key)
118        .expect("Failed to get key")
119        .into();
120    
121    0
122}
123
124#[no_mangle]
125pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheModule_getStats(
126    mut env: JNIEnv,
127    _class: JClass,
128    ptr: jlong,
129) -> jlong {
130    if !check_not_null(&mut env, ptr, "RiCacheModule") {
131        return 0;
132    }
133    
134    let _module = unsafe { &*(ptr as *const RiCacheModule) };
135    
136    let stats = Box::new(RiCacheStats::default());
137    Box::into_raw(stats) as jlong
138}
139
140#[no_mangle]
141pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheModule_free0(
142    _env: JNIEnv,
143    _class: JClass,
144    ptr: jlong,
145) {
146    if ptr != 0 {
147        unsafe {
148            let _ = Box::from_raw(ptr as *mut RiCacheModule);
149        }
150    }
151}
152
153// =============================================================================
154// RiCacheConfig JNI Bindings
155// =============================================================================
156
157#[no_mangle]
158pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheConfig_new0(
159    _env: JNIEnv,
160    _class: JClass,
161) -> jlong {
162    let config = Box::new(RiCacheConfig::default());
163    Box::into_raw(config) as jlong
164}
165
166#[no_mangle]
167pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheConfig_setEnabled(
168    mut env: JNIEnv,
169    _class: JClass,
170    ptr: jlong,
171    enabled: jboolean,
172) {
173    if !check_not_null(&mut env, ptr, "RiCacheConfig") {
174        return;
175    }
176    
177    let config = unsafe { &mut *(ptr as *mut RiCacheConfig) };
178    config.enabled = enabled != 0;
179}
180
181#[no_mangle]
182pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheConfig_setDefaultTtlSecs(
183    mut env: JNIEnv,
184    _class: JClass,
185    ptr: jlong,
186    ttl: jlong,
187) {
188    if !check_not_null(&mut env, ptr, "RiCacheConfig") {
189        return;
190    }
191    
192    let config = unsafe { &mut *(ptr as *mut RiCacheConfig) };
193    config.default_ttl_secs = ttl as u64;
194}
195
196#[no_mangle]
197pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheConfig_setBackendType(
198    mut env: JNIEnv,
199    _class: JClass,
200    ptr: jlong,
201    backend_type: jint,
202) {
203    if !check_not_null(&mut env, ptr, "RiCacheConfig") {
204        return;
205    }
206    
207    let config = unsafe { &mut *(ptr as *mut RiCacheConfig) };
208    config.backend_type = match backend_type {
209        0 => RiCacheBackendType::Memory,
210        1 => RiCacheBackendType::Redis,
211        2 => RiCacheBackendType::Hybrid,
212        _ => RiCacheBackendType::Memory,
213    };
214}
215
216#[no_mangle]
217pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheConfig_setRedisUrl(
218    mut env: JNIEnv,
219    _class: JClass,
220    ptr: jlong,
221    url: JString,
222) {
223    if !check_not_null(&mut env, ptr, "RiCacheConfig") {
224        return;
225    }
226    
227    let config = unsafe { &mut *(ptr as *mut RiCacheConfig) };
228    config.redis_url = env.get_string(&url)
229        .expect("Failed to get redis url")
230        .into();
231}
232
233#[no_mangle]
234pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheConfig_free0(
235    _env: JNIEnv,
236    _class: JClass,
237    ptr: jlong,
238) {
239    if ptr != 0 {
240        unsafe {
241            let _ = Box::from_raw(ptr as *mut RiCacheConfig);
242        }
243    }
244}
245
246// =============================================================================
247// RiCacheStats JNI Bindings
248// =============================================================================
249
250#[no_mangle]
251pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheStats_getHits(
252    mut env: JNIEnv,
253    _class: JClass,
254    ptr: jlong,
255) -> jlong {
256    if !check_not_null(&mut env, ptr, "RiCacheStats") {
257        return 0;
258    }
259    
260    let stats = unsafe { &*(ptr as *const RiCacheStats) };
261    stats.hits as jlong
262}
263
264#[no_mangle]
265pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheStats_getMisses(
266    mut env: JNIEnv,
267    _class: JClass,
268    ptr: jlong,
269) -> jlong {
270    if !check_not_null(&mut env, ptr, "RiCacheStats") {
271        return 0;
272    }
273    
274    let stats = unsafe { &*(ptr as *const RiCacheStats) };
275    stats.misses as jlong
276}
277
278#[no_mangle]
279pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheStats_free0(
280    _env: JNIEnv,
281    _class: JClass,
282    ptr: jlong,
283) {
284    if ptr != 0 {
285        unsafe {
286            let _ = Box::from_raw(ptr as *mut RiCacheStats);
287        }
288    }
289}
290
291// =============================================================================
292// RiCachePolicy JNI Bindings
293// =============================================================================
294
295#[no_mangle]
296pub extern "system" fn Java_com_dunimd_ri_cache_RiCachePolicy_new0(
297    _env: JNIEnv,
298    _class: JClass,
299) -> jlong {
300    let policy = Box::new(RiCachePolicy::default());
301    Box::into_raw(policy) as jlong
302}
303
304#[no_mangle]
305pub extern "system" fn Java_com_dunimd_ri_cache_RiCachePolicy_setTtlSecs0(
306    mut env: JNIEnv,
307    _class: JClass,
308    ptr: jlong,
309    ttl_secs: jlong,
310) {
311    if !check_not_null(&mut env, ptr, "RiCachePolicy") {
312        return;
313    }
314    
315    let policy = unsafe { &mut *(ptr as *mut RiCachePolicy) };
316    policy.ttl = if ttl_secs >= 0 {
317        Some(std::time::Duration::from_secs(ttl_secs as u64))
318    } else {
319        None
320    };
321}
322
323#[no_mangle]
324pub extern "system" fn Java_com_dunimd_ri_cache_RiCachePolicy_getTtlSecs0(
325    mut env: JNIEnv,
326    _class: JClass,
327    ptr: jlong,
328) -> jlong {
329    if !check_not_null(&mut env, ptr, "RiCachePolicy") {
330        return -1;
331    }
332    
333    let policy = unsafe { &*(ptr as *const RiCachePolicy) };
334    policy.ttl.map(|d| d.as_secs() as jlong).unwrap_or(-1)
335}
336
337#[no_mangle]
338pub extern "system" fn Java_com_dunimd_ri_cache_RiCachePolicy_setRefreshOnAccess0(
339    mut env: JNIEnv,
340    _class: JClass,
341    ptr: jlong,
342    refresh_on_access: jboolean,
343) {
344    if !check_not_null(&mut env, ptr, "RiCachePolicy") {
345        return;
346    }
347    
348    let policy = unsafe { &mut *(ptr as *mut RiCachePolicy) };
349    policy.refresh_on_access = refresh_on_access != 0;
350}
351
352#[no_mangle]
353pub extern "system" fn Java_com_dunimd_ri_cache_RiCachePolicy_getRefreshOnAccess0(
354    mut env: JNIEnv,
355    _class: JClass,
356    ptr: jlong,
357) -> jboolean {
358    if !check_not_null(&mut env, ptr, "RiCachePolicy") {
359        return 0;
360    }
361    
362    let policy = unsafe { &*(ptr as *const RiCachePolicy) };
363    if policy.refresh_on_access { 1 } else { 0 }
364}
365
366#[no_mangle]
367pub extern "system" fn Java_com_dunimd_ri_cache_RiCachePolicy_setMaxSize0(
368    mut env: JNIEnv,
369    _class: JClass,
370    ptr: jlong,
371    max_size: jlong,
372) {
373    if !check_not_null(&mut env, ptr, "RiCachePolicy") {
374        return;
375    }
376    
377    let policy = unsafe { &mut *(ptr as *mut RiCachePolicy) };
378    policy.max_size = if max_size >= 0 {
379        Some(max_size as usize)
380    } else {
381        None
382    };
383}
384
385#[no_mangle]
386pub extern "system" fn Java_com_dunimd_ri_cache_RiCachePolicy_getMaxSize0(
387    mut env: JNIEnv,
388    _class: JClass,
389    ptr: jlong,
390) -> jlong {
391    if !check_not_null(&mut env, ptr, "RiCachePolicy") {
392        return -1;
393    }
394    
395    let policy = unsafe { &*(ptr as *const RiCachePolicy) };
396    policy.max_size.map(|s| s as jlong).unwrap_or(-1)
397}
398
399#[no_mangle]
400pub extern "system" fn Java_com_dunimd_ri_cache_RiCachePolicy_free0(
401    _env: JNIEnv,
402    _class: JClass,
403    ptr: jlong,
404) {
405    if ptr != 0 {
406        unsafe {
407            let _ = Box::from_raw(ptr as *mut RiCachePolicy);
408        }
409    }
410}
411
412// =============================================================================
413// RiCachedValue JNI Bindings
414// =============================================================================
415
416#[no_mangle]
417pub extern "system" fn Java_com_dunimd_ri_cache_RiCachedValue_new0(
418    mut env: JNIEnv,
419    _class: JClass,
420    value: JString,
421    ttl_secs: jlong,
422) -> jlong {
423    let value_str: String = env.get_string(&value)
424        .expect("Failed to get value")
425        .into();
426    
427    let ttl = if ttl_secs >= 0 { Some(ttl_secs as u64) } else { None };
428    let cached_value = Box::new(RiCachedValue::new(value_str, ttl));
429    Box::into_raw(cached_value) as jlong
430}
431
432#[no_mangle]
433pub extern "system" fn Java_com_dunimd_ri_cache_RiCachedValue_getValue0(
434    mut env: JNIEnv,
435    _class: JClass,
436    ptr: jlong,
437) -> jstring {
438    if !check_not_null(&mut env, ptr, "RiCachedValue") {
439        return std::ptr::null_mut();
440    }
441    
442    let cached_value = unsafe { &*(ptr as *const RiCachedValue) };
443    env.new_string(&cached_value.value)
444        .expect("Failed to create string")
445        .into_raw()
446}
447
448#[no_mangle]
449pub extern "system" fn Java_com_dunimd_ri_cache_RiCachedValue_getExpiresAt0(
450    mut env: JNIEnv,
451    _class: JClass,
452    ptr: jlong,
453) -> jlong {
454    if !check_not_null(&mut env, ptr, "RiCachedValue") {
455        return -1;
456    }
457    
458    let cached_value = unsafe { &*(ptr as *const RiCachedValue) };
459    cached_value.expires_at.unwrap_or(0) as jlong
460}
461
462#[no_mangle]
463pub extern "system" fn Java_com_dunimd_ri_cache_RiCachedValue_getLastAccessed0(
464    mut env: JNIEnv,
465    _class: JClass,
466    ptr: jlong,
467) -> jlong {
468    if !check_not_null(&mut env, ptr, "RiCachedValue") {
469        return -1;
470    }
471    
472    let cached_value = unsafe { &*(ptr as *const RiCachedValue) };
473    cached_value.last_accessed.unwrap_or(0) as jlong
474}
475
476#[no_mangle]
477pub extern "system" fn Java_com_dunimd_ri_cache_RiCachedValue_isExpired0(
478    mut env: JNIEnv,
479    _class: JClass,
480    ptr: jlong,
481) -> jboolean {
482    if !check_not_null(&mut env, ptr, "RiCachedValue") {
483        return 0;
484    }
485    
486    let cached_value = unsafe { &*(ptr as *const RiCachedValue) };
487    if cached_value.is_expired() { 1 } else { 0 }
488}
489
490#[no_mangle]
491pub extern "system" fn Java_com_dunimd_ri_cache_RiCachedValue_touch0(
492    mut env: JNIEnv,
493    _class: JClass,
494    ptr: jlong,
495) {
496    if !check_not_null(&mut env, ptr, "RiCachedValue") {
497        return;
498    }
499    
500    let cached_value = unsafe { &mut *(ptr as *mut RiCachedValue) };
501    cached_value.touch();
502}
503
504#[no_mangle]
505pub extern "system" fn Java_com_dunimd_ri_cache_RiCachedValue_isStale0(
506    mut env: JNIEnv,
507    _class: JClass,
508    ptr: jlong,
509    max_idle_secs: jlong,
510) -> jboolean {
511    if !check_not_null(&mut env, ptr, "RiCachedValue") {
512        return 0;
513    }
514    
515    let cached_value = unsafe { &*(ptr as *const RiCachedValue) };
516    if cached_value.is_stale(max_idle_secs as u64) { 1 } else { 0 }
517}
518
519#[no_mangle]
520pub extern "system" fn Java_com_dunimd_ri_cache_RiCachedValue_free0(
521    _env: JNIEnv,
522    _class: JClass,
523    ptr: jlong,
524) {
525    if ptr != 0 {
526        unsafe {
527            let _ = Box::from_raw(ptr as *mut RiCachedValue);
528        }
529    }
530}
531
532// =============================================================================
533// RiCacheManager JNI Bindings
534// =============================================================================
535
536#[no_mangle]
537pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheManager_new0(
538    _env: JNIEnv,
539    _class: JClass,
540) -> jlong {
541    use crate::cache::RiMemoryCache;
542    use std::sync::Arc;
543    
544    let backend = Arc::new(RiMemoryCache::new());
545    let manager = Box::new(RiCacheManager::new(backend));
546    Box::into_raw(manager) as jlong
547}
548
549#[no_mangle]
550pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheManager_get0(
551    mut env: JNIEnv,
552    _class: JClass,
553    ptr: jlong,
554    key: JString,
555) -> jstring {
556    if !check_not_null(&mut env, ptr, "RiCacheManager") {
557        return std::ptr::null_mut();
558    }
559    
560    let manager = unsafe { &*(ptr as *const RiCacheManager) };
561    let key_str: String = env.get_string(&key)
562        .expect("Failed to get key")
563        .into();
564    
565    let rt = tokio::runtime::Runtime::new().expect("Failed to create runtime");
566    let result = rt.block_on(async {
567        manager.get::<String>(&key_str).await
568    });
569    
570    match result {
571        Ok(Some(value)) => env.new_string(value)
572            .expect("Failed to create string")
573            .into_raw(),
574        _ => std::ptr::null_mut(),
575    }
576}
577
578#[no_mangle]
579pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheManager_set0(
580    mut env: JNIEnv,
581    _class: JClass,
582    ptr: jlong,
583    key: JString,
584    value: JString,
585    ttl_secs: jlong,
586) {
587    if !check_not_null(&mut env, ptr, "RiCacheManager") {
588        return;
589    }
590    
591    let manager = unsafe { &*(ptr as *const RiCacheManager) };
592    let key_str: String = env.get_string(&key)
593        .expect("Failed to get key")
594        .into();
595    let value_str: String = env.get_string(&value)
596        .expect("Failed to get value")
597        .into();
598    let ttl = if ttl_secs >= 0 { Some(ttl_secs as u64) } else { None };
599    
600    let rt = tokio::runtime::Runtime::new().expect("Failed to create runtime");
601    let _ = rt.block_on(async {
602        manager.set(&key_str, &value_str, ttl).await
603    });
604}
605
606#[no_mangle]
607pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheManager_delete0(
608    mut env: JNIEnv,
609    _class: JClass,
610    ptr: jlong,
611    key: JString,
612) -> jboolean {
613    if !check_not_null(&mut env, ptr, "RiCacheManager") {
614        return 0;
615    }
616    
617    let manager = unsafe { &*(ptr as *const RiCacheManager) };
618    let key_str: String = env.get_string(&key)
619        .expect("Failed to get key")
620        .into();
621    
622    let rt = tokio::runtime::Runtime::new().expect("Failed to create runtime");
623    let result = rt.block_on(async {
624        manager.delete(&key_str).await
625    });
626    
627    match result {
628        Ok(deleted) => if deleted { 1 } else { 0 },
629        _ => 0,
630    }
631}
632
633#[no_mangle]
634pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheManager_exists0(
635    mut env: JNIEnv,
636    _class: JClass,
637    ptr: jlong,
638    key: JString,
639) -> jboolean {
640    if !check_not_null(&mut env, ptr, "RiCacheManager") {
641        return 0;
642    }
643    
644    let manager = unsafe { &*(ptr as *const RiCacheManager) };
645    let key_str: String = env.get_string(&key)
646        .expect("Failed to get key")
647        .into();
648    
649    let rt = tokio::runtime::Runtime::new().expect("Failed to create runtime");
650    let exists = rt.block_on(async {
651        manager.exists(&key_str).await
652    });
653    
654    if exists { 1 } else { 0 }
655}
656
657#[no_mangle]
658pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheManager_clear0(
659    mut env: JNIEnv,
660    _class: JClass,
661    ptr: jlong,
662) {
663    if !check_not_null(&mut env, ptr, "RiCacheManager") {
664        return;
665    }
666    
667    let manager = unsafe { &*(ptr as *const RiCacheManager) };
668    
669    let rt = tokio::runtime::Runtime::new().expect("Failed to create runtime");
670    let _ = rt.block_on(async {
671        manager.clear().await
672    });
673}
674
675#[no_mangle]
676pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheManager_stats0(
677    mut env: JNIEnv,
678    _class: JClass,
679    ptr: jlong,
680) -> jlong {
681    if !check_not_null(&mut env, ptr, "RiCacheManager") {
682        return 0;
683    }
684    
685    let manager = unsafe { &*(ptr as *const RiCacheManager) };
686    
687    let rt = tokio::runtime::Runtime::new().expect("Failed to create runtime");
688    let stats = rt.block_on(async {
689        manager.stats().await
690    });
691    
692    let stats_box = Box::new(stats);
693    Box::into_raw(stats_box) as jlong
694}
695
696#[no_mangle]
697pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheManager_cleanupExpired0(
698    mut env: JNIEnv,
699    _class: JClass,
700    ptr: jlong,
701) -> jlong {
702    if !check_not_null(&mut env, ptr, "RiCacheManager") {
703        return 0;
704    }
705    
706    let manager = unsafe { &*(ptr as *const RiCacheManager) };
707    
708    let rt = tokio::runtime::Runtime::new().expect("Failed to create runtime");
709    let result = rt.block_on(async {
710        manager.cleanup_expired().await
711    });
712    
713    match result {
714        Ok(count) => count as jlong,
715        _ => 0,
716    }
717}
718
719#[no_mangle]
720pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheManager_invalidatePattern0(
721    mut env: JNIEnv,
722    _class: JClass,
723    ptr: jlong,
724    pattern: JString,
725) {
726    if !check_not_null(&mut env, ptr, "RiCacheManager") {
727        return;
728    }
729    
730    let manager = unsafe { &*(ptr as *const RiCacheManager) };
731    let pattern_str: String = env.get_string(&pattern)
732        .expect("Failed to get pattern")
733        .into();
734    
735    let rt = tokio::runtime::Runtime::new().expect("Failed to create runtime");
736    let _ = rt.block_on(async {
737        manager.invalidate_pattern(&pattern_str).await
738    });
739}
740
741#[no_mangle]
742pub extern "system" fn Java_com_dunimd_ri_cache_RiCacheManager_free0(
743    _env: JNIEnv,
744    _class: JClass,
745    ptr: jlong,
746) {
747    if ptr != 0 {
748        unsafe {
749            let _ = Box::from_raw(ptr as *mut RiCacheManager);
750        }
751    }
752}