aboutsummaryrefslogtreecommitdiff
path: root/lib/cpluff/libcpluff/docsrc/mainprog.dox
blob: 78407d032ea50040a3e2a8144ae770581ecab396 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
/*-------------------------------------------------------------------------
 * C-Pluff, a plug-in framework for C
 * Copyright 2007 Johannes Lehtinen
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *-----------------------------------------------------------------------*/

/**
 * @page cMainProgram Main program
 *
 * @section cMainProgramOverview Overview
 *
 * The main program is the part of executable that is located outside the
 * plug-in framework. The main program is responsible for setting up
 * the plug-in framework and for loading the desired set of
 * @ref plugin "plug-ins". The main program should preferably be very
 * thin, a mere plug-in loader, because it can not fully participate in plug-in
 * interaction. C-Pluff distribution provides a plug-in loader,
 * @ref cpluff-loader, which can be used as a generic main program for
 * arbitrary plug-in collections.
 *
 * @section cMainProgramResponsibilities Responsibilities
 *
 * The main program has several responsibilities:
 *
 * - @ref cMainProgramInitFramework "initializing the plug-in framework"
 * - @ref cMainProgramCreateContext "creating a plug-in context"
 * - @ref cMainProgramLoad "loading plug-ins"
 * - @ref cMainProgramExec "controlling plug-in execution"
 * - @ref cMainProgramChange "changing plug-in configuration" (opt.)
 * - @ref cMainProgramDestroyFramework "destroying the plug-in framework"
 *
 * @subsection cMainProgramInitFramework Initializing the plug-in framework
 *
 * Plug-in framework, or the C-Pluff library, must be initialized before its
 * services can be used.
 * Initialization is not a thread-safe operation and should generally be
 * done by the main program before any additional plug-in framework accessing
 * threads are started. Initialization is done by calling ::cp_init.
 * Additionally, the main program can use ::cp_set_fatal_error_handler to register
 * a function that is called when a fatal error occurs. A fatal error is one
 * that prevents the framework from continuing operation. For example,
 * errors in operating system locking operations and a NULL pointer being
 * passed as an argument which is expected to have a non-NULL value are fatal
 * erors.
 *
 * Here is an example of possible initialization code.
 *
 * @code
 * #include <locale.h>
 * #include <cpluff.h>
 *
 * void handle_fatal_error(const char *msg) {
 *
 *   // ... log error, flush logs, send bug report, etc. ...
 *
 *   fprintf(stderr, "A fatal error occurred: %s\n", msg);
 *   abort();
 * }
 *
 * void initialize(void) {
 *   cp_status_t status;
 *
 *   setlocale(LC_ALL, "");
 *   cp_set_fatal_error_handler(handle_fatal_error);
 *   status = cp_init();
 *   if (status != CP_OK) {
 *     // ... handle initialization failure ...
 *   }
 * }
 * @endcode
 *
 * @subsection cMainProgramCreateContext Creating a plug-in context
 *
 * A plug-in context represents the co-operation environment of a set of
 * plug-ins from the perspective of a particular participating plug-in or
 * the perspective of the main program. From main program perspective, a
 * plug-in context is a container for a set of plug-ins. A plug-in can interact
 * with other plug-ins in the same container.
 *
 * An extensible application can have more than one plug-in container but
 * usually one container should suffice. Due to the nature of C programs,
 * plug-ins deployed to different containers are not very well insulated from
 * each other. For example, global variables provided by a plug-in in one
 * container are visible to all plug-ins in all containers. Also, by placing
 * all plug-ins in the same container they can more efficiently share common
 * base components which themselves might provide extensibility.
 *
 * A main program creates a plug-in context, to be used as a container for
 * plugins, using ::cp_create_context.
 *
 * @code
 * #include <cpluff.h>
 *
 * cp_context_t *ctx;
 *
 * void create_context(void) {
 *   cp_status_t status;
 *
 *   ctx = cp_create_context(&status);
 *   if (ctx == NULL) {
 *     // ... handle initialization failure ...
 *   }
 * }
 * @endcode
 *
 * @subsection cMainProgramLoad Loading plug-ins
 *
 * An extensible application is made of plug-ins that can be added and removed
 * dynamically. The plug-ins are loaded by the main program using the services
 * provided by the framework. The framework provides couple of alternative
 * ways of loading plug-ins.
 *
 * As a lowest level operation, the main program can
 * load individual plug-ins from known locations using
 * ::cp_load_plugin_descriptor and ::cp_install_plugin. Here is example code
 * that loads a set of plug-ins from file system locations listed in a file.
 *
 * @code
 * #include <stdio.h>
 * #include <cpluff.h>
 *
 * extern cp_context_t *ctx;
 * static const char pluginListFile[] = "/etc/example/plugins.list";
 *
 * void load_plugins(void) {
 *   char plugindir[128];
 *   FILE *lf;
 *
 *   // Open plug-in list file
 *   lf = fopen(pluginListFile, "r");
 *   if (lf == NULL) {
 *     // ... handle loading failure ...
 *   }
 *
 *   // Load each listed plug-in
 *   while (fgets(plugindir, 128, lf) != NULL) {
 *     cp_plugin_info_t *plugininfo;
 *     cp_status_t status;
 *     int i;
 *
 *     // Remove possible trailing newline from plug-in location
 *     for (i = 0; plugindir[i + 1] != '\0'; i++);
 *     if (plugindir[i] == '\n') {
 *       plugindir[i] = '\0';
 *     }
 *
 *     // Load plug-in descriptor
 *     plugininfo = cp_load_plugin_descriptor(ctx, plugindir, &status);
 *     if (pinfo == NULL) {
 *       // ... handle loading failure ...
 *     }
 *
 *     // Install plug-in descriptor
 *     status = cp_install_plugin(ctx, plugininfo);
 *     if (status != CP_OK) {
 *       // ... handle loading failure ...
 *     }
 *
 *     // Release plug-in descriptor information
 *     cp_release_info(ctx, plugininfo);
 *   }
 *
 *   // Close plug-in list file
 *   fclose(lf);
 * }
 * @endcode
 *
 * Alternatively, the main program can register and load plug-in collections.
 * A plug-in collection is a file system directory which includes individual
 * plug-ins in subdirectories, one plug-in in each subdirectory. Plug-in
 * collections can be registered with a plug-in context using
 * ::cp_register_pcollection. Plug-ins of the collection can then be scanned
 * and loaded using ::cp_scan_plugins. Here is example code loading plug-ins
 * from a plug-in collection.
 * 
 * @code
 * #include <cpluff.h>
 *
 * extern cp_context_t *ctx;
 * static const char pluginCollectionDir[] = "/etc/example/plugins";
 *
 * void load_plugins(void) {
 *   cp_status_t status;
 *
 *   status = cp_register_pcollection(ctx, pluginCollectionDir);
 *   if (status != CP_OK) {
 *     // ... handle loading failure ...
 *   }
 *   status = cp_scan_plugins(ctx, 0);
 *   if (status != CP_OK) {
 *     // ... handle loading failure ...
 *     // (notice that some plug-ins might have been loaded)
 *   }
 * }
 * @endcode
 *
 * @subsection cMainProgramExec Controlling plug-in execution
 *
 * The main program controls plug-in execution by starting and stopping
 * plug-ins and by executing run functions registered by plug-ins.
 * Additionally, the main program can pass startup arguments to plug-ins.
 *
 * When plug-ins are installed they are not yet activated and their
 * runtime library is not even loaded at that point. The main program
 * typically activates plug-ins by starting a main plug-in
 * responsible for user interface or core application logic. This plug-in
 * then implicitly causes other plug-ins to be activated via dependencies and
 * by dynamically resolving symbols provided by other plug-ins. Plug-ins
 * recursively activate each other until all initially needed plug-ins have
 * been started. Some plug-ins might be activated at a later time when their
 * functionality is needed, for example due to user action.
 *
 * If a plug-in needs to perform background operations, that is operations
 * executed outside the invocation of plug-in provided interface functions,
 * then it can either start a new thread or it can register a run function.
 * A run function is a function that is typically executed as part of the
 * main loop by the main program.
 *
 * The following example code shows how a main program might initialize
 * plug-in startup arguments using ::cp_set_context_args, start the core
 * plug-in using ::cp_start_plugin and then execute plug-in run functions
 * using ::cp_run_plugins.
 *
 * @code
 * #include <cpluff.h>
 *
 * extern cp_context_t *ctx;
 * static const char corePluginId[] = "org.example.core";
 *
 * void run_plugins(char *argv[]) {
 *   cp_status_t status;
 *
 *   // Set plug-in startup arguments
 *   cp_set_context_args(ctx, argv);
 *
 *   // Start the core plug-in, possibly activating other plug-ins as well
 *   status = cp_start_plugin(ctx, corePluginId);
 *   if (status != CP_OK) {
 *     // ... handle startup failure ...
 *   }
 *
 *   // Execute plug-ins until there is no more work to be done
 *   cp_run_plugins(ctx);
 * }
 *
 * int main(int argc, char *argv[]) {
 *   // ... do initialization and load plug-ins ...
 *
 *   run_plugins(argv);
 *
 *   // ... do destruction ...
 * }
 * @endcode
 *
 * Alternatively, if the main program has some operations it must perform
 * as part of the main loop, the call to ::cp_run_plugins can be replaced
 * by code using ::cp_run_plugins_step like in the following example.
 *
 * @code
 * void mainloop(void) {
 *   int finished = 0;
 *
 *   while (!finished) {
 *     // ... do main program specific operations ...
 *
 *     finished = !cp_run_plugins_step(ctx);
 *   }
 * }
 * @endcode
 *
 * @subsection cMainProgramChange Changing plug-in configuration
 *
 * C-Pluff has been designed to allow dynamic changes to the plug-in
 * configuration, that is plug-ins being added or removed without shutting
 * down the application or the framework. It is the responsibility of the
 * main program to manage such changes if the application is to support
 * dynamic configuration changes.
 *
 * Adding plug-ins is straightforward because there is no need to
 * consider dependencies of active plug-ins. For example, if one uses
 * plug-in collections as introduced above then new plug-ins can be
 * deployed under the plug-in collection directory while the application is
 * running and the main program can load them incrementally by calling
 * ::cp_scan_plugins again. This call might be activated by some user interface
 * element, for example a plug-in manager component which just downloaded and
 * installed new plug-ins as requested by the user. The flags
 * #CP_SP_STOP_ALL_ON_INSTALL and #CP_SP_RESTART_ACTIVE
 * orred together can be used to cause all active plug-ins to be restarted
 * if they do not otherwise notice the extensions provided by new plug-ins.
 *
 * Upgrading plug-ins is almost as straightforward because the C-Pluff
 * framework manages plug-in dependencies (assuming the plug-ins have
 * declared their dependencies properly). The new version of a plug-in
 * can be deployed under the plug-in collection directory in a
 * new subdirectory parallel to the old version while the application is
 * running. The main program can then call ::cp_scan_plugins with
 * #CP_SP_UPGRADE and #CP_SP_RESTART_ACTIVE orred together. This will stop
 * the old version of the upgraded plug-in (implicitly stopping all plug-ins
 * that depend on it), unload the plug-in from the framework, install the
 * new version of the plug-in and finally restart plug-ins that were
 * active before the operation. The old version of the plug-in can now
 * be removed from the plug-in collection. Again, #CP_SP_STOP_ALL_ON_UPGRADE
 * can be added to restart all active plug-ins.
 *
 * Deleting plug-ins must be done by first stopping and unloading the
 * plug-in to be deleted using ::cp_uninstall_plugin. The the plug-in can
 * be removed from the plug-in collection.
 *
 * @subsection cMainProgramDestroyFramework Destroying the plug-in framework
 *
 * The plug-in framework can be destroyed and all resources released by
 * calling ::cp_destroy as many times as ::cp_init has been called. This
 * is not a thread-safe operation and should generally be done by the main
 * program just before application exits. The destroy function
 * stops and unloads all plug-ins and destroys all plug-in contexts before
 * destroying the core framework.
 *
 * Individual plug-in contexts can be destroyed by calling
 * ::cp_destroy_context. The destroy function stops and unloads all plug-ins
 * before destroying the context itself.
 */