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