1 /*
2  * go-plugin-loader.c: Base class for plugin loaders.
3  *
4  * Author: Zbigniew Chyla (cyba@gnome.pl)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) version 3.
10  *
11  * This library 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  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
19  * USA.
20  */
21 
22 #include <goffice/goffice-config.h>
23 #include <goffice/app/go-plugin-loader.h>
24 #include <goffice/app/go-plugin.h>
25 #include <goffice/app/go-plugin-service.h>
26 #include <goffice/app/error-info.h>
27 
28 #include <gsf/gsf-impl-utils.h>
29 #include <glib/gi18n-lib.h>
30 
31 #define PL_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_INTERFACE ((o), GO_TYPE_PLUGIN_LOADER, GOPluginLoaderClass))
32 
33 /**
34  * GOPluginLoaderClass:
35  * @base: base interface.
36  * @load_base: loads the plugin without activating any service.
37  * @unload_base: unloads the plugin if possible.
38  * @set_attributes: sets attiributes for the module.
39  * @service_load: loads a service.
40  * @service_unload: unloads a service if possible.
41  * @load_service_file_opener: loads a file opener service.
42  * @unload_service_file_opener: unloads a file opener service.
43  * @load_service_file_saver: loads a file saver service.
44  * @unload_service_file_saver: unloads a file saver service.
45  * @load_service_plugin_loader: loads a plugin loader service.
46  * @unload_service_plugin_loader: unloads a plugin loader service.
47  **/
48 
49 gboolean
go_plugin_loader_is_base_loaded(GOPluginLoader * loader)50 go_plugin_loader_is_base_loaded (GOPluginLoader *loader)
51 {
52 	return g_object_get_data (G_OBJECT (loader), "is-base-loaded") != NULL;
53 }
54 
55 /**
56  * go_plugin_loader_get_plugin:
57  * @l: #GOPluginLoader
58  *
59  * Returns: (transfer full): the plugin
60  **/
61 GOPlugin *
go_plugin_loader_get_plugin(GOPluginLoader * l)62 go_plugin_loader_get_plugin (GOPluginLoader *l)
63 {
64 	return g_object_get_data (G_OBJECT (l), "plugin");
65 }
66 
67 void
go_plugin_loader_set_plugin(GOPluginLoader * l,GOPlugin * p)68 go_plugin_loader_set_plugin (GOPluginLoader *l, GOPlugin *p)
69 {
70 	g_object_set_data (G_OBJECT (l), "plugin", p);
71 }
72 
73 void
go_plugin_loader_set_attributes(GOPluginLoader * loader,GHashTable * attrs,GOErrorInfo ** err)74 go_plugin_loader_set_attributes (GOPluginLoader *loader, GHashTable *attrs,
75 				 GOErrorInfo **err)
76 {
77 	g_return_if_fail (GO_IS_PLUGIN_LOADER (loader));
78 
79 	GO_INIT_RET_ERROR_INFO (err);
80 	if (PL_GET_CLASS (loader)->set_attributes)
81 		PL_GET_CLASS (loader)->set_attributes (loader, attrs, err);
82 	else
83 		*err = go_error_info_new_printf (_("Loader has no set_attributes method.\n"));
84 }
85 
86 void
go_plugin_loader_load_base(GOPluginLoader * loader,GOErrorInfo ** err)87 go_plugin_loader_load_base (GOPluginLoader *loader, GOErrorInfo **err)
88 {
89 	GOPluginLoaderClass *go_plugin_loader_class;
90 
91 	g_return_if_fail (GO_IS_PLUGIN_LOADER (loader));
92 	g_return_if_fail (!go_plugin_loader_is_base_loaded (loader));
93 
94 	go_plugin_loader_class = PL_GET_CLASS (loader);
95 	if (go_plugin_loader_class->load_base != NULL)
96 		go_plugin_loader_class->load_base (loader, err);
97 	else
98 		*err = go_error_info_new_printf (_("Loader has no load_base method.\n"));
99 	if (*err == NULL)
100 		g_object_set_data (G_OBJECT (loader), "is-base-loaded", GINT_TO_POINTER (1));
101 }
102 
103 void
go_plugin_loader_unload_base(GOPluginLoader * loader,GOErrorInfo ** err)104 go_plugin_loader_unload_base (GOPluginLoader *loader, GOErrorInfo **err)
105 {
106 	GOPluginLoaderClass *go_plugin_loader_class;
107 
108 	g_return_if_fail (GO_IS_PLUGIN_LOADER (loader));
109 
110 	go_plugin_loader_class = PL_GET_CLASS (loader);
111 	if (go_plugin_loader_class->unload_base != NULL) {
112 		go_plugin_loader_class->unload_base (loader, err);
113 		if (*err == NULL)
114 			g_object_set_data (G_OBJECT (loader), "is-base-loaded", NULL);
115 	}
116 }
117 
118 void
go_plugin_loader_load_service(GOPluginLoader * l,GOPluginService * s,GOErrorInfo ** err)119 go_plugin_loader_load_service (GOPluginLoader *l, GOPluginService *s, GOErrorInfo **err)
120 {
121 	GOPluginLoaderClass *klass;
122 	void (*load_service_method) (GOPluginLoader *, GOPluginService *, GOErrorInfo **) = NULL;
123 
124 	g_return_if_fail (GO_IS_PLUGIN_LOADER (l));
125 	g_return_if_fail (GO_IS_PLUGIN_SERVICE (s));
126 	g_return_if_fail (go_plugin_loader_is_base_loaded (l));
127 
128 	GO_INIT_RET_ERROR_INFO (err);
129 
130 	klass = PL_GET_CLASS (l);
131 	if (klass->service_load && (klass->service_load) (l, s, err))
132 		return;
133 
134 	if (GO_IS_PLUGIN_SERVICE_FILE_OPENER (s)) {
135 		load_service_method = klass->load_service_file_opener;
136 	} else if (GO_IS_PLUGIN_SERVICE_FILE_SAVER (s)) {
137 		load_service_method = klass->load_service_file_saver;
138 	} else if (GO_IS_PLUGIN_SERVICE_PLUGIN_LOADER (s)) {
139 		load_service_method = klass->load_service_plugin_loader;
140 	} else if (GO_IS_PLUGIN_SERVICE_SIMPLE (s)) {
141 		load_service_method = NULL;
142 	} else {
143 		*err = go_error_info_new_printf (_("Service '%s' not supported by loader."),
144 			G_OBJECT_TYPE_NAME (s));
145 	}
146 	if (load_service_method != NULL)
147 		load_service_method (l, s, err);
148 
149 	if (*err == NULL) {
150 		gpointer num_services = g_object_get_data (G_OBJECT (l), "num-services");
151 		g_object_set_data (G_OBJECT (l), "num-services",
152 		    GINT_TO_POINTER (GPOINTER_TO_INT (num_services) + 1));
153 	}
154 }
155 
156 void
go_plugin_loader_unload_service(GOPluginLoader * l,GOPluginService * s,GOErrorInfo ** err)157 go_plugin_loader_unload_service (GOPluginLoader *l, GOPluginService *s, GOErrorInfo **err)
158 {
159 	GOPluginLoaderClass *klass;
160 	void (*unload_service_method) (GOPluginLoader *, GOPluginService *, GOErrorInfo **) = NULL;
161 	GOErrorInfo *error = NULL;
162 
163 	g_return_if_fail (GO_IS_PLUGIN_LOADER (l));
164 	g_return_if_fail (GO_IS_PLUGIN_SERVICE (s));
165 
166 	GO_INIT_RET_ERROR_INFO (err);
167 
168 	klass = PL_GET_CLASS (l);
169 	if (klass->service_unload && (klass->service_unload) (l, s, err))
170 		return;
171 
172 	if (GO_IS_PLUGIN_SERVICE_FILE_OPENER (s)) {
173 		unload_service_method = klass->unload_service_file_opener;
174 	} else if (GO_IS_PLUGIN_SERVICE_FILE_SAVER (s)) {
175 		unload_service_method = klass->unload_service_file_saver;
176 	} else if (GO_IS_PLUGIN_SERVICE_PLUGIN_LOADER (s)) {
177 		unload_service_method = klass->unload_service_plugin_loader;
178 	} else if (GO_IS_PLUGIN_SERVICE_SIMPLE (s)) {
179 		unload_service_method = NULL;
180 	} else
181 		*err = go_error_info_new_printf (_("Service '%s' not supported by loader."),
182 			G_OBJECT_TYPE_NAME (s));
183 
184 	if (unload_service_method != NULL)
185 		unload_service_method (l, s, &error);
186 	if (error == NULL) {
187 		gpointer num_services = g_object_get_data (G_OBJECT (l), "num-services");
188 		g_return_if_fail (num_services != NULL);
189 		g_object_set_data (G_OBJECT (l), "num-services",
190 		    GINT_TO_POINTER (GPOINTER_TO_INT (num_services) - 1));
191 		if (GPOINTER_TO_INT (num_services) == 1) {
192 			go_plugin_loader_unload_base (l, &error);
193 			go_error_info_free (error);
194 		}
195 	} else
196 		*err = error;
197 }
198 
199 GType
go_plugin_loader_get_type(void)200 go_plugin_loader_get_type (void)
201 {
202 	static GType go_plugin_loader_type = 0;
203 
204 	if (!go_plugin_loader_type) {
205 		static GTypeInfo const go_plugin_loader_info = {
206 			sizeof (GOPluginLoaderClass),	/* class_size */
207 			NULL,				/* base_init */
208 			NULL,				/* base_finalize */
209 		};
210 
211 		go_plugin_loader_type = g_type_register_static (G_TYPE_INTERFACE,
212 			"GOPluginLoader", &go_plugin_loader_info, 0);
213 	}
214 
215 	return go_plugin_loader_type;
216 }
217