Adaptive Framework  0.9.0
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
afw_action.c
Go to the documentation of this file.
1 // See the 'COPYING' file in the project root for licensing information.
2 /*
3  * Adaptive Framework Action
4  *
5  * Copyright (c) 2010-2023 Clemson University
6  *
7  */
8 
14 #include "afw_internal.h"
15 
16 static void
17 impl_call_function(
18  const afw_compile_value_contextual_t *contextual,
19  const afw_value_function_definition_t *function,
20  const afw_object_t *parent_request,
21  const afw_object_t *action_entry,
22  const afw_content_type_t *response_content_type,
23  const afw_object_t *action_response_entry,
24  const afw_pool_t *p, afw_xctx_t *xctx)
25 {
26  const afw_value_function_parameter_t *const *a;
27  afw_size_t argc, i;
28  const afw_data_type_t *data_type;
29  const afw_value_t **argv;
30  const afw_value_t *args;
31  const afw_value_t *result;
32  const afw_value_t *const *vargs;
33  const afw_value_t *const *varg;
34  const afw_value_t *value;
35  const afw_utf8_t *const *flag_ids;
36  afw_value_info_t info;
37  afw_boolean_t minArgs_found;
38 
39  /* Determine argc. */
40  for (argc = 0,
41  a = function->parameters,
42  varg = NULL,
43  vargs = NULL,
44  minArgs_found = false;
45  *a;
46  a++)
47  {
48  if (minArgs_found) {
49  AFW_THROW_ERROR_Z(general,
50  "minArgs must be on last parameter", xctx);
51  }
52  if ((*a)->minArgs == -1) {
53  argc++;
54  }
55  else {
56  minArgs_found = true;
57  args = afw_object_get_property(action_entry,
58  &(*a)->name, xctx);
59  if (!args && parent_request) {
60  args = afw_object_get_property(parent_request,
61  &(*a)->name, xctx);
62  }
63  if (args) {
64  vargs = afw_value_as_array_of_values(args, p, xctx);
65  for (varg = vargs; *varg; varg++) {
66  argc++;
67  }
68  }
69  }
70  }
71 
72  /* Build argv. */
73  argv = afw_pool_calloc(p, sizeof(afw_value_t *) * (argc + 1), xctx);
74  argv[0] = (const afw_value_t *)function;
75  for (i = 1, a = function->parameters; i <= argc; i++, a++) {
76 
77  /* If this is not minArgs parameter ... */
78  if ((*a)->minArgs == -1) {
79  argv[i] = afw_object_get_property(action_entry, &(*a)->name,
80  xctx);
81  if (argv[i]) {
82  if (afw_value_is_object(argv[i]) && parent_request) {
83  value = afw_object_get_property(parent_request,
84  &(*a)->name, xctx);
85  if (afw_value_is_object(value)) {
86  argv[i] = afw_value_create_object(
88  ((const afw_value_object_t *)value)->
89  internal,
90  ((const afw_value_object_t *)argv[i])->
91  internal,
92  p, xctx), p, xctx);
93  }
94  }
95  }
96  else if (parent_request) {
97  argv[i] = afw_object_get_property(parent_request,
98  &(*a)->name, xctx);
99  }
100 
101  /* If arg's data type doesn't match declared value, convert. */
102  if (argv[i]) {
103  if ((*a)->data_type &&
104  (*a)->data_type != afw_value_quick_data_type(argv[i]))
105  {
106  argv[i] = afw_value_convert(argv[i],
107  (*a)->data_type, true, p, xctx);
108  }
109  }
110 
111  /* If arg is NULL and not optional, throw error. */
112  else if (!(*a)->optional) {
113  AFW_THROW_ERROR_FZ(general, xctx,
114  "Missing parameter %" AFW_UTF8_FMT,
115  AFW_UTF8_FMT_ARG(&(*a)->name));
116  }
117  }
118 
119  /* If this is minArgs parameter, move remaining to argv. */
120  else if (vargs) {
121  for (varg = vargs; *varg; varg++, i++) {
122  argv[i] = *varg;
123 
124  /* If arg's data type doesn't match declared, convert. */
125  if ((*a)->data_type &&
126  (*a)->data_type != afw_value_quick_data_type(argv[i]))
127  {
128  argv[i] = afw_value_convert(argv[i],
129  (*a)->data_type, true, p, xctx);
130  }
131  }
132  }
133  }
134 
135  /* Set flags. */
136  value = afw_object_get_property(action_entry, &afw_s__flags_, xctx);
137  if (!value && parent_request) {
138  value = afw_object_get_property(parent_request, &afw_s__flags_, xctx);
139  }
140  if (value) {
141  flag_ids = afw_value_as_array_of_utf8(value, p, xctx);
142  afw_flag_set_to_defaults_plus_array(flag_ids, xctx);
143  }
144 
145  /* Call function. */
146  result = afw_value_call_built_in_function(
147  contextual, function, argc, argv, p, xctx);
148 
149  /* Set result if not undefined. */
150  if (result) {
151 
152  /* Make sure result if evaluated. */
153  if (!afw_value_is_fully_evaluated(result, xctx)) {
154  afw_value_get_info(result, &info, p, xctx);
155  AFW_THROW_ERROR_FZ(general, xctx,
156  "Function %" AFW_UTF8_FMT
157  " returned a value that is not fully evaluated. ("
158  "%" AFW_UTF8_FMT " %" AFW_UTF8_FMT ")",
159  AFW_UTF8_FMT_ARG(&function->functionId),
160  AFW_UTF8_FMT_ARG(info.value_inf_id),
161  AFW_UTF8_FMT_OPTIONAL_ARG(info.detail)
162  );
163  }
164 
165  /* Set result property in result. */
166  afw_object_set_property(action_response_entry, &afw_s_result, result,
167  xctx);
168 
169  /* Set resultDataType property in result. */
170  data_type = afw_value_quick_data_type(result);
171  if (data_type) {
172  afw_object_set_property_as_string(action_response_entry,
173  &afw_s_resultDataType, &data_type->data_type_id, xctx);
174  }
175  }
176 }
177 
178 
179 static void
180 impl_add_stream_properties(
181  const afw_object_t *response,
182  const afw_pool_t *p,
183  afw_xctx_t *xctx)
184 {
185  afw_utf8_t string;
186 
187  if (afw_flag_by_id_is_active(&afw_s_a_flag_response_console, xctx) &&
188  !afw_flag_by_id_is_active(&afw_s_a_flag_response_console_stream, xctx) &&
189  afw_stream_standard_is_set(console, xctx))
190  {
192  afw_stream_standard(console, xctx),
193  &string, xctx);
194  afw_object_set_property_as_string(response, &afw_s_console,
195  afw_utf8_clone(&string, p, xctx), xctx);
196  afw_stream_standard_release(console, xctx);
197  }
198 
199  if (afw_flag_by_id_is_active(&afw_s_a_flag_response_stderr, xctx) &&
200  !afw_flag_by_id_is_active(&afw_s_a_flag_response_stderr_stream, xctx) &&
201  afw_stream_standard_is_set(stderr, xctx))
202  {
204  afw_stream_standard(stderr, xctx),
205  &string, xctx);
206  afw_object_set_property_as_string(response, &afw_s_stderr,
207  afw_utf8_clone(&string, p, xctx), xctx);
208  afw_stream_standard_release(stderr, xctx);
209  }
210 
211  if (afw_flag_by_id_is_active(&afw_s_a_flag_response_stdout, xctx) &&
212  !afw_flag_by_id_is_active(&afw_s_a_flag_response_stdout_stream, xctx) &&
213  afw_stream_standard_is_set(stdout, xctx))
214  {
216  afw_stream_standard(stdout, xctx),
217  &string, xctx);
218  afw_object_set_property_as_string(response, &afw_s_stdout,
219  afw_utf8_clone(&string, p, xctx), xctx);
220  afw_stream_standard_release(stdout, xctx);
221  }
222 }
223 
224 
225 
226 /* Perform actions(s) specified in _AdaptiveActions_ object. */
227 AFW_DEFINE(const afw_object_t *)
229  const afw_object_t *request,
230  const afw_content_type_t *response_content_type,
231  const afw_object_t *response,
232  const afw_pool_t *p, afw_xctx_t *xctx)
233 {
234  const afw_list_t *actions;
235  const afw_object_t *action_entry;
236  const afw_list_t *action_response_entries;
237  const afw_object_t *action_response_entry;
238  const afw_value_t *action_response_entry_value;
239  const afw_utf8_t *functionId;
240  const afw_value_function_definition_t *function;
241  const afw_utf8_t *name;
242  afw_integer_t action_number = 0;
243  const afw_value_t *value;
244  const afw_iterator_t *iterator;
245  const afw_object_t *error;
246  const afw_stream_t *stream;
247  afw_compile_value_contextual_t *contextual;
248 
249 
250  /* If existing response not passed, make a new one. */
251  if (!response) {
252  response = afw_object_create_managed(p, xctx);
253  }
254 
255  contextual = afw_pool_calloc_type(response->p,
257  action_response_entry = NULL;
258 
259  AFW_TRY{
260 
261  /* Get actions property. If it doesn't exist, process single function. */
262  name = &afw_s_actions;
263  value = afw_object_get_property(request, name, xctx);
264  if (!value) {
265  name = &afw_s_function;
266  value = afw_object_get_property(request, name, xctx);
267  if (!value) {
268  AFW_THROW_ERROR_Z(syntax,
269  "Either actions or function property must be specified",
270  xctx);
271  }
272  else {
273  functionId = afw_value_as_utf8(value, response->p, xctx);
274 
275  /* Get function. */
276  function = afw_environment_get_function(functionId, xctx);
277  if (!function) {
278  AFW_THROW_ERROR_FZ(syntax, xctx,
279  "Unknown function %" AFW_UTF8_FMT,
280  AFW_UTF8_FMT_ARG(functionId));
281  }
282 
283  /* Call function. */
284  contextual->source_location = &afw_s_action;
285  impl_call_function(contextual, function, NULL,
286  request, response_content_type, response,
287  response->p, xctx);
288 
289  afw_object_set_property_as_string(response, &afw_s_status,
290  &afw_s_success, xctx);
291 
292  break;
293  }
294  }
295 
296  /* Make sure actions property is multiple actions list. */
297  if (!afw_value_is_list(value)) {
298  AFW_THROW_ERROR_FZ(syntax, xctx,
299  "Property %" AFW_UTF8_FMT " of actions is missing or invalid",
300  AFW_UTF8_FMT_ARG(name));
301  }
302  actions = ((const afw_value_list_t *)value)->internal;
303 
304  /* Create list for action response entries if not application/x-afw. */
305  action_response_entries = NULL;
306  if (!afw_content_type_is_application_afw(response_content_type)) {
307  action_response_entries = afw_list_of_create(
308  afw_data_type_object, response->p, xctx);
309  afw_object_set_property_as_list(response, &afw_s_actions,
310  action_response_entries, xctx);
311  }
312 
313  /* Process each action. */
314  for (iterator = NULL, action_number = 1; ; action_number++) {
315 
316  /* Get next action. If there are not more, break. */
317  value = afw_list_get_next_value(actions, &iterator,
318  response->p, xctx);
319  if (!value) break;
320 
321  /* Action must be a single_object. */
322  if (!afw_value_is_object(value)) {
323  AFW_THROW_ERROR_Z(syntax,
324  "Entries in actions list must be objects",
325  xctx);
326  }
327  action_entry = ((const afw_value_object_t *)value)->internal;
328 
329  /* Create action result entry. */
330  if (afw_content_type_is_application_afw(response_content_type)) {
331  action_response_entry = afw_object_create_managed(
332  response->p, xctx);
333  }
334  else {
335  action_response_entry = afw_object_create(
336  response->p, xctx);
337  }
338  action_response_entry_value = afw_value_create_object(
339  action_response_entry, response->p, xctx);
340  if (!afw_content_type_is_application_afw(response_content_type)) {
341  afw_list_add_value(action_response_entries,
342  action_response_entry_value, xctx);
343  }
344 
345  /* Get required function. */
346  name = &afw_s_function;
347  value = afw_object_get_property(action_entry, name, xctx);
348  if (!value) {
349  value = afw_object_get_property(request, name, xctx);
350  }
351  functionId = afw_value_as_utf8(value, action_response_entry->p, xctx);
352  if (!functionId) {
353  AFW_THROW_ERROR_FZ(syntax, xctx,
354  "Property %" AFW_UTF8_FMT " of action %" AFW_INTEGER_FMT
355  " is missing or invalid",
356  AFW_UTF8_FMT_ARG(name), action_number);
357  }
358 
359  /* Get function. */
360  function = afw_environment_get_function(functionId, xctx);
361  if (!function) {
362  AFW_THROW_ERROR_FZ(syntax, xctx,
363  "Unknown function %" AFW_UTF8_FMT
364  " in action %" AFW_INTEGER_FMT,
365  AFW_UTF8_FMT_ARG(functionId), action_number);
366  }
367 
368  /* Call function. */
369  contextual->source_location =
370  afw_utf8_printf(response->p, xctx,
371  "action%d", action_number);
372  impl_call_function(contextual, function, request,
373  action_entry, response_content_type, action_response_entry,
374  response->p, xctx);
375 
376  /* if application/x-afw, write response. */
377  if (afw_content_type_is_application_afw(response_content_type)) {
378  impl_add_stream_properties(action_response_entry, p, xctx);
379  stream = afw_stream_standard(response_body, xctx);
380  afw_object_set_property(action_response_entry,
381  &afw_s_intermediate, afw_value_true, xctx);
383  response_content_type,
384  action_response_entry_value,
385  NULL, (void *)stream, stream->write_cb,
386  p, xctx);
387  afw_stream_flush(stream, xctx);
388  afw_object_release(action_response_entry, xctx);
389  }
390  }
391 
392  /* Set status to success. */
393  afw_object_set_property_as_string(response, &afw_s_status,
394  &afw_s_success, xctx);
395  }
396 
398 
399  /* Add error to response object. */
401  &afw_s_status, &afw_s_error, xctx);
402  error = afw_object_create_embedded(response, &afw_s_error, xctx);
403  afw_error_add_to_object(error, &this_THROWN_ERROR, xctx);
404 
405  /* If multiple actions, add actionNumber to error. */
406  if (action_number > 0) {
408  &afw_s_actionNumber, action_number, xctx);
409  }
410  }
411 
412  AFW_FINALLY{
413  impl_add_stream_properties(response, p, xctx);
414  }
415 
416  AFW_ENDTRY;
417 
418  return response;
419 }
420 
AFW_DEFINE(const afw_object_t *)
Adaptive Framework Core Internal.
afw_action_perform(const afw_object_t *request, const afw_content_type_t *response_content_type, const afw_object_t *response, const afw_pool_t *p, afw_xctx_t *xctx)
Perform actions(s) specified in AdaptiveActions object.
Definition: afw_action.c:228
afw_object_set_property_as_integer(const afw_object_t *object, const afw_utf8_t *property_name, afw_integer_t internal, afw_xctx_t *xctx)
Set property function for data type integer values.
#define afw_value_is_list(A_VALUE)
Macro to determine if value is evaluated 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.
afw_data_type_object
Data type struct for object.
afw_value_create_object(const afw_object_t *internal, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for unmanaged data type object value.
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
struct afw_iterator_s afw_iterator_t
#define AFW_UTF8_FMT_OPTIONAL_ARG(A_STRING)
Convenience Macro for use with AFW_UTF8_FMT to specify optional arg.
Definition: afw_common.h:616
#define AFW_INTEGER_FMT
Format string specifier used for afw_integer_t.
Definition: afw_common.h:326
_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
apr_size_t afw_size_t
size_t.
Definition: afw_common.h:151
apr_int64_t afw_integer_t
typedef for big signed int.
Definition: afw_common.h:321
#define afw_content_type_write_value(instance, value, options, context, callback, p, xctx)
Call method write_value of interface afw_content_type.
#define afw_content_type_is_application_afw(instance)
Determine if content type it application/x-afw.
const afw_value_function_definition_t * afw_environment_get_function(const afw_utf8_t *function_id, afw_xctx_t *xctx)
Get the function instance associated with function id.
#define AFW_FINALLY
Always executed regardless of error.
Definition: afw_error.h:702
#define AFW_CATCH_UNHANDLED
Catch an unhandled error that occurs in a AFW_TRY block.
Definition: afw_error.h:684
#define AFW_ENDTRY
Ends an AFW try block.
Definition: afw_error.h:727
void afw_error_add_to_object(const afw_object_t *object, const afw_error_t *error, afw_xctx_t *xctx)
Add error info to existing object using specified pool.
Definition: afw_error.c:862
#define AFW_TRY
Begin an AFW TRY block.
Definition: afw_error.h:634
#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
afw_boolean_t afw_flag_by_id_is_active(const afw_utf8_t *flag_id, afw_xctx_t *xctx)
Determine if flag for flag id is set in xctx.
Definition: afw_flag.c:565
afw_flag_set_to_defaults_plus_array(const afw_utf8_t *const *flag_ids, afw_xctx_t *xctx)
Set xctx default flags plus one or more additional flags.
Definition: afw_flag.c:797
#define afw_list_get_next_value(instance, iterator, p, xctx)
Call method get_next_value of interface afw_list.
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_object_get_property(instance, property_name, xctx)
Call method get_property of interface afw_object.
#define afw_object_release(instance, xctx)
Call method release of interface afw_object.
#define afw_object_create_managed(p, xctx)
Create an empty entity object in its own pool.
Definition: afw_object.h:913
#define afw_object_create(p, xctx)
Create an empty unmanaged object in memory.
Definition: afw_object.h:948
const afw_object_t * afw_object_create_merged(const afw_object_t *primary, const afw_object_t *secondary, const afw_pool_t *p, afw_xctx_t *xctx)
Create a memory object with properties from two other objects.
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
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_calloc(instance, size, xctx)
Call method calloc 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
#define afw_stream_flush(instance, xctx)
Call method flush of interface afw_stream.
#define afw_stream_standard_is_set(enum_suffix, xctx)
Determine if an xctx's standard stream is set.
Definition: afw_stream.h:134
#define afw_stream_standard(enum_suffix, xctx)
Get xctx stream instance.
Definition: afw_stream.h:122
#define afw_stream_standard_release(enum_suffix, xctx)
Release an xctx's stream.
Definition: afw_stream.h:161
void afw_utf8_stream_get_current_cached_string(const afw_stream_t *stream, afw_utf8_t *current_cached_string, afw_xctx_t *xctx)
Get the current string in a UTF-8 writer.
const afw_utf8_t * afw_utf8_clone(const afw_utf8_t *string, const afw_pool_t *p, afw_xctx_t *xctx)
Clone a utf-8 string into a specific pool.
Definition: afw_utf8.h:347
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
#define afw_value_get_info(instance, info, p, xctx)
Call method get_info of interface afw_value.
afw_value_as_array_of_utf8(const afw_value_t *value, const afw_pool_t *p, afw_xctx_t *xctx)
Return a NULL terminated list of utf8 in a specified pool.
Definition: afw_value.c:827
#define afw_value_quick_data_type(A_VALUE)
Get the easily accessible data type for a value.
Definition: afw_value.h:739
afw_value_as_utf8(const afw_value_t *value, const afw_pool_t *p, afw_xctx_t *xctx)
Definition: afw_value.c:456
afw_value_convert(const afw_value_t *value, const afw_data_type_t *to_data_type, afw_boolean_t required, const afw_pool_t *p, afw_xctx_t *xctx)
Convert a value to a value/data type.
Definition: afw_value.c:584
afw_value_is_fully_evaluated(const afw_value_t *value, afw_xctx_t *xctx)
Determine if value and all of it contained values are evaluated.
Definition: afw_value.c:218
afw_value_true
Adaptive value true.
Definition: afw_value.h:348
afw_value_as_array_of_values(const afw_value_t *value, const afw_pool_t *p, afw_xctx_t *xctx)
Return a NULL terminated list of values in a specified pool.
Definition: afw_value.c:817
Contextual information provided in some values.
const afw_utf8_t * source_location
Source location.
Interface afw_content_type public struct.
Interface afw_data_type public struct.
Interface afw_list public struct.
Interface afw_object public struct.
Interface afw_pool public struct.
Interface afw_stream public struct.
NFC normalized UTF-8 string.
Definition: afw_common.h:545
Struct for function value.
Definition: afw_value.h:102
Struct for adaptive function parameter.
Definition: afw_value.h:68
Filled in by afw_value get_info method.
Definition: afw_value.h:49
struct for data type list values.
struct for data type object values.
Interface afw_value public struct.
Interface afw_xctx public struct.