OSDN Git Service

a442226cae6edfb0893af8b4762a4d7c3f377a42
[pf3gnuchains/gcc-fork.git] / libjava / classpath / native / jni / gconf-peer / GConfNativePeer.c
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 /** GConfClient backend */
59 static GConfClient *client = 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 GConfClient and initialize the
74  * the type system.
75  * The client reference should be released with g_object_unref after use.
76  * This functions must be called with gdk lock held.
77  */
78 static void init_gconf_client (void);
79
80 /**
81  * Throws a new runtime exception after a failure, with the given message.
82  */
83 static void throw_exception (JNIEnv * env, const char *msg);
84
85 /**
86  * Throws the given exception after a failure, with the given message.
87  */
88 static void
89 throw_exception_by_name (JNIEnv * env, const char *name, const char *msg);
90
91 /**
92  * Return a reference to a java.util.ArrayList class.
93  */
94 static gboolean set_jlist_class (JNIEnv * env);
95
96 /**
97  * Builds a new reference to a new java.util.ArrayList instace.
98  * The instance should be freed by the caller after use.
99  */
100 static jclass get_jlist_reference (JNIEnv * env, jclass jlist_class);
101
102 /* ***** END: PRIVATE FUNCTIONS DELCARATION ***** */
103
104 /* ***** NATIVE FUNCTIONS ***** */
105
106 /*
107  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
108  * Method:    init_class
109  * Signature: ()V
110  */
111 JNIEXPORT void
112 JNICALL Java_gnu_java_util_prefs_gconf_GConfNativePeer_init_1class
113   (JNIEnv *env, jclass clazz)
114 {
115   if (reference_count == 0)
116     {
117       Java_gnu_java_util_prefs_gconf_GConfNativePeer_init_1id_1cache
118                 (env, clazz);
119       return;
120     }
121
122   reference_count++;
123 }
124
125 /*
126  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
127  * Method:    init_id_chache
128  * Signature: ()V
129  */
130 JNIEXPORT void
131 JNICALL Java_gnu_java_util_prefs_gconf_GConfNativePeer_init_1id_1cache
132   (JNIEnv *env, jclass clazz __attribute__ ((unused)))
133 {
134   reference_count++;
135
136   gdk_threads_enter ();
137   init_gconf_client ();
138   gdk_threads_leave ();
139
140   /* if client is null, there is probably an out of memory */
141   if (client == NULL)
142     {
143       /* release the string and throw a runtime exception */
144       throw_exception (env,
145                 "Unable to initialize GConfClient in native code\n");
146       return;
147     }
148
149   /* ***** java.util.ArrayList ***** */
150   if (set_jlist_class (env) == FALSE)
151     {
152       throw_exception (env,
153                 "Unable to get valid reference to java.util.List in native code\n");
154       return;
155     }
156 }
157
158 /*
159  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
160  * Method:    gconf_client_gconf_client_all_keys
161  * Signature: (Ljava/lang/String;)Ljava/util/List;
162  */
163 JNIEXPORT jobject JNICALL
164 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1gconf_1client_1all_1keys
165   (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring node)
166 {
167   /* TODO: check all the calls to gdk_threads_enter/leave */
168   
169   const char *dir = NULL;
170   GError *err = NULL;
171   GSList *entries = NULL;
172   GSList *tmp;
173
174   /* java.util.ArrayList */
175   jobject jlist = NULL;
176
177   dir = JCL_jstring_to_cstring (env, node);
178   if (dir == NULL)
179     {
180       return NULL;
181     }
182
183   gdk_threads_enter ();
184   entries = gconf_client_all_entries (client, dir, &err);
185   gdk_threads_leave ();
186   if (err != NULL)
187     {
188       throw_exception_by_name (env, "java/util/prefs/BackingStoreException",
189                                err->message);
190       g_error_free (err);
191       err = NULL;
192
193       JCL_free_cstring (env, node, dir);
194       return NULL;
195     }
196
197   jlist = get_jlist_reference (env, jlist_class);
198   if (jlist == NULL)
199     {
200       throw_exception_by_name (env, "java/util/prefs/BackingStoreException",
201                                "Unable to get java.util.List reference in native code\n");
202       JCL_free_cstring (env, node, dir);
203       g_slist_foreach (entries, (GFunc) gconf_entry_free, NULL);
204       g_slist_free (entries);
205       return NULL;
206     }
207
208   tmp = entries;
209   while (tmp != NULL)
210     {
211       const char *_val = gconf_entry_get_key (tmp->data);
212       _val = strrchr (_val, '/');
213       ++_val;
214       (*env)->CallBooleanMethod (env, jlist, jlist_add_id,
215                                  (*env)->NewStringUTF (env, _val));
216       tmp = g_slist_next (tmp);
217     }
218
219   /* clean up things */
220   JCL_free_cstring (env, node, dir);
221   g_slist_foreach (entries, (GFunc) gconf_entry_free, NULL);
222   g_slist_free (entries);
223   
224   return jlist;
225 }
226
227 /*
228  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
229  * Method:    gconf_client_gconf_client_all_nodes
230  * Signature: (Ljava/lang/String;)Ljava/util/List;
231  */
232 JNIEXPORT jobject JNICALL
233 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1gconf_1client_1all_1nodes
234   (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring node)
235 {
236   const char *dir = NULL;
237   GError *err = NULL;
238   GSList *entries = NULL;
239   GSList *tmp;
240
241   /* java.util.ArrayList */
242   jobject jlist = NULL;
243
244   dir = JCL_jstring_to_cstring (env, node);
245   if (dir == NULL)
246     {
247       return NULL;
248     }
249
250   gdk_threads_enter ();
251   entries = gconf_client_all_dirs (client, dir, &err);
252   gdk_threads_leave ();
253   if (err != NULL)
254     {
255       throw_exception_by_name (env, "java/util/prefs/BackingStoreException",
256                                err->message);
257       g_error_free (err);
258       err = NULL;
259       JCL_free_cstring (env, node, dir);
260       return NULL;
261     }
262
263   jlist = get_jlist_reference (env, jlist_class);
264   if (jlist == NULL)
265     {
266       throw_exception_by_name (env, "java/util/prefs/BackingStoreException",
267                                "Unable to get java.util.List reference in native code\n");
268       JCL_free_cstring (env, node, dir);
269       g_slist_foreach (entries, (GFunc) gconf_entry_free, NULL);
270       g_slist_free (entries);
271       return NULL;
272     }
273
274   tmp = entries;
275   while (tmp != NULL)
276     {
277       const char *_val = tmp->data;
278       _val = strrchr (_val, '/');
279       ++_val;
280       (*env)->CallBooleanMethod (env, jlist, jlist_add_id,
281                                  (*env)->NewStringUTF (env, _val));
282       tmp = g_slist_next (tmp);
283     }
284
285   /* clean up things */
286   JCL_free_cstring (env, node, dir);
287   g_slist_foreach (entries, (GFunc) gconf_entry_free, NULL);
288   g_slist_free (entries);
289
290   return jlist;
291 }
292
293 /*
294  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
295  * Method:    gconf_client_suggest_sync
296  * Signature: ()V
297  */
298 JNIEXPORT void JNICALL
299 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1suggest_1sync
300   (JNIEnv *env, jclass clazz __attribute__ ((unused)))
301 {
302   GError *err = NULL;
303
304   gdk_threads_enter ();
305   gconf_client_suggest_sync (client, &err);
306   gdk_threads_leave ();
307   if (err != NULL)
308     {
309       throw_exception_by_name (env, "java/util/prefs/BackingStoreException",
310                                                    err->message);
311       g_error_free (err);
312       err = NULL;
313     }
314 }
315
316 /*
317  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
318  * Method:    gconf_client_unset
319  * Signature: (Ljava/lang/String;)Z
320  */
321 JNIEXPORT jboolean JNICALL
322 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1unset
323   (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring key)
324 {
325   const char *_key = NULL;
326   gboolean result = JNI_FALSE;
327   GError *err = NULL;
328
329   _key = JCL_jstring_to_cstring (env, key);
330   if (_key == NULL)
331     {
332       return JNI_FALSE;
333     }
334
335   gdk_threads_enter ();
336   result = gconf_client_unset (client, _key, &err);
337   gdk_threads_leave ();
338   if (err != NULL)
339     {
340       result = JNI_FALSE;
341       g_error_free (err);
342       err = NULL;
343     }
344     
345   JCL_free_cstring (env, key, _key);
346
347   return result;
348 }
349
350 /*
351  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
352  * Method:    gconf_client_get_string
353  * Signature: (Ljava/lang/String;)Ljava/lang/String;
354  */
355 JNIEXPORT jstring JNICALL
356 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1get_1string
357   (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring key)
358 {
359   const char *_key = NULL;
360   const char *_value = NULL;
361   GError *err = NULL;
362   jstring result = NULL;
363
364   _key = JCL_jstring_to_cstring (env, key);
365   if (_key == NULL)
366     {
367       return NULL;
368     }
369
370   gdk_threads_enter ();
371   _value = gconf_client_get_string (client, _key, &err);
372   gdk_threads_leave ();
373   JCL_free_cstring (env, key, _key);
374   if (err != NULL)
375     {
376       /* just in case */
377       if (_value != NULL) g_free ((gpointer) _value);
378       g_error_free (err);
379       err = NULL;
380       
381       return NULL;
382     }
383
384   /* Even if Gconf reported no error it is possible that NULL was returned */
385   /* and it should be prevented to create a Java string from that value. */
386   if (_value != NULL)
387     {
388       result = (*env)->NewStringUTF (env, _value);
389       g_free ((gpointer) _value);
390     }
391
392   return result;
393 }
394
395 /*
396  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
397  * Method:    gconf_client_set_string
398  * Signature: (Ljava/lang/String;Ljava/lang/String;)Z
399  */
400 JNIEXPORT jboolean JNICALL
401 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1set_1string
402   (JNIEnv *env, jclass clazz __attribute__ ((unused)),
403    jstring key, jstring value)
404 {
405   const char *_key = NULL;
406   const char *_value = NULL;
407   GError *err = NULL;
408
409   gboolean result = JNI_FALSE;
410
411   /* load an UTF string from the virtual machine. */
412   _key = JCL_jstring_to_cstring (env, key);
413   _value = JCL_jstring_to_cstring (env, value);
414   if (_key == NULL || _value == NULL)
415     {
416       return JNI_FALSE;
417     }
418
419   gdk_threads_enter ();
420   result = gconf_client_set_string (client, _key, _value, &err);
421   gdk_threads_leave ();
422   if (err != NULL)
423         {
424           g_error_free (err);
425       err = NULL;
426       result = JNI_FALSE;
427         }
428         
429   JCL_free_cstring (env, key, _key);
430   JCL_free_cstring (env, value, _value);
431
432   return (jboolean) result;
433 }
434
435 /*
436  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
437  * Method:    gconf_client_remove_dir
438  * Signature: (Ljava/lang/String;)V
439  */
440 JNIEXPORT void JNICALL
441 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1remove_1dir
442   (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring node)
443 {
444   const char *dir = NULL;
445
446   dir = JCL_jstring_to_cstring (env, node);
447   if (dir == NULL)
448     return;
449
450   gdk_threads_enter ();
451   gconf_client_remove_dir (client, dir, NULL);
452   gdk_threads_leave ();
453
454   JCL_free_cstring (env, node, dir);
455 }
456
457 /*
458  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
459  * Method:    gconf_client_add_dir
460  * Signature: (Ljava/lang/String;)V
461  */
462 JNIEXPORT void JNICALL
463 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1add_1dir
464   (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring node)
465 {
466   const char *dir = NULL;
467
468   dir = JCL_jstring_to_cstring (env, node);
469   if (dir == NULL)
470     return;
471
472   /* ignore errors */
473   gdk_threads_enter ();
474   gconf_client_add_dir (client, dir, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
475   gdk_threads_leave ();
476
477   JCL_free_cstring (env, node, dir);
478 }
479
480 /*
481  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
482  * Method:    gconf_client_dir_exists
483  * Signature: (Ljava/lang/String;)Z
484  */
485 JNIEXPORT jboolean JNICALL
486 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1dir_1exists
487   (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring node)
488 {
489   const char *dir = NULL;
490   GError *err = NULL;
491   jboolean value = JNI_FALSE;
492
493   dir = JCL_jstring_to_cstring (env, node);
494   if (dir == NULL)
495     return value;
496
497   /* on error return false */
498   gdk_threads_enter ();
499   value = gconf_client_dir_exists (client, dir, &err);
500   gdk_threads_leave ();
501   if (err != NULL)
502     value = JNI_FALSE;
503
504   JCL_free_cstring (env, node, dir);
505
506   return value;
507 }
508
509 /*
510  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
511  * Method:    finalize_class
512  * Signature: ()V
513  */
514 JNIEXPORT void
515 JNICALL Java_gnu_java_util_prefs_gconf_GConfNativePeer_finalize_1class
516   (JNIEnv *env, jclass clazz __attribute__ ((unused)))
517 {
518   if (reference_count == 0)
519     {
520       /* last reference, free all resources and return */
521       gdk_threads_enter ();
522       g_object_unref (G_OBJECT (client));
523       gdk_threads_leave ();
524
525       (*env)->DeleteGlobalRef (env, jlist_class);
526
527       jlist_class = NULL;
528       jlist_init_id = NULL;
529       jlist_add_id = NULL;
530
531       return;
532     }
533
534   reference_count--;
535 }
536
537 /* ***** END: NATIVE FUNCTIONS ***** */
538
539 /* ***** PRIVATE FUNCTIONS IMPLEMENTATION ***** */
540
541 static void throw_exception (JNIEnv *env, const char *msg)
542 {
543   throw_exception_by_name (env, "java/lang/RuntimeException", msg);
544 }
545
546 static void
547 throw_exception_by_name (JNIEnv *env, const char *name, const char *msg)
548 {
549   JCL_ThrowException (env, name, msg);
550 }
551
552 static void init_gconf_client (void)
553 {
554   g_type_init ();
555   client = gconf_client_get_default ();
556 }
557
558 static gboolean set_jlist_class (JNIEnv *env)
559 {
560   jclass local_jlist_class = NULL;
561
562   /* gets a reference to the ArrayList class */
563   local_jlist_class = JCL_FindClass (env, "java/util/ArrayList");
564   if (local_jlist_class == NULL)
565     {
566       return FALSE;
567     }
568
569   jlist_class = (*env)->NewGlobalRef (env, local_jlist_class);
570   (*env)->DeleteLocalRef (env, local_jlist_class);
571   if (jlist_class == NULL)
572     {
573       return FALSE;
574     }
575
576   /* and initialize it */
577   jlist_init_id = (*env)->GetMethodID (env, jlist_class, "<init>", "()V");
578   if (jlist_init_id == NULL)
579     {
580       return FALSE;
581     }
582
583   jlist_add_id = (*env)->GetMethodID (env, jlist_class, "add",
584                                                                   "(Ljava/lang/Object;)Z");
585   if (jlist_add_id == NULL)
586     {
587       return FALSE;
588     }
589
590   return TRUE;
591 }
592
593 static jobject get_jlist_reference (JNIEnv *env, jclass jlist_class)
594 {
595   return (*env)->NewObject (env, jlist_class, jlist_init_id);
596 }
597
598 /* ***** END: PRIVATE FUNCTIONS IMPLEMENTATION ***** */