OSDN Git Service

Merged gcj-eclipse branch to trunk.
[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 JNICALL
112 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 JNICALL
131 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_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_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   const char *_val = NULL;
171   const char *_val_unescaped = NULL;
172   
173   GError *err = NULL;
174   GSList *entries = NULL;
175   GSList *tmp;
176
177   /* java.util.ArrayList */
178   jobject jlist = NULL;
179
180   dir = JCL_jstring_to_cstring (env, node);
181   if (dir == NULL)
182     {
183       return NULL;
184     }
185
186   gdk_threads_enter ();
187   entries = gconf_client_all_entries (client, dir, &err);
188   gdk_threads_leave ();
189   if (err != NULL)
190     {
191       throw_exception_by_name (env, "java/util/prefs/BackingStoreException",
192                                err->message);
193       g_error_free (err);
194       err = NULL;
195
196       JCL_free_cstring (env, node, dir);
197       return NULL;
198     }
199
200   jlist = get_jlist_reference (env, jlist_class);
201   if (jlist == NULL)
202     {
203       throw_exception_by_name (env, "java/util/prefs/BackingStoreException",
204                                "Unable to get java.util.List reference in native code\n");
205       JCL_free_cstring (env, node, dir);
206       g_slist_foreach (entries, (GFunc) gconf_entry_free, NULL);
207       g_slist_free (entries);
208       return NULL;
209     }
210
211   tmp = entries;
212   while (tmp != NULL)
213     {
214       _val = gconf_entry_get_key (tmp->data);
215       _val = strrchr (_val, '/');
216       ++_val;
217       
218       _val_unescaped = gconf_unescape_key (_val, strlen (_val));
219       
220       (*env)->CallBooleanMethod (env, jlist, jlist_add_id,
221                                  (*env)->NewStringUTF (env, _val_unescaped));
222          
223       tmp = g_slist_next (tmp);
224       
225       g_free ((gpointer) _val_unescaped);
226     }
227
228   /* clean up things */
229   JCL_free_cstring (env, node, dir);
230   g_slist_foreach (entries, (GFunc) gconf_entry_free, NULL);
231   g_slist_free (entries);
232   
233   return jlist;
234 }
235
236 /*
237  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
238  * Method:    gconf_client_all_nodes
239  * Signature: (Ljava/lang/String;)Ljava/util/List;
240  */
241 JNIEXPORT jobject JNICALL
242 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1all_1nodes
243   (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring node)
244 {
245   const char *dir = NULL;
246   const char *_val = NULL;
247   const char *_val_unescaped = NULL;
248   
249   GError *err = NULL;
250   GSList *entries = NULL;
251   GSList *tmp;
252
253   /* java.util.ArrayList */
254   jobject jlist = NULL;
255
256   dir = JCL_jstring_to_cstring (env, node);
257   if (dir == NULL)
258     {
259       return NULL;
260     }
261
262   gdk_threads_enter ();
263   entries = gconf_client_all_dirs (client, dir, &err);
264   gdk_threads_leave ();
265   if (err != NULL)
266     {
267       throw_exception_by_name (env, "java/util/prefs/BackingStoreException",
268                                err->message);
269       g_error_free (err);
270       err = NULL;
271       JCL_free_cstring (env, node, dir);
272       return NULL;
273     }
274
275   jlist = get_jlist_reference (env, jlist_class);
276   if (jlist == NULL)
277     {
278       throw_exception_by_name (env, "java/util/prefs/BackingStoreException",
279                                "Unable to get java.util.List reference in native code\n");
280       JCL_free_cstring (env, node, dir);
281       g_slist_foreach (entries, (GFunc) gconf_entry_free, NULL);
282       g_slist_free (entries);
283       return NULL;
284     }
285
286   tmp = entries;
287   while (tmp != NULL)
288     {
289       _val = tmp->data;
290       
291       _val = strrchr (_val, '/');
292       ++_val;
293       
294       _val_unescaped = gconf_unescape_key (_val, strlen (_val));
295       
296       (*env)->CallBooleanMethod (env, jlist, jlist_add_id,
297                                  (*env)->NewStringUTF (env, _val_unescaped));
298       
299       tmp = g_slist_next (tmp);
300       
301       g_free ((gpointer) _val_unescaped);
302     }
303
304   /* clean up things */
305   JCL_free_cstring (env, node, dir);
306   g_slist_foreach (entries, (GFunc) gconf_entry_free, NULL);
307   g_slist_free (entries);
308
309   return jlist;
310 }
311
312 /*
313  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
314  * Method:    gconf_client_suggest_sync
315  * Signature: ()V
316  */
317 JNIEXPORT void JNICALL
318 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1suggest_1sync
319   (JNIEnv *env, jclass clazz __attribute__ ((unused)))
320 {
321   GError *err = NULL;
322
323   gdk_threads_enter ();
324   gconf_client_suggest_sync (client, &err);
325   gdk_threads_leave ();
326   if (err != NULL)
327     {
328       throw_exception_by_name (env, "java/util/prefs/BackingStoreException",
329                                                    err->message);
330       g_error_free (err);
331       err = NULL;
332     }
333 }
334
335 /*
336  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
337  * Method:    gconf_client_unset
338  * Signature: (Ljava/lang/String;)Z
339  */
340 JNIEXPORT jboolean JNICALL
341 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1unset
342   (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring key)
343 {
344   const char *_key = NULL;
345   gboolean result = JNI_FALSE;
346   GError *err = NULL;
347
348   _key = JCL_jstring_to_cstring (env, key);
349   if (_key == NULL)
350     {
351       return JNI_FALSE;
352     }
353
354   gdk_threads_enter ();
355   result = gconf_client_unset (client, _key, &err);
356   gdk_threads_leave ();
357   if (err != NULL)
358     {
359       result = JNI_FALSE;
360       g_error_free (err);
361       err = NULL;
362     }
363     
364   JCL_free_cstring (env, key, _key);
365
366   return result;
367 }
368
369 /*
370  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
371  * Method:    gconf_client_get_string
372  * Signature: (Ljava/lang/String;)Ljava/lang/String;
373  */
374 JNIEXPORT jstring JNICALL
375 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1get_1string
376   (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring key)
377 {
378   const char *_key = NULL;
379   const char *_value = NULL;
380   GError *err = NULL;
381   jstring result = NULL;
382
383   _key = JCL_jstring_to_cstring (env, key);
384   if (_key == NULL)
385     {
386       return NULL;
387     }
388
389   gdk_threads_enter ();
390   _value = gconf_client_get_string (client, _key, &err);
391   gdk_threads_leave ();
392   JCL_free_cstring (env, key, _key);
393   if (err != NULL)
394     {
395       /* just in case */
396       if (_value != NULL) g_free ((gpointer) _value);
397       g_error_free (err);
398       err = NULL;
399       
400       return NULL;
401     }
402
403   /* Even if Gconf reported no error it is possible that NULL was returned */
404   /* and it should be prevented to create a Java string from that value. */
405   if (_value != NULL)
406     {
407       result = (*env)->NewStringUTF (env, _value);
408       g_free ((gpointer) _value);
409     }
410
411   return result;
412 }
413
414 /*
415  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
416  * Method:    gconf_client_set_string
417  * Signature: (Ljava/lang/String;Ljava/lang/String;)Z
418  */
419 JNIEXPORT jboolean JNICALL
420 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1set_1string
421   (JNIEnv *env, jclass clazz __attribute__ ((unused)),
422    jstring key, jstring value)
423 {
424   const char *_key = NULL;
425   const char *_value = NULL;
426   GError *err = NULL;
427
428   gboolean result = JNI_FALSE;
429
430   /* load an UTF string from the virtual machine. */
431   _key = JCL_jstring_to_cstring (env, key);
432   _value = JCL_jstring_to_cstring (env, value);
433   if (_key == NULL || _value == NULL)
434     {
435       return JNI_FALSE;
436     }
437
438   gdk_threads_enter ();
439   result = gconf_client_set_string (client, _key, _value, &err);
440   gdk_threads_leave ();
441   if (err != NULL)
442         {
443       g_error_free (err);
444       err = NULL;
445       result = JNI_FALSE;
446         }
447         
448   JCL_free_cstring (env, key, _key);
449   JCL_free_cstring (env, value, _value);
450
451   return (jboolean) result;
452 }
453
454 /*
455  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
456  * Method:    gconf_client_remove_dir
457  * Signature: (Ljava/lang/String;)V
458  */
459 JNIEXPORT void JNICALL
460 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1remove_1dir
461   (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring node)
462 {
463   const char *dir = NULL;
464
465   dir = JCL_jstring_to_cstring (env, node);
466   if (dir == NULL)
467     return;
468
469   gdk_threads_enter ();
470   gconf_client_remove_dir (client, dir, NULL);
471   gdk_threads_leave ();
472
473   JCL_free_cstring (env, node, dir);
474 }
475
476 /*
477  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
478  * Method:    gconf_client_add_dir
479  * Signature: (Ljava/lang/String;)V
480  */
481 JNIEXPORT void JNICALL
482 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1add_1dir
483   (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring node)
484 {
485   const char *dir = NULL;
486
487   dir = JCL_jstring_to_cstring (env, node);
488   if (dir == NULL)
489     return;
490
491   /* ignore errors */
492   gdk_threads_enter ();
493   gconf_client_add_dir (client, dir, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
494   gdk_threads_leave ();
495
496   JCL_free_cstring (env, node, dir);
497 }
498
499 /*
500  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
501  * Method:    gconf_client_dir_exists
502  * Signature: (Ljava/lang/String;)Z
503  */
504 JNIEXPORT jboolean JNICALL
505 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1client_1dir_1exists
506   (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring node)
507 {
508   const char *dir = NULL;
509   GError *err = NULL;
510   jboolean value = JNI_FALSE;
511
512   dir = JCL_jstring_to_cstring (env, node);
513   if (dir == NULL)
514     return value;
515
516   /* on error return false */
517   gdk_threads_enter ();
518   value = gconf_client_dir_exists (client, dir, &err);
519   gdk_threads_leave ();
520   if (err != NULL)
521     value = JNI_FALSE;
522
523   JCL_free_cstring (env, node, dir);
524
525   return value;
526 }
527
528 /*
529  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
530  * Method:    finalize_class
531  * Signature: ()V
532  */
533 JNIEXPORT void JNICALL
534 Java_gnu_java_util_prefs_gconf_GConfNativePeer_finalize_1class
535   (JNIEnv *env, jclass clazz __attribute__ ((unused)))
536 {
537   if (reference_count == 0)
538     {
539       /* last reference, free all resources and return */
540       gdk_threads_enter ();
541       g_object_unref (G_OBJECT (client));
542       gdk_threads_leave ();
543
544       (*env)->DeleteGlobalRef (env, jlist_class);
545
546       jlist_class = NULL;
547       jlist_init_id = NULL;
548       jlist_add_id = NULL;
549
550       return;
551     }
552
553   reference_count--;
554 }
555
556 /*
557  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
558  * Method:    Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1escape_1key
559  * Signature: (Ljava/lang/String;)Z
560  */
561 JNIEXPORT jstring JNICALL
562 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1escape_1key
563   (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring plain)
564 {
565   const char *escaped = NULL;
566   const char *_plain = NULL;
567   jstring result = NULL;
568   
569   _plain = JCL_jstring_to_cstring (env, plain);
570   if (_plain == NULL)
571     {
572       return NULL;
573     }
574
575   gdk_threads_enter ();
576   escaped = gconf_escape_key (_plain, strlen (_plain));
577   gdk_threads_leave ();
578   
579   JCL_free_cstring (env, plain, _plain);
580   /* check for NULL, if so prevent string creation */
581   if (escaped != NULL)
582     {
583       result = (*env)->NewStringUTF (env, escaped);
584       g_free ((gpointer) escaped);
585     }
586   
587   return result;
588 }
589
590 /*
591  * Class:     gnu_java_util_prefs_gconf_GConfNativePeer
592  * Method:    Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1unescape_1key
593  * Signature: (Ljava/lang/String;)Z
594  */
595 JNIEXPORT jstring JNICALL
596 Java_gnu_java_util_prefs_gconf_GConfNativePeer_gconf_1unescape_1key
597   (JNIEnv *env, jclass clazz __attribute__ ((unused)), jstring escaped)
598 {
599   const char *plain = NULL;
600   const char *_escaped = NULL;
601   jstring result = NULL;
602   
603   _escaped = JCL_jstring_to_cstring (env, escaped);
604   if (_escaped == NULL)
605     {
606       return NULL;
607     }
608
609   gdk_threads_enter ();
610   plain = gconf_unescape_key (_escaped, strlen (_escaped));
611   gdk_threads_leave ();
612   
613   JCL_free_cstring (env, escaped, _escaped);
614   /* check for NULL, if so prevent string creation */
615   if (plain != NULL)
616     {
617       result = (*env)->NewStringUTF (env, plain);
618       g_free ((gpointer) plain);
619     }
620   
621   return result;
622 }
623
624 /* ***** END: NATIVE FUNCTIONS ***** */
625
626 /* ***** PRIVATE FUNCTIONS IMPLEMENTATION ***** */
627
628 static void throw_exception (JNIEnv *env, const char *msg)
629 {
630   throw_exception_by_name (env, "java/lang/RuntimeException", msg);
631 }
632
633 static void
634 throw_exception_by_name (JNIEnv *env, const char *name, const char *msg)
635 {
636   JCL_ThrowException (env, name, msg);
637 }
638
639 static void init_gconf_client (void)
640 {
641   g_type_init ();
642   client = gconf_client_get_default ();
643 }
644
645 static gboolean set_jlist_class (JNIEnv *env)
646 {
647   jclass local_jlist_class = NULL;
648
649   /* gets a reference to the ArrayList class */
650   local_jlist_class = JCL_FindClass (env, "java/util/ArrayList");
651   if (local_jlist_class == NULL)
652     {
653       return FALSE;
654     }
655
656   jlist_class = (*env)->NewGlobalRef (env, local_jlist_class);
657   (*env)->DeleteLocalRef (env, local_jlist_class);
658   if (jlist_class == NULL)
659     {
660       return FALSE;
661     }
662
663   /* and initialize it */
664   jlist_init_id = (*env)->GetMethodID (env, jlist_class, "<init>", "()V");
665   if (jlist_init_id == NULL)
666     {
667       return FALSE;
668     }
669
670   jlist_add_id = (*env)->GetMethodID (env, jlist_class, "add",
671                                                                   "(Ljava/lang/Object;)Z");
672   if (jlist_add_id == NULL)
673     {
674       return FALSE;
675     }
676
677   return TRUE;
678 }
679
680 static jobject get_jlist_reference (JNIEnv *env, jclass jlist_class)
681 {
682   return (*env)->NewObject (env, jlist_class, jlist_init_id);
683 }
684
685 /* ***** END: PRIVATE FUNCTIONS IMPLEMENTATION ***** */