7. UDR Plugins
Data sent between agents in workflows is either represented as UDRs (Usage Detail Records) or as raw data. Raw data is sent as bytearrays, while UDRs are to be treated as individual records.
Due to the various formats of incoming data, does not provide any hardcoded formatting rules. Instead, it provides the Ultra subsystem where nearly any format may be defined and handled using the Ultra Format Definition Language (UFDL). Such definitions will automatically compile into classes, implementing the DRUDR
interface. In addition, the DTK provides the possibility of coding such classes directly in Java.
DRUDR
UDR related classes are located in the package com.digitalroute.devkit.drudr.
DRUDR
UDRs developed using the DTK must extend the DRAbstractUDR
class, which uses Java reflection to implement all DRUDR
methods, except for the actual field data manipulation. A DRUDR
class is intended to be a data carrier, and thus it will require methods for setting and retrieving user defined values, as it walks its way through a workflow. Such values are referred to as fields.
By implementing method names prefixed with the get_
and/or set_
keywords, the UDR subsystem uses Java reflection mechanisms to obtain information about available fields, such as their access type and data type. DRUDR
s contain a list of possible error codes that may be useful if UDRs are routed to ECS. Error codes may be added using addErrorCode
, examined via getErrorCodes
and removed by clearErrors
. Finally, a description of the UDR Type and its fields may be obtained using getDRUDRDesc
.
Example - Creating a UDR
A UDR is created to contain the three fields: name
, age
and isChild
. Note, it is not the variable names but the method names that determine the field names. The isChild
field will not be possible to populate since it does not have a set_
method.
Concerning writeTo / readFrom:
These are method for serializing (writeTo) and deserializing (readFrom) the UDRs for internal encoding/decoding. An implementation can be seen in the example below. Please note that the order of the fields must be the same in readFrom and writeTo. If an extra field is added later, the version can be used to make sure that both the old and the new format can be read.
public class MyUDR extends DRAbstractUDR { private final static String S_NAME = "Name"; private final static String S_AGE = "Age"; private final static String S_CONTEXT = "Context"; private final static float VERSION = 1.1f; private String _name; private int _age; Object _context; public void set_name(String newName) { _name = newName; } public String get_name() { return _name; } public void set_age(int newAge) { _age = newAge; } public int get_age() { return _age; } public void set_context(Object context) { _context = context; } public Object get_context() { return _context; } public boolean get_isChild() { // Read only field return _age < 18; } @Override public float writeTo(final DROutputStream out) throws DRException { super.writeTo(out); out.setString(S_NAME, _name); out.setInt(S_AGE, _age); out.setObject(S_CONTEXT, _context, Object.class); return VERSION; } @Override public void readFrom(final DRInputStream in, final float version) throws DRException { super.readFrom(in, version); _name = in.getString(S_NAME); _age = in.getInt(S_AGE); if (version >= 1.1f) { _context = in.getObject(S_CONTEXT, Object.class); } } }
The above UDR class can be instantiated and used as follows from DTK code:
MyUDR udr = new MyUDR(); udr.setValue("name", "Karen"); udr.setValue("age", 10); udr.setValue("isChild", true); // Will cause exception System.out.println( "Name: " + udr.getValue("name") + "Age: " + udr.getValue("age") + "Child: " + udr.getValue("isChild"));
or used as follows in APL code:
MyUDR udr = udrCreate(MyUDR); udr.name = "Karen"; udr.age = 10; udr.isChild = true; // Will cause APL compilation error debug( "Name: " + udr.name + "Age: " + udr.age + "Child: " + udr.isChild);
The Ultra format system allows the definition of nested UDRs. That is, for instance, a UDR within another UDR. Addressing fields in such UDRs is done by so called qualified names where a dot (".") separates each level.
For a DRUDR
plugin example, see:
com.digitalroute.devkit.examples.udr.*
DRUDRDesc
The DRUDRDesc
class contains information about a specific UDR Type. An instance of this class may be obtained from a DRUDR
and a list of all available UDR Types in the system from the DREnvironment
. The class offers methods such as getFields
, which returns a list of DRUDRField
instances that describe each field.
DRUDRDesc
extends the DRUDRType
class, where each returned field's type may be examined. A returned field could be a primitive field but also a nested UDR (DRUDRDesc
), a list (DRUDRListDesc
), a map (DRUDRMapDesc
), a table (DRUDRTableType
) or a byte array (DRUDRRawDataDesc
).
automatically creates DRUDRDesc
instances for all UDRs defined in the system.
DRUDRField
A DRUDRField
represents an element within a UDR. The getFieldName
method returns the element name and getType
returns the type of the element. The returned type could be a primitive field, such as a string or integer, but also a composite type, such as another DRUDRDesc
or any other DTUDRType
subtype.
If traversing a nested DRUDRDesc
, the returned field's type has to be examined and if it is of type DRUDRDesc
the a further examination needs to be performed.
DRUDRType
To be able to support type validation and automatic code generation, implements a type description system that is separate from standard Java class handling. The base class for all type descriptions is DRUDRType
, and various UDR types are described by subclasses of DRUDRDesc
.
The following table lists the available types in , their type descriptions and the runtime implementation classes.
Type | Type Description | Java Object Type |
---|---|---|
any | DRUDRType.PT_ANY() | Object |
bigint | DRUDRType.PT_BIGINT() | BigInteger |
bitset | DRUDRType.PT_BIT_SET() | DRBitSet |
boolean | DRUDRType.PT_BOOLEAN() | Boolean |
byte | DRUDRType.PT_BYTE() | byte |
bytearray | DRUDRRawDataDesc | byte[] |
char | DRUDRType.PT_CHAR() | char |
date | DRUDRType.PT_DATE() | DRDate |
float | DRUDRType.PT_FLOAT() | float |
double | DRUDRType.PT_DOUBLE() | double |
int | DRUDRType.PT_INT() | int |
ipaddress | DRUDRType.PT_IPADDRESS() | DRIPAddress |
long | DRUDRType.PT_LONG() | long |
short | DRUDRType.PT_SHORT() | short |
string | DRUDRType.PT_STRING() | String |
table | DRUDRTableType | DRTable |
list type | DRUDRListDesc | DRList |
map type | DRUDRMapDesc | Map |
General UDR type | DRUDRDesc | DRUDR subtype |
DevKit UDR type | DRUDRClassDesc | DRAbstractUDR subclass |