1 /*
2 * libosinfo:
3 *
4 * Copyright (C) 2009-2020 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21 #include <osinfo/osinfo.h>
22 #include <glib/gi18n-lib.h>
23
24 /**
25 * SECTION:osinfo_entity
26 * @short_description: Abstract base class for metadata objects
27 * @see_also: #OsinfoList, #OsinfoDb
28 *
29 * #OsinfoEntity is an abstract base class for all objects against which
30 * metadata needs to be recorded. Every object has a unique identifier,
31 * which is recommended to be in URI format. Named, multi-valued data
32 * parameters can be associated with each entity. When filtering lists
33 * of entities, the parameter values can be used for matching.
34 */
35
36 struct _OsinfoEntityPrivate
37 {
38 gchar *id;
39
40 // Key: gchar*
41 // Value: GList of gchar* values
42 GHashTable *params;
43 };
44
45 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(OsinfoEntity, osinfo_entity, G_TYPE_OBJECT);
46
47 static void osinfo_entity_finalize(GObject *object);
48
49 enum {
50 PROP_0,
51
52 PROP_ID,
53
54 LAST_PROP
55 };
56 static GParamSpec *properties[LAST_PROP];
57
58 static void
osinfo_entity_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)59 osinfo_entity_set_property(GObject *object,
60 guint property_id,
61 const GValue *value,
62 GParamSpec *pspec)
63 {
64 OsinfoEntity *entity = OSINFO_ENTITY(object);
65
66 switch (property_id)
67 {
68 case PROP_ID:
69 g_free(entity->priv->id);
70 entity->priv->id = g_value_dup_string(value);
71 break;
72 default:
73 /* We don't have any other property... */
74 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
75 break;
76 }
77 }
78
79 static void
osinfo_entity_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)80 osinfo_entity_get_property(GObject *object,
81 guint property_id,
82 GValue *value,
83 GParamSpec *pspec)
84 {
85 OsinfoEntity *entity = OSINFO_ENTITY(object);
86
87 switch (property_id)
88 {
89 case PROP_ID:
90 g_value_set_string(value, entity->priv->id);
91 break;
92 default:
93 /* We don't have any other property... */
94 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
95 break;
96 }
97 }
98
99 static void
osinfo_entity_finalize(GObject * object)100 osinfo_entity_finalize(GObject *object)
101 {
102 OsinfoEntity *entity = OSINFO_ENTITY(object);
103
104 g_free(entity->priv->id);
105 g_hash_table_destroy(entity->priv->params);
106
107 /* Chain up to the parent class */
108 G_OBJECT_CLASS(osinfo_entity_parent_class)->finalize(object);
109 }
110
111 /* Init functions */
112 static void
osinfo_entity_class_init(OsinfoEntityClass * klass)113 osinfo_entity_class_init(OsinfoEntityClass *klass)
114 {
115 GObjectClass *g_klass = G_OBJECT_CLASS(klass);
116
117 g_klass->set_property = osinfo_entity_set_property;
118 g_klass->get_property = osinfo_entity_get_property;
119 g_klass->finalize = osinfo_entity_finalize;
120
121 /**
122 * OsinfoEntity:id:
123 *
124 * The unique identifier for the entity The format of identifiers
125 * is undefined, but the recommended practice is to use a URI.
126 * This parameter must be set at time of construction as no
127 * default value is provided.
128 */
129 properties[PROP_ID] = g_param_spec_string("id",
130 "ID",
131 _("Unique identifier"),
132 NULL /* default value */,
133 G_PARAM_CONSTRUCT |
134 G_PARAM_READWRITE |
135 G_PARAM_STATIC_STRINGS);
136
137 g_object_class_install_properties(g_klass, LAST_PROP, properties);
138 }
139
140
osinfo_entity_param_values_free(gpointer values)141 static void osinfo_entity_param_values_free(gpointer values)
142 {
143 g_list_free_full(values, g_free);
144 }
145
146
147 static void
osinfo_entity_init(OsinfoEntity * entity)148 osinfo_entity_init(OsinfoEntity *entity)
149 {
150 entity->priv = osinfo_entity_get_instance_private(entity);
151 entity->priv->params = g_hash_table_new_full(g_str_hash,
152 g_str_equal,
153 g_free,
154 osinfo_entity_param_values_free);
155 }
156
157
158 /**
159 * osinfo_entity_set_param:
160 * @entity: an #OsinfoEntity containing the parameters
161 * @key: the name of the key
162 * @value: the data to associated with that key
163 *
164 * Sets a new parameter against the entity. If the key already
165 * has a value associated with it, the existing value will be
166 * cleared.
167 */
osinfo_entity_set_param(OsinfoEntity * entity,const gchar * key,const gchar * value)168 void osinfo_entity_set_param(OsinfoEntity *entity, const gchar *key, const gchar *value)
169 {
170 GList *values = NULL;
171
172 g_return_if_fail(OSINFO_IS_ENTITY(entity));
173 g_return_if_fail(key != NULL);
174 g_return_if_fail(value != NULL);
175
176 values = g_list_append(values, g_strdup(value));
177 g_hash_table_replace(entity->priv->params, g_strdup(key), values);
178 }
179
180
181 /**
182 * osinfo_entity_set_param_boolean:
183 * @entity: an #OsinfoEntity containing the parameters
184 * @key: the name of the key
185 * @value: the boolean value to be associated with that key
186 *
187 * Sets a new parameter against the entity. If the key already
188 * has a value associated with it, the existing value will be
189 * cleared.
190 *
191 * Since: 0.2.0
192 */
osinfo_entity_set_param_boolean(OsinfoEntity * entity,const gchar * key,gboolean value)193 void osinfo_entity_set_param_boolean(OsinfoEntity *entity, const gchar *key, gboolean value)
194 {
195 osinfo_entity_set_param(entity, key, value ? "true" : "false");
196 }
197
198 /**
199 * osinfo_entity_set_param_int64:
200 * @entity: an #OsinfoEntity containing the parameters
201 * @key: the name of the key
202 * @value: the int64 value to be associated with that key
203 *
204 * Sets a new parameter against the entity. If the key already
205 * has a value associated with it, the existing value will be
206 * cleared.
207 *
208 * Since: 0.2.1
209 */
osinfo_entity_set_param_int64(OsinfoEntity * entity,const gchar * key,gint64 value)210 void osinfo_entity_set_param_int64(OsinfoEntity *entity, const gchar *key, gint64 value)
211 {
212 gchar *str;
213
214 str = g_strdup_printf("%"G_GINT64_FORMAT, value);
215 osinfo_entity_set_param(entity, key, str);
216 g_free(str);
217 }
218
219 /**
220 * osinfo_entity_set_param_enum:
221 * @entity: an #OsinfoEntity containing the parameters
222 * @key: the name of the key
223 * @value: the enum value to be associated with that key
224 * @enum_type: the enum type
225 *
226 * Sets a new parameter against the entity. If the key already
227 * has a value associated with it, the existing value will be
228 * cleared.
229 *
230 * Since: 0.2.2
231 */
osinfo_entity_set_param_enum(OsinfoEntity * entity,const gchar * key,gint value,GType enum_type)232 void osinfo_entity_set_param_enum(OsinfoEntity *entity, const gchar *key, gint value, GType enum_type)
233 {
234 GEnumClass *enum_class;
235 GEnumValue *enum_value;
236
237 g_return_if_fail(G_TYPE_IS_ENUM(enum_type));
238
239 enum_class = g_type_class_ref(enum_type);
240 enum_value = g_enum_get_value(enum_class, value);
241 g_type_class_unref(enum_class);
242 g_return_if_fail(enum_value != NULL);
243
244 osinfo_entity_set_param(entity, key, enum_value->value_nick);
245 }
246
247 /**
248 * osinfo_entity_add_param:
249 * @entity: an #OsinfoEntity containing the parameters
250 * @key: the name of the key
251 * @value: the data to associated with that key
252 *
253 * Adds a new parameter against the entity. A key can have multiple
254 * values associated. Thus repeated calls with the same key will
255 * build up a list of possible values.
256 */
osinfo_entity_add_param(OsinfoEntity * entity,const gchar * key,const gchar * value)257 void osinfo_entity_add_param(OsinfoEntity *entity, const gchar *key, const gchar *value)
258 {
259 GList *values = NULL;
260 gpointer origKey = NULL;
261 gpointer foundValue = NULL;
262 gboolean found;
263
264 g_return_if_fail(OSINFO_IS_ENTITY(entity));
265 g_return_if_fail(key != NULL);
266 g_return_if_fail(value != NULL);
267
268 // First check if there exists an existing array of entries for this key
269 // If not, create a ptrarray of strings for this key and insert into map
270 found = g_hash_table_lookup_extended(entity->priv->params, key, &origKey, &foundValue);
271 if (found) {
272 g_hash_table_steal(entity->priv->params, key);
273 g_free(origKey);
274 values = foundValue;
275 }
276
277 values = g_list_append(values, g_strdup(value));
278 g_hash_table_insert(entity->priv->params, g_strdup(key), values);
279 }
280
281
282 /**
283 * osinfo_entity_clear_param:
284 * @entity: an #OsinfoEntity containing the parameters
285 * @key: the name of the key
286 *
287 * Remove all values associated with a key
288 */
osinfo_entity_clear_param(OsinfoEntity * entity,const gchar * key)289 void osinfo_entity_clear_param(OsinfoEntity *entity, const gchar *key)
290 {
291 g_return_if_fail(OSINFO_IS_ENTITY(entity));
292
293 g_hash_table_remove(entity->priv->params, key);
294 }
295
296 /**
297 * osinfo_entity_get_id:
298 * @entity: an #OsinfoEntity
299 *
300 * Retrieves the unique key for the entity. The format of identifiers
301 * is undefined, but the recommended practice is to use a URI.
302 *
303 * Returns: (transfer none): the unique key for the entity
304 */
osinfo_entity_get_id(OsinfoEntity * entity)305 const gchar *osinfo_entity_get_id(OsinfoEntity *entity)
306 {
307 g_return_val_if_fail(OSINFO_IS_ENTITY(entity), NULL);
308
309 return entity->priv->id;
310 }
311
312
313 /**
314 * osinfo_entity_get_param_keys:
315 * @entity: an #OsinfoEntity containing the parameters
316 *
317 * Retrieve all the known parameter keys associated with
318 * the entity
319 *
320 * Returns: (transfer container) (element-type utf8): The list of string parameters
321 */
osinfo_entity_get_param_keys(OsinfoEntity * entity)322 GList *osinfo_entity_get_param_keys(OsinfoEntity *entity)
323 {
324 GList *keys;
325
326 g_return_val_if_fail(OSINFO_IS_ENTITY(entity), NULL);
327
328 keys = g_hash_table_get_keys(entity->priv->params);
329 keys = g_list_append(keys, (char *)"id");
330
331 return keys;
332 }
333
334
335 /**
336 * osinfo_entity_get_param_value:
337 * @entity: an #OsinfoEntity containing the parameters
338 * @key: the name of the key
339 *
340 * Retrieve the parameter value associated with a named key. If
341 * multiple values are stored against the key, only the first
342 * value is returned. If no value is associated, NULL is returned
343 *
344 * Returns: (transfer none): the value associated with the key, or NULL
345 */
osinfo_entity_get_param_value(OsinfoEntity * entity,const gchar * key)346 const gchar *osinfo_entity_get_param_value(OsinfoEntity *entity, const gchar *key)
347 {
348 GList *values;
349
350 g_return_val_if_fail(OSINFO_IS_ENTITY(entity), NULL);
351 g_return_val_if_fail(key != NULL, NULL);
352
353 if (g_str_equal(key, OSINFO_ENTITY_PROP_ID))
354 return entity->priv->id;
355
356 values = g_hash_table_lookup(entity->priv->params, key);
357
358 if (values)
359 return values->data;
360 return NULL;
361 }
362
str_to_bool(const char * str)363 static gboolean str_to_bool(const char *str)
364 {
365 return (g_strcmp0("true", str) == 0 || g_strcmp0("yes", str) == 0);
366 }
367
368 /**
369 * osinfo_entity_get_param_value_boolean:
370 * @entity: an #OsinfoEntity containing the parameters
371 * @key: the name of the key
372 *
373 * Retrieve the parameter value associated with a named key as a
374 * boolean. If multiple values are stored against the key, only the
375 * first value is returned. If no value is associated, FALSE is returned
376 *
377 * Returns: the value associated with the key as a boolean, or FALSE
378 *
379 * Since: 0.2.0
380 */
osinfo_entity_get_param_value_boolean(OsinfoEntity * entity,const gchar * key)381 gboolean osinfo_entity_get_param_value_boolean(OsinfoEntity *entity, const gchar *key)
382 {
383 const gchar *value = osinfo_entity_get_param_value(entity, key);
384
385 return value && str_to_bool(value);
386 }
387
388 /**
389 * osinfo_entity_get_param_value_boolean_with_default:
390 * @entity: an #OsinfoEntity containing the parameters
391 * @key: the name of the key
392 * @default_value: the value to be returned in case there's no value
393 * associated with the @key
394 *
395 * Retrieve the parameter value associated with a named key as a
396 * boolean. If multiple values are stored against the key, only the
397 * first value is returned. If no value is associated, @default_value
398 * is returned.
399 *
400 * Returns: the value associated with the key as a boolean, or
401 * @default_value
402 *
403 * Since: 0.2.1
404 */
osinfo_entity_get_param_value_boolean_with_default(OsinfoEntity * entity,const char * key,gboolean default_value)405 gboolean osinfo_entity_get_param_value_boolean_with_default(OsinfoEntity *entity,
406 const char *key,
407 gboolean default_value)
408 {
409 const gchar *value;
410
411 value = osinfo_entity_get_param_value(entity, key);
412 if (value == NULL)
413 return default_value;
414 else
415 return str_to_bool(value);
416 }
417
418 /**
419 * osinfo_entity_get_param_value_int64:
420 * @entity: an #OsinfoEntity containing the parameters
421 * @key: the name of the key
422 *
423 * Retrieve the parameter value associated with a named key as an
424 * int64. If multiple values are stored against the key, only the
425 * first value is returned. If no value is associated, -1 is returned.
426 *
427 * Returns: the value associated with the key as an int64, or -1.
428 *
429 * Since: 0.2.1
430 */
osinfo_entity_get_param_value_int64(OsinfoEntity * entity,const gchar * key)431 gint64 osinfo_entity_get_param_value_int64(OsinfoEntity *entity,
432 const gchar *key)
433 {
434 return osinfo_entity_get_param_value_int64_with_default(entity, key, -1);
435 }
436
437 /**
438 * osinfo_entity_get_param_value_int64_with_default:
439 * @entity: an #OsinfoEntity containing the parameters
440 * @key: the name of the key
441 * @default_value: the value to be returned in case there's no value
442 * associated with the @key
443 *
444 * Retrieve the parameter value associated with a named key as an
445 * int64. If multiple values are stored against the key, only the
446 * first value is returned. If no value is associated, @default_value
447 * is returned.
448 *
449 * Returns: the value associated with the key as an int64, or
450 * @default_value
451 *
452 * Since: 0.2.1
453 */
osinfo_entity_get_param_value_int64_with_default(OsinfoEntity * entity,const gchar * key,gint64 default_value)454 gint64 osinfo_entity_get_param_value_int64_with_default(OsinfoEntity *entity,
455 const gchar *key,
456 gint64 default_value)
457 {
458 const gchar *str;
459
460 str = osinfo_entity_get_param_value(entity, key);
461
462 if (str == NULL)
463 return default_value;
464
465 return g_ascii_strtoll(str, NULL, 0);
466 }
467
468 /**
469 * osinfo_entity_get_param_value_enum:
470 * @entity: an #OsinfoEntity containing the parameters
471 * @key: the name of the key
472 * @enum_type: the enum type
473 * @default_value: the default value to be used, in case there's
474 * no value associated with the key
475 *
476 * Retrieve the parameter value associated with a named key as an
477 * enum value. If multiple values are stored against the key, only
478 * the first value is returned. If no value is associated, the
479 * @default_value is returned.
480 *
481 * Returns: the enum value associated with the key, or @default_value.
482 *
483 * Since: 0.2.2
484 */
osinfo_entity_get_param_value_enum(OsinfoEntity * entity,const char * key,GType enum_type,gint default_value)485 gint osinfo_entity_get_param_value_enum(OsinfoEntity *entity,
486 const char *key,
487 GType enum_type,
488 gint default_value)
489 {
490 const gchar *nick;
491 GEnumClass *enum_class;
492 GEnumValue *enum_value;
493
494 g_return_val_if_fail(G_TYPE_IS_ENUM(enum_type), default_value);
495
496 nick = osinfo_entity_get_param_value(entity, key);
497 if (nick == NULL)
498 return default_value;
499
500 enum_class = g_type_class_ref(enum_type);
501 enum_value = g_enum_get_value_by_nick(enum_class, nick);
502 g_type_class_unref(enum_class);
503
504 if (enum_value != NULL)
505 return enum_value->value;
506
507 g_return_val_if_reached(default_value);
508 }
509
510 /**
511 * osinfo_entity_get_param_value_list:
512 * @entity: an #OsinfoEntity containing the parameters
513 * @key: the name of the key
514 *
515 * Retrieve all the parameter values associated with a named
516 * key. If no values are associated, NULL is returned
517 *
518 * Returns: (transfer container) (element-type utf8): the values associated with the key
519 */
osinfo_entity_get_param_value_list(OsinfoEntity * entity,const gchar * key)520 GList *osinfo_entity_get_param_value_list(OsinfoEntity *entity, const gchar *key)
521 {
522 GList *values;
523
524 g_return_val_if_fail(OSINFO_IS_ENTITY(entity), NULL);
525 g_return_val_if_fail(key != NULL, NULL);
526
527 if (g_str_equal(key, OSINFO_ENTITY_PROP_ID))
528 return g_list_append(NULL, entity->priv->id);
529
530 values = g_hash_table_lookup(entity->priv->params, key);
531
532 return g_list_copy(values);
533 }
534