dotnet plugin: First stub for a .NET integration plugin using Mono.
[collectd.git] / src / dotnet.c
1 /**
2  * collectd - src/dotnet.c
3  * Copyright (C) 2010  Florian Forster
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *   Florian Forster <ff at octo.it>
25  **/
26
27 #include "collectd.h"
28 #include "plugin.h"
29 #include "common.h"
30 #include "configfile.h"
31
32 #include <glib.h>
33 #include <mono/jit/jit.h>
34 #include <mono/metadata/assembly.h>
35
36 static MonoDomain *domain = NULL;
37
38 static int dotnet_log (int severity, MonoString *message) /* {{{ */
39 {
40   char *tmp = mono_string_to_utf8 (message);
41
42   DEBUG ("dotnet_log (severity = %i, message = \"%s\");", severity, tmp);
43
44   return (0);
45 } /* }}} int dotnet_log */
46
47 static int dotnet_register_read (MonoString *name, MonoObject *obj) /* {{{ */
48 {
49   char *name_utf8 = mono_string_to_utf8 (name);
50   MonoClass *class;
51   MonoMethod *method;
52
53   DEBUG ("dotnet_register_read: name = \"%s\";", name_utf8);
54
55   class = mono_object_get_class (obj);
56
57   method = mono_class_get_method_from_name (mono_object_get_class (obj),
58       /* name = */ "read", /* param count = */ 0);
59   if (method == NULL)
60   {
61     ERROR ("dotnet_register_read: Can't find method read():int.");
62     return (-1);
63   }
64
65   DEBUG ("dotnet_register_read: Class %s successfully registered.",
66       mono_class_get_name (class));
67   return (0);
68 } /* }}} int dotnet_register_read */
69
70 static int dotnet_load_class (const char *assembly_name, /* {{{ */
71     const char *name_space, const char *class_name)
72 {
73   MonoAssembly *assembly;
74   MonoImage *image;
75   MonoClass *class;
76   MonoObject *obj;
77
78   assembly = mono_domain_assembly_open (domain, assembly_name);
79   if (assembly == NULL)
80   {
81     ERROR ("dotnet plugin: mono_domain_assembly_open (\"%s\") failed.",
82         assembly_name);
83     return (-1);
84   }
85
86   image = mono_assembly_get_image (assembly);
87   if (image == NULL)
88   {
89     ERROR ("mono_assembly_get_image failed.");
90     mono_jit_cleanup (domain);
91     return (-1);
92   }
93
94   class = mono_class_from_name (image,
95       (name_space != NULL) ? name_space : "",
96       class_name);
97   if (class == NULL)
98   {
99     ERROR ("dotnet plugin: Looking up class \"%s\" in assembly \"%s\" failed.",
100         class_name, assembly_name);
101     return (-1);
102   }
103
104   obj = mono_object_new (domain, class);
105   if (obj == NULL)
106   {
107     ERROR ("Creating a \"%s\" object failed.", class_name);
108     return (-1);
109   }
110
111   mono_runtime_object_init (obj);
112
113   DEBUG ("dotnet plugin: Successfully created a \"%s\" object.", class_name);
114
115   return (0);
116 } /* }}} int dotnet_load_class */
117
118 /*
119  * <Plugin dotnet>
120  *   <LoadPlugin "Foobar">
121  *     NameSpace "MyCompany"
122  *     Assembly "path/to/file.dll"
123  *   </LoadPlugin>
124  *
125  *   <Plugin "Foobar">
126  *     ...
127  *   </Plugin>
128  * </Plugin>
129  */
130 static int dotnet_config_loadplugin (oconfig_item_t *ci) /* {{{ */
131 {
132   char *class_name = NULL;
133   char *name_space = NULL;
134   char *assembly_name = NULL;
135   int status;
136   int i;
137
138   status = cf_util_get_string (ci, &class_name);
139   if (status != 0)
140     return (status);
141   assert (class_name != NULL);
142
143   for (i = 0; i < ci->children_num; i++)
144   {
145     oconfig_item_t *child = ci->children + i;
146
147     if (strcasecmp ("NameSpace", child->key) == 0)
148       cf_util_get_string (child, &name_space);
149     else if (strcasecmp ("Assembly", child->key) == 0)
150       cf_util_get_string (child, &assembly_name);
151     else
152       WARNING ("dotnet plugin: Config option \"%s\" is not allowed here.",
153           child->key);
154   }
155
156   if (assembly_name == NULL)
157   {
158     ERROR ("dotnet plugin: No \"Assembly\" option within this \"LoadPlugin\" "
159         "block (class \"%s\").", class_name);
160     sfree (class_name);
161     sfree (name_space);
162   }
163
164   status = dotnet_load_class (assembly_name, name_space, class_name);
165   if (status != 0)
166     return (status);
167
168   return (0);
169 } /* }}} int dotnet_config_loadplugin */
170
171 static int dotnet_config (oconfig_item_t *ci) /* {{{ */
172 {
173   int i;
174
175   for (i = 0; i < ci->children_num; i++)
176   {
177     oconfig_item_t *child = ci->children + i;
178
179     if (strcasecmp ("LoadPlugin", child->key) == 0)
180       dotnet_config_loadplugin (child);
181     else
182       WARNING ("dotnet plugin: Ignoring unknown config option \"%s\".",
183           child->key);
184   }
185
186   return (0);
187 } /* }}} int dotnet_config */
188
189 void module_register (void)
190 {
191   domain = mono_jit_init (PACKAGE_NAME);
192   if (domain == NULL)
193   {
194     ERROR ("dotnet plugin: mono_jit_init failed.");
195     return;
196   }
197
198   mono_add_internal_call ("CollectdAPI.Collectd::log", dotnet_log);
199   mono_add_internal_call ("CollectdAPI.Collectd::registerRead", dotnet_register_read);
200
201   plugin_register_complex_config ("dotnet", dotnet_config);
202 } /* void module_register */
203
204 /* vim: set sw=2 sts=2 et fdm=marker : */