1 /* GConfNativePeer.c -- Implements native methods for class GConfNativePeer
2 Copyright (C) 2003, 2004 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
37
38 #include <stdio.h>
39 #include <string.h>
40
41 #include <jni.h>
42
43 #include <glib.h>
44 #include <gdk/gdk.h>
45 #include <gconf/gconf-client.h>
46
47 #include "jcl.h"
48
49 #include "gnu_java_util_prefs_gconf_GConfNativePeer.h"
50
51 /*
52 * Cached id, methods and objects
53 */
54
55 /** Reference count */
56 static int reference_count = 0;
57
58 /** GConfEngine backend */
59 static GConfEngine *engine = NULL;
60
61 /** java.util.ArrayList class */
62 static jclass jlist_class = NULL;
63
64 /** java.util.ArrayList constructor id */
65 static jmethodID jlist_init_id = NULL;
66
67 /** ava.util.ArrayList add id */
68 static jmethodID jlist_add_id = NULL;
69
70 /* ***** PRIVATE FUNCTIONS DELCARATION ***** */
71
72 /**
73 * Gets the reference of the default GConfEngine..
74 * The client reference should be released with g_object_unref after use.
75 */
76 static void init_gconf (void);
77
78 /**
79 * Throws a new runtime exception after a failure, with the given message.
80 */
81 static void throw_exception (JNIEnv * env, const char *msg);
82
83 /**
84 * Throws the given exception after a failure, with the given message.
85 */
86 static void
87 throw_exception_by_name (JNIEnv * env, const char *name, const char *msg);
88
89 /**
90 * Return a reference to a java.util.ArrayList class.
91 */
92 static gboolean set_jlist_class (JNIEnv * env);
93
94 /**
95 * Builds a new reference to a new java.util.ArrayList instace.
96 * The instance should be freed by the caller after use.
97 */
98 static jclass get_jlist_reference (JNIEnv * env, jclass jlist_class);
99
100 /* ***** END: PRIVATE FUNCTIONS DELCARATION ***** */
101
102 /* ***** NATIVE FUNCTIONS ***** */
103
104 /*
105 * Class: gnu_java_util_prefs_gconf_GConfNativePeer
106 * Method: init_class
107 * Signature: ()V
108 */
109 JNIEXPORT void JNICALL
Java_gnu_java_util_prefs_gconf_GConfNativePeer_init_1class(JNIEnv * env,jclass clazz)110 Java_gnu_java_util_prefs_gconf_GConfNativePeer_init_1class
111 (JNIEnv *env, jclass clazz)
112 {
113 if (reference_count == 0)
114 {
115 Java_gnu_java_util_prefs_gconf_GConfNativePeer_init_1id_1cache
116 (env, clazz);
117 return;
118 }
119
120 reference_count++;
121 }
122
123 /*
124 * Class: gnu_java_util_prefs_gconf_GConfNativePeer
125 * Method: init_id_chache
126 * Signature: ()V
127 */
128 JNIEXPORT void JNICALL
Java_gnu_java_util_prefs_gconf_GConfNativePeer_init_1id_1cache(JNIEnv * env,jclass clazz)129 Java_gnu_java_util_prefs_gconf_GConfNativePeer_init_1id_1cache
130 (JNIEnv *env, jclass clazz __attribute__ ((unused)))
131 {
132 reference_count++;
133
134 init_gconf ();
135
136 /* if engine is null, there is probably an out of memory */
137 if (engine == NULL)
138 {
139 /* release the string and throw a runtime exception */
140 throw_exception (env,
141 "Unable to initialize GConfEngine in native code\n");
142 return;
143 }
144
145 /* ***** java.util.ArrayList ***** */
146 if (set_jlist_class (env) == FALSE)
147 {
148 throw_exception (env,
149 "Unable to get valid reference to java.util.List in native code\n");
150 return;
151 }
152 }
153
154 /*
155 * Class: gnu_java_util_prefs_gconf_GConfNativePeer
156 * Method: gconf_all_keys
157 * Signature: (Ljava/lang/String;)Ljava/util/List;
158 */
159 JNIEXPORT jobject JNICALL
Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1all_1keys(JNIEnv * env,jclass clazz,jstring node)160 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1all_1keys
161 (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring node)
162 {
163 /* TODO: check all the calls to gdk_threads_enter/leave */
164
165 const char *dir = NULL;
166 const char *_val = NULL;
167 const char *_val_unescaped = NULL;
168
169 GError *err = NULL;
170 GSList *entries = NULL;
171 GSList *tmp;
172
173 /* java.util.ArrayList */
174 jobject jlist = NULL;
175
176 dir = JCL_jstring_to_cstring (env, node);
177 if (dir == NULL)
178 {
179 return NULL;
180 }
181
182 entries = gconf_engine_all_entries (engine, dir, &err);
183 if (err != NULL)
184 {
185 throw_exception_by_name (env, "java/util/prefs/BackingStoreException",
186 err->message);
187 g_error_free (err);
188 err = NULL;
189
190 JCL_free_cstring (env, node, dir);
191 return NULL;
192 }
193
194 jlist = get_jlist_reference (env, jlist_class);
195 if (jlist == NULL)
196 {
197 throw_exception_by_name (env, "java/util/prefs/BackingStoreException",
198 "Unable to get java.util.List reference in native code\n");
199 JCL_free_cstring (env, node, dir);
200 g_slist_foreach (entries, (GFunc) gconf_entry_free, NULL);
201 g_slist_free (entries);
202 return NULL;
203 }
204
205 tmp = entries;
206 while (tmp != NULL)
207 {
208 _val = gconf_entry_get_key (tmp->data);
209 _val = strrchr (_val, '/');
210 ++_val;
211
212 _val_unescaped = gconf_unescape_key (_val, strlen (_val));
213
214 (*env)->CallBooleanMethod (env, jlist, jlist_add_id,
215 (*env)->NewStringUTF (env, _val_unescaped));
216
217 tmp = g_slist_next (tmp);
218
219 g_free ((gpointer) _val_unescaped);
220 }
221
222 /* clean up things */
223 JCL_free_cstring (env, node, dir);
224 g_slist_foreach (entries, (GFunc) gconf_entry_free, NULL);
225 g_slist_free (entries);
226
227 return jlist;
228 }
229
230 /*
231 * Class: gnu_java_util_prefs_gconf_GConfNativePeer
232 * Method: gconf_all_nodes
233 * Signature: (Ljava/lang/String;)Ljava/util/List;
234 */
235 JNIEXPORT jobject JNICALL
Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1all_1nodes(JNIEnv * env,jclass clazz,jstring node)236 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1all_1nodes
237 (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring node)
238 {
239 const char *dir = NULL;
240 const char *_val = NULL;
241 const char *_val_unescaped = NULL;
242
243 GError *err = NULL;
244 GSList *entries = NULL;
245 GSList *tmp;
246
247 /* java.util.ArrayList */
248 jobject jlist = NULL;
249
250 dir = JCL_jstring_to_cstring (env, node);
251 if (dir == NULL)
252 {
253 return NULL;
254 }
255
256 entries = gconf_engine_all_dirs (engine, dir, &err);
257 if (err != NULL)
258 {
259 throw_exception_by_name (env, "java/util/prefs/BackingStoreException",
260 err->message);
261 g_error_free (err);
262 err = NULL;
263 JCL_free_cstring (env, node, dir);
264 return NULL;
265 }
266
267 jlist = get_jlist_reference (env, jlist_class);
268 if (jlist == NULL)
269 {
270 throw_exception_by_name (env, "java/util/prefs/BackingStoreException",
271 "Unable to get java.util.List reference in native code\n");
272 JCL_free_cstring (env, node, dir);
273 g_slist_foreach (entries, (GFunc) gconf_entry_free, NULL);
274 g_slist_free (entries);
275 return NULL;
276 }
277
278 tmp = entries;
279 while (tmp != NULL)
280 {
281 _val = tmp->data;
282
283 _val = strrchr (_val, '/');
284 ++_val;
285
286 _val_unescaped = gconf_unescape_key (_val, strlen (_val));
287
288 (*env)->CallBooleanMethod (env, jlist, jlist_add_id,
289 (*env)->NewStringUTF (env, _val_unescaped));
290
291 tmp = g_slist_next (tmp);
292
293 g_free ((gpointer) _val_unescaped);
294 }
295
296 /* clean up things */
297 JCL_free_cstring (env, node, dir);
298 g_slist_foreach (entries, (GFunc) gconf_entry_free, NULL);
299 g_slist_free (entries);
300
301 return jlist;
302 }
303
304 /*
305 * Class: gnu_java_util_prefs_gconf_GConfNativePeer
306 * Method: gconf_suggest_sync
307 * Signature: ()V
308 */
309 JNIEXPORT void JNICALL
Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1suggest_1sync(JNIEnv * env,jclass clazz)310 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1suggest_1sync
311 (JNIEnv *env, jclass clazz __attribute__ ((unused)))
312 {
313 GError *err = NULL;
314
315 gconf_engine_suggest_sync (engine, &err);
316 if (err != NULL)
317 {
318 throw_exception_by_name (env, "java/util/prefs/BackingStoreException",
319 err->message);
320 g_error_free (err);
321 err = NULL;
322 }
323 }
324
325 /*
326 * Class: gnu_java_util_prefs_gconf_GConfNativePeer
327 * Method: gconf_unset
328 * Signature: (Ljava/lang/String;)Z
329 */
330 JNIEXPORT jboolean JNICALL
Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1unset(JNIEnv * env,jclass clazz,jstring key)331 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1unset
332 (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring key)
333 {
334 const char *_key = NULL;
335 gboolean result = JNI_FALSE;
336 GError *err = NULL;
337
338 _key = JCL_jstring_to_cstring (env, key);
339 if (_key == NULL)
340 {
341 return JNI_FALSE;
342 }
343
344 result = gconf_engine_unset (engine, _key, &err);
345 if (err != NULL)
346 {
347 result = JNI_FALSE;
348 g_error_free (err);
349 err = NULL;
350 }
351
352 JCL_free_cstring (env, key, _key);
353
354 return result;
355 }
356
357 /*
358 * Class: gnu_java_util_prefs_gconf_GConfNativePeer
359 * Method: gconf_get_string
360 * Signature: (Ljava/lang/String;)Ljava/lang/String;
361 */
362 JNIEXPORT jstring JNICALL
Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1get_1string(JNIEnv * env,jclass clazz,jstring key)363 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1get_1string
364 (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring key)
365 {
366 const char *_key = NULL;
367 const char *_value = NULL;
368 GError *err = NULL;
369 jstring result = NULL;
370
371 _key = JCL_jstring_to_cstring (env, key);
372 if (_key == NULL)
373 {
374 return NULL;
375 }
376
377 _value = gconf_engine_get_string (engine, _key, &err);
378 JCL_free_cstring (env, key, _key);
379 if (err != NULL)
380 {
381 /* just in case */
382 if (_value != NULL) g_free ((gpointer) _value);
383 g_error_free (err);
384 err = NULL;
385
386 return NULL;
387 }
388
389 /* Even if Gconf reported no error it is possible that NULL was returned */
390 /* and it should be prevented to create a Java string from that value. */
391 if (_value != NULL)
392 {
393 result = (*env)->NewStringUTF (env, _value);
394 g_free ((gpointer) _value);
395 }
396
397 gconf_engine_suggest_sync (engine, NULL);
398
399 return result;
400 }
401
402 /*
403 * Class: gnu_java_util_prefs_gconf_GConfNativePeer
404 * Method: gconf_set_string
405 * Signature: (Ljava/lang/String;Ljava/lang/String;)Z
406 */
407 JNIEXPORT jboolean JNICALL
Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1set_1string(JNIEnv * env,jclass clazz,jstring key,jstring value)408 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1set_1string
409 (JNIEnv *env, jclass clazz __attribute__ ((unused)),
410 jstring key, jstring value)
411 {
412 const char *_key = NULL;
413 const char *_value = NULL;
414 GError *err = NULL;
415
416 gboolean result = JNI_FALSE;
417
418 /* load an UTF string from the virtual machine. */
419 _key = JCL_jstring_to_cstring (env, key);
420 _value = JCL_jstring_to_cstring (env, value);
421 if (_key == NULL || _value == NULL)
422 {
423 return JNI_FALSE;
424 }
425
426 result = gconf_engine_set_string (engine, _key, _value, &err);
427 if (err != NULL)
428 {
429 g_error_free (err);
430 err = NULL;
431 result = JNI_FALSE;
432 }
433
434 JCL_free_cstring (env, key, _key);
435 JCL_free_cstring (env, value, _value);
436
437 return (jboolean) result;
438 }
439
440 /*
441 * Class: gnu_java_util_prefs_gconf_GConfNativePeer
442 * Method: gconf_dir_exists
443 * Signature: (Ljava/lang/String;)Z
444 */
445 JNIEXPORT jboolean JNICALL
Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1dir_1exists(JNIEnv * env,jclass clazz,jstring node)446 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1dir_1exists
447 (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring node)
448 {
449 const char *dir = NULL;
450 GError *err = NULL;
451 jboolean value = JNI_FALSE;
452
453 dir = JCL_jstring_to_cstring (env, node);
454 if (dir == NULL)
455 return value;
456
457 /* on error return false */
458 value = gconf_engine_dir_exists (engine, dir, &err);
459 if (err != NULL)
460 value = JNI_FALSE;
461
462 JCL_free_cstring (env, node, dir);
463
464 return value;
465 }
466
467 /*
468 * Class: gnu_java_util_prefs_gconf_GConfNativePeer
469 * Method: finalize_class
470 * Signature: ()V
471 */
472 JNIEXPORT void JNICALL
Java_gnu_java_util_prefs_gconf_GConfNativePeer_finalize_1class(JNIEnv * env,jclass clazz)473 Java_gnu_java_util_prefs_gconf_GConfNativePeer_finalize_1class
474 (JNIEnv *env, jclass clazz __attribute__ ((unused)))
475 {
476 if (reference_count == 0)
477 {
478 /* last reference, free all resources and return */
479 g_object_unref (G_OBJECT (engine));
480
481 (*env)->DeleteGlobalRef (env, jlist_class);
482
483 jlist_class = NULL;
484 jlist_init_id = NULL;
485 jlist_add_id = NULL;
486
487 return;
488 }
489
490 reference_count--;
491 }
492
493 /*
494 * Class: gnu_java_util_prefs_gconf_GConfNativePeer
495 * Method: Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1escape_1key
496 * Signature: (Ljava/lang/String;)Z
497 */
498 JNIEXPORT jstring JNICALL
Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1escape_1key(JNIEnv * env,jclass clazz,jstring plain)499 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1escape_1key
500 (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring plain)
501 {
502 const char *escaped = NULL;
503 const char *_plain = NULL;
504 jstring result = NULL;
505
506 _plain = JCL_jstring_to_cstring (env, plain);
507 if (_plain == NULL)
508 {
509 return NULL;
510 }
511
512 escaped = gconf_escape_key (_plain, strlen (_plain));
513
514 JCL_free_cstring (env, plain, _plain);
515 /* check for NULL, if so prevent string creation */
516 if (escaped != NULL)
517 {
518 result = (*env)->NewStringUTF (env, escaped);
519 g_free ((gpointer) escaped);
520 }
521
522 return result;
523 }
524
525 /*
526 * Class: gnu_java_util_prefs_gconf_GConfNativePeer
527 * Method: Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1unescape_1key
528 * Signature: (Ljava/lang/String;)Z
529 */
530 JNIEXPORT jstring JNICALL
Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1unescape_1key(JNIEnv * env,jclass clazz,jstring escaped)531 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1unescape_1key
532 (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring escaped)
533 {
534 const char *plain = NULL;
535 const char *_escaped = NULL;
536 jstring result = NULL;
537
538 _escaped = JCL_jstring_to_cstring (env, escaped);
539 if (_escaped == NULL)
540 {
541 return NULL;
542 }
543
544 plain = gconf_unescape_key (_escaped, strlen (_escaped));
545
546 JCL_free_cstring (env, escaped, _escaped);
547 /* check for NULL, if so prevent string creation */
548 if (plain != NULL)
549 {
550 result = (*env)->NewStringUTF (env, plain);
551 g_free ((gpointer) plain);
552 }
553
554 return result;
555 }
556
557 /* ***** END: NATIVE FUNCTIONS ***** */
558
559 /* ***** PRIVATE FUNCTIONS IMPLEMENTATION ***** */
560
throw_exception(JNIEnv * env,const char * msg)561 static void throw_exception (JNIEnv *env, const char *msg)
562 {
563 throw_exception_by_name (env, "java/lang/RuntimeException", msg);
564 }
565
566 static void
throw_exception_by_name(JNIEnv * env,const char * name,const char * msg)567 throw_exception_by_name (JNIEnv *env, const char *name, const char *msg)
568 {
569 JCL_ThrowException (env, name, msg);
570 }
571
init_gconf(void)572 static void init_gconf (void)
573 {
574 engine = gconf_engine_get_default ();
575 }
576
set_jlist_class(JNIEnv * env)577 static gboolean set_jlist_class (JNIEnv *env)
578 {
579 jclass local_jlist_class = NULL;
580
581 /* gets a reference to the ArrayList class */
582 local_jlist_class = JCL_FindClass (env, "java/util/ArrayList");
583 if (local_jlist_class == NULL)
584 {
585 return FALSE;
586 }
587
588 jlist_class = (*env)->NewGlobalRef (env, local_jlist_class);
589 (*env)->DeleteLocalRef (env, local_jlist_class);
590 if (jlist_class == NULL)
591 {
592 return FALSE;
593 }
594
595 /* and initialize it */
596 jlist_init_id = (*env)->GetMethodID (env, jlist_class, "<init>", "()V");
597 if (jlist_init_id == NULL)
598 {
599 return FALSE;
600 }
601
602 jlist_add_id = (*env)->GetMethodID (env, jlist_class, "add",
603 "(Ljava/lang/Object;)Z");
604 if (jlist_add_id == NULL)
605 {
606 return FALSE;
607 }
608
609 return TRUE;
610 }
611
get_jlist_reference(JNIEnv * env,jclass jlist_class)612 static jobject get_jlist_reference (JNIEnv *env, jclass jlist_class)
613 {
614 return (*env)->NewObject (env, jlist_class, jlist_init_id);
615 }
616
617 /* ***** END: PRIVATE FUNCTIONS IMPLEMENTATION ***** */
618