00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <midgard/midgard.h>
00020 #include <midgard/midgard_legacy.h>
00021 #include <libxml/parser.h>
00022 #include <libxml/tree.h>
00023 #include <libxml/xmlreader.h>
00024 #include <libxml/parserInternals.h>
00025
00026 static const gchar *MIDGARD_OBJECT_HREF = "http://www.midgard-project.org/midgard_object/1.8";
00027
00028 static void _write_nodes(GObject *object, xmlNodePtr node)
00029 {
00030 g_assert(object);
00031 g_assert(node);
00032
00033 guint prop_n;
00034 MgdObject *mgdobject = (MgdObject *) object;
00035 MidgardReflectionProperty *mrp = NULL;
00036 GParamSpec **pspec = g_object_class_list_properties(
00037 G_OBJECT_GET_CLASS(G_OBJECT(object)), &prop_n);
00038
00039 if(MIDGARD_IS_OBJECT(object)) {
00040 MidgardObjectClass *klass =
00041 MIDGARD_OBJECT_GET_CLASS(object);
00042 if(klass)
00043 mrp = midgard_reflection_property_new(klass);
00044 }
00045
00046 GValue pval = {0, }, *lval;
00047 GString *gstring;
00048 gchar *strprop = NULL;
00049 xmlChar *escaped;
00050 guint i;
00051 xmlNodePtr op_node = NULL;
00052 const gchar *linktype;
00053 MidgardCollector *mc;
00054 guint _uint;
00055 gint _int;
00056
00057 for(i = 0; i < prop_n; i++) {
00058
00059 g_value_init(&pval,pspec[i]->value_type);
00060 g_object_get_property(G_OBJECT(object),
00061 pspec[i]->name, &pval);
00062
00063
00064
00065
00066 if(mrp){
00067 if(midgard_reflection_property_is_link(mrp,
00068 pspec[i]->name)){
00069
00070 lval = g_new0(GValue, 1);
00071 switch(pspec[i]->value_type) {
00072
00073 case G_TYPE_UINT:
00074 g_value_init(lval, G_TYPE_UINT);
00075 _uint = g_value_get_uint(&pval);
00076 if(!_uint){
00077 g_value_unset(lval);
00078 goto export_unchecked_property;
00079 }
00080 g_value_set_uint(lval, _uint);
00081 break;
00082
00083 case G_TYPE_INT:
00084 g_value_init(lval, G_TYPE_INT);
00085 _int = g_value_get_int(&pval);
00086 if(!_int){
00087 g_value_unset(lval);
00088 goto export_unchecked_property;
00089 }
00090 g_value_set_int(lval, _int);
00091 break;
00092
00093 default:
00094 goto export_unchecked_property;
00095 }
00096
00097 linktype =
00098 midgard_reflection_property_get_link_name(
00099 mrp, pspec[i]->name);
00100
00101 if(linktype){
00102 mc = midgard_collector_new(
00103 mgdobject->mgd->_mgd,
00104 linktype,
00105 "id",
00106 lval);
00107
00108 midgard_collector_set_key_property(
00109 mc,
00110 "guid", NULL);
00111 if(!midgard_collector_execute(mc)){
00112 g_object_unref(mc);
00113 g_value_unset(&pval);
00114 continue;
00115 }
00116 const gchar **linkguid =
00117 midgard_collector_list_keys(mc);
00118 if(linkguid[0])
00119 strprop = g_strdup(linkguid[0]);
00120 if(!strprop)
00121 strprop = g_strdup("");
00122
00123
00124 escaped = xmlEncodeEntitiesReentrant(
00125 NULL, (const xmlChar*)strprop);
00126 xmlNewTextChild(node, NULL,
00127 BAD_CAST pspec[i]->name,
00128 BAD_CAST escaped);
00129
00130 g_free(linkguid);
00131 g_free(strprop);
00132 g_free(escaped);
00133 g_object_unref(mc);
00134 }
00135 g_value_unset(&pval);
00136 continue;
00137 }
00138 }
00139
00140 export_unchecked_property:
00141 switch(pspec[i]->value_type) {
00142
00143 case G_TYPE_STRING:
00144 strprop = g_value_dup_string(&pval);
00145 if(!strprop)
00146 strprop = g_strdup("");
00147 escaped = xmlEncodeEntitiesReentrant(
00148 NULL, (const xmlChar*)strprop);
00149 xmlNewTextChild(node, NULL,
00150 BAD_CAST pspec[i]->name,
00151 BAD_CAST escaped);
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 g_free(strprop);
00166 g_free(escaped);
00167 break;
00168
00169 case G_TYPE_INT:
00170 gstring = g_string_new("");
00171 g_string_append_printf(gstring,
00172 "%d", g_value_get_int(&pval));
00173 strprop = g_string_free(gstring, FALSE);
00174 xmlNewChild(node, NULL,
00175 BAD_CAST pspec[i]->name,
00176 BAD_CAST (xmlChar *)strprop);
00177 g_free(strprop);
00178 break;
00179
00180 case G_TYPE_UINT:
00181 if(!g_str_equal(pspec[i]->name,
00182 "sitegroup")) {
00183 gstring = g_string_new("");
00184 g_string_append_printf(gstring,
00185 "%i", g_value_get_uint(&pval));
00186 strprop = g_string_free(gstring, FALSE);
00187 xmlNewChild(node, NULL,
00188 BAD_CAST pspec[i]->name,
00189 BAD_CAST (xmlChar *)strprop);
00190 g_free(strprop);
00191 }
00192 break;
00193
00194 case G_TYPE_FLOAT:
00195 gstring = g_string_new("");
00196 g_string_append_printf(gstring,
00197 "%g", g_value_get_float(&pval));
00198 strprop = g_string_free(gstring, FALSE);
00199 xmlNewChild(node, NULL,
00200 BAD_CAST pspec[i]->name,
00201 BAD_CAST (xmlChar *)strprop);
00202 g_free(strprop);
00203 break;
00204
00205 case G_TYPE_BOOLEAN:
00206 if(g_value_get_boolean(&pval))
00207 strprop = "1";
00208 else
00209 strprop = "0";
00210
00211 xmlNewChild(node, NULL,
00212 BAD_CAST pspec[i]->name,
00213 BAD_CAST (xmlChar *)strprop);
00214 break;
00215
00216 case G_TYPE_OBJECT:
00217 op_node = xmlNewNode(NULL,
00218 BAD_CAST pspec[i]->name);
00219 _write_nodes(G_OBJECT(g_value_get_object(&pval)),
00220 op_node);
00221 xmlAddChild(node, op_node);
00222 break;
00223 }
00224 g_value_unset(&pval);
00225 }
00226 g_free(pspec);
00227 if(mrp)
00228 g_object_unref(mrp);
00229 }
00230
00231 gchar *_midgard_core_object_to_xml(MgdObject *object)
00232 {
00233 g_assert(object);
00234
00235 xmlDocPtr doc = NULL;
00236 xmlNodePtr root_node = NULL;
00237
00238 LIBXML_TEST_VERSION;
00239
00240 doc = xmlNewDoc(BAD_CAST "1.0");
00241 root_node = xmlNewNode(NULL,
00242 BAD_CAST "midgard_object");
00243 xmlNewNs(root_node,
00244 BAD_CAST MIDGARD_OBJECT_HREF,
00245 NULL);
00246 xmlNodePtr object_node =
00247 xmlNewNode(NULL, BAD_CAST G_OBJECT_TYPE_NAME(G_OBJECT(object)));
00248 xmlAddChild(root_node, object_node);
00249 xmlDocSetRootElement(doc, root_node);
00250
00251 _write_nodes(G_OBJECT(object), object_node);
00252
00253 xmlChar *buf;
00254 gint size;
00255 xmlDocDumpFormatMemoryEnc(doc, &buf, &size, "UTF-8", 1);
00256
00257 xmlFreeDoc(doc);
00258 xmlCleanupParser();
00259
00260 return (gchar*) buf;
00261 }
00262
00263
00264 static xmlNode *_get_type_node(xmlNode *node)
00265 {
00266 xmlNode *cur = NULL;
00267 for (cur = node; cur; cur = cur->next) {
00268 if (cur->type == XML_ELEMENT_NODE)
00269 return cur;
00270 }
00271 return NULL;
00272 }
00273
00274 static gboolean _nodes2object(GObject *object, xmlNode *node)
00275 {
00276 g_assert(object);
00277 g_assert(node);
00278
00279 xmlNode *cur = NULL;
00280 GObject *prop_object;
00281 gchar *nodeprop;
00282 xmlChar *decoded;
00283 xmlParserCtxtPtr parser;
00284 MgdObject *mobject = MIDGARD_OBJECT(object);
00285 MgdObject *lobject = NULL;
00286 MidgardReflectionProperty *mrp = NULL;
00287 const gchar *linktype = NULL;
00288
00289 if(MIDGARD_IS_OBJECT(object)) {
00290 MidgardObjectClass *klass =
00291 MIDGARD_OBJECT_GET_CLASS(mobject);
00292 if(klass)
00293 mrp = midgard_reflection_property_new(klass);
00294 }
00295
00296
00297 for (cur = node; cur; cur = cur->next) {
00298 if (cur->type == XML_ELEMENT_NODE) {
00299
00300 GParamSpec *pspec = g_object_class_find_property(
00301 G_OBJECT_GET_CLASS(G_OBJECT(object)),
00302 (const gchar *)cur->name);
00303 if(pspec) {
00304 GValue pval = {0, };
00305 g_value_init(&pval, pspec->value_type);
00306 nodeprop = (gchar *)xmlNodeGetContent(cur);
00307
00308 if(mrp) {
00309 if(midgard_reflection_property_is_link(
00310 mrp, pspec->name)){
00311 linktype =
00312 midgard_reflection_property_get_link_name(
00313 mrp, pspec->name);
00314 }
00315 }
00316
00317
00318 if(linktype && midgard_is_guid(
00319 (const gchar *) nodeprop)){
00320
00321
00322 lobject = midgard_get_object_by_guid(
00323 mobject->mgd->_mgd,
00324 (const gchar *) nodeprop);
00325
00326 if(!lobject){
00327 g_object_unref(mrp);
00328 g_value_unset(&pval);
00329 midgard_set_error(mobject->mgd->_mgd,
00330 MGD_GENERIC_ERROR,
00331 MGD_ERR_MISSED_DEPENDENCE,
00332 " Can not import %s. "
00333 "No '%s' object identified by '%s'",
00334 G_OBJECT_TYPE_NAME(object),
00335 linktype, nodeprop);
00336 g_clear_error(&mobject->mgd->_mgd->err);
00337 g_warning("%s", mobject->mgd->_mgd->errstr);
00338 return FALSE;
00339 }
00340
00341 GValue tval = {0, };
00342 g_value_init(&tval, G_TYPE_UINT);
00343
00344 g_object_get_property(G_OBJECT(lobject),
00345 "id", &tval);
00346
00347 if(G_VALUE_TYPE(&pval) == G_TYPE_INT)
00348 g_value_transform((const GValue *) &tval,
00349 &pval);
00350 else
00351 g_value_copy((const GValue*) &tval,
00352 &pval);
00353
00354 g_object_unref(lobject);
00355 g_value_unset(&tval);
00356 continue;
00357 }
00358
00359 switch (pspec->value_type) {
00360
00361 case G_TYPE_STRING:
00362 parser = xmlNewParserCtxt();
00363 decoded =
00364 xmlStringDecodeEntities(parser,
00365 (const xmlChar *) nodeprop,
00366 XML_SUBSTITUTE_PEREF |
00367 XML_SUBSTITUTE_REF,
00368 0, 0, 0);
00369 g_value_set_string(&pval,
00370 (gchar *)decoded);
00371 g_free(decoded);
00372 xmlClearParserCtxt(parser);
00373 g_free(parser);
00374 break;
00375
00376 case G_TYPE_INT:
00377 if(nodeprop)
00378 g_value_set_int(&pval,
00379 (gint)atoi((gchar *)nodeprop));
00380 break;
00381
00382 case G_TYPE_UINT:
00383 if(nodeprop)
00384 g_value_set_uint(&pval,
00385 (guint)atoi((gchar *)nodeprop));
00386 break;
00387
00388 case G_TYPE_FLOAT:
00389 g_value_set_float(&pval,
00390 (gfloat)atof((gchar *)nodeprop));
00391 break;
00392
00393 case G_TYPE_BOOLEAN:
00394 g_value_set_boolean(&pval,
00395 (gboolean)atoi((gchar*)nodeprop));
00396 break;
00397
00398 case G_TYPE_OBJECT:
00399 g_object_get(G_OBJECT(object),
00400 (const gchar *) cur->name,
00401 &prop_object, NULL);
00402 _nodes2object(prop_object, cur->children);
00403 g_value_set_object(&pval, prop_object);
00404 break;
00405
00406 default:
00407
00408 break;
00409 }
00410 g_object_set_property(
00411 G_OBJECT(object),
00412 (const gchar *) cur->name,
00413 &pval);
00414 g_value_unset(&pval);
00415 } else {
00416 g_warning("Undefined property '%s' for '%s'",
00417 cur->name, G_OBJECT_TYPE_NAME(object));
00418 }
00419 }
00420 }
00421
00422 if(mrp)
00423 g_object_unref(mrp);
00424
00425 return TRUE;
00426 }
00427
00428 MgdObject *_midgard_core_object_from_xml(MidgardConnection *mgd, gchar *xml)
00429 {
00430 if(xml == NULL)
00431 g_warning("Creating Midgard Object from xml requires xml."
00432 "NULL passed");
00433
00434 LIBXML_TEST_VERSION
00435
00436
00437 xmlDocPtr doc =
00438 xmlReadMemory(xml, strlen(xml), "midgard_object.xml", NULL, 0);
00439 if(!doc) {
00440 g_warning("Can not parse given xml");
00441 return NULL;
00442 }
00443
00444 xmlNodePtr root = xmlDocGetRootElement(doc);
00445 if(!root) {
00446 g_warning("Can not find root element for given xml");
00447 xmlFreeDoc(doc);
00448 return NULL;
00449 }
00450
00451
00452 if(!g_str_equal(root->ns->href, MIDGARD_OBJECT_HREF)
00453 || !g_str_equal(root->name, "midgard_object")) {
00454 g_warning("Skipping invalid midgard_object xml");
00455 xmlFreeDoc(doc);
00456 return NULL;
00457 }
00458
00459
00460
00461 xmlNodePtr child = _get_type_node(root->children);
00462 if(!child) {
00463 g_warning("Can not get midgard type name from the given xml");
00464 xmlFreeDoc(doc);
00465 return NULL;
00466 }
00467
00468 if(!g_type_from_name((const gchar *)child->name)) {
00469 g_warning("Type %s is not initialized in type system",
00470 root->name);
00471 xmlFreeDoc(doc);
00472 return NULL;
00473 }
00474 MgdObject *object = midgard_object_new(mgd->mgd, (const gchar *)child->name, NULL);
00475 if(!object) {
00476 g_warning("Can not create %s instance", child->name);
00477 xmlFreeDoc(doc);
00478 return NULL;
00479 }
00480
00481 if(!_nodes2object(G_OBJECT(object), child->children)) {
00482 g_object_unref(object);
00483 object = NULL;
00484 }
00485
00486 xmlFreeDoc(doc);
00487 xmlCleanupParser();
00488
00489 return object;
00490 }