desc.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. #include "desc.h"
  2. LSUP_rc
  3. LSR_desc_new_multi (LSUP_Graph *const *data, LSR_Desc **rsrc_p)
  4. {
  5. LSUP_rc rc = LSUP_OK;
  6. LSR_Desc *rsrc;
  7. MALLOC_GUARD (rsrc, LSUP_MEM_ERR);
  8. uuid_generate_random (rsrc->id);
  9. // Default context graph.
  10. rsrc->main_data = LSUP_graph_new (LSUP_term_new_from_buffer (
  11. LSUP_default_env->default_ctx), LSUP_STORE_MEM);
  12. LSUP_GraphIterator *lu_it, *add_it, *admin_add_it = NULL;
  13. LSUP_Term *dest_s, *dest_p, *dest_o;
  14. LSUP_Triple src_spo_s, dest_spo_s;
  15. LSUP_Triple
  16. *src_spo = &src_spo_s,
  17. *dest_spo = &dest_spo_s;
  18. LSUP_Term *rsrc_uri = LSR_id_to_urn (rsrc->id, NULL);
  19. LSUP_Term *rdf_t = LSUP_iriref_new ("rdf:type", LSUP_DEF_NSM);
  20. // Count graphs inserted and allocate space.
  21. size_t ct = 0;
  22. while (data[ct]) ct++;
  23. rsrc->user_data = calloc (sizeof (*rsrc->user_data), ct + 1);
  24. if (UNLIKELY (! rsrc->user_data)) return LSUP_MEM_ERR;
  25. /* BEGIN adding user data. */
  26. // Loop over input graphs.
  27. for (size_t i = 0; i < ct; i++) {
  28. LSUP_Term *gr_uri = LSUP_term_copy (LSUP_graph_uri (data[i]));
  29. LSUP_Term *rel_uri = LSUP_iriref_relative (rsrc_uri, gr_uri);
  30. if (strstr (rel_uri->data, "#__") == rel_uri->data) {
  31. log_error ("Fragment URI cannot start with double underscore.");
  32. rc = LSUP_VALUE_ERR;
  33. }
  34. LSUP_term_free (rel_uri);
  35. if (rc < 0) goto finally;
  36. rsrc->user_data[i] = LSUP_graph_new (gr_uri, LSUP_STORE_MEM);
  37. add_it = LSUP_graph_add_init (rsrc->user_data[i]);
  38. lu_it = LSUP_graph_lookup (rsrc->user_data[i], NULL, NULL, NULL, NULL);
  39. // Loop over graph triples.
  40. while (LSUP_graph_iter_next (lu_it, src_spo) == LSUP_OK) {
  41. dest_s = LSUP_IS_IRI (src_spo->s) ?
  42. LSUP_iriref_relative (rsrc_uri, src_spo->s) : src_spo->s;
  43. dest_p = LSUP_term_copy (src_spo->p);
  44. dest_o = LSUP_IS_IRI (src_spo->s) ?
  45. LSUP_iriref_relative (rsrc_uri, src_spo->s) : src_spo->s;
  46. LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
  47. // if the pred is managed, ignore the triple and send a warning.
  48. if (hashmap_get(LSR_managed_preds, dest_spo->p)) {
  49. log_warn (
  50. "Predicate %s is managed. Skipping triple.",
  51. dest_p->data);
  52. goto loop_end;
  53. }
  54. /*
  55. * If the subject or object is a resource, check if it exists; if
  56. * it does, add triple to user_data; if not, return an error.
  57. */
  58. uuid_t id_tmp;
  59. LSUP_rc tmp_rc;
  60. // Check subject.
  61. if (LSR_IS_RSRC_IRI (dest_s)) {
  62. uuid_parse (dest_s->data + strlen (LSR_RSRC_PFX), id_tmp);
  63. tmp_rc = LSR_desc_get (id_tmp, NULL);
  64. if (tmp_rc != LSUP_OK) {
  65. log_error (
  66. "Referenced subject does not exist: %s",
  67. dest_s->data + strlen (LSR_RSRC_PFX));
  68. rc = LSUP_VALUE_ERR;
  69. goto finally;
  70. }
  71. }
  72. // Check object.
  73. if (LSR_IS_RSRC_IRI (dest_o)) {
  74. uuid_parse (dest_o->data + strlen (LSR_RSRC_PFX), id_tmp);
  75. tmp_rc = LSR_desc_get (id_tmp, NULL);
  76. if (tmp_rc != LSUP_OK) {
  77. log_error (
  78. "Referenced object does not exist: %s",
  79. dest_o->data + strlen (LSR_RSRC_PFX));
  80. rc = LSUP_VALUE_ERR;
  81. goto finally;
  82. }
  83. }
  84. // RDF type check.
  85. if (
  86. LSUP_term_equals (
  87. gr_uri, LSUP_iriref_absolute (rsrc_uri, dest_spo->s))
  88. && LSUP_term_equals (rdf_t, dest_spo->p)
  89. ) {
  90. // If the resource is a special type, handle specific workflow.
  91. // TODO
  92. if (hashmap_get (LSR_managed_types, dest_spo->o)) {
  93. }
  94. }
  95. // Add triple to user_data.
  96. LSUP_graph_add_iter (add_it, dest_spo);
  97. loop_end:
  98. if (dest_s != src_spo->s) LSUP_term_free (dest_s);
  99. if (dest_o != src_spo->o) LSUP_term_free (dest_o);
  100. }
  101. // Add user graph metadata to default graph.
  102. admin_add_it = LSUP_graph_add_init (rsrc->main_data);
  103. dest_s = gr_uri;
  104. dest_p = LSUP_iriref_new ("rdf:type", LSUP_DEF_NSM);
  105. dest_o = LSUP_iriref_new ("lsup:Metadata", LSUP_DEF_NSM);
  106. LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
  107. LSUP_graph_add_iter (admin_add_it, dest_spo);
  108. LSUP_term_free (dest_o);
  109. dest_o = LSUP_iriref_new ("lsup:UserMetadata", LSUP_DEF_NSM);
  110. LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
  111. LSUP_graph_add_iter (admin_add_it, dest_spo);
  112. LSUP_term_free (dest_o);
  113. LSUP_term_free (dest_p);
  114. // Relationship between data graph and resource.
  115. dest_p = LSUP_iriref_new ("foaf:primaryTopic", LSUP_DEF_NSM);
  116. dest_o = rsrc_uri;
  117. LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
  118. LSUP_graph_add_iter (admin_add_it, dest_spo);
  119. LSUP_term_free (dest_p);
  120. LSUP_graph_iter_free (lu_it);
  121. LSUP_graph_add_done (add_it);
  122. LSUP_graph_add_done (admin_add_it);
  123. lu_it = add_it = admin_add_it = NULL;
  124. }
  125. /* END adding user data. */
  126. /* BEGIN adding managed (admin) data. */
  127. LSUP_Term *gr_uri = LSR_id_to_urn (rsrc->id, "__admin");
  128. rsrc->admin_data = LSUP_graph_new (gr_uri, LSUP_STORE_MEM);
  129. admin_add_it = LSUP_graph_add_init (rsrc->admin_data);
  130. dest_s = LSUP_iriref_new("", NULL); // Relative to resource URI.
  131. LSUP_Triple admin_spo_s;
  132. LSUP_Triple *admin_spo = &admin_spo_s;
  133. // RDF types.
  134. dest_p = rdf_t;
  135. dest_o = LSUP_iriref_new ("lsup:Resource", LSUP_DEF_NSM);
  136. LSUP_triple_init (admin_spo, dest_s, dest_p, dest_o);
  137. LSUP_graph_add_iter (admin_add_it, admin_spo);
  138. LSUP_term_free (dest_o);
  139. dest_o = LSUP_iriref_new ("lsup:DescriptiveResource", LSUP_DEF_NSM);
  140. LSUP_triple_init (admin_spo, dest_s, dest_p, dest_o);
  141. LSUP_graph_add_iter (admin_add_it, admin_spo);
  142. LSUP_term_free (dest_o);
  143. // Timestamps. For now, second precision is fine.
  144. time_t now;
  145. time (&now);
  146. char buf [sizeof ("0000-00-00T00:00:00Z")];
  147. strftime (buf, sizeof (buf), "%FT%TZ", gmtime (&now));
  148. dest_p = LSUP_iriref_new ("lsup:created", LSUP_DEF_NSM);
  149. dest_o = LSUP_literal_new (
  150. buf, LSUP_iriref_new ("xsd:dateTime", LSUP_DEF_NSM));
  151. LSUP_triple_init (admin_spo, dest_s, dest_p, dest_o);
  152. LSUP_graph_add_iter (admin_add_it, admin_spo);
  153. LSUP_term_free (dest_p);
  154. dest_p = LSUP_iriref_new ("lsup:lastModified", LSUP_DEF_NSM);
  155. LSUP_triple_init (admin_spo, dest_s, dest_p, dest_o);
  156. LSUP_graph_add_iter (admin_add_it, admin_spo);
  157. LSUP_term_free (dest_p);
  158. LSUP_term_free (dest_o);
  159. LSUP_graph_add_done (admin_add_it);
  160. /* END adding admin data. */
  161. /* BEGIN adding graph metadata (main). */
  162. admin_add_it = LSUP_graph_add_init (rsrc->main_data);
  163. LSUP_term_free (dest_s);
  164. dest_s = gr_uri;
  165. dest_p = rdf_t;
  166. dest_o = LSUP_iriref_new ("lsup:Metadata", LSUP_DEF_NSM);
  167. LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
  168. LSUP_graph_add_iter (admin_add_it, dest_spo);
  169. LSUP_term_free (dest_o);
  170. dest_o = LSUP_iriref_new ("lsup:AdminMetadata", LSUP_DEF_NSM);
  171. LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
  172. LSUP_graph_add_iter (admin_add_it, dest_spo);
  173. LSUP_term_free (dest_o);
  174. // Relationship between data graph and resource.
  175. dest_p = LSUP_iriref_new ("foaf:primaryTopic", LSUP_DEF_NSM);
  176. dest_o = rsrc_uri;
  177. LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
  178. LSUP_graph_add_iter (admin_add_it, dest_spo);
  179. LSUP_term_free (dest_p);
  180. LSUP_graph_add_done (admin_add_it);
  181. admin_add_it = NULL;
  182. /* END adding graph metadata. */
  183. finally:
  184. LSUP_term_free (rsrc_uri);
  185. LSUP_term_free (rdf_t);
  186. if (rc < 0) goto fail;
  187. rsrc->flags |= LSR_RS_DIRTY;
  188. *rsrc_p = rsrc;
  189. return rc;
  190. fail:
  191. LSUP_graph_iter_free (lu_it);
  192. LSUP_graph_add_done (add_it);
  193. LSUP_graph_add_done (admin_add_it);
  194. LSR_desc_free (rsrc);
  195. *rsrc_p = NULL;
  196. return rc;
  197. }
  198. LSUP_rc
  199. LSR_desc_store (const LSR_Desc *rsrc)
  200. {
  201. // TODO Make atomic. Needs to implement transactions in backend.
  202. LSR_Desc *old_rsrc;
  203. LSUP_rc rc = LSR_desc_get (rsrc->id, &old_rsrc);
  204. if (UNLIKELY (rc < 0)) return rc;
  205. // Remove all existing user graphs.
  206. if (old_rsrc) {
  207. LSUP_Term *main_data_urn = LSUP_graph_uri (old_rsrc->main_data);
  208. // TODO Handle managed preds and types.
  209. // TODO Handle conflict between disjoint managed types.
  210. // TODO Retain created and created_by.
  211. for (size_t i = 0; old_rsrc->user_data[i] != NULL; i++) {
  212. LSUP_Term *gr_uri = LSUP_graph_uri (old_rsrc->user_data[i]);
  213. size_t ct;
  214. // Remove triples from user graph.
  215. LSUP_graph_remove (old_rsrc->user_data[i], NULL, NULL, NULL, &ct);
  216. log_debug ( "Removed %lu triples from graph %s", ct, gr_uri->data);
  217. // Remove user graph metadata.
  218. LSUP_graph_remove (old_rsrc->main_data, gr_uri, NULL, NULL, NULL);
  219. LSUP_graph_remove (old_rsrc->main_data, NULL, NULL, gr_uri, NULL);
  220. }
  221. }
  222. // Add new triples.
  223. for (size_t i = 0; rsrc->user_data[i] != NULL; i++) {
  224. LSUP_Term *gr_uri = LSUP_graph_uri (rsrc->user_data[i]);
  225. LSUP_graph_store (rsrc->user_data[i], NULL, NULL);
  226. }
  227. // Update admin data.
  228. LSUP_graph_store (rsrc->admin_data, NULL, NULL);
  229. // Update graph metadata.
  230. LSUP_graph_store (rsrc->main_data, NULL, NULL);
  231. }
  232. LSUP_rc
  233. LSUP_desc_update (LSR_id id, LSUP_Term **remove, LSUP_Triple *add)
  234. {
  235. }
  236. LSUP_rc
  237. LSR_desc_get (const uuid_t id, LSR_Desc **rsrc)
  238. {
  239. LSUP_rc rc = LSUP_OK;
  240. LSUP_Term *default_gr_uri = LSUP_term_new_from_buffer (
  241. LSUP_default_env->default_ctx);
  242. LSUP_Graph *main_gr = LSUP_graph_new (default_gr_uri, LSUP_STORE_MDB);
  243. LSUP_Term
  244. *s = LSR_id_to_urn (id, NULL),
  245. *p = LSUP_iriref_new ("rdf:type", LSUP_DEF_NSM),
  246. *o = LSUP_iriref_new ("lsup:Resource", LSUP_DEF_NSM);
  247. LSUP_Triple *spo = LSUP_triple_new (s, p, o);
  248. LSUP_triple_free (spo);
  249. if (!LSUP_graph_contains (main_gr, spo)) {
  250. rc = LSUP_NORESULT;
  251. goto finally;
  252. }
  253. LSUP_term_free (o);
  254. o = LSUP_iriref_new ("lsup:DescriptiveResource", LSUP_DEF_NSM);
  255. spo = LSUP_triple_new (s, p, o);
  256. if (!LSUP_graph_contains (main_gr, spo)) {
  257. log_error ("%s is not a descriptive resource.", o->data);
  258. rc = LSUP_NORESULT;
  259. goto finally;
  260. }
  261. LSUP_term_free (p);
  262. p = LSUP_iriref_new ("foaf:primaryTopic", LSUP_DEF_NSM);
  263. size_t ct = 0, i = 0;
  264. // Find all graphs making up the resource.
  265. LSUP_GraphIterator *it = LSUP_graph_lookup (main_gr, NULL, p, s, &ct);
  266. LSUP_Graph **data = calloc (sizeof (*data), ct + 1);
  267. while (LSUP_graph_iter_next (it, spo)) {
  268. data[i] = LSUP_graph_new (spo->s, LSUP_STORE_MDB);
  269. if (! data[i++]) break; // Last slot remains NULL (sentinel).
  270. }
  271. LSUP_graph_iter_free (it);
  272. rc = LSR_desc_new_multi (data, rsrc);
  273. i = 0;
  274. while (i < ct) LSUP_graph_free (data[i++]);
  275. free (data);
  276. finally:
  277. LSUP_triple_free (spo);
  278. LSUP_term_free (s);
  279. LSUP_term_free (p);
  280. LSUP_term_free (o);
  281. LSUP_graph_free (main_gr);
  282. return rc;
  283. }
  284. void LSR_desc_free (LSR_Desc *rsrc)
  285. {
  286. size_t i = 0;
  287. while (rsrc->user_data[i])
  288. LSUP_graph_free (rsrc->user_data[i++]);
  289. free (rsrc->user_data);
  290. LSUP_graph_free (rsrc->admin_data);
  291. LSUP_graph_free (rsrc->main_data);
  292. free (rsrc);
  293. }