Accelerator Independent Data Access / PVAccess 2.0
AIDA-PVA is the latest version of the AIDA framework. Built on top of EPICS 7 it enables client applications to programmatically access and manage any device or database on the SLAC Network using simple channel names.
Loading...
Searching...
No Matches
aida_pva_server_helper.c File Reference

This file contain functions and MACROS that should be used directly Native Channel Providers. More...

#include "apdesc.h"
#include "aida_pva_server_helper.h"

Go to the source code of this file.

Functions

void aidaThrow (JNIEnv *env, vmsstat_t status, char *exception, const char *message)
 To log any exceptions and throw back to java. More...
 
void aidaThrowNonOsException (JNIEnv *env, char *exception, const char *message)
 To log any non-OS exceptions and throw back to java. More...
 
void * allocateMemory (JNIEnv *env, void *source, size_t size, bool nullTerminate, char *message)
 Allocate memory and copy the source to it if specified. More...
 
int endsWith (const char *str, char *suffix)
 Check if a string str, ends with another string suffix. More...
 
Argument getArgument (Arguments arguments, char *name)
 Get a named argument. More...
 
json_value * getJsonRoot (json_value *jsonValue)
 
json_value * getJsonValue (Value *value, char *passedInPath)
 Get the json value from the given value identified by the path. More...
 
Value getNamedArrayValue (JNIEnv *env, Arguments arguments, char *name)
 Get value from a named argument in the provided arguments structure. More...
 
Value getNamedValue (JNIEnv *env, Arguments arguments, char *name)
 Get value from a named argument in the provided arguments structure. More...
 
int groupNameFromUri (char groupName[], const char *uri)
 Get the Display group name from a URI. More...
 
vmsstat_t init (const char *processName, bool initMessageServices)
 Call standalone_init() More...
 
int pmuFromDeviceName (JNIEnv *env, char *device, char *primary, char *micro, int4u *unit)
 Get primary, micro and unit from a device name. More...
 
void pmuStringFromUri (char *pmuString, const char *uri)
 Get the pmu part of a URI. More...
 
void secnFromUri (const char *uri, int4u *secn)
 Get secondary from pseudo secondary (containing a colon) number from URI e.g. More...
 
const char * secondaryFromUri (const char *uri)
 Get secondary from URI. More...
 
unsigned long int STANDALONE_INIT (const struct dsc$descriptor_s *name, const long int *dbinit, const struct msginit *msginit, const long int *query, const long int *set)
 standalone init is used to initialise standalone processes More...
 
int startsWith (const char *str, char *prefix)
 Check if a string starts with another string. More...
 
void uriLegacyName (char legacyName[MAX_URI_LEN], const char *uri)
 Convert the given URI to the legacy AIDA name for low level functions that still require it that way. More...
 
void uriToSlcName (char slcName[MAX_URI_LEN], const char *uri)
 Convert all URIs to slac names before making queries. More...
 

Detailed Description

This file contain functions and MACROS that should be used directly Native Channel Providers.

These functions provide all of the features that allow the Channel Provider to implement its service.

MEMBER=SLCLIBS:AIDA_PVALIB ATTRIBUTES=JNI

  • MACROS to allocate, track and release memory
  • Throwing exceptions and determining if one has been thrown
  • Argument processing, except ascanf() and avscanf()
  • MACROS and functions to construct and decode URIs into their constituent parts

Definition in file aida_pva_server_helper.c.

Function Documentation

◆ aidaThrow()

void aidaThrow ( JNIEnv *  env,
vmsstat_t  status,
char *  exception,
const char *  message 
)

To log any exceptions and throw back to java.

Exception Handling.

The #exception is formatted in a standard way using the VMS status code and its associated message and the optionally supplied #message. The #exception is always assumed to be from the edu.stanford.slac.except package

Parameters
envthe JNI environment. Used in all functions involving JNI
statusthe VMS status code to luck up and display text for.
exceptionthe string representation of the exception class to throw.
messagethe optional message to attach to the exception. If NULL it is ignored.

Definition at line 92 of file aida_pva_server_helper.c.

93{
94 // Clear any exception that may be in the process of being thrown (unlikely)
95 if ((*env)->ExceptionCheck(env)) {
96 (*env)->ExceptionClear(env);
97 }
98
99 char vmsErrorMessage[BUFSIZ] = { '\0' };
100 $DESCRIPTOR(MESSAGE, vmsErrorMessage);
101 struct dsc$descriptor errorMessageDescriptor = { BUFSIZ, DSC$K_DTYPE_T, DSC$K_CLASS_S, (char*)&vmsErrorMessage };
102
103 // Get the message text associated with the VMS message code. if the cause is an OS error
104 if (!SUCCESS(status)) {
105 ERRTRANSLATE(&status, &errorMessageDescriptor);
106 strncat(errorMessageDescriptor.dsc$a_pointer, "; ",
107 MIN(strlen("; "), BUFSIZ - strlen(errorMessageDescriptor.dsc$a_pointer)));
108 }
109
110 // Add exception
111 strncat(errorMessageDescriptor.dsc$a_pointer, exception,
112 MIN(strlen(exception), BUFSIZ - strlen(errorMessageDescriptor.dsc$a_pointer)));
113
114 // If a message is specified then append it to the vms message string
115 if (message) {
116 strncat(errorMessageDescriptor.dsc$a_pointer, "; ",
117 MIN(strlen("; "), BUFSIZ - strlen(errorMessageDescriptor.dsc$a_pointer)));
118 strncat(errorMessageDescriptor.dsc$a_pointer, message,
119 MIN(strlen(message), BUFSIZ - strlen(errorMessageDescriptor.dsc$a_pointer)));
120 }
121
122 fprintf(stderr, "AIDA Exception: %s: %s\n", exception, errorMessageDescriptor.dsc$a_pointer);
123
124 // Create the fully qualified java class name of the exception to throw
125 char classToCreate[BUFSIZ] = "edu/stanford/slac/except/";
126 strcat (classToCreate, exception);
127
128 // Create the java exception class
129 jclass exceptionClass;
130 exceptionClass = (*env)->FindClass(env, classToCreate);
131 if (!exceptionClass) {
132 fprintf(stderr, "FATAL: Failed to create object of class: %s\n", classToCreate);
133 exit((int)status);
134 }
135
136 // Throw the given exception to Java server code, giving the
137 // VMS error text and supplied message as the exception text.
138 (*env)->ThrowNew(env, exceptionClass, errorMessageDescriptor.dsc$a_pointer);
139}

Referenced by aidaRequestBoolean(), aidaRequestBooleanArray(), aidaRequestByte(), aidaRequestByteArray(), aidaRequestDouble(), aidaRequestDoubleArray(), aidaRequestFloat(), aidaRequestFloatArray(), aidaRequestInteger(), aidaRequestIntegerArray(), aidaRequestLong(), aidaRequestLongArray(), aidaRequestShort(), aidaRequestShortArray(), aidaRequestString(), aidaRequestTable(), aidaServiceInit(), aidaSetValue(), aidaSetValueWithResponse(), and aidaThrowNonOsException().

◆ aidaThrowNonOsException()

void aidaThrowNonOsException ( JNIEnv *  env,
char *  exception,
const char *  message 
)

To log any non-OS exceptions and throw back to java.

The #exception is formatted in a standard way with the optionally supplied #message. The #exception is always assumed to be from the edu.stanford.slac.except package

Parameters
envthe JNI environment. Used in all functions involving JNI
exceptionthe string representation of the exception class to throw.
messagethe optional message to attach to the exception. If NULL it is ignored.

Definition at line 75 of file aida_pva_server_helper.c.

76{
77 aidaThrow(env, 1, exception, message);
78}
void aidaThrow(JNIEnv *env, vmsstat_t status, char *exception, const char *message)
To log any exceptions and throw back to java.

References aidaThrow().

Referenced by aidaRequestBoolean(), aidaRequestBooleanArray(), aidaRequestByte(), aidaRequestByteArray(), aidaRequestDouble(), aidaRequestDoubleArray(), aidaRequestFloat(), aidaRequestFloatArray(), aidaRequestInteger(), aidaRequestIntegerArray(), aidaRequestLong(), aidaRequestLongArray(), aidaRequestShort(), aidaRequestShortArray(), aidaRequestString(), aidaRequestStringArray(), aidaRequestTable(), aidaSetValue(), aidaSetValueWithResponse(), allocateMemory(), getClassAndValueOfMethod(), newObject(), newObjectFromClass(), pmuFromDeviceName(), tableAddColumn(), tableAddField(), tableAddLabel(), tableCreate(), toBoolean(), toBooleanArray(), toByte(), toByteArray(), toDouble(), toDoubleArray(), toFloat(), toFloatArray(), toInteger(), toIntegerArray(), toLong(), toLongArray(), toShort(), toShortArray(), toStringArray(), and toTable().

◆ allocateMemory()

void * allocateMemory ( JNIEnv *  env,
void *  source,
size_t  size,
bool  nullTerminate,
char *  message 
)

Allocate memory and copy the source to it if specified.

Memory Handling.

If the null terminate flag is set null terminate the allocate space, at the last position

Parameters
envto be used to throw exceptions using aidaThrow() and aidaThrowNonOsException()
sourcesource of data to copy to newly allocated space, NULL to not copy
sizethe amount of space to allocate
nullTerminatetrue to null terminate
messagethe message to display if anything goes wrong
Returns
the allocated memory

Definition at line 629 of file aida_pva_server_helper.c.

630{
631 void* data = malloc(size);
632 if (!data) {
634 return NULL;
635 }
636 if (source) {
637 memcpy(data, source, size - (nullTerminate ? 1 : 0));
638 if (nullTerminate) {
639 *(char*)((char*)data + size - 1) = 0x0;
640 }
641 }
642 return data;
643}
#define AIDA_INTERNAL_EXCEPTION
Use this string to signal Internal Exceptions in aidaThrow()
void aidaThrowNonOsException(JNIEnv *env, char *exception, const char *message)
To log any non-OS exceptions and throw back to java.

References AIDA_INTERNAL_EXCEPTION, and aidaThrowNonOsException().

◆ endsWith()

int endsWith ( const char *  str,
char *  suffix 
)

Check if a string str, ends with another string suffix.

String Handling.

Parameters
strthe string to check.
suffixthe suffix to look for at the end of str
Returns
true if str ends with suffix. false

Definition at line 148 of file aida_pva_server_helper.c.

149{
150 if (!str || !suffix) {
151 return false;
152 }
153 size_t lenstr = strlen(str);
154 size_t lenSuffix = strlen(suffix);
155 if (lenSuffix > lenstr)
156 return false;
157 return !strncasecmp(str + lenstr - lenSuffix, suffix, lenSuffix);
158}

Referenced by aidaRequestBoolean(), aidaRequestBooleanArray(), aidaRequestByte(), aidaRequestByteArray(), aidaRequestDouble(), aidaRequestDoubleArray(), aidaRequestFloat(), aidaRequestFloatArray(), aidaRequestInteger(), aidaRequestIntegerArray(), aidaRequestLong(), aidaRequestLongArray(), aidaRequestShort(), aidaRequestShortArray(), aidaRequestString(), aidaRequestStringArray(), aidaRequestTable(), and aidaSetValueWithResponse().

◆ getArgument()

Argument getArgument ( Arguments  arguments,
char *  name 
)

Get a named argument.

Parameters
argumentsarguments
namename
Returns
Argument

Definition at line 184 of file aida_pva_server_helper.c.

185{
186 Argument noArgument;
187 memset(&noArgument, 0, sizeof(Argument));
188
189 for (int i = 0; i < arguments.argumentCount; i++) {
190 Argument argument = arguments.arguments[i];
191 if (!strcasecmp(argument.name, name)) {
192 if (strlen(argument.value) > 0) {
193 return argument;
194 }
195 }
196 }
197 return noArgument;
198}
A single request argument.
char * value
The string value of the argument.
char * name
The name of the argument.
int argumentCount
The number of arguments sent with this request.
Argument * arguments
The array of Arguments.

References Arguments::argumentCount, Arguments::arguments, Argument::name, and Argument::value.

◆ getJsonRoot()

json_value * getJsonRoot ( json_value *  jsonValue)
Skip root element if it is _array otherwise return unchanged

This is because our json parser can't process arrays at the top level and so we insert
an object at the top level with an "_array" element if we find an array at the top level
Parameters
jsonValuethe json value traverse
Returns
json value

Definition at line 404 of file aida_pva_server_helper.c.

405{
406 if (jsonValue->type == json_object && jsonValue->u.object.length == 1
407 && strcmp(jsonValue->u.object.values[0].name, "_array") == 0) {
408 jsonValue = jsonValue->u.object.values[0].value;
409 }
410 return jsonValue;
411}

Referenced by getJsonValue().

◆ getJsonValue()

json_value * getJsonValue ( Value value,
char *  passedInPath 
)

Get the json value from the given value identified by the path.

Parameters
valuethe given value
passedInPathis an absolute reference to the element within the json of the given value. e.g. root.collection.[0].name
Returns
pointer to the json_value

Definition at line 347 of file aida_pva_server_helper.c.

348{
349 if (value->type != AIDA_JSON_TYPE || !value->value.jsonValue) {
350 return NULL;
351 }
352
353 json_value* jsonValue = getJsonRoot(value->value.jsonValue);
354
355 // If there is no path then we already have the json value
356 if (!passedInPath || strlen(passedInPath) == 0) {
357 return jsonValue;
358 }
359
360 // can't use const for strtok
361 char path[strlen(passedInPath) + 1];
362 strcpy(path, passedInPath);
363
364 int len;
365 char name[256];
366 char* arrayRef;
367
368 // Extract the first token
369 char* token = strtok(path, ".");
370
371 while (token) {
372 if (*token == '[') {
373 // if array is at top level
374 jsonValue = processArrayReference(jsonValue, token);
375 } else if ((arrayRef = strstr(token, "["))) {
376 // element followed by array ref
377 len = (int)(arrayRef - token);
378 strncpy(name, token, len);
379 name[len] = 0x0;
380 jsonValue = navigateToObjectElement(jsonValue, name);
381
382 jsonValue = processArrayReference(jsonValue, arrayRef);
383 } else {
384 // element only
385 jsonValue = navigateToObjectElement(jsonValue, token);
386 }
387
388 // Next token
389 token = strtok(NULL, ".");
390 }
391
392 return jsonValue;
393}
json_value * getJsonRoot(json_value *jsonValue)
@ AIDA_JSON_TYPE
Argument was provided as JSON text.
ValueContents value
The value's contents, either a string or parsed json.
Type type
AIDA_STRING_TYPE or AIDA_JSON_TYPE.
json_value * jsonValue
The parsed json_value of this Value if the type is AIDA_JSON_TYPE.

References AIDA_JSON_TYPE, getJsonRoot(), ValueContents::jsonValue, Value::type, and Value::value.

◆ getNamedArrayValue()

Value getNamedArrayValue ( JNIEnv *  env,
Arguments  arguments,
char *  name 
)

Get value from a named argument in the provided arguments structure.

Get array value from a named argument in the provided arguments structure.

Parameters
envthe JNI environment. Used in all functions involving JNI
argumentsprovided arguments structure
nameprovided name
Returns
the extracted Value

Definition at line 335 of file aida_pva_server_helper.c.

336{
337 return getNamedValueImpl(env, arguments, name, true);
338}

Referenced by getArrayValue().

◆ getNamedValue()

Value getNamedValue ( JNIEnv *  env,
Arguments  arguments,
char *  name 
)

Get value from a named argument in the provided arguments structure.

Parameters
envthe JNI environment. Used in all functions involving JNI
argumentsprovided arguments structure
nameprovided name
Returns
the extracted Value

Definition at line 322 of file aida_pva_server_helper.c.

323{
324 return getNamedValueImpl(env, arguments, name, false);
325}

Referenced by getValue().

◆ groupNameFromUri()

int groupNameFromUri ( char  groupName[],
const char *  uri 
)

Get the Display group name from a URI.

URI Handling for group, secn, pmu and slacName.

Parameters
groupNamepre-allocated space to store the group name
urithe new format AIDA PV name
Returns
EXIT_SUCCESS if all goes well EXIT_FAILURE otherwise

Definition at line 472 of file aida_pva_server_helper.c.

473{
474 strcpy(groupName, uri);
475 char* groupNameEnd = strrchr(groupName, ':');
476 if (groupNameEnd) {
477 *groupNameEnd = 0x0;
478 }
479 return EXIT_SUCCESS;
480}

◆ init()

vmsstat_t init ( const char *  processName,
bool  initMessageServices 
)

Call standalone_init()

Initialisation.

Parameters
processNamethe name of the process being initialised
initMessageServicesboolean to determine if the message service needs to be initialised
Returns
vms status code

Definition at line 50 of file aida_pva_server_helper.c.

51{
52 const struct msginit msg_init_s = { 1, /* init msg service */
53 1 }; /* init slcnet */
54
55 vmsstat_t status;
56 $DESCRIPTOR (PROCESS_NAME, processName); // Ignored in standalone_init() call
57
58 status = STANDALONE_INIT(&PROCESS_NAME, &((long)(TRUE)),
59 initMessageServices ? &msg_init_s : NULL,
60 &((long)(FALSE)), &((long)(FALSE)));
61
62 return status;
63}
unsigned long int STANDALONE_INIT(const struct dsc$descriptor_s *name, const long int *dbinit, const struct msginit *msginit, const long int *query, const long int *set)
standalone init is used to initialise standalone processes

References STANDALONE_INIT().

Referenced by aidaServiceInit().

◆ pmuFromDeviceName()

int pmuFromDeviceName ( JNIEnv *  env,
char *  device,
char *  primary,
char *  micro,
int4u *  unit 
)

Get primary, micro and unit from a device name.

Parameters
envthe JNI environment. Used in all functions involving JNI
devicepre-allocated space to store the device
primarypre-allocated space to store the primary
micropre-allocated space to store the micro
unitpre-allocated space to store the unit

Definition at line 542 of file aida_pva_server_helper.c.

543{
544 // Copy each part to the provided variables
545 char* nextPart = strtok(device, ":");
546 unsigned long len;
547 if (nextPart) {
548 len = strlen(nextPart);
549 if (len != 4) {
550 aidaThrowNonOsException(env, UNABLE_TO_GET_DATA_EXCEPTION, "Device name is not valid");
551 return EXIT_FAILURE;
552 }
553 memcpy(primary, nextPart, PRIM_LEN);
554 nextPart = strtok(NULL, ":");
555 if (nextPart) {
556 len = strlen(nextPart);
557 if (len != 4 || !isdigit(nextPart[2]) || !isdigit(nextPart[3])) {
558 aidaThrowNonOsException(env, UNABLE_TO_GET_DATA_EXCEPTION, "Device name is not valid");
559 return EXIT_FAILURE;
560 }
561 memcpy(micro, nextPart, MICRO_LEN);
562 nextPart = strtok(NULL, ":");
563 if (nextPart) {
564 len = strlen(nextPart);
565 if (len < 1 || len > 4 || !isdigit(nextPart[0]) || (len > 1 && !isdigit(nextPart[1]))
566 || (len > 2 && !isdigit(nextPart[2])) || (len > 3 && !isdigit(nextPart[3]))) {
567 aidaThrowNonOsException(env, UNABLE_TO_GET_DATA_EXCEPTION, "Device name is not valid");
568 return EXIT_FAILURE;
569 }
570 *unit = (int4u)atol(nextPart);
571 }
572 }
573 }
574 return EXIT_SUCCESS;
575}
#define UNABLE_TO_GET_DATA_EXCEPTION
Use this string to signal Exceptions when trying to Get Data in aidaThrow()
#define PRIM_LEN
The length of the primary part of a PMU string.
Definition: aida_pva_uri.h:24
#define MICRO_LEN
The length of the micro part of a PMU string.
Definition: aida_pva_uri.h:28

References aidaThrowNonOsException(), MICRO_LEN, PRIM_LEN, and UNABLE_TO_GET_DATA_EXCEPTION.

Referenced by aidaRequestTable().

◆ pmuStringFromUri()

void pmuStringFromUri ( char *  pmuString,
const char *  uri 
)

Get the pmu part of a URI.

Parameters
pmuStringthe pre-allocated space to store the pmu string
urithe new format AIDA PV name

Definition at line 523 of file aida_pva_server_helper.c.

524{
525 unsigned long pmuEnd = strrchr(uri, ':') - uri;
526 if (pmuEnd >= MAX_URI_LEN) {
527 pmuEnd = MAX_URI_LEN - 1;
528 }
529 strncpy(pmuString, uri, pmuEnd);
530 pmuString[pmuEnd] = 0x0;
531}
#define MAX_URI_LEN
The maximum length of a URI.
Definition: aida_pva_uri.h:20

References MAX_URI_LEN.

◆ secnFromUri()

void secnFromUri ( const char *  uri,
int4u *  secn 
)

Get secondary from pseudo secondary (containing a colon) number from URI e.g.

Get secondary from pseudo secondary (containing a colon) number from URI.

BD01:BEND:BDES => BEND as int4u

Parameters
urithe new format AIDA PV name
secnpointer to an int to store the secondary as a number

Definition at line 489 of file aida_pva_server_helper.c.

490{
491 char uriCopy[strlen(uri) + 1];
492 strcpy(uriCopy, uri);
493 char* secondary = strrchr(uriCopy, ':');
494 if (secondary) {
495 memcpy(secn, secondary + 1, sizeof(int4u));
496 return;
497 }
498 fprintf(stderr, "Warning: Found corrupt URI when trying to extract secn: %s\n", uri);
499 *secn = 0;
500}

◆ secondaryFromUri()

const char * secondaryFromUri ( const char *  uri)

Get secondary from URI.

Just points into the URI so don't go messing with it

Parameters
urithe new format AIDA PV name

Definition at line 507 of file aida_pva_server_helper.c.

508{
509 char* secondary = strrchr(uri, ':');
510 if (!secondary) {
511 fprintf(stderr, "Warning: Secondary not found in uri: %s\n", uri);
512 return uri;
513 }
514 return secondary + 1;
515}

Referenced by aidaRequestStringArray().

◆ STANDALONE_INIT()

unsigned long int STANDALONE_INIT ( const struct dsc$descriptor_s *  name,
const long int *  dbinit,
const struct msginit *  msginit,
const long int *  query,
const long int *  set 
)

standalone init is used to initialise standalone processes

Parameters
nameprocess name
dbinitdbinit
msginitmsginit
queryquery
setset
Returns
status

Referenced by init().

◆ startsWith()

int startsWith ( const char *  str,
char *  prefix 
)

Check if a string starts with another string.

Parameters
str
prefix
Returns
true if string starts with prefix

Definition at line 166 of file aida_pva_server_helper.c.

167{
168 if (!str || !prefix) {
169 return false;
170 }
171 size_t lenstr = strlen(str);
172 size_t lenPrefix = strlen(prefix);
173 if (lenPrefix > lenstr)
174 return false;
175 return !strncasecmp(str, prefix, lenPrefix);
176}

Referenced by aidaRequestLong(), aidaRequestShort(), aidaRequestString(), aidaRequestStringArray(), and aidaSetValue().

◆ uriLegacyName()

void uriLegacyName ( char  legacyName[MAX_URI_LEN],
const char *  uri 
)

Convert the given URI to the legacy AIDA name for low level functions that still require it that way.

Parameters
legacyNamepointer to space to store the legacy AIDA name
urithe new format AIDA PV name

Definition at line 599 of file aida_pva_server_helper.c.

600{
601 char* firstSeparator = strchr(uri, ':');
602 char* secondSeparator = strchr(firstSeparator + 1, ':');
603 char* lastSeparator = strrchr(uri, ':');
604 // See how many colons. If only three then this is a pseudo and we need to separate after first
605 if (lastSeparator == secondSeparator) {
606 // This has only three parts so separate at first colon
607 memcpy(legacyName, uri, firstSeparator - uri);
608 memcpy(legacyName + (firstSeparator - uri), "//", 2);
609 strcpy(legacyName + (firstSeparator - uri) + 2, firstSeparator + 1);
610 } else {
611 // Normal URI separate at last colon
612 memcpy(legacyName, uri, lastSeparator - uri);
613 memcpy(legacyName + (lastSeparator - uri), "//", 2);
614 strcpy(legacyName + (lastSeparator - uri) + 2, lastSeparator + 1);
615 }
616}

◆ uriToSlcName()

void uriToSlcName ( char  slcName[MAX_URI_LEN],
const char *  uri 
)

Convert all URIs to slac names before making queries.

Parameters
slcNamepointer to space to store the SLC name
urithe new format AIDA PV name

Definition at line 583 of file aida_pva_server_helper.c.

584{
585 char* separator = strrchr(uri, ':');
586 if (separator) {
587 memcpy(slcName, uri, separator - uri);
588 memcpy(slcName + (separator - uri), ".", 1);
589 strcpy(slcName + (separator - uri) + 1, separator + 1);
590 }
591}