Advanced
Data access
To configure access to a data operation, create a DataAccessRight instance with the element on which the data operation is defined.
For the functionality prefix the name of the dataOperation with .operation
E.g. to allow users to perform the retryDocumentGeneration data operation on the Invoice data element of the Booking component, enter the following:
| field | value |
|---|---|
| forProfile | user |
| element | "booking_invoice" |
| functionality | "operation.retryDocumentGeneration" |
| authorized | "true" |
Nested parameter objects
We have previously seen parameter objects are defined as groups. This allows us to specify nested structures!
The first parameterGroup in a DataOperation will not have a name, we call this the root group. The parameter object will always start at the root and follow its parameters from there. A special GroupParameter is used to define a parameter which points to another group, effectively creating a nesting.
<dataOperation>
<parameterGroups>
<parameterGroup>
<parameters>
<parameter type="operations::TypedParameter">
<name>name</name>
<type>String</type>
</parameter>
<parameter type="operations::GroupParameter">
<name>addresses</name>
<targetGroup>component::DataElement::DataOperation::address</targetGroup>
</parameter>
</parameters>
</parameterGroup>
<parameterGroup>
<name>address</name>
<parameters>
<parameter type="operations::TypedParameter">
<name>street</name>
<type>String</type>
</parameter>
<parameter type="operations::TypedParameter">
<name>country</name>
<type>String</type>
</parameter>
</parameters>
</parameterGroup>
</parameterGroups>
</dataOperation>
name: string
addresses:
- street: string
country: string
The nesting of ParameterGroups is especially useful when defining operations like the BatchUpdateOperation when you want to specify different values for each element.
Error handling
To provide a clear interface we need to handle our errors carefully. To allow granular definition and re-use of errors
we model ErrorCode and ErrorCorrelation. Error codes define a technology-agnostic error while error correlations map
this to technology specific errors.
Take internal_error for example, it is defined as:
<dataResource type="operations::ErrorCode">
<errorCode>
<code>internal_error</code>
<description>Internal server error</description>
</errorCode>
</dataResource>
And correlated to Java Exceptions with:
<dataResource type="operations::ErrorCorrelation">
<errorCorrelation>
<name>jdk:logic:internal_error</name>
<technology>JDK</technology>
<layerType>LOGIC_LAYER</layerType>
<errorCode>internal_error</errorCode>
<definition>java.lang.RuntimeException</definition>
<options>
<error.jdk.exception.unchecked/>
</options>
</errorCorrelation>
</dataResource>
This tells the expanders it should catch java.lang.RuntimeException any time a DataOperation has the internal_error.
To make things a bit easier, many errors are added by default:
unexpected_errorwhen exceptions are thrown in places we don't expect them.internal_errorwhen some runtime exception occurs during the operation.diagnostic_errorwhen a CRUD operation has issues, it usually reports this through Diagnostics. These can be mapped to an exception to make handling them easier and provide a stack trace as close as possible to the issue.
You can define additional ErrorCodes and ErrorCorrelations as a child of Component.