desc.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  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 (
  11. LSUP_default_ctx, LSUP_STORE_HTABLE, NULL, NULL, 0);
  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_default_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 (
  37. gr_uri, LSUP_STORE_HTABLE, NULL, NULL, 0);
  38. add_it = LSUP_graph_add_init (rsrc->user_data[i]);
  39. lu_it = LSUP_graph_lookup (rsrc->user_data[i], NULL, NULL, NULL, NULL);
  40. // Loop over graph triples.
  41. while (LSUP_graph_iter_next (lu_it, &src_spo) == LSUP_OK) {
  42. dest_s = LSUP_IS_IRI (src_spo->s) ?
  43. LSUP_iriref_relative (rsrc_uri, src_spo->s) : src_spo->s;
  44. dest_p = LSUP_term_copy (src_spo->p);
  45. dest_o = LSUP_IS_IRI (src_spo->s) ?
  46. LSUP_iriref_relative (rsrc_uri, src_spo->s) : src_spo->s;
  47. LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
  48. // if the pred is managed, ignore the triple and send a warning.
  49. if (hashmap_get(LSR_managed_preds, dest_spo->p)) {
  50. log_warn (
  51. "Predicate %s is managed. Skipping triple.",
  52. dest_p->data);
  53. goto loop_end;
  54. }
  55. /*
  56. * If the subject or object is a resource, check if it exists; if
  57. * it does, add triple to user_data; if not, return an error.
  58. */
  59. uuid_t id_tmp;
  60. LSUP_rc tmp_rc;
  61. // Check subject.
  62. if (LSR_IS_RSRC_IRI (dest_s)) {
  63. uuid_parse (dest_s->data + strlen (LSR_RSRC_PFX), id_tmp);
  64. tmp_rc = LSR_desc_get (id_tmp, NULL);
  65. if (tmp_rc != LSUP_OK) {
  66. log_error (
  67. "Referenced subject does not exist: %s",
  68. dest_s->data + strlen (LSR_RSRC_PFX));
  69. rc = LSUP_VALUE_ERR;
  70. goto finally;
  71. }
  72. }
  73. // Check object.
  74. if (LSR_IS_RSRC_IRI (dest_o)) {
  75. uuid_parse (dest_o->data + strlen (LSR_RSRC_PFX), id_tmp);
  76. tmp_rc = LSR_desc_get (id_tmp, NULL);
  77. if (tmp_rc != LSUP_OK) {
  78. log_error (
  79. "Referenced object does not exist: %s",
  80. dest_o->data + strlen (LSR_RSRC_PFX));
  81. rc = LSUP_VALUE_ERR;
  82. goto finally;
  83. }
  84. }
  85. // RDF type check.
  86. if (
  87. LSUP_term_equals (
  88. gr_uri, LSUP_iriref_absolute (rsrc_uri, dest_spo->s))
  89. && LSUP_term_equals (rdf_t, dest_spo->p)
  90. ) {
  91. // If the resource is a special type, handle specific workflow.
  92. // TODO
  93. if (hashmap_get (LSR_managed_types, dest_spo->o)) {
  94. }
  95. }
  96. // Add triple to user_data.
  97. LSUP_graph_add_iter (add_it, dest_spo);
  98. loop_end:
  99. if (dest_s != src_spo->s) LSUP_term_free (dest_s);
  100. if (dest_o != src_spo->o) LSUP_term_free (dest_o);
  101. }
  102. // Add user graph metadata to default graph.
  103. admin_add_it = LSUP_graph_add_init (rsrc->main_data);
  104. dest_s = gr_uri;
  105. dest_p = LSUP_iriref_new ("rdf:type", LSUP_default_nsm);
  106. dest_o = LSUP_iriref_new ("lsup:Metadata", LSUP_default_nsm);
  107. LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
  108. LSUP_graph_add_iter (admin_add_it, dest_spo);
  109. LSUP_term_free (dest_o);
  110. dest_o = LSUP_iriref_new ("lsup:UserMetadata", LSUP_default_nsm);
  111. LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
  112. LSUP_graph_add_iter (admin_add_it, dest_spo);
  113. LSUP_term_free (dest_o);
  114. LSUP_term_free (dest_p);
  115. // Relationship between data graph and resource.
  116. dest_p = LSUP_iriref_new ("foaf:primaryTopic", LSUP_default_nsm);
  117. dest_o = rsrc_uri;
  118. LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
  119. LSUP_graph_add_iter (admin_add_it, dest_spo);
  120. LSUP_term_free (dest_p);
  121. LSUP_graph_iter_free (lu_it);
  122. LSUP_graph_add_done (add_it);
  123. LSUP_graph_add_done (admin_add_it);
  124. lu_it = add_it = admin_add_it = NULL;
  125. }
  126. /* END adding user data. */
  127. /* BEGIN adding managed (admin) data. */
  128. LSUP_Term *gr_uri = LSR_id_to_urn (rsrc->id, "__admin");
  129. rsrc->admin_data = LSUP_graph_new (
  130. gr_uri, LSUP_STORE_HTABLE, NULL, NULL, 0);
  131. admin_add_it = LSUP_graph_add_init (rsrc->admin_data);
  132. dest_s = LSUP_iriref_new("", NULL); // Relative to resource URI.
  133. LSUP_Triple admin_spo_s;
  134. LSUP_Triple *admin_spo = &admin_spo_s;
  135. // RDF types.
  136. dest_p = rdf_t;
  137. dest_o = LSUP_iriref_new ("lsup:Resource", LSUP_default_nsm);
  138. LSUP_triple_init (admin_spo, dest_s, dest_p, dest_o);
  139. LSUP_graph_add_iter (admin_add_it, admin_spo);
  140. LSUP_term_free (dest_o);
  141. dest_o = LSUP_iriref_new ("lsup:DescriptiveResource", LSUP_default_nsm);
  142. LSUP_triple_init (admin_spo, dest_s, dest_p, dest_o);
  143. LSUP_graph_add_iter (admin_add_it, admin_spo);
  144. LSUP_term_free (dest_o);
  145. // Timestamps. For now, second precision is fine.
  146. time_t now;
  147. time (&now);
  148. char buf [sizeof ("0000-00-00T00:00:00Z")];
  149. strftime (buf, sizeof (buf), "%FT%TZ", gmtime (&now));
  150. dest_p = LSUP_iriref_new ("lsup:created", LSUP_default_nsm);
  151. dest_o = LSUP_literal_new (
  152. buf, LSUP_iriref_new ("xsd:dateTime", LSUP_default_nsm));
  153. LSUP_triple_init (admin_spo, dest_s, dest_p, dest_o);
  154. LSUP_graph_add_iter (admin_add_it, admin_spo);
  155. LSUP_term_free (dest_p);
  156. dest_p = LSUP_iriref_new ("lsup:lastModified", LSUP_default_nsm);
  157. LSUP_triple_init (admin_spo, dest_s, dest_p, dest_o);
  158. LSUP_graph_add_iter (admin_add_it, admin_spo);
  159. LSUP_term_free (dest_p);
  160. LSUP_term_free (dest_o);
  161. LSUP_graph_add_done (admin_add_it);
  162. /* END adding admin data. */
  163. /* BEGIN adding graph metadata (main). */
  164. admin_add_it = LSUP_graph_add_init (rsrc->main_data);
  165. LSUP_term_free (dest_s);
  166. dest_s = gr_uri;
  167. dest_p = rdf_t;
  168. dest_o = LSUP_iriref_new ("lsup:Metadata", LSUP_default_nsm);
  169. LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
  170. LSUP_graph_add_iter (admin_add_it, dest_spo);
  171. LSUP_term_free (dest_o);
  172. dest_o = LSUP_iriref_new ("lsup:AdminMetadata", LSUP_default_nsm);
  173. LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
  174. LSUP_graph_add_iter (admin_add_it, dest_spo);
  175. LSUP_term_free (dest_o);
  176. // Relationship between data graph and resource.
  177. dest_p = LSUP_iriref_new ("foaf:primaryTopic", LSUP_default_nsm);
  178. dest_o = rsrc_uri;
  179. LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
  180. LSUP_graph_add_iter (admin_add_it, dest_spo);
  181. LSUP_term_free (dest_p);
  182. LSUP_graph_add_done (admin_add_it);
  183. admin_add_it = NULL;
  184. /* END adding graph metadata. */
  185. finally:
  186. LSUP_term_free (rsrc_uri);
  187. LSUP_term_free (rdf_t);
  188. if (rc < 0) goto fail;
  189. rsrc->flags |= LSR_RS_DIRTY;
  190. *rsrc_p = rsrc;
  191. return rc;
  192. fail:
  193. LSUP_graph_iter_free (lu_it);
  194. LSUP_graph_add_done (add_it);
  195. LSUP_graph_add_done (admin_add_it);
  196. LSR_desc_free (rsrc);
  197. *rsrc_p = NULL;
  198. return rc;
  199. }
  200. LSUP_rc
  201. LSR_desc_store (const LSR_Desc *rsrc)
  202. {
  203. // TODO Make atomic. Needs to implement transactions in backend.
  204. LSR_Desc *old_rsrc;
  205. LSUP_rc rc = LSR_desc_get (rsrc->id, &old_rsrc);
  206. if (UNLIKELY (rc < 0)) return rc;
  207. // Remove all existing user graphs.
  208. if (old_rsrc) {
  209. LSUP_Term *main_data_urn = LSUP_graph_uri (old_rsrc->main_data);
  210. // TODO Handle managed preds and types.
  211. // TODO Handle conflict between disjoint managed types.
  212. // TODO Retain created and created_by.
  213. for (size_t i = 0; old_rsrc->user_data[i] != NULL; i++) {
  214. LSUP_Term *gr_uri = LSUP_graph_uri (old_rsrc->user_data[i]);
  215. size_t ct;
  216. // Remove triples from user graph.
  217. LSUP_graph_remove (old_rsrc->user_data[i], NULL, NULL, NULL, &ct);
  218. log_debug ( "Removed %lu triples from graph %s", ct, gr_uri->data);
  219. // Remove user graph metadata.
  220. LSUP_graph_remove (old_rsrc->main_data, gr_uri, NULL, NULL, NULL);
  221. LSUP_graph_remove (old_rsrc->main_data, NULL, NULL, gr_uri, NULL);
  222. }
  223. }
  224. // Add new triples.
  225. for (size_t i = 0; rsrc->user_data[i] != NULL; i++) {
  226. LSUP_Term *gr_uri = LSUP_graph_uri (rsrc->user_data[i]);
  227. LSUP_graph_store (rsrc->user_data[i], NULL, NULL);
  228. }
  229. // Update admin data.
  230. LSUP_graph_store (rsrc->admin_data, NULL, NULL);
  231. // Update graph metadata.
  232. LSUP_graph_store (rsrc->main_data, NULL, NULL);
  233. }
  234. LSUP_rc
  235. LSUP_desc_update (LSR_id id, LSUP_Term **remove, LSUP_Triple *add)
  236. {
  237. }
  238. LSUP_rc
  239. LSR_desc_get (const uuid_t id, LSR_Desc **rsrc_p)
  240. {
  241. LSUP_rc rc = LSUP_OK;
  242. LSUP_Graph *main_gr = LSUP_graph_new (
  243. LSUP_default_ctx, LSR_DEFAULT_BACKEND, NULL, NULL, 0);
  244. LSUP_Term
  245. *s = LSR_id_to_urn (id, NULL),
  246. *p = LSUP_iriref_new ("rdf:type", LSUP_default_nsm),
  247. *o = LSUP_iriref_new ("lsup:Resource", LSUP_default_nsm);
  248. LSUP_Triple *spo = LSUP_triple_new (s, p, o);
  249. LSUP_triple_free (spo);
  250. if (!LSUP_graph_contains (main_gr, spo)) {
  251. rc = LSUP_NORESULT;
  252. goto finally;
  253. }
  254. LSUP_term_free (o);
  255. o = LSUP_iriref_new ("lsup:DescriptiveResource", LSUP_default_nsm);
  256. spo = LSUP_triple_new (s, p, o);
  257. if (!LSUP_graph_contains (main_gr, spo)) {
  258. log_error ("%s is not a descriptive resource.", o->data);
  259. rc = LSUP_NORESULT;
  260. goto finally;
  261. }
  262. LSUP_term_free (p);
  263. p = LSUP_iriref_new ("foaf:primaryTopic", LSUP_default_nsm);
  264. size_t ct = 0, i = 0;
  265. // Find all graphs making up the resource.
  266. LSUP_GraphIterator *it = LSUP_graph_lookup (main_gr, NULL, p, s, &ct);
  267. LSUP_Graph **data = calloc (sizeof (*data), ct + 1);
  268. while (LSUP_graph_iter_next (it, &spo)) {
  269. data[i] = LSUP_graph_new (spo->s, LSR_DEFAULT_BACKEND, NULL, NULL, 0);
  270. if (! data[i++]) break; // Last slot remains NULL (sentinel).
  271. }
  272. LSUP_graph_iter_free (it);
  273. rc = LSR_desc_new_multi (data, rsrc_p);
  274. i = 0;
  275. while (i < ct) LSUP_graph_free (data[i++]);
  276. free (data);
  277. finally:
  278. LSUP_triple_free (spo);
  279. LSUP_term_free (s);
  280. LSUP_term_free (p);
  281. LSUP_term_free (o);
  282. LSUP_graph_free (main_gr);
  283. return rc;
  284. }
  285. LSUP_Graph *
  286. LSR_desc_metadata (const LSR_Desc *rsrc)
  287. {
  288. uuid_t uuid;
  289. char
  290. *rsrc_uri_str = LSUP_graph_uri (rsrc->admin_data)->data,
  291. *frag = "#metadata-",
  292. uuid_str [UUID_STR_LEN],
  293. id_str [8],
  294. *uri_str = malloc (
  295. strlen (frag) + strlen (rsrc_uri_str) + sizeof (id_str));
  296. if (UNLIKELY (!uri_str)) return NULL;
  297. uuid_generate_random (uuid);
  298. uuid_unparse_lower (uuid, uuid_str);
  299. strncpy (id_str, uuid_str, sizeof (id_str) - 1);
  300. sprintf (uri_str, "%s%s%s", rsrc_uri_str, frag, id_str);
  301. LSUP_Graph *res = LSUP_graph_copy (rsrc->admin_data);
  302. if (LIKELY (res))
  303. LSUP_graph_set_uri (res, LSUP_iriref_new (uri_str, NULL));
  304. free (uri_str);
  305. free (rsrc_uri_str);
  306. free (uuid);
  307. return res;
  308. }
  309. LSUP_Graph **
  310. LSR_desc_user_data (const LSR_Desc *rsrc)
  311. {
  312. uuid_t uuid;
  313. char
  314. *rsrc_uri_str = LSUP_graph_uri (rsrc->admin_data)->data,
  315. *frag = "#metadata-",
  316. uuid_str [UUID_STR_LEN],
  317. id_str [8],
  318. *uri_str = malloc (
  319. strlen (frag) + strlen (rsrc_uri_str) + sizeof (id_str));
  320. if (UNLIKELY (!uri_str)) return NULL;
  321. size_t ct = 0;
  322. while (rsrc->user_data[ct]) ct ++;
  323. LSUP_Graph **res = malloc (sizeof *res * (ct + 1));
  324. if (UNLIKELY (!res)) return NULL;
  325. for (size_t i = 0; i < ct; i++) {
  326. uuid_generate_random (uuid);
  327. uuid_unparse_lower (uuid, uuid_str);
  328. strncpy (id_str, uuid_str, sizeof (id_str) - 1);
  329. sprintf (uri_str, "%s%s%s", rsrc_uri_str, frag, id_str);
  330. res[i] = LSUP_graph_copy (rsrc->user_data[i]);
  331. if (LIKELY (res))
  332. LSUP_graph_set_uri (res[i], LSUP_iriref_new (uri_str, NULL));
  333. }
  334. res[ct] = NULL;
  335. free (uri_str);
  336. free (rsrc_uri_str);
  337. free (uuid);
  338. return res;
  339. }
  340. void LSR_desc_free (LSR_Desc *rsrc)
  341. {
  342. size_t i = 0;
  343. while (rsrc->user_data[i])
  344. LSUP_graph_free (rsrc->user_data[i++]);
  345. free (rsrc->user_data);
  346. LSUP_graph_free (rsrc->admin_data);
  347. LSUP_graph_free (rsrc->main_data);
  348. free (rsrc);
  349. }
  350. LSUP_rc
  351. LSR_desc_store (const LSR_Desc *rsrc)
  352. {
  353. // TODO Make atomic. Needs to implement transactions in backend.
  354. LSR_Desc *old_rsrc;
  355. LSUP_rc rc = LSR_desc_get (rsrc->id, &old_rsrc);
  356. if (UNLIKELY (rc < 0)) return rc;
  357. // Remove all existing user graphs.
  358. if (rc == LSUP_OK) {
  359. //LSUP_Term *main_data_urn = LSUP_graph_uri (old_rsrc->main_data);
  360. for (size_t i = 0; old_rsrc->user_data[i] != NULL; i++) {
  361. LSUP_Term *gr_uri = LSUP_graph_uri (old_rsrc->user_data[i]);
  362. size_t ct;
  363. // Remove triples from user graph.
  364. LSUP_graph_remove (old_rsrc->user_data[i], NULL, NULL, NULL, &ct);
  365. log_debug ( "Removed %lu triples from graph %s", ct, gr_uri->data);
  366. // Remove user graph metadata.
  367. LSUP_graph_remove (old_rsrc->main_data, gr_uri, NULL, NULL, NULL);
  368. LSUP_graph_remove (old_rsrc->main_data, NULL, NULL, gr_uri, NULL);
  369. }
  370. } else rc = LSUP_OK;
  371. // Add new triples.
  372. for (size_t i = 0; rsrc->user_data[i] != NULL; i++) {
  373. //LSUP_Term *gr_uri = LSUP_graph_uri (rsrc->user_data[i]);
  374. log_trace ("Storing data graph #%lu", i);
  375. LSUP_graph_store (rsrc->user_data[i], NULL, NULL);
  376. }
  377. // Update admin data.
  378. LSUP_graph_store (rsrc->admin_data, NULL, NULL);
  379. // Update graph metadata.
  380. LSUP_graph_store (rsrc->main_data, NULL, NULL);
  381. return rc;
  382. }
  383. LSUP_rc
  384. LSUP_desc_update (LSR_id id, LSUP_Term **remove, LSUP_Triple *add)
  385. {
  386. LSUP_rc rc = LSUP_OK;
  387. return rc;
  388. }