Adaptive Framework  0.9.0
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
afw_adaptor_modify.c
Go to the documentation of this file.
1 // See the 'COPYING' file in the project root for licensing information.
2 /*
3  * Adaptive Framework Adaptor Modify Object
4  *
5  * Copyright (c) 2010-2023 Clemson University
6  *
7  */
8 
14 #include "afw_internal.h"
15 
16 
17 
18 static const afw_value_string_t
19 impl_value_set_property = {
21  AFW_UTF8_LITERAL("set_property")
22 };
23 
24 
25 /* Work area used for reconcile. */
26 typedef struct impl_reconcile_wa_s {
27  const afw_list_t *entries;
28  const afw_pool_t *p;
29  afw_xctx_t *xctx;
31 
32 
33 
34 /* Array of entry type ids. */
35 static const afw_utf8_t * entry_type[] = {
36 #define XX(id, _) &afw_s_ ## id,
38 #undef XX
39  NULL
40 };
41 
42 
43 /* Array to determine if type has a value. */
44 static const afw_boolean_t entry_type_has_value[] = {
45 #define XX(id, has) has,
47 #undef XX
48  false
49 };
50 
51 
52 /* Array of entry type ids as adaptive string values. */
53 static const afw_value_string_t entry_type_value[] = {
54 #define XX(id, _) { &afw_value_evaluated_string_inf, \
55  { #id, sizeof(#id) - 1 } },
57 #undef XX
58  {NULL}
59 };
60 
61 
62 
63 /*
64  * Find the innermost object/property name using name entry list. Create
65  * objects as needed if requested.
66  */
67 static const afw_object_t *
68 impl_find_object(
69  const afw_utf8_t * *property_name,
70  afw_boolean_t create_if_necessary,
71  const afw_object_t *entity,
72  const afw_object_path_property_name_entry_t *first_property_name_entry,
73  afw_xctx_t *xctx)
74 {
75  const afw_object_t *result;
76  const afw_object_t *object;
78 
79  result = entity;
80  *property_name = &first_property_name_entry->property_name;
81  for (entry = first_property_name_entry; entry->next; entry = entry->next)
82  {
83  *property_name = &entry->next->property_name;
85  &entry->property_name, xctx);
86  if (!object) {
87  if (create_if_necessary) {
88  object = afw_object_create_embedded(result,
89  &entry->property_name, xctx);
90  }
91  else {
92  result = NULL;
93  break;
94  }
95  }
96  result = object;
97  }
98 
99  return result;
100 }
101 
102 
103 /* Set a property using name entry list. */
104 static void
105 impl_set_property(
106  const afw_object_t *object,
107  const afw_object_path_property_name_entry_t *first_property_name_entry,
108  const afw_value_t *value,
109  afw_xctx_t *xctx)
110 {
111  const afw_object_t *obj;
112  const afw_utf8_t *property_name;
113 
114  obj = impl_find_object(&property_name, true, object,
115  first_property_name_entry, xctx);
116  afw_object_set_property(obj, property_name, value, xctx);
117 }
118 
119 
120 
121 /* Convert entry type mnemonic to enum. */
124  const afw_utf8_t *mnemonic)
125 {
127 
128  for (i = 0;
129  entry_type[i] && !afw_utf8_equal(entry_type[i], mnemonic);
130  i++);
131 
132  return (entry_type[i]) ? i : afw_adaptor_modify_entry_type_invalid;
133 }
134 
135 
136 
137 /* Convert entry type enum to mnemonic. */
138 AFW_DEFINE(const afw_utf8_t *)
141 {
142  return (type < 0 || type >= afw_adaptor_modify_entry_type_invalid)
143  ? NULL
144  : entry_type[type];
145 }
146 
147 
148 
149 /* Convert entry type enum to mnemonic. */
150 AFW_DEFINE(const afw_value_t *)
153 {
154  return (type < 0 || type >= afw_adaptor_modify_entry_type_invalid)
155  ? NULL
156  : (const afw_value_t *)&entry_type_value[type];
157 }
158 
159 
160 
161 /* Create modify entries from list of tuple lists in specified pool. */
162 AFW_DEFINE(const afw_adaptor_modify_entry_t * const *)
164  const afw_list_t *list, const afw_pool_t *p, afw_xctx_t *xctx)
165 {
166  apr_array_header_t *ary;
167  const afw_iterator_t *entry_i;
168  const afw_iterator_t *tuple_i;
169  const afw_iterator_t *names_i;
170  const afw_list_t *tuple;
172  const afw_utf8_t *s;
173  const afw_value_t *value;
174  afw_object_path_property_name_entry_t *property_name_entry;
175  afw_object_path_property_name_entry_t *prev_property_name_list;
176 
177  ary = apr_array_make(afw_pool_get_apr_pool(p),
178  5, sizeof(afw_adaptor_modify_entry_t *));
179  entry_i = NULL;
180  for (;;) {
181 
182  /* Get next tuple. Break out of loop if there are no more. */
183  tuple_i = NULL;
184  tuple = afw_list_of_list_get_next(list, &entry_i, xctx);
185  if (!tuple) {
186  break;
187  }
188 
189  /* Allocate entry. */
191 
192  /* Entry type. */
193  s = afw_list_of_string_get_next(tuple, &tuple_i, xctx);
194  if (!s) {
195  goto error;
196  }
198  if (entry->type == afw_adaptor_modify_entry_type_invalid) {
199  goto error;
200  }
201 
202  /* Entry name/names. */
203  value = afw_list_get_next_value(tuple, &tuple_i, p, xctx);
204  if (!value) {
205  goto error;
206  }
207  if (afw_value_is_string(value)) {
208  entry->first_property_name_entry = property_name_entry =
210  s = &((const afw_value_string_t *)value)->internal;
211  property_name_entry->property_name.s = s->s;
212  property_name_entry->property_name.len = s->len;
213  }
214  else if (afw_value_is_list(value)) {
215  for (names_i = NULL, prev_property_name_list = NULL;;) {
217  ((const afw_value_list_t *)value)->internal,
218  &names_i, xctx);
219  if (!s) {
220  if (!prev_property_name_list) {
221  goto error;
222  }
223  break;
224  }
225  if (!prev_property_name_list) {
226  property_name_entry = afw_pool_calloc_type(p,
228 
229  }
230  property_name_entry = afw_pool_calloc_type(p,
232  property_name_entry->property_name.s = s->s;
233  property_name_entry->property_name.len = s->len;
234  if (prev_property_name_list) {
235  prev_property_name_list->next = property_name_entry;
236  }
237  else {
238  entry->first_property_name_entry = property_name_entry;
239  }
240  prev_property_name_list = property_name_entry;
241  }
242  }
243 
244  /* Get value. */
245  entry->value = afw_list_get_next_value(tuple, &tuple_i, p, xctx);
246  if ((entry->value && !entry_type_has_value[entry->type]) ||
247  (!entry->value && entry_type_has_value[entry->type]))
248  {
249  goto error;
250  }
251 
252  /* It's an error if there is a 4th value in tuple. */
253  if (entry->value) {
254  if (afw_list_get_next_value(tuple, &tuple_i, p, xctx)) {
255  goto error;
256  }
257  }
258 
259  /* Push entry on entry list. */
260  APR_ARRAY_PUSH(ary, afw_adaptor_modify_entry_t *) = entry;
261  }
262 
263  /* NULL terminate entries list and return it. */
264  APR_ARRAY_PUSH(ary, afw_adaptor_modify_entry_t *) = NULL;
265  return (const afw_adaptor_modify_entry_t **)ary->elts;
266 
267 error:
268  AFW_THROW_ERROR_FZ(general, xctx,
269  "Modify entry tuple number %d is invalid",
270  ary->nelts + 1);
271 
272 }
273 
274 
275 /* Create modify entries from list of tuple lists in specified pool. */
276 AFW_DEFINE(const afw_list_t *)
278  const afw_adaptor_modify_entry_t * const *entries,
279  const afw_pool_t *p, afw_xctx_t *xctx)
280 {
281  const afw_list_t *result;
282  const afw_list_t *tuple;
283  const afw_list_t *name_list;
284  const afw_object_path_property_name_entry_t *property_name_entry;
285  const afw_adaptor_modify_entry_t * const *e;
286  const afw_value_t *value;
287 
288  /* Create list for result. */
289  result = afw_list_of_create(afw_data_type_list, p, xctx);
290 
291  /* Process all modify entries. */
292  for (e = entries; *e; e++) {
293 
294  /* Create a new list for tuple. */
295  tuple = afw_list_create_generic(p, xctx);
296 
297  /* Entry type. */
298  value = afw_adaptor_modify_entry_type_value((*e)->type);
299  if (!value) {
300  AFW_THROW_ERROR_Z(general, "Invalid type", xctx);
301  }
302  afw_list_add_value(tuple, value, xctx);
303 
304  /* Property name or list of names. */
305  if ((*e)->first_property_name_entry->next) {
306  name_list = afw_list_create_generic(p, xctx);
307  for (property_name_entry = (*e)->first_property_name_entry;
308  property_name_entry;
309  property_name_entry = property_name_entry->next)
310  {
311  value = afw_value_create_string(
312  &property_name_entry->property_name,
313  p, xctx);
314  afw_list_add_value(name_list, value, xctx);
315  }
316  value = afw_value_create_list(name_list, p, xctx);
317  }
318  else {
319  value = afw_value_create_string(
320  &(*e)->first_property_name_entry->property_name,
321  p, xctx);
322  }
323  afw_list_add_value(tuple, value, xctx);
324 
325  /* Value. */
326  if ((*e)->value) {
327  afw_list_add_value(tuple, (*e)->value, xctx);
328  }
329 
330  /* Add tuple to result list. */
331  value = afw_value_create_list(tuple, p, xctx);
332  afw_list_add_value(result, value, xctx);
333 
334  }
335 
336  /* Return result list. */
337  return result;
338 }
339 
340 
341 
342 /* Apply modify entries to unnormalize object. */
343 AFW_DEFINE(void)
345  const afw_adaptor_modify_entry_t * const *entries,
346  const afw_object_t *object,
347  afw_xctx_t *xctx)
348 {
349  const afw_pool_t *p = object->p;
350  const afw_adaptor_modify_entry_t * const * entry;
351  const afw_object_path_property_name_entry_t *first_property_name_entry;
352  const afw_value_t *value, *old_value = NULL;
353  const afw_value_t *new_value;
354  const afw_list_t *list;
355  const afw_object_t *obj;
356  const afw_utf8_t *property_name = NULL;
357  const afw_utf8_t *s;
358 
360  // const afw_iterator_t *iterator = NULL;
361 
362  /* Process all entries. */
363  for (entry = entries; *entry; entry++)
364  {
365  first_property_name_entry = ((*entry)->first_property_name_entry);
366  value = (*entry)->value;
367 
368  /* Process based on entry type. */
369  switch ((*entry)->type) {
370 
371 
372  /* Add value. */
373  case afw_adaptor_modify_entry_type_add_value:
374 
376  AFW_THROW_ERROR_FZ(general, xctx,
377  "add_value %" AFW_UTF8_FMT
378  " must be a defined and evaluated value",
380  &first_property_name_entry->property_name));
381  }
382 
383  /* If object already has this property, add value to it. */
385  first_property_name_entry, xctx);
386 
387  if (old_value) {
388 
389  /* If old value is a list, just add new value to it. */
390  if (afw_value_is_list(old_value)) {
391  list = afw_value_as_list(old_value, xctx);
392  afw_list_add_value(list, value, xctx);
393  }
394 
395  /*
396  * If value is a single value, add it and new value to a list and use
397  * that. This may result in a list with value of different data type,
398  * as well as a property being a list of values that later will be
399  * one value. When the result object is actually used, it will probably
400  * be normalize using an object type, which will resolve this either
401  * by converting values or indication properties in error.
402  */
403  else {
404  list = afw_list_create_generic(object->p, xctx);
405  afw_list_add_value(list, old_value, xctx);
406  afw_list_add_value(list, value, xctx);
407  value = afw_value_create_list(list,
408  p, xctx);
409  impl_set_property(object, first_property_name_entry, value,
410  xctx);
411  }
412 
413  }
414 
415  else {
416  impl_set_property(object, first_property_name_entry, value,
417  xctx);
418  }
419 
420  break;
421 
422 
423  /* Remove property. Fail is silent. */
424  case afw_adaptor_modify_entry_type_remove_property:
425 
426  obj = impl_find_object(&property_name, false, object,
427  first_property_name_entry, xctx);
428  if (obj) {
429  impl_set_property(object, first_property_name_entry, NULL,
430  xctx);
431  }
432 
433  break;
434 
435 
436  /* Remove value. */
437  case afw_adaptor_modify_entry_type_remove_value:
439  first_property_name_entry, xctx);
440 
441  if (old_value) {
442 
443  if (afw_value_is_list(old_value)) {
444  list = ((const afw_value_list_t *)old_value)
445  ->internal;
446  afw_list_remove_value(list, value, xctx);
447  new_value = afw_value_create_list(list, p, xctx);
448  impl_set_property(object, first_property_name_entry,
449  new_value, xctx);
450  }
451 
452  else {
453  if (!afw_value_equal(value, old_value, xctx)) {
455  first_property_name_entry, p, xctx);
456  AFW_THROW_ERROR_FZ(general, xctx,
457  "Error: Value does not exist for property %"
458  AFW_UTF8_FMT,
459  AFW_UTF8_FMT_ARG(s));
460  }
461  else {
462  impl_set_property(object, first_property_name_entry,
463  NULL, xctx);
464  }
465  }
466  }
467 
468  else {
469  /* There are no values that exist for this property */
471  first_property_name_entry, p, xctx);
472  AFW_THROW_ERROR_FZ(general, xctx,
473  "Error: Value does not exist for property %" AFW_UTF8_FMT,
474  AFW_UTF8_FMT_ARG(s));
475  }
476 
477  break;
478 
479 
480  /* Set property. */
481  case afw_adaptor_modify_entry_type_set_property:
482 
483  obj = impl_find_object(&property_name, true, object,
484  first_property_name_entry, xctx);
485 
486  afw_object_set_property(obj, property_name,
487  value, xctx);
488 
489  break;
490 
491 
492  /* Invalid modify type. */
493  default:
494  AFW_THROW_ERROR_FZ(general, xctx, "Invalid modify type %d",
495  (*entry)->type);
496  }
497  }
498 
499 }
500 
501 
502 static void
503 impl_add_reconcile_property(
505  const afw_object_type_property_type_t *embedding_pt,
506  const afw_utf8_t *embedding_property_name,
508  const afw_utf8_t *property_name,
509  const afw_list_t *property_names,
510  const afw_value_t *value)
511 {
512  const afw_list_t *new_property_names;
513  const afw_list_t *tuple;
514  const afw_value_t *v;
515 
516  if (embedding_pt && !embedding_pt->allow_write) {
517  //return; /** @fixme Ignore these on reconcile???
518  AFW_THROW_ERROR_FZ(general, wa->xctx,
519  "Property %" AFW_UTF8_FMT " can not be modified",
520  AFW_UTF8_FMT_ARG(embedding_property_name));
521  //*/
522  }
523 
524  if (pt && !pt->allow_write) {
525  // return; /** @fixme Ignore these on reconcile???
526  AFW_THROW_ERROR_FZ(general, wa->xctx,
527  "Property %" AFW_UTF8_FMT " can not be modified",
528  AFW_UTF8_FMT_ARG(property_name));
529  //*/
530  }
531 
532  tuple = afw_list_create_generic(wa->p, wa->xctx);
533 
534  /* Entry type. */
535  v = (const afw_value_t *)((value)
536  ? &entry_type_value[afw_adaptor_modify_entry_type_set_property]
537  : &entry_type_value[afw_adaptor_modify_entry_type_remove_property]);
538  afw_list_add_value(tuple, v, wa->xctx);
539 
540  /* Property name. */
541  if (property_names) {
542  new_property_names = afw_list_create_or_clone(
543  property_names, afw_data_type_string, false,
544  wa->p, wa->xctx);
545  v = afw_value_create_string(property_name,
546  wa->p, wa->xctx);
547  afw_list_add_value(new_property_names, v, wa->xctx);
548  v = afw_value_create_list(new_property_names,
549  wa->p, wa->xctx);
550  }
551  else {
552  v = afw_value_create_string(property_name,
553  wa->p, wa->xctx);
554  }
555  afw_list_add_value(tuple, v, wa->xctx);
556 
557  /* Value */
558  if (value) {
559  afw_list_add_value(tuple, value, wa->xctx);
560  }
561 
562  /* Add tuple to entries. */
563  v = afw_value_create_list(tuple, wa->p, wa->xctx);
564  afw_list_add_value(wa->entries, v, wa->xctx);
565 }
566 
567 
568 static void
569 impl_reconcile_object(
571  const afw_object_type_property_type_t *embedding_pt,
572  const afw_utf8_t *embedding_property_name,
573  const afw_object_type_t *object_type,
574  const afw_list_t *property_names,
575  const afw_object_t *original,
576  const afw_object_t *modified,
577  const afw_object_t *journal_entry)
578 {
579  const afw_iterator_t *iterator;
580  const afw_utf8_t *property_name;
581  const afw_value_t *original_value;
582  const afw_value_t *modified_value;
583  const afw_value_t *value;
584  const afw_list_t *new_property_names;
586  const afw_object_type_t *property_object_type;
587  const afw_utf8_t *object_type_id;
588  const afw_object_t *object = NULL;
589 
590  /* Run though modified producing set_property if different from original. */
591  for (iterator = NULL;;) {
592 
593  /* Get next property and stop looping if there are no more. */
594  modified_value = afw_object_get_next_property(modified,
595  &iterator, &property_name, wa->xctx);
596  if (!modified_value) break;
597 
598  /* Get property type. */
599  pt = afw_object_type_property_type_get(object_type,
600  property_name, wa->xctx);
601  if (!pt) {
602  AFW_THROW_ERROR_FZ(general, wa->xctx,
603  "Missing property type for %" AFW_UTF8_FMT,
604  AFW_UTF8_FMT_ARG(property_name));
605  }
606 
607  /* Normalize modified value. */
608  modified_value = afw_object_type_property_type_normalize(pt,
609  modified_value, wa->p, wa->xctx);
610 
611  /*
612  * Try to get original value with same property name. If there is not
613  * one or modified value is an object but original is not, add value.
614  */
615  original_value = afw_object_get_property(original,
616  property_name, wa->xctx);
617  if (!original_value ||
618  (afw_value_is_object(modified_value) &&
619  !afw_value_is_object(original_value)))
620  {
621  impl_add_reconcile_property(wa,
622  embedding_pt, embedding_property_name,
623  pt, property_name,
624  property_names, modified_value);
625  }
626 
627  /* If there is a corresponding original value, set if different. */
628  else {
629 
630  /* Handled case where original and modified are both objects */
631  if (afw_value_is_object(modified_value)) {
632  new_property_names =
634  property_names, afw_data_type_string, false,
635  wa->p, wa->xctx);
636  value = afw_value_create_string(property_name,
637  wa->p, wa->xctx);
638  afw_list_add_value(new_property_names, value, wa->xctx);
639 
640  /* Try getting object type id from pt. */
641  object_type_id = pt->data_type_parameter;
642 
643  /*
644  * If object id is not in pt, try to get object type id from
645  * modified object.
646  */
647  if (!object_type_id) {
648  object = ((const afw_value_object_t *)
649  modified_value)->internal;
650  object_type_id = afw_object_meta_get_object_type_id(object, xctx);
651  }
652  if (!object_type_id && object->meta.meta_object) {
653  object_type_id = afw_object_meta_get_object_type_id(
654  object, xctx);
655  }
656 
657  /*
658  * If object type id still not determined, try getting it from
659  * original object.
660  */
661  if (!object_type_id) {
662  object = ((const afw_value_object_t *)
663  original_value)->internal;
664  object_type_id = afw_object_meta_get_object_type_id(object, xctx);
665  }
666  if (!object_type_id && object->meta.meta_object) {
667  object_type_id = afw_object_meta_get_object_type_id(
668  object, xctx);
669  }
670 
671  /* Get the property's object type. Error if not available. */
672  property_object_type = NULL;
673  if (object_type_id) {
674  property_object_type = afw_adaptor_get_object_type(
675  object_type->adaptor_id, object_type_id,
676  journal_entry,
677  wa->xctx);
678  }
679  if (!property_object_type) {
680  AFW_THROW_ERROR_Z(general,
681  "object type needed to reconcile embedded object",
682  wa->xctx);
683  }
684 
685  /* Reconcile the two objects. */
686  impl_reconcile_object(wa,
687  pt, property_name,
688  property_object_type,
689  new_property_names,
690  ((const afw_value_object_t *)original_value)
691  ->internal,
692  ((const afw_value_object_t *)modified_value)
693  ->internal,
694  journal_entry);
695  }
696 
697  else {
698  original_value = afw_object_type_property_type_normalize(pt,
699  original_value, wa->p, wa->xctx);
700  if (!afw_value_equal(modified_value, original_value, wa->xctx))
701  {
702  impl_add_reconcile_property(wa,
703  embedding_pt, embedding_property_name,
704  pt, property_name,
705  property_names, modified_value);
706  }
707  }
708  }
709  }
710 
711  /* Run though original producing remove_property if not in modified. */
712  for (iterator = NULL;;) {
713  original_value = afw_object_get_next_property(original,
714  &iterator, &property_name, wa->xctx);
715  if (!original_value) break;
716 
717  if (!afw_object_has_property(modified, property_name, wa->xctx))
718  {
719  pt = afw_object_type_property_type_get(object_type,
720  property_name, wa->xctx);
721  impl_add_reconcile_property(wa,
722  embedding_pt, embedding_property_name,
723  pt, property_name,
724  property_names, NULL);
725  }
726  }
727 }
728 
729 
730 /* Produce modify entries needed to reconcile two objects. */
731 AFW_DEFINE(void)
733  const afw_utf8_t * *adaptor_id,
734  const afw_utf8_t * *object_type_id,
735  const afw_utf8_t * *object_id,
736  const afw_list_t * *entries,
737  const afw_object_t *original,
738  const afw_object_t *modified,
739  const afw_object_t *journal_entry,
740  const afw_pool_t *p, afw_xctx_t *xctx)
741 {
743  const afw_utf8_t *original_path;
744  const afw_utf8_t *path;
745  const afw_object_type_t *object_type;
746  const afw_object_path_parsed_t *parsed_path;
747 
748  original_path = afw_object_meta_get_path(original, xctx);
749  path = afw_object_meta_get_path(modified, xctx);
750 
751  if (!original_path || !path || !afw_utf8_equal(original_path, path))
752  {
753  AFW_THROW_ERROR_Z(general,
754  "reconcile expects original and modified "
755  "paths to match",
756  xctx);
757  }
758 
759  /* Parse path and make sure it is an entity. */
760  parsed_path = afw_object_path_parse(path, NULL, NULL, p, xctx);
761  if (!parsed_path || parsed_path->first_property_name) {
762  AFW_THROW_ERROR_Z(general,
763  "reconcile_object() expects path to be an entity",
764  xctx);
765  }
766  *adaptor_id = &parsed_path->adaptor_id;
767  *object_type_id = &parsed_path->object_type_id;
768  *object_id = &parsed_path->entity_object_id;
769 
770  object_type = afw_adaptor_get_object_type(*adaptor_id, *object_type_id,
771  journal_entry, xctx);
772  if (!object_type) {
773  AFW_THROW_ERROR_FZ(general, xctx,
774  "Object type %" AFW_UTF8_FMT
775  " does not exist in Adaptor %" AFW_UTF8_FMT,
776  AFW_UTF8_FMT_ARG(*object_type_id),
777  AFW_UTF8_FMT_ARG(*adaptor_id));
778  }
779 
780  wa.entries = afw_list_of_create(afw_data_type_list, p, xctx);
781  wa.p = p;
782  wa.xctx = xctx;
783 
784  impl_reconcile_object(&wa, NULL, NULL, object_type, NULL,
785  original, modified, journal_entry);
786 
787  *entries = wa.entries;
788 }
789 
790 
791 
792 /* Patch object and remove from cache. */
793 AFW_DEFINE(void)
795  const afw_utf8_t *adaptor_id,
796  const afw_utf8_t *object_type_id,
797  const afw_utf8_t *object_id,
798  const afw_list_t *entries,
799  const afw_object_t *journal_entry,
800  const afw_object_t *adaptor_type_specific,
801  afw_xctx_t *xctx)
802 {
803  const afw_adaptor_session_t *session;
804  const afw_adaptor_modify_entry_t * const *entry;
805  const afw_object_t *request;
806  afw_adaptor_impl_request_t impl_request;
807 
808  /* Set request in journal entry. */
809  afw_memory_clear(&impl_request);
810  impl_request.request = request = afw_object_create_embedded(
811  journal_entry, &afw_s_request, xctx);
812  impl_request.p = request->p;
813  impl_request.journal_entry = journal_entry;
814  impl_request.resource_id = afw_utf8_printf(impl_request.p, xctx,
815  "/"
816  "%" AFW_UTF8_FMT "/"
817  "%" AFW_UTF8_FMT "/"
818  "%" AFW_UTF8_FMT,
819  AFW_UTF8_FMT_ARG(adaptor_id),
820  AFW_UTF8_FMT_ARG(object_type_id),
821  AFW_UTF8_FMT_ARG(object_id));
823  &afw_s_resourceId, impl_request.resource_id, xctx);
825  &afw_s_function, &afw_s_modify_object, xctx);
827  &afw_s_adaptorId, adaptor_id, xctx);
829  &afw_s_objectType, object_type_id, xctx);
831  &afw_s_objectId, object_id, xctx);
833  &afw_s_entries, entries, xctx);
834 
835  /* Parse entries. */
836  entry = afw_adaptor_modify_entries_from_list(entries, xctx->p, xctx);
837 
838  /* Get an active session with adaptor. */
839  session = afw_adaptor_session_get_cached(adaptor_id, true, xctx);
840 
841  /* Action prologue. */
842  afw_adaptor_internal_journal_prologue(session, journal_entry, xctx);
843 
844  /* If one of the core object types, handle special */
846  {
847 
848  /* Journal entry. */
849  if (afw_utf8_equal(object_type_id,
851  {
852  AFW_THROW_ERROR_Z(general,
853  "modify_object() is not supported for "
855  xctx);
856  }
857  }
858 
859  /* Modify object. */
860  afw_adaptor_session_modify_object(session, &impl_request,
861  object_type_id, object_id, entry,
862  adaptor_type_specific, xctx);
863 
864  /* Action epilogue. */
865  afw_adaptor_internal_journal_epilogue(session, journal_entry, true, xctx);
866 }
867 
868 
869 
870 /* Modify using update object and remove from cache. */
871 AFW_DEFINE(void)
873  const afw_utf8_t *adaptor_id,
874  const afw_utf8_t *object_type_id,
875  const afw_utf8_t *object_id,
876  const afw_object_t *update_object,
877  const afw_object_t *journal_entry,
878  const afw_object_t *adaptor_type_specific,
879  afw_xctx_t *xctx)
880 {
881  const afw_iterator_t *iterator;
882  const afw_utf8_t *property_name;
883  const afw_value_t *value;
884  const afw_list_t *entries;
885  const afw_list_t *entry;
886  const afw_value_t *entry_value;
887  const afw_value_t *property_name_value;
888 
889 
903  /* Convert update_object to list of modify entries. */
904  entries = afw_list_of_create(afw_data_type_list, xctx->p, xctx);
905  iterator = NULL;
906  while ((value = afw_object_get_next_property(update_object,
907  &iterator, &property_name, xctx)))
908  {
909  /* Add ["set_property", <property name>, value]. */
910  entry = afw_list_create_generic(xctx->p, xctx);
911  afw_list_add_value(entry,
912  (const afw_value_t *)&impl_value_set_property,
913  xctx);
914  property_name_value = afw_value_create_string(
915  property_name, xctx->p, xctx);
916  afw_list_add_value(entry, property_name_value, xctx);
917  afw_list_add_value(entry, value, xctx);
918  entry_value = afw_value_create_list(entry, xctx->p, xctx);
919  afw_list_add_value(entries, entry_value, xctx);
920  }
921 
922  /* Modify object. */
924  adaptor_id, object_type_id, object_id,
925  entries, journal_entry, adaptor_type_specific, xctx);
926 }
AFW_DEFINE(const afw_object_t *)
Adaptive Framework Core Internal.
void afw_adaptor_internal_journal_epilogue(const afw_adaptor_session_t *session, const afw_object_t *journal_entry, afw_boolean_t modification, afw_xctx_t *xctx)
#define afw_adaptor_session_modify_object(instance, impl_request, object_type_id, object_id, entry, adaptor_type_specific, xctx)
Call method modify_object of interface afw_adaptor_session.
afw_adaptor_modify_using_update_object(const afw_utf8_t *adaptor_id, const afw_utf8_t *object_type_id, const afw_utf8_t *object_id, const afw_object_t *update_object, const afw_object_t *journal_entry, const afw_object_t *adaptor_type_specific, afw_xctx_t *xctx)
Modify using update object and remove from cache.
afw_adaptor_modify_entries_apply_to_unnormalized_object(const afw_adaptor_modify_entry_t *const *entries, const afw_object_t *object, afw_xctx_t *xctx)
Apply modify entries to an unnormalized object.
afw_adaptor_modify_entry_type_value(afw_adaptor_modify_entry_type_t type)
Convert entry type enum to value.
afw_adaptor_modify_entries_from_list(const afw_list_t *list, const afw_pool_t *p, afw_xctx_t *xctx)
Create modify entries from list of tuple lists in specified pool.
afw_adaptor_modify_entry_type_mnemonic(afw_adaptor_modify_entry_type_t type)
Convert entry type enum to mnemonic.
afw_adaptor_modify_needed_to_reconcile(const afw_utf8_t **adaptor_id, const afw_utf8_t **object_type_id, const afw_utf8_t **object_id, const afw_list_t **entries, const afw_object_t *original, const afw_object_t *modified, const afw_object_t *journal_entry, const afw_pool_t *p, afw_xctx_t *xctx)
Produce modify needed to reconcile two objects.
afw_adaptor_session_get_cached(const afw_utf8_t *adaptor_id, afw_boolean_t begin_transaction, afw_xctx_t *xctx)
Get/create an active cached session for adaptor_id.
Definition: afw_adaptor.c:375
afw_adaptor_get_object_type(const afw_utf8_t *adaptor_id, const afw_utf8_t *object_type_id, const afw_object_t *journal_entry, afw_xctx_t *xctx)
Get and cache AdaptiveObjectType object.
Definition: afw_adaptor.c:437
afw_adaptor_modify_entry_type(const afw_utf8_t *mnemonic)
Convert entry type mnemonic to enum.
afw_adaptor_modify_object(const afw_utf8_t *adaptor_id, const afw_utf8_t *object_type_id, const afw_utf8_t *object_id, const afw_list_t *entries, const afw_object_t *journal_entry, const afw_object_t *adaptor_type_specific, afw_xctx_t *xctx)
Modify object and remove from cache.
#define AFW_ADAPTOR_MODIFY_ENTRY_TYPE_MAP(XX)
Adaptor session modify type map.
enum afw_adaptor_modify_entry_type_e afw_adaptor_modify_entry_type_t
Adaptor session modify type enum.
afw_adaptor_modify_entries_to_list(const afw_adaptor_modify_entry_t *const *entries, const afw_pool_t *p, afw_xctx_t *xctx)
Create a list from modify entries in specified pool.
afw_value_create_list(const afw_list_t *internal, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for unmanaged data type list value.
#define afw_value_is_list(A_VALUE)
Macro to determine if value is evaluated list.
afw_data_type_list
Data type struct for list.
#define afw_list_of_list_get_next(list, iterator, xctx)
Get next value from list of list.
afw_value_as_list(const afw_value_t *value, afw_xctx_t *xctx)
Typesafe cast of data type list.
afw_object_set_property_as_list(const afw_object_t *object, const afw_utf8_t *property_name, const afw_list_t *internal, afw_xctx_t *xctx)
Set property function for data type list values.
#define afw_value_is_object(A_VALUE)
Macro to determine if value is evaluated object.
#define afw_object_old_get_property_as_object(object, property_name, xctx)
Get property function for data type object value.
afw_value_create_string(const afw_utf8_t *internal, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for unmanaged data type string value.
afw_data_type_string
Data type struct for string.
#define afw_list_of_string_get_next(list, iterator, xctx)
Get next value from list of string.
afw_value_evaluated_string_inf
Unmanaged evaluated value inf for data type string.
#define afw_value_is_string(A_VALUE)
Macro to determine if value is evaluated string.
afw_object_set_property_as_string(const afw_object_t *object, const afw_utf8_t *property_name, const afw_utf8_t *internal, afw_xctx_t *xctx)
Set property function for data type string values.
#define AFW_UTF8_FMT_ARG(A_STRING)
Convenience Macro for use with AFW_UTF8_FMT to specify arg.
Definition: afw_common.h:605
#define AFW_UTF8_LITERAL(A_STRING)
String literal initializer.
Definition: afw_common.h:582
struct afw_iterator_s afw_iterator_t
_Bool afw_boolean_t
Definition: afw_common.h:373
#define AFW_UTF8_FMT
Format string specifier used for afw_utf8_t.
Definition: afw_common.h:588
#define AFW_THROW_ERROR_FZ(code, xctx, format_z,...)
Macro used to set error and 0 rv in xctx and throw it.
Definition: afw_error.h:319
#define AFW_THROW_ERROR_Z(code, message_z, xctx)
Macro used to set error and 0 rv in xctx and throw it.
Definition: afw_error.h:283
#define afw_list_get_next_value(instance, iterator, p, xctx)
Call method get_next_value of interface afw_list.
afw_list_remove_value(const afw_list_t *instance, const afw_value_t *value, afw_xctx_t *xctx)
Call method remove_value of interface afw_list_setter.
Definition: afw_list.c:168
const afw_list_t * afw_list_create_or_clone(const afw_list_t *list, const afw_data_type_t *data_type, afw_boolean_t clone_values, const afw_pool_t *p, afw_xctx_t *xctx)
Create a clone of a list in memory.
#define afw_list_create_generic(p, xctx)
Create an value list in memory.
Definition: afw_list.h:81
afw_list_add_value(const afw_list_t *instance, const afw_value_t *value, afw_xctx_t *xctx)
Call method add_value of interface afw_list_setter.
Definition: afw_list.c:104
#define afw_list_of_create(data_type, p, xctx)
Create an list of a specific data type in memory.
Definition: afw_list.h:64
#define afw_memory_clear(to)
Clear preallocated memory for sizeof(*(to)).
Definition: afw_memory.h:47
#define afw_object_get_property(instance, property_name, xctx)
Call method get_property of interface afw_object.
#define afw_object_get_next_property(instance, iterator, property_name, xctx)
Call method get_next_property of interface afw_object.
#define afw_object_has_property(instance, property_name, xctx)
Call method has_property of interface afw_object.
#define afw_object_meta_get_object_type_id(instance, xctx)
Get object's object_type_id.
afw_object_meta_get_path(const afw_object_t *instance, afw_xctx_t *xctx)
Get an object's path.
afw_object_path_property_name_list_get_property(const afw_object_t *object, const afw_object_path_property_name_entry_t *first_property_name, afw_xctx_t *xctx)
Get object property value using property names.
afw_object_path_parse(const afw_utf8_t *path, const afw_utf8_t *current_path, const afw_object_options_t *default_options, const afw_pool_t *p, afw_xctx_t *xctx)
Parse an object value path in specific pool.
afw_object_path_make_property_name_expression(const afw_object_path_property_name_entry_t *first, const afw_pool_t *p, afw_xctx_t *xctx)
Construct a property name expression from property name list.
afw_object_type_property_type_get(const afw_object_type_t *object_type, const afw_utf8_t *property_name, afw_xctx_t *xctx)
Get property type object for property.
afw_object_type_property_type_normalize(const afw_object_type_property_type_t *pt, const afw_value_t *value, const afw_pool_t *p, afw_xctx_t *xctx)
Normalize a value based on property type.
#define AFW_OBJECT_S_CORE_ID_PREFIX
String prefix for all core adaptive object types.
Definition: afw_object.h:33
#define AFW_OBJECT_Q_OBJECT_TYPE_ID_JOURNAL_ENTRY
Quoted object type id for Journal Entry object.
Definition: afw_object.h:60
afw_object_set_property(const afw_object_t *instance, const afw_utf8_t *property_name, const afw_value_t *value, afw_xctx_t *xctx)
Set the value of an object's property.
Definition: afw_object.c:46
#define AFW_OBJECT_S_OBJECT_TYPE_ID_JOURNAL_ENTRY
String object type id for Journal Entry object.
Definition: afw_object.h:63
const afw_object_t * afw_object_create_embedded(const afw_object_t *embedding_object, const afw_utf8_t *property_name, afw_xctx_t *xctx)
Create an empty embedded object in a memory object.
#define afw_pool_get_apr_pool(instance)
Call method get_apr_pool of interface afw_pool.
#define afw_pool_calloc_type(instance, type, xctx)
Macro to allocate cleared memory to hold type in pool.
Definition: afw_pool.h:167
afw_boolean_t afw_utf8_equal(const afw_utf8_t *s1, const afw_utf8_t *s2)
Check to see if a string equals another string.
afw_utf8_printf(const afw_pool_t *p, afw_xctx_t *xctx, const afw_utf8_z_t *format,...)
Create a utf-8 string using a c format string in specified pool.
Definition: afw_utf8.c:459
afw_boolean_t afw_utf8_starts_with(const afw_utf8_t *string, const afw_utf8_t *starts_with)
Check to see if a string starts with another string.
afw_value_equal(const afw_value_t *value1, const afw_value_t *value2, afw_xctx_t *xctx)
Test whether two values are equal.
Definition: afw_value.c:851
#define afw_value_is_defined_and_evaluated(A_VALUE)
Macro to determine if value is defined and evaluated.
Definition: afw_value.h:481
Internal request info used by afw_adaptor_impl*() functions.
const afw_utf8_t * resource_id
resource id
const afw_object_t * journal_entry
Journal entry.
const afw_object_t * request
Request object.
const afw_pool_t * p
Pool used.
Adaptor modify entry.
afw_adaptor_modify_entry_type_t type
Modify type.
const afw_value_t * value
Associated value.
const afw_object_path_property_name_entry_t * first_property_name_entry
First entry in property name list.
Interface afw_adaptor_session public struct.
Interface afw_list public struct.
const afw_object_t * meta_object
Meta object.
Definition: afw_common.h:761
Typedef for parsed object path.
Property name path struct.
Interface afw_object public struct.
Struct for afw_object_type_property_type_t.
Struct for afw_object_type_t.
Interface afw_pool public struct.
NFC normalized UTF-8 string.
Definition: afw_common.h:545
struct for data type list values.
struct for data type object values.
Interface afw_value public struct.
struct for data type string values.
Interface afw_xctx public struct.