Ultra
Ultra
8.1
The contents of this document are subject to revision without further notice due to continued progress in methodology, design, and
manufacturing.
Digital Route AB shall have no liability for any errors or damage of any kind resulting from the use of this document.
DigitalRoute® and MediationZone® are registered trademarks of Digital Route AB. All other trade names and marks mentioned herein are
the property of their respective holders.
Table of Contents
1. Format Management Overview 5
2. Ultra Format Configuration 7
3. UDR File Editor 12
3.1 Editing a UDR 13
3.2 Editing a Bulk of UDRs 15
4. UDR Views 19
5. Ultra Format Converter 21
6. Introduction to the Ultra Format Definition Language 23
6.1 Building Blocks 23
6.2 The Ultra Module 29
7. External - Sequential Format 32
7.1 Record Declaration 32
7.2 Field Declarations 34
7.3 Expressions 43
8. External - Ericsson IOG/IN Records 44
9. External - ASN.1 Formats 45
10. Internal Formats 49
11. In-maps 52
11.1 Examples of Non-Automatic Maps 53
11.2 Automatic Maps 54
11.3 discard_output Specification 58
12. Decoders 59
13. Out-maps 61
14. Encoders 63
15. A Constructed Decoder Example 64
16. A Sequential Format Example 68
17. An ASN.1 Format Example 72
18. XML Schema Support 78
18.1 Overview 78
18.2 External - XML Records 79
18.2.1 XML Data Type Mapping 79
18.2.2 AnyType UDR Type 80
18.2.3 XML Schema Extensions 80
18.3 IPDR Compliance 80
18.4 XML Schema Limitations 81
18.5 An XML Format Example 81
19. Google Protocol Buffer Support 84
20. Avro Support 89
Ultra Reference Guide
This document describes the Ultra Format Management utilities of the MediationZone Platform.
This user's guide includes a detailed description of the Ultra Format Definition Language and how to create format definitions in the
language syntax.
4
1. Format Management Overview
MediationZone is capable of handling various Usage Detail Record (UDR) formats provided that their structure is known. Vendor UDR
formats are often complex and hard to work with in agents that will view or manipulate data. Therefore, MediationZone converts the
external UDR formats to an internal representation, and vice versa when UDRs are leaving the system.
In order to make this conversion, both internal and external format definitions have to be defined. When the definitions exist, there must be
a mapping description that maps each external field of interest to an internal field.
Ultra does not require a one-to-one relationship between external and internal field names. Normally, only fields of interest or those that are
needed when leaving the system are declared in the internal format definition. Often the internal definition holds additional fields that are
initially empty and then populated on the way through a workflow. MediationZone does not constrain how these fields are used.
In this example the external field E1C is not needed and not mapped at all. Internally IFA and IFB are manipulated. IFE is given
a value, probably depending on values defined in IFC and IFD during the UDRs way through the workflow. At exit, the two
original fields are mapped into E2A and E2B plus the new (IFE) into E2C.
MediationZone introduces a language called Ultra Format Definition Language (UFDL) that is used when describing UDR formats and
mappings.
Apart from describing external formats, internal formats and mappings, the UFDL requires separate decoder and encoder specifications. A
decoder or encoder refers to one or several mappings that are used for the actual translation.
Format Storage
In order to operate on UDRs, there must be a compiled version (Java class) of the internal format definition available in the Code or Ultra
server. Such Java classes are introduced into the servers in two different ways:
1. Format definitions entered in the Ultra Format Editor are compiled and inserted in the Ultra server when saved.
2. Precompiled format definitions (for instance; Radius, NetFlow, and SNMP protocols) are inserted in the Code server during
package commit.
A format can be recompiled while workflows using it are running. In this case, the changes to the format will take effect the next time the
workflow is activated.
All Java classes generated by the Ultra server are kept in the system. This is to make UDRs, for instance stored in ECS, using the old
format version reprocessable. For further information, see 5. Ultra Format Converter.
5
Note!
Saving a format in the Ultra Format Editor may take some time, since the system may have to re-validate and regenerate many
dependent configurations.
If an Ultra format is moved to another directory, or is renamed, the configurations using the format will become invalid.
MZ Tagged Formats
There are two built-in external formats that can be used between workflows, typically by Inter Workflow agents; MZ Tagged Format and
MZ Tagged (compressed). Using the compressed format will reduce the size of the UDRs significantly. However, since compression
will require more CPU, you should consider the trade off between I/O and CPU when choosing encoder. No Decoder or Encoder needs to
be defined in Ultra to handle these formats.
The MZ Tagged formats contain header data that is based on the time zone settings of the host on which it was generated. This is
important to consider when you compare output from identical workflows that are running on hosts with different time zone settings. The
binary data may differ due to the header content.
Decoding of an UDR
The Ultra engine is designed to decode only the necessary parts of an Usage Detail Record, UDR, to keep workflow performance as high
as possible. By default (that is, provided that Full Decode is not selected), the decoder will only decode enough to calculate the size of the
UDRs. The UDR content will be decoded as the field values are accessed. Hence, if there is a decoding error, this may not be discovered
by the decoder however by the agent accessing a specific field.
Note!
Full decoding of complicated nested UDR structures can be time consuming. In most cases the performance cost of this option
is however small.
6
2. Ultra Format Configuration
The Ultra Format Editor allows users to introduce format definitions in the system to be used by agents in workflows. Definitions are
described using the Ultra Format Definition Language (UFDL).
A saved format definition will have its name displayed in the title. Other than selecting Decoder, Encoder, and UDR Type definitions,
formats can be imported from APL code, as well as directly from other Ultra definitions:
To open the editor, click the New Configuration button in the upper left part of the MediationZone Desktop dialog, and then select Ultra
Format from the menu.
Syntax Highlighting
In the code area, the different parts of the code are color coded according to type, for easier identification, and when right-clicking in the
code area, a context sensitive popup menu appears, enabling easy access to the most common actions you might want to perform.
Blue - Functions
Green - Types
Orange - Comments
Yellow/Green - Values
The menu items that are specific for Ultra Format Editor are described in the following sections:
7
The File Menu
Item Description
Import... Select this option to import code from an external file. Note that the file has to reside on the host where the client is running.
Export... Select this option to export your code to an *.ufl file that can be edited in other code editors, or be used by other
MediationZone systems.
Validate Compiles the current Ultra code, checking for grammatical and syntactical errors. The status of the compilation is displayed in
a dialog. Upon failure, the erroneous line is highlighted and a message, including the line number, is displayed.
Redo Select this option to redo the last action you "undid" with the Undo option.
Find... Displays a dialog where chosen text may be searched for and, optionally, replaced
Find Repeats the search for the last string entered in the Find dialog
Again
8
The View Menu
Item Description
History Each time a configuration is saved, a new version is created. Many versions of a configuration may exist but only the last
version can be modified and executed. The old versions are kept for log and rollback reasons. Select History to examine
old configurations in the Historical Configurations panel. The panel will appear at the bottom of the Configuration tab and
holds a list of all versions. Arrow buttons are used to step back and forward between the different versions. Rollback to an
old version of a configuration is handled by opening and saving the old version. A comment is automatically added, stating
that the current version was created from a historic one.
A configuration history
References Click to see the Reference Viewer listing references to and from the active configuration. The Reference Viewer includes
the following tabs:
Used By: Displays a list of other configurations that refer to the configuration. For example: a workflow group that
refers to a workflow.
Uses: Displays a list of other configurations that the configuration refers to. For example: a workflow configuration
that refers to a specific profile.
Access: Displays the group of users that may access the configuration, and the user that created (owns) the
configuration.
The additional buttons that are specific for Ultra Format Editor tabs are described in the following sections:
9
Buttons Description
Validate Compiles the current Ultra code, checking for grammatical and syntactical errors. The status of the compilation is displayed
in a dialog. Upon failure, the erroneous line is highlighted and a message, including the line number, is displayed.
Redo Select this option to redo the last action you "undid" with the Undo option.
Find... Displays a dialog where chosen text may be searched for and, optionally, replaced
Find Again Repeats the search for the last string entered in the Find dialog
Zoom Out Zoom out the code area by modifying the font size. The default value is 12(pt). Clicking the button between the Zoom Out
and Zoom In buttons will reset the zoom level to the default value. Changing the view scale does not affect the
configuration.
Zoom In Zoom in the code area by modifying the font size. The default value is 12(pt). Clicking the button between the Zoom Out
and Zoom In buttons will reset the zoom level to the default value. Changing the view scale does not affect the
configuration.
To hide or display the Configuration Diff panel, click the vertical Diff button to the right of the Ultra Format Editor. The panel can be
hidden or visible. By default, it is hidden.
10
Ultra Format Editor - Configuration Diff panel
You can navigate through the differences by scrolling both panes in parallel using the scroll bar to the right of either pane. If you want to
scroll through each pane separately, hover over the pane that you want to scroll through, and use the scroll wheel on your mouse.
If you want to skip through each difference in the panes, you can use the navigation buttons, Previous, Next and Refresh, which are
described below.
Item Description
History Click the History drop box to select the version to which you want to compare the version currently displayed.
You can also display and view encrypted configurations. If you select an encrypted configuration, you are prompted to enter
the relevant password to decrypt the configuration.
Previous Click this button to skip to the previous difference in the configurations. The previous difference is highlighted in green.
Next Click this button to skip to the next difference in the configurations. The next difference is highlighted in green.
Refresh Click this button to display the updated version of the configuration. Configurations are not locked when you display them in
Configuration Diff. If another user has modified and saved a configuration that you are viewing in this tool, you can click this
button to view the latest updated version.
11
3. UDR File Editor
The UDR File Editor allows the user to view and edit the content of UDR files.
The UDR file may be of any format as long as it has an associated decoder. The Open dialog enables decoder selection. Correspondingly,
the Save dialog includes a selection of encoders to use.
Since UDRs often contain a large number of fields, it is possible to create a UDR View to select fields and be viewed directly as columns in
the UDR list (select UDR View... in the Edit menu). Each UDR can also be opened in a separate dialog where all fields are available.
Note!
The UDR File Editor will by default only support input files up to size 3MB. If the file size exceeds this limit, the UDR File Editor
will only read up to 3MB of the file and then stop, showing only the read records.
To support decoding of files larger than 3MB, the Desktop property mz.gui.udreditor.limit must be set for the
corresponding Desktop. See 2.6.9 Desktop Properties in the System Administration User's Guide. Setting the property to yes
means the 3MB limit applies. Setting the property to no will bypass the limitation mechanism, which may potentially cause out of
memory errors in the Desktop.
Several UDR file editors can be used simultaneously, however avoid editing the same UDR from several different editors, since
there is no functionality to handle real-time co-authoring.
To open the UDR File Editor, click the Tools button in the upper left part of the MediationZone Desktop window, and then select UDR File
Editor from the menu.
Setting Description
UDR A list from which a UDR view may be selected. A UDR view is a user defined filter which displays additional columns
View containing UDR field data. If(None) is selected, the list will consist of two columns only: Pos and Type. However, if a file is
opened, a third column Orig Pos will become visible as well. For further information, see 4. UDR Views.
Orig Pos Shows the original position of the UDR. New indicates that the UDR did not exist prior to the last Save.
Pos The current position of the UDR. The order applies upon saving.
Field All columns following the Type column, will list the field names of the UDR type according to the UDR view selection. If there
Name is no field with the defined name, No such field is stated.
12
Ultra File Editor Menu
The main menu changes depending on which Configuration type that has been opened in the currently active tab. There is a set of
standard menu items that are visible for all configurations and these are described in 2.1 Menus and Buttons in the Desktop User's Guide.
The menu items that are specific for UDR File Editor are described in the following sections:
File Menu
Item Description
Open... Displays a dialog where the local file system can be browsed for files to open. The Decoder used for reading the file is also
configured here.
Full Decode is enabled by default, which ensures that any decoding errors are detected when the file is read. If this option is
disabled, decoding errors may not be detected until the UDR fields are accessed.
Export Saves the selected UDRs in an ASCII file, which may be opened in any text editor. All UDRs are displayed as rows, where the
fields are separated by any of the following:
Comma
Semicolon
Tab
Non-existing fields are marked [null]. The first line will always hold the field names.
Print Prints a summary table based on the current UDR selection (the Table option). It is also possible to get a detailed printout (the
Details option). In the latter case the UDRs will be presented the way they appear when you click on the Edit button.
Edit Menu
Item Description
Bulk Opens a new dialog from which a group of selected UDRs can be edited simultaneously. For further information, see 3.2
Edit... Editing a Bulk of UDRs.
UDR A list from which a UDR view may be selected. A UDR view is a user defined filter which displays additional columns
View containing UDR field data. If(None) is selected, the list will consist of two columns only: Pos and Type. However, if a file is
opened, a third column Orig Pos will become visible as well. For further information, see 4. UDR Views.
13
3.1 Editing a UDR
Double-clicking a UDR will result in a new dialog, containing the complete UDR which allows the contained data to be edited.
Item Description
Name The name of the UDR fields. A black field (MANDATORY) can be edited, however, Present cannot be disabled. A red field
(OPTIONAL) can be edited as well as set to Present. Note that removing a field containing sub-fields and then creating it
again will not recreate the sub-fields. The same applies to elements in a list field.
The special field OriginalData holds the raw UDR input data.
Value Holds the field values. To edit a value, select the value and enter the new value.
Present Shows whether the fields are present in the UDR View or not
Show Only displays present fields (as specified by the Present flag)
Only
Present
Place the pointer on the Name column and right-click to select either Add Entry, Remove Entry... or Create UDR.
Place the pointer on the Value column and right-click to select Advanced Edit....
14
Edit UDR dialog - editing byte array fields
Setting Description
Advanced Opens up a new dialog, where the field value may be changed. To append values, click on the subsequent byte and type in
Edit... the value. In this case (byte array) only hexadecimal digits are allowed.
15
The Bulk Editor
Setting Description
Auto Edit This mode allows the editing of a bulk of UDRs using matchers and assignments. For further information, see the section
below, Bulk Edit - Auto Edit Mode.
Manual Selecting this feature will disable both the Matchers and Assignments, and allow the user to write custom APL code in the
APL Edit APL View that becomes visible below. For further information, see the section below, Bulk Edit - Manual APL Edit.
Activation This section shows the Target UDR Count and an Edit button.
If you click on the Edit button, the Bulk Edit Result dialog will open, if the configuration is valid, showing the type of changes
performed.
Matchers Defines the UDRs targeted for update. For further information about adding Matchers, see the section below, Add
Matcher.
Join Style Indicates if All or Any will apply to the conditions in the Matchers list
Assignments Defines the changes to be made to the targeted UDRs. For further information about adding Assignments, see the
section below, Add Assignment.
Add Matcher
A Matcher is added by selecting Add in the Matchers section. The following dialog is displayed:
16
Setting Description
UDR Field List of available fields to use as matchers. Depending on the field type, the Matcher Type list updates to display valid
choices.
Matcher Defines the check criterion for the field. The content of the list varies depending on the field type. Supported types and
Type some of their possible matchers are:
Parameter Some field types can consist of several parts. For instance, date types can contain separate values for year, month, and
day. Regular numeric/alphanumeric fields will have Value stated.
Is APL Indicates the possibility to enter variable values for the validation field via the use of APL code in the Value column. This
feature makes it possible to refer to other fields within the same UDR (as well as call to APL functions) during processing.
In the image below, the P155_PackageLength field is of type int.
Add Matcher
Value The value of the field. By default, a constant is entered. If Is APL is selected, APL syntax can be used to create a variable
definition.
Add Assignment
An Assignment is added by selecting Add in the Assignments section. The following dialog is displayed:
17
Setting Description
UDR Field List of available fields for assignment. Depending on the field type, the Assignment Type list will update to display valid
choices.
Assignment Defines the changes to be made to the field. The content of the list varies depending on the field type. Supported types
Type and some of their possible assignments:
Parameter Some field types can consist of several parts. For instance, date types can contain separate values for year, month, and
day. Regular numeric/alphanumeric fields will have Value stated.
If the field is a bytearray, a hex editor will open when you click in the Value cell where you can enter the bytearray value
in hex format.
Is APL Indicates the possibility to enter variable values for the validation field via the use of APL code in the Value column. This
feature makes it possible to refer to other fields within the same UDR (as well as call to APL functions) during processing.
Value The value of the field. By default, a constant is entered. If Is APL is selected, APL syntax can be used to create a variable
definition.
Note!
When editing UDRs in manual mode, the changes of the UDRs will not be traceable. All UDRs in the batch will be updated,
although their values may not be changed.
18
4. UDR Views
From the UDR View Editor, it is possible to define filters to control how UDR data is listed and presented in the UDR File Editor main
window and the Aggregation Session Inspector.
Applying a view will add the fields of the view as columns. A UDR View does not have to be applicable on all UDR types within a displayed
file. If a field does not exist for a particular UDR, no such field is displayed.
The UDR View Editor is found in the UDR File Editor, which is opened by clicking the Tools button in the upper left part of the
MediationZone Desktop window, and then selecting UDR File Editor from the menu.
19
UDR View Editor
Setting Description
UDR Fields Displays the selected fields that builds the view
20
5. Ultra Format Converter
When an Ultra Format Definition is updated, the MediationZone system by default automatically updates persistent data when it is
accessed, in order to reflect changes. The automatic conversion can either be completely disabled, or enabled only for a selection of
formats. It is also possible to set default values for added fields. The access group is permitted to launch and maintain the data in the Ultra
Format Converter.
The following list of MediationZone applications shows agents able to handle persistent data, and how they handle historic (outdated)
UDRs when the automatic conversion is enabled (or the specific format is part of the selection in the Ultra Format Converter).
Application Handling
Aggregation All UDRs belonging to the same format definition - historic and updated - will be considered valid for comparison.
Sessions
If historic UDRs exist within old sessions, or the session format itself has been updated, the session and its
content will be updated the next time it is accessed.
ECS UDRs will be updated whenever they are read from ECS by the ECS collection agent or accessed through the
ECS Inspector.
Note!
Attempts to collect, process or update historic UDR data when the automatic conversion for a specific format is disabled causes
the workflow to abort (or an exception, when done outside workflow processing).
Conversion Rules
Fields removed from the format definition are deleted and cannot be retrieved. Added fields are by default either set to 0 (zero) (numeric
types), false (boolean types), or null (all other types). Changing the type of existing fields may cause the field content to be deleted.
For instance, changing from string to int sets the field to 0 (zero), provided that no valid default value is defined.
Only numerical types (int, long, etc) are directly interchangeable. If a numeric value exceeds the number of bytes allowed in the new
type, it will be truncated.
21
Ultra Format Converter
Setting Description
Convert Indicates the UDR types for which the conversion is enabled. There are two options:
Selected Only - Only the formats listed in this window will be considered.
All - All formats will be considered, regardless of the types listed.
UDR A list of the formats included as valid for conversion (provided that Selected Only is the selected Convert option).
Types
Note!
It is not possible to assign values to old, already existing fields (it can be configured, however will have no effect
upon update.)
22
6. Introduction to the Ultra Format Definition
Language
Ultra Format Definition Language (UFDL) is the language used to configure the MediationZone format handling subsystem. It describes the
physical structure of incoming and outgoing (external) data, internal (working) formats, as well as decoding and encoding rules.
The agents responsible for translations are the Decoder and Encoder agents. The Decoder converts external raw data (byte arrays) into
internal data (UDRs). The Encoder works the other way around, converting internal formats into raw output data for the forwarding agents.
UFDL syntax is entered in the Ultra Format Editor which is opened by clicking the New Configuration button in the upper left part of the
MediationZone Desktop window, and then selecting Ultra Format from the menu.
Block Description
External An external format describes the physical layout of the raw data. It can be declared in multiple ways such as through an
formats asn_block (for BER or PER encoded formats) or an external block.
Internal An internal format describes the structure of the internal, working UDR type. These formats are used in workflow activities
formats (such as APL processing) and are declared through an internal block or generated from an automatic in-map (through a
target_internal specification).
In-map A mapping from an external type to an internal type. This is the basic component used to describe a decoder, and it is
declared through the in_map specification.
Note!
Mapping between different Ultra formats may work, but is not supported, for example, between xml format and
ASN.1 formats. Instead you need to add an Analysis agent to execute the conversion.
Out-map A mapping from an internal type to an external type. This is the basic component used to describe an encoder, and it is
declared through the out_map specification.
Note!
Mapping between different Ultra formats may work, but is not supported, for example, between xml format and
ASN.1 formats. Instead you need to add an Analysis agent to execute the conversion.
Decoder A decoder uses one or more in-maps to specify a set of decoding rules to be used when decoding input data. Blocking
specification as well as other file structure specifications can also be added.
Encoder An encoder uses one or more out-maps to specify a set of encoding rules to be used when decoding input data. Blocking
specifications can also be added.
23
As an example, consider a incoming call detail record containing information on the type of call, who made the call and which number was
dialed. That means that the record contains three fields. Two fields and new termination marks (;) for each field in the record in order to
conform to the expected output format must be added.
Concerning both incoming and outgoing external formats, each record (the last field in the record) is terminated by a newline character.
As can be seen in the image above, An example of two external format definitions, an external specification is used to describe the raw
data formats.
The UDR format used by the processing agents is generated through the target_internal specification. This format is automatically
generated based on the incoming external data and includes any fields in the internal specification of the in-map.
In this case, the generated internal format will consist of the fields from the external incoming format with two additional fields. Hence, we
introduce an internal containing the new fields only.
Finally, the in_map and out_map definitions are used when creating decoder and encoder definitions to be used in MediationZone.
24
external recA {
int type : static_size(1);
ascii Anum : static_size(8);
ascii Bnum : terminated_by(0xA);
};
internal recA_int {
int field1;
int field2;
};
external recB {
int type : terminated_by(";");
ascii Anum : terminated_by(";");
ascii Bnum : terminated_by(";");
int field1 : terminated_by(";");
int field2 : terminated_by(0xA);
};
External
Network elements delivering data to MediationZone produce records in various physical formats. An external format describes the physical
structure of the incoming data, as well as the data delivered by the MediationZone system. It can be any type of ASCII, XML or binary data.
Typically, one external block per record type is defined. File headers and trailers are also considered being records.
The external formats are described through a number of different methods with different syntax. The external formats, currently supported
by the MediationZone Platform, are:
Sequential formats: ASCII or binary based on static or dynamic sizes for both records and fields (see 7. External - Sequential
Format). The generic external specifications are defined via the external block.
Ericsson IOG/IN formats: (see 8. External - Ericsson IOG/IN Records). This special format type is described through the inw
variant of the external block.
ASN.1 based formats: A subset of ASN.1 is supported (see 9. External - ASN.1 Formats). These formats can be used to specify
either BER or PER encodings.
XML formats: A subset of the standard XML schema syntax is supported and can be used to handle different XML formats. For
further information, see 18. XML Schema Support.
Records of different format types may exist in the same record. An example of this could be a BER (ASN.1) record that contains a field
whose format is a sequential record (specified through an external block). The image below, A definition of a sequential external record,
illustrates the syntax for a sequential record type.
25
Internal and In-Map
There are two ways to define an internal UDR format in UFDL. Either by using the automatic generation through an in_map specification,
or through an internal declaration block. For more complex formats it is often impractical to manually write an internal format if all that is
desired is a direct mapping from the fields in the external format. In these cases the target_internal specification in the in_map is
used. An additional internal block can be specified in the in_map if additional processing fields are needed.
The in_map manages the mapping of external data into the internal UDR structure. An external must be defined, and one or both of the
internal and target_internal options must be used to specify the internal format to map to.
For information about how to specify an internal format, see 10. Internal Formats. For information about in_map specifications, see 11.
In-maps.
internal AXE_DAM {
string ANumberAreaCode;
string ANumberClass : optional;
string BR_IncomingPQR;
string BR_NumberClass;
intLen ANumber;
intLen BRNumber;
intLen BSNumber;
string PreProcRecordClass;
};
An internal type declared through target_internal will automatically be generated based on the fields of the external and internal
formats.
The target_internal is the format used by the processing agents in MediationZone. It can be a direct representation of the external
incoming format, or a combination of the external and additional fields from an internal definition. An internal definition is needed in case
any changes to the default mapping from the external format are required or if several externals are mapped to the same UDR.
To understand the structure of the generated target_internal format, it is necessary to understand how the automatic mapping of an
in_map is performed. When automatically mapping an external format (that is, using the automatic keyword), all external fields are
mapped to an internal field unless the external format specifies a different automatic mapping behavior (for example through the
external_only keyword).
The automatic in-map generation will perform the following steps for each external field:
1. If the field has an explicit mapping specified, use that mapping (explicit field mapping specifications overrides automatic mapping).
2. If there is a field in the internal format with the same name as in the external, the external format field is mapped to the
internal field.
3. Otherwise, a new field is created in the generated internal format with the same name as the external field, and a type is chosen
according to the external format (the default mapping type).
If the automatic mapping algorithm requires new fields, a new internal type is first created. This type will get the name specified in the
target_internal, and is a subtype of the internal type (if specified). Decoders using this in_map will then produce records of that
internal type.
The external field default mapping type depends on the external format specification and if the external field is of a constructed type (a list
or record type), the automatic mapping logic will be applied recursively to any sub-formats.
Other than automatic mappings, it is possible to specify explicit type mappings, where the corresponding external and internal fields are
specified directly.
26
A resulting target_internal
In the image above, a resulting target_internal, a combination of explicit (the e: and i: specifications) and automatic mapping is
used to create the resulting target_internal CDR_TI.
Event Types
Event format types are special internal types that can be sent to the MediationZone Event Server. Events store additional internal
information used during the event processing. For performance reasons, and in order to avoid confusion, event types should only be used
as “message UDRs” dispatched to the Event Server. In other words, do not use event UDRs to transport ordinary UDR data.
Event types are declared in the same way as internal types, except for the keyword event, which is used instead of internal. For
further information, see 10. Internal Formats.
The following code will result in the events shown in the image below, Event format showing added fields:
event AMA_Event {
int anum;
int bnum;
...
}
For further information about Event handling, see the Desktop User's Guide.
27
Decoder
A Decoder defines what external records to accept, and describes any additional file structure information, such as whether file blocking is
used in the input data.
A decoder definition consists of in_maps or other decoders. The most basic decoder definition uses the single in-map argument. In the
following example, myDecoder will appear in the configuration of a Decoder agent:
Example - Decoder
The decoder myDecoder is created by taking one in-map. The incoming data is blocked in 2048 bytes, with the block padding
0x00.
A decoder definition can consist of several in-maps, that is, the data stream received may contain several record type definitions. Another
possible definition is combining several decoders, called constructed decoder .
The image below, Two ways of defining a decoder, introduces some validation logic to the incoming stream of data.
The first case, TTFile1, will require a batch to start with a header, end with a trailer, and contain any number of UDRs in between. The
second decoder definition (TTFile2) ignores the order and occurrence of arriving records. For further information about decoder
specifications, see 12. Decoders.
Out-map
An out-map defines how the internal data will be mapped to the outgoing format. It requires an internal and an external definition as
arguments and maps fields either automatically or through explicit field mappings.
In the image above, The minimum required to define an out-map, it is shown how an external Access_Reject_Ext is created using
the internal Access_Reject_Int. The automatic keyword map all fields with the same name, while field names present in the
internal, but not the external, are ignored. For further details about how to specify an out_map see 13. Out-maps.
Encoder
Encoders define the rules for mapping internal UDRs to external data structures (raw data).
An encoder must be defined in order to make any out_map usable, that is, selectable from the dialog. The most basic definition will have
one out_map as its only argument. In the following example, myEncoder will appear in the configuration dialog of an Encoder agent:
28
Example - Encoder
Similar to a decoder, an encoder takes one or several out-maps to define the structure of the outgoing data. For detailed information about
encoder specifications, see 14. Encoders.
In Analysis and Aggregation agents, module names are not needed if the format is selected in the UDR Types list in the configuration
dialog of the agent. Also, the APL Editor allows selection of the UDR types from a list. Right-click in the Code Area to display the UDR
Assistance... via which the UDR Internal Format Browser can be opened.
If none of these lists are used, the full format name must be referred to, or the import keyword must be used. The module name must be
prefixed with ultra.to distinguish format imports from APL code imports.
The module in this example is named Default.CDR, and contains the target_internal CDR_TI which is to be used in a
function created in the APL Editor.
import ultra.Default.CDR;
CDR_TI newUDR() {
CDR_TI myUDR = udrCreate( CDR_TI );
myUDR.field1 = 22;
myUDR.field2 = 55;
return myUDR;
}
Case 2 - no import
Default.CDR.CDR_TI newUDR() {
Default.CDR.CDR_TI myUDR = udrCreate( Default.CDR.CDR_TI );
myUDR.field1 = 22;
myUDR.field2 = 55;
return myUDR;
}
29
Using import in UFDL Code
Suppose there is a format definition with the module name Default.AMA containing an internal myInt, and a new format definition must
include the internal in the in_map. This can be accomplished in two ways:
Case 1 - import
import Default.AMA;
in_map exMap : external( myCDR ),
internal( myInt ),
target_internal( myCDR_TI ) {
automatic;
};
Case 2 - no import
Note!
Referring to ASN.1 structures from outside the format definition will require the ASN.1 module (if defined) to be part of
the reference.
When invoking the import ultra. function from within the folder that contains the UFDL file, you do not need to
specify the folder name.
References from within the same module but outside of the asn_block:
If there is a name in the same format definition (outside of any asn_block specifications), choose that name.
If there is a name in the asn_block specification, choose that name.
Evaluate the import statements.
asn_block {
exchangeRec DEFINITIONS IMPLICIT TAGS ::=
BEGIN
main_udr ::= SEQUENCE
// Field specifications
};
30
Note!
References to existing ASN.1 formats in UFDL requires the ASN.1 module to be part of the reference. Suppose the previous
external specification, saved under the name Default.myASNformat, is to be included in a new in_map:
Case 1 - import
import Default.myASNformat.exchangeRec;
Case 2 - no import
31
7. External - Sequential Format
A sequential external format specification consists of two parts; the record declaration and the field declarations. The record declaration
can contain information about UDR size and how the record type is identified. The field declarations may be grouped into larger structures
such as bit_block and set. The syntax of the external format declarations is declared as follows:
The comma separated elements of the record declaration list may be (in any order):
terminated_by( <terminator> )
dynamic_size( <expression> )
static_size( <constant expression> )
identified_by( <conditional expression> )
field declarations
bit_block declarations
set declarations
switched_set declarations
1. If this record is a sub-record (a field of another record) and the parent external field size is specified, that size is used. How field
sizes are calculated depends on the external type of the parent record type. A typical case appears if an ASN.1/BER type
contains a sequential subtype, in which case the BER size specification is used.
2. If the static_size option is specified, that size is used.
3. If the dynamic_size option is specified, that value is calculated and used.
4. If the terminated_by option is specified, the input stream is scanned until the terminator is found (this implies that no field can
contain this terminator since the first occurrence will be seen as the end of the UDR). The record size includes the termination
character but will never take up more than the total remaining size in the UDR.
5. If everything else fails, an attempt to calculate the size is made by summarizing the total size of all content declarations.
terminated_by
The function terminated_by identifies how a record is terminated. Records can be terminated by a byte constant or EOF (end of file).
The constant can be declared numerically (decimal or hexadecimal), or as a plain ASCII char. In the latter case, the literal must be
enclosed in quotes.
Note!
32
Example - Using terminated_by
dynamic_size
Binary encodings that vary in size often contain a field with information on their specific length. In these cases, the dynamic_size
declaration may be used, specifying how to calculate the record size from the values of one or more fields.
Example - dynamic_size
static_size
Records of fixed size are declared using static_size.
Example - static_size
identified_by
If the identified_by option is present, it specifies the condition under which a record of this type is present in the stream. This is used
when the input data contains different record types, in which case the decoder uses the identified_by expression to evaluate if the
data matches the record type.
The condition is also evaluated when deciding whether to use a specific out map during encoding.
33
Example - identified_by
34
Primitive Description
Field Type
ascii ASCII encoded string. This type may also be used for other types of string encodings with the character_encoding
option. The default encoding used is ISO8859-1.
asn_length Special type used to encode a BER encoded size specification. It decodes to the BER length specification as well as
the length of the length specification itself. The type makes it possible to decode some special cases of BER encoded
data without using ASN.1 format specifications. The special option content_only could also be used to only get the
BER length specification.
bcd Array of digits encoded in BCD. Nibble order can be specified as bcd(msn_fd) or bcd(lsn_fd). The msn_fd
means that the most significant nibble is the first digit, while lsn_fd uses the least significant nibble as first digit. The
msn_fd is default.
ebcdic A special case of ascii type, equivalent to ascii: character_encoding("Cp1047"). All options available for
ascii fields are also available for ebcdic fields.
float types ( Binary encoded float value. This type supports IEEE754 standard 32-bit and 64-bit data encodings. The only
float, difference between float and double is that the field is automatically mapped to their corresponding internal type.
double)
integer types ( Binary coded integer value. The first byte is the most significant (that is, big endian order). The field can be used with
byte , short the field options unsigned or signed to specify if the data will be decoded unsigned (which is the default) or two-
, int , long , complement signed. The byte order can also be explicitly specified by, for instance, using int(little_endian) or
bigint ) int(big_endian) as the type name.
The only difference between the types, when using an automatic in_map, is that the field is automatically mapped to
their corresponding internal type.
Note!
Since the integer types are handled internally as fixed-length signed integers (except for bigint), there can
be overflows in both decoding and encoding. If this occurs the integer values are truncated.
msp_length Special type used to decode the length field in a Siemens MSP billing event. The length field specifies the event length
excluding the length field itself.
external MSP_BILLING_EVENT
{
msp_length l : external_only;
ascii v : dynamic_size(l);
};
external MySubUDR {
int dataLength : static_size(1);
ascii secretData : dynamic_size(dataLength);
};
external MyUDR {
int elementCount : terminated_by(":");
list<MySubUDR> myList : element_count(elementCount);
int userType : terminated_by(0xA);
};
The list can have any of the following field size options static_size, dynamic_size, terminated_by or
element_count. For further information, see the section below, Field Size Specifications
35
Primitive Field Options
Primitive Field Description
Option
character_encoding Specifies that the field is encoded with the encoding named <encoding_name>, using the standard Java
(<encoding_name>) encoding support.
encode_value Specifies that the encoded value of the field always is <expr>, regardless of whether decoded or set value is
(<expr>) chosen during the processing. This is used for encoding only.
float, double Informs the decoder that the value is actually a float value specified as a string and that the automatic
mapping of the field is the internal type float or double. Only applicable for ascii fields.
int(base10), int Informs the decoder that the value is actually an integer of decimal or hexadecimal base and that the
(base16) automatic mapping of the field is of the internal type int. The integer types (byte, short, long, bigint)
can be used instead of int, in which case automatic mapping is done to the specified type. Only applicable
for ascii and bcd fields.
lsb The least significant bit of the field is <int_constant>. Value range is zero (0) to seven (7) (both inclusive).
(<int_constant>) Only applicable for size one (1) integer type fields. This option is typically used together with the lsb option.
msb The most significant bit of the field is <int_constant>. Value range is zero (0) to seven (7) (both inclusive).
(<int_constant>) Only applicable for size one (1) integer type fields. This option is typically used together with the lsb option.
native_size Specifies the number of BCD digits for a bcd declared field. This size does not cover field size calculation and
(<expr>) dynamic_size must generally also be specified.
byte_alignment Specifies that a field begins at the next even multiple of an alignment byte size. The value must be an even
(<int_constant>) power of 2 (for example 1, 2, 4, or 8). This field option can also be used in a bit_block or repeat_block .
For an example of how this option can be used, see the section below, Bit Blocks.
Note!
The byte_alignment field option is used for decoding only, and counts from the start of the UDR.
element_count(<expr>) Used to specify the size of a list field (in number of elements)
bit_size(<expr>) Used to specify a size of a field (in bits). This size specification can only be used inside a
bit_block.
When decoding a field, the size calculation is done in two steps. First the occupying size is calculated. This is the required field size in the
record. After that the core size and offset is calculated, which is the part of the field actually decoded into the internal field.
36
2. If dynamic_size is specified, then this one is used.
4. If terminated_by is specified, then this one is used. The field size includes the termination character but will never take up
more than the total remaining size in the UDR. (The reason that this is not considered as a decoding error is to support the
trailing_optional field option).
5. Otherwise (if the field type supports it) the field size will be deduced directly from the type. This is supported by constructed types
(sub-records) and the asn_length primitive type.
The core field data always has the full occupying size for constructed fields (record fields). For primitive fields the size is specified as
follows:
1. For a BCD field, with native_size specified, this along with the alignment specification is used.
2. If terminated_by is used to find the occupying size, this terminator char (or nibble for BCD) is removed.
3. Any padding is removed (while considering the alignment specification). The padding is either specified with padded_with or
with terminated_by providing the occupying size is not calculated using the terminator (this case is present due to historical
reasons and in current versions padded_with should be used instead). If the field is an ASCII field, space is used as default
padding.
trailing_optional The field is present unless the end of the UDR data has been reached. This is a convenient option equivalent
to present if(remaining_size >0).
external_only The field will not be automatically created in the target_internal when performing automatic mapping. This is
useful for fields containing “decoding logic” and provide no useful information after decoding. Typical examples
could be recordLength and recordType fields.
Example - udr_size
external SimpleSequential {
int recordType : static_size(1);
ascii secretData : dynamic_size(udr_size-1);
};
37
In the previous example, the size of SimpleSequential is unknown at declaration time. However, when a size is provided (specified in a
parent record type), the secretData field will occupy this entire space minus one byte (which is used by the recordType field in this
example).
Note!
If the size is not supplied by a parent record, the record size calculation rules will result in an undefined size since the udr_size
value is unavailable before the size has been calculated. This would cause a decoding error.
The other special value that depends on the record size is remaining_size, which is the size remaining until the end of the record. The
previous example could have been written using remaining_size instead of udr_size, and is shown in the following example.
Example - remaining_size
external SimpleSequential {
int recordType : static_size(1);
ascii secretData : dynamic_size(remaining_size);
};
Bit Blocks
Bit blocks are used when the data record contains fields that are not byte aligned. When declaring fields in bit blocks there are two ways to
specify which bits to use for the field content. When using a bit_block of a single byte, it is possible to specify the most and least
significant bit of the field using msb and lsb, as previously described. The alternative is to use the bit_size option to specify the number
of bits spanned by the field.
You can also use the byte_alignment field option if you need to specify from which byte a field begins. This field option can only be
used for decoding. For further information on byte_alignment, see the section above, Primitive Field Types.
bit_block : static_size(1) {
int LACLength : msb(7), lsb(4);
int OwnerIDLength : msb(3), lsb(0);
};
bit_block
int hour : bit_size(5);
int minute: bit_size(6);
int second: bit_size(6);
int eventId: bit_size(3);
};
38
This example shows how the byte_alignment field option can be used in a bit_block , in which the secondBit field
begins in the last byte in a bit_block of five bytes:
external BitBlock_ByteAlignment {
bit_block : static_size(5) {
byte firstBit: bit_size(1);
byte secondBit: bit_size(1), byte_alignment(4);
};
};
Except for simple fields, a bit_block can contain repeat_block constructs in the contents part. For a description of repeat_block
see the section below, Repeat Blocks.
Repeat Blocks
A repeat_block can be used to specify that a group of fields is to be repeated a specified number of times. Currently this construct can
only be used inside bit_block structures or another repeat_block structure. However this is restricted to a maximum of two levels of
repeat_block. See the example below.
You can also use the byte_alignment field option if you need to specify from which byte a field begins. This field option can only be
used for decoding. For further information on byte_alignment, see the section above, Primitive Field Types.
Example - repeat_block
external BitBlockTest {
bit_block : dynamic_size(remaining_size){
int string_count: bit_size(8);
repeat_block(string_count) {
int string_length: bit_size(8);
repeat_block(string_length) {
int character: bit_size(8);
};
};
};
};
In the UDR Internal Format Browser, the structure of the UDR Type for this example appears as shown below:
39
Note!
Constructed Types
A sequential field can be a type that is an instance of another external format.
external MyParentFormat {
int field1 : static_size(4);
MyEnclosedFormat field1;
};
set Construct
The set construct is used for decoding formats containing optional blocks of additional data. The syntax of the set Construct is declared as
follows:
external MyFormat:
dynamic_size(recordSize) {
int recordSize: static_size(4);
set : dynamic_size( remaining_size ) {
MyPackage1 package1: optional;
MyPackage2 package2: optional;
list<MyPackage3> package3;
};
};
All the formats, MyPackage1-3, must be declared with the identified_by option. The optional packages may appear in any order in
the input file, however it is confirmed they do not appear more than once. Currently all fields in a set construct must be declared optional.
40
If the field type in the set is a list type, the set may contain multiple records of the list element type. The list type fields are not optional.
Instead, when no matching records are found, the list is empty.
If a size is not specified on the set level, Ultra cannot validate that all the data in the UDR has been decoded. The user is therefore
recommended to specify the size, unless the set size in advance is unknown (for instance if the record is terminated by a terminator
package or the set size calculation is needed for the record size calculation). The dynamic_size(remaining_size) specification used
in the previous example is often correct.
switched_set Construct
The switched_set construct can often be used instead of the set construct. It has advantages (in performance and in ease of usage)
especially when the separate sub-packages are simple. The syntax is however more complex compared to the basic set construct. The
syntax of the switched_set construct is declared as follows:
The size specification is allowed to contain normal size options. The other parts of the declaration are the prefix fields, decoded for each
package in the set and the prefix fields. All the prefixes must have static sizes. The switch field must be one of the prefix fields.The syntax
of the switch case is declared as follows:
The case fields are normal field specifications with the additional possibility of declaring list fields for the case where a package can be
present repeatedly. If include_prefix is specified, then the case body will be decoded including the prefix fields. The syntax of the
default case is declared as follows:
default [: include_prefix] {
<case fields>
};
2. Decode the case matching the value of the switch field. If no case matches, decode the default case. If there is no default case,
end the switched_set decoding.
3. Repeat steps 1-2 until the switched_set size (or the end of the UDR) has been reached.
41
};
default: include_prefix {
list<ascii> defaultContent:
dynamic_size( packageLength + 2 );
};
};
};
1. udr_size - evaluates to the encoded size of the UDR. That means this is not necessarily the same value as during decoding.
3. field_present(fieldName) - evaluates to true if the named field is present in the encoding. It is always true for non-
optional external fields.
4. case_size - this is only usable within switched_set blocks and evaluates to the encoded size of the current case (including
prefix fields).
If the size expressions are used, the field encoding has to be postponed until the size is known. To be able to do this, Ultra requires that
any such fields are static_size. An example of these concepts is presented next.
When processing an encode_value instruction, Ultra automatically decides how to convert the value depending on the result type of the
expression. When deciding this, Ultra starts with the default internal type of the external field. If in this case, the type is called
defaultType and the expression type is encodeType, the encoding rules are:
2. If the defaultType is string or bytearray and the encodeType is numeric, encode it as a simple ascii value (one byte).
3. If the defaultType is bytearray and the encodeType is string, do standard encoding (ISO-8859-1) of the string.
4. If the encodeType is string and the external base type is ascii (for example using int(base10)), use direct string encoding.
If none of these rules are applicable, the format will not compile. To understand what this means, consider the following field definitions.
42
encode_value("10");
ascii intField2: static_size(1), int(base10),
encode_value(10);
strField1 Both defaultType and encodeType are string. The normal encoding will be used to get the result "1" (since
static_size(1) is used, the result "10" is truncated to one byte).
strField2 defaultType is string and encodeType is byte (numeric). This means that the second rule is applied, and the result
is ascii 10 (newline).
intField1 defaultType is int and encodeType is string. There is no mapping between these types however, since the
external base type is ascii, the string is mapped out as for strField1, and the result is "1".
intField2 defaultType is int and encodeType is byte. Since encodeType is directly assignable to defaultType, it is
mapped out as normal, and the output is again "1".
7.3 Expressions
UFDL may use APL in order to introduce expressions to validate the incoming data. Basically all APL functions are available, except for
plug-ins.
external myRecord :
identified_by( !strStartsWith( myField, "0201" ) ) {
ascii myField : terminated_by(0xA);
};
43
8. External - Ericsson IOG/IN Records
Record Declaration
The syntax of an IN external format is declared as follows:
No size declarations are necessary for an IN record since it is given by the enclosing sequential record. In fact, an INW record can only be
used as the final field in a sequential record.
Field Declaration
The syntax of an IN field is declared as follows:
Option Description
num_frame Indicates that the field has a number frame. Two fields will be generated if this is specified, one with the specified
field name and the other suffixed with _NumFrame.
gnci Indicates that the field has a GNCI. Two fields will be generated if this is specified, one with the specified field
name and one suffixed with _GNCI.
gnci on As gnci, however the GNCI is only present if the expression is evaluated to true.
(<expr>)
44
9. External - ASN.1 Formats
Ultra provides support for parsing a subset of ASN.1 definitions, which can be used to decode from and encode to the corresponding BER
or PER encoded data. ASN.1 parsing is requested in UFDL via the asn_block construct. The syntax of the ASN.1 blocks is declared as
follows:
asn_block {
-- ASN.1 definitions here
};
All ASN.1 constructed types declared either SEQUENCE, SET or CHOICE, will be treated as an external format declaration. The name of
the resulting external format will be the name of the ASN.1 definition. Any ASN.1 module name will be added to the name space (that is,
the total name space for the ASN.1 definition is <folder>.<configuration name>.<ASN.1 module name>).
All occurrences of the dash character (-) in identifiers will be converted to underscores since dashes are not valid in Ultra type naming.
Any in-map or out-map using an external ASN.1 type will by default specify BER encoding. PER encoding can be selected by specifying
one of the map options to PER_aligned or PER_unaligned.
Notes on ASN.1
Inter Module References
It is currently not possible to refer to non-constructed types or list types (that is, SEQUENCE OF and SET OF) declared in other modules.
These must be contained within the asn_block where they are referred to. Any constructed ASN.1 types referred to must be specified in
an ASN.1 IMPORT statement to be available. For instance,
If TAC and MobileOriginated are declared in another asn_block in the same module,
BOOLEAN boolean
bcd string
OCTET bytearray
STRING
ENUMERATED int
INTEGER int
45
By default, the float ultra type will be automatically mapped to the REAL ASN.1 type. Substituting ASN.1 type REAL with
bigdec will cast the field as BigDecimal type.
Mapping to bigdecimal
//Create a flat internal that will be used to populate with integer and bigdecimal
values.
internal flatInternal {
int calledNumber;
bigdec duration;
};
BIT STRING bitset mapping is used. Bitset is mapped to Bit String and vice versa; bitset<->bitstring
For BER BIT STRING encoding: '0410'H is the correct encoding of the bit string '0001'B ("{3}" in APL debug, length of 4
bits.
Note!
The string representation here does not actually give complete information since the length is not included. It
can be inconvenient to have the same string representation for '0001'B and '000100'B, but the reason is that
the same string representation as the Java BitSet class is used. In BER, these values are handled differently.
For example, '0001'B is encoded as 0x0410, while '000100'B is encoded as 0x0210.
For further information about how BIT STRING is encoded/decoded in BER, see ITU-T specification X.690 (the first byte
is not part of the bitstring itself - instead it encodes the number of unused trailing bits in the last byte in the bitstring
encoding, which starts after the first byte).
Ultra Extensions
Within a UFDL asn_block it is possible to use some extensions which are not part of the ASN.1 standard. These are added to provide
better automatic decoding support for some formats.
bcd(lsn_fd)
bcd(msn_fd)
bcd(lsn_fd) terminated_by(<expr>)
bcd(msn_fd) terminated_by(<expr>)
Data Support
Many ASN.1 formats declare date and time information as OCTET STRING . The date type converter has been introduced to manage an
automatic conversion to date instances. A possible syntax of date declaration is declared as follows:
46
Note!
It is also possible to use sequential formats to describe constructed ASN.1 types. In this case the tag must be declared as constructed
(a MediationZone specific keyword) to allow Ultra to correctly encode the type.
within an asn_block (module GSM), can be brought outside the asn_block and be redefined as:
external GSM.AddressString {
bit_block : static_size(1) {
int npi : msb(3), lsb(0);
int ton : msb(7), lsb(4);
};
bcd(msn_fd) msisdn : dynamic_size(udr_size-1),
terminated_by(0xF);
};
An example of a complex type, occurs when a field fieldB is to be decoded differently depending on the value of another field
fieldA. The ASN.1 definition
external ComplexType_Seq {
int tagA: static_size(1);
int lengthA: static_size(1);
int fieldA: dynamic_size(lengthA);
47
bigint Support
Since INTEGER types are automatically mapped to int, which is a 32-bit integer type, INTEGERs longer than 4 bytes will cause decoding
errors. This can be avoided by using the bigint type in place of INTEGER. The only difference between bigint and INTEGER is that
bigint is automatically mapped to the MediationZone bigint type, which can support INTEGERs of any size.
COMPONENTS OF
WITH COMPONENT
WITH COMPONENTS
ABSENT/PRESENT
ANY, ANY DEFINED BY
ObjectDescriptor
DEFAULT
DEFINITIONS
EXPLICIT, EXPLICIT TAGS
INCLUDES
MACRO
PRIVATE
UTCTime
EXTERNAL
GeneralizedTime
OPERATIONS
There are also limitations regarding the support of value notation or macro notation the only thing supported is the ability to declare
INTEGER constants and use them in constraint specifications.
There is also only limited support for information object classes and OBJECT IDENTIFIER types. Object identifiers will be decoded to
bytearrays and the information object content will only be decoded according to the class definition.
BER Limitations
In addition to the general ASN.1 limitations there are also some limitations regarding BER that must be taken in consideration, which are:
Explicit tags are not supported - All tags are by default implicit (except for tags of CHOICE types, which are always assumed to be
explicit according to the ASN.1 standard). Any attempt to specify explicit tagging will result in a compilation error.
All string fields are encoded/decoded according to ISO8859-1 except for UTF8String.
No validation to ensure that mandatory fields are actually present is performed for SEQUENCE and SET types.
Not all character types are supported. GraphicalString, IA5String, VisibleString, NumericString, and
UTF8String are supported.
PER Limitations
In addition to the general ASN.1 limitations there are also some limitations regarding PER that must be taken in consideration, which are:
For string types, constraints on the permitted alphabet are not handled.
Fragmented encoding (encoding for large size fields) is not supported.
Not all character types are supported. Currently only the GraphicalString, IA5String, VisibleString,
NumericString, and UTF8String are supported.
48
10. Internal Formats
MediationZone uses internal formats to represent data entities that it can process. All processing agents (for instance, Analysis and
Aggregation) work with these internal formats.
boolean Boolean.
date Date type, with capability to hold date parts, time parts or both.
ipaddress An IP address.
drudr An instance of any other internal (all internal are drudr instances).
string String.
field_type can also be any other internal or list type that is defined in either the same ultra file or in another. See the example below.
Case 1:
internal I1 {
I2 f1;
};
internal I2 {
list<int> f1;
};
Case 2:
49
In file A
internal I1 {
<foldername>.<filename>.I2 f1;
//When referring an internal from another file
that is in the same folder, the folder name can be omitted.
};
In file B
internal I2 {
list<int> f1;
};
where ElementType may be any of the previous, including an internal format identifier, or another list type.
internal I1 {
list<list<I2> > f1;
};
internal I1 {
drudr f1: optional;
};
internal I1 {
map<string, int> f1;
};
Internal formats can also be automatically generated from in_map definitions. For further information, see target_internal specification in
11. In-maps.
Class Specifications
All internal formats will be compiled into Java classes. It is possible to specify additional interfaces for the class to implement:
50
internal I1 :
implements("Interface1"), implements("Interface2") {
...
};
However, this requires that Interface1 and Interface2 only declare methods that are later generated by Ultra when it creates the
Java class. For further information about methods and types for UDR type methods, see the Development Toolkit user's guide.
Format Inheritance
It is possible to use alternative base UDR definitions for the generated Ultra classes by use of the extends_class or extends option.
extends_class is used by some MediationZone agents (for instance, the HTTP agent) for better processing support.
Example - extends_class
internal I1 :
extends_class( com.mysite.myDTKUltraFormat ) {
...
};
Example - extends
internal A {
int a;
...
};
internal B : extends ( A ) {
int b;
...
};
Multiple inheritance is not supported, i e you can only use the extends or extends_class option once in the definition of an internal
format.
Event Types
It is possible to declare user defined event types in Ultra by using the event keyword instead of internal. Such an event is a special
type of internal format with added event processing support.
51
11. In-maps
The in_map construct is used to map external formats to internal formats during decoding. The general syntax for an in-map declaration
is as follows:
Option Description
external Specifies the external format to map from. This is a mandatory parameter.
(<external_name>)
internal The internal format name to map to. This is a mandatory parameter, unless target_internal is
(<internal_name>) specified.
target_internal The target internal format name created when automatically generating a map. This parameter is
(<target_internal_name>) only valid for automatic mappings.
discard_output Specifies that the in_map will produce no output when used in a decoder. This can be useful for
uninteresting "filler records" that are not needed for processing.
emit_field(field1, Specifies that a decoder using this in_map will not route out the top level UDR. Instead, the content
field2, ...) (records or list of records) of the named fields are routed.
Specially named options can also be supplied in the in_map depending on the type of the external format. The type specific options are:
Option Description
ipdr_compact Only applicable for XML based formats (IPDR formats). Specifies that the IPDR "compact" encoding is to be used.
PER_aligned Only applicable for ASN.1 based formats. Specifies that PER encoding (ALIGNED version) is to be used.
PER_unaligned Only applicable for ASN.1 based formats. Specifies that PER encoding (UNALIGNED version) is to be used.
Option Description
<explicit map Describes how the external fields are mapped to the internal fields. These specifications are optional.
specifications>
i:<internal field> and
e:<external field>
[ using in_map <sub_map> ] ;
<automatic> Specifies that all external fields not explicitly mapped in <explicit_map_specifications> will be
implicitly mapped according to the external formats implicit type conversions. It is also possible to control the
behavior of the automatic mapping through options or a specification block, see the section below,
Automatic Maps, for details).
<sub-external This is used to handle the special case where the mapped external is the parent of other externals that must
specifications> be considered for decoding. This is currently only supported for XML schema based externals where it is
used to support, for instance, IPDR decoding.
ignore_unknown_tags This option can be used to ignore unknown tags when the external format is ASN.1 BER.
52
Example - ignore_unknown_tags
in_map inMapIgnoringUnknownTags:
external(Udr),
target_internal(Udr),
ignore_unknown_tags {
automatic;
};
will create an in_map called inMapIgnoringUnknownTags that will simply ignore any unknown
tags in the BER encoding.
Note!
This functionality can also be achieved by using the ASN.1 extensibility syntax. For
example, entering:
In the following example a decoder, based on the in_map, will do the following:
2. Associate ef1 with if1, that is, any reference to if1 will force decoding of the information of ef1 and in the process
convert it to an integer.
3. Associate ef2 with if2, that is, any reference to if2 will force decoding of the information of ef2 and in the process
convert it to a string.
external ExtFormat {
ascii ef1 : static_size(4), padded_with(" ");
int ef2 : static_size(2);
};
internal IntFormat {
int if1;
ascii if2;
};
53
in_map InMapFormat: external(ExtFormat), internal(IntFormat) {
e:ef1 and i:if1;
e:ef2 and i:if2;
};
In the following example a decoder, based on the in_map, will do the following:
2. Associate ef1 with if1, that is, any reference to if1 will force decoding of the information of ef1. The conversion
between ExtFormat1 andIntFormat1 is, in this case, dictated by the in-map named InMapFormat1 as declared in
InMapFormat2.
external ExtFormat1 {
ascii ef1 : static_size(4);
};
external ExtFormat2 {
ExtFormat1 ef1;
};
internal IntFormat1 {
int if1;
};
internal IntFormat2 {
IntFormat1 if1;
};
As seen in the example, explicit map specifications for complex formats can become very large, even describing all the internals to map
data too, can be a huge task. This is why automatic mapping is normally used.
1. Evaluate if the in_map contains an explicit mapping for the external field. If so, use that explicit mapping.
2. If the preceding step fails, evaluate if the internal format (if specified) contains a field name that is identical to the external field
name. If so, create with appropriate type conversions, a mapping between the two field names.
3. If the preceding step fails and the external field is not marked as external_only, create a new field (with the same field name
and the appropriate type) in the target_internal. Then create a mapping from the external field to this new internal field.
54
The type of the created internal field is controlled by the external field type.
Primitive Maps to the corresponding primitive internal type. This depends on the external format specification.
external
External Unless a using in_map specification is applicable, a new in_map is automatically created to handle the mapping
format between the external sub-record and the internal field. The automatic map has by default no specified internal or
(sub- target_internal name, however this can be modified with automatic mapping specifications.
record)
List Maps to an internal list type, where the list element type is deduced from the external list element type according to these
rules (recursively).
target_internal
When using automatic, a new internal format may be automatically generated if any new internal fields are needed for the automatic
mapping. The name of this new internal format is given by the target_internal specification of an in_map declaration. If no
target_internal name specification is given, the format will still be generated if needed, however without usable name (that is, the
format cannot be directly referred to in APL).
If a target_internal name has been given, this format will be created even if no new fields are created.
If the in_map has a specified internal format, the generated format is a subtype of this format (hence, inherits all its fields).
The syntax for the two forms of mapping specifications is declared as follows:
and
internal IntBase {
int recordSequenceNumber;
};
asn_block {
ExtDataFile ::= CHOICE(
mc MobileCall,
dp DataPacket)
MobileCall ::= SET ( ... )
DataPacket ::= SET ( ... )
};
in_map InMapDataFile :
external(ExtDataFile),
target_internal(IntDataFile) {
automatic;
};
55
In this case two new internal types will automatically be generated for MobileCall and DataPacket. However, they must usually be
given a name or in other cases inherit the fields of some declared base internal format. This can be accomplished by adding some
automatic mapping specifications:
in_map InMapDataFile :
external(ExtDataFile),
target_internal(IntDataFile) {
automatic {
MobileCall: internal(BaseInt),
target_internal(TIMobileCall);
DataPacket: internal(BaseInt),
target_internal(TIDataPacket);
};
};
This could also be done by specifying a using in_map declaration. For instance, the previous example is equivalent to the more
complicated one:
in_map InMapDataFile :
external(ExtDataFile),
target_internal(IntDataFile) {
automatic {
MobileCall: using in_map MobileCallMap;
DataPacket: using in_map DataPacketMap;
};
};
The type map specifications are inherited by every automatically generated sub-map:
asn_block {
...
MobileCall ::= SET (location Location;)
...
};
external Location {
int longitude;
int latitude;
};
in_map InMapDataFile :
external(ExtDataFile),
target_internal(IntDataFile) {
automatic {
MobileCall: internal(BaseInt),
target_internal(TIMobileCall);
DataPacket: internal(BaseInt),
target_internal(TIDataPacket);
56
Location: internal(BaseInt),
target_internal(TILocation);
};
};
In this example, even though Location is not a part of the direct mapping of ExtDataFile itself, the type map information will still be
considered when creating TIMobileCall.
The use_external_names specification will ease the syntax by removing the need of all the target_internal specifications. The
general syntax for a use_external_names declaration is as follows:
The previous example includes all of the specified external definitions within the file. Hence, the in_map could be rewritten as:
Example - in_map
It is possible to combine this with automatic mapping specifications. In this case the explicit specifications will override the
use_external_names behavior.
57
If automatic mapping specifications are in use, these will override the internal specifications on the automatic level (even if they only
specify target_internal).
This example will produce DataTarget UDRs and discard any filler (assuming that the referred formats have been properly defined).
58
12. Decoders
A decoder specifies how data is arriving from a source. There are two basic types of decoders:
Simple Decoders
The syntax of a simple decoder is declared as follows:
Option Description
block_size(<size>) Specifies that this is a blocked format with specified block size.
terminated_by(<terminator>) Specifies the block filler used. This option has no effect if block_size has not been specified.
The decoder may contain one or several in-maps, depending on whether it manages a single or multiple (mixed) record type. For multiple
maps, the corresponding external records except the last one must support identification. The decoder will try each in_map in the
specified order. The first one, for which the identification criteria are met, will be used.
How the record identification is specified depends on the actual external record type. For example, sequential external records must use
the identified_byoption while BER encoded records support identification by the standard tagging scheme.
Simple decoders may be given blocking information through the block_size and terminated_by constructs. The block_size
parameter contains the size of a block and the terminated_by parameter specifies the start of a padding character.
This decoder starts by reading the next byte and evaluates if it equals 0x00. Should it be 0x00, it will jump to the next even boundary of
2048 and repeat this procedure. If it is not 0x00, it will evaluate the identification for both of the externals specified in Map1 and Map2 (in
that order).
Constructed Decoders
A constructed decoder is defined in terms of a number of other simple or constructed decoders. They are used to specify the decoders to
be used in sequence, for example to specify separate decoders managing header, trailer, and record information. For instance, three
external record types (Rheader, Rudr, Rtrailer), with corresponding in_maps (Mheader, Mudr, and Mtrailer) and decoders (
Dheader, Dudr, and Dtrailer).
The following constructed decoder specifies the header record to be decoded first. Then any number of UDR records are decoded,
followed by a single trailer record.
59
decoder TTFile {
decoder Dheader;
decoder Dudr *;
decoder Dtrailer;
};
As can be seen, the constructed decoder does not (and cannot) have any decoder options.
The asterisk after Dudr indicates that zero or more entries can occur before a terminating trailer record. For such a sub-decoder, the
constructed decoder will switch to the next decoder when the sub-decoder cannot handle the input (as deduced by the identification criteria
of the in_maps in the sub-decoder). In this case this means that the Dudr decoder must support identification logic, or the Dtrailer
decoder will never be reached (and the decoder will abort with an "Unexpected EOF" error).
This example could also have been supported with a simple decoder:
decoder TTFile :
in_map(Mheader), in_map(Mudr), in_map(Mtrailer);
The difference is that the order of header, UDR, and trailer would not be enforced for the simple decoder. The simple decoder will also not
work if, for instance, the header does not support identification.
60
13. Out-maps
Out-maps are used in encoders to map an internal format to an external format.
Example - out_map
internal IFormat1 {
int f1;
ascii f2;
};
external EFormat1 {
ascii f1 : static_size(2), terminated_by(" ");
ascii f2 : static_size(10), terminated_by(" ");
};
out_map OutMap : internal(IFormat1), external(EFormat1) {
automatic;
};
The automatic mapping for out-maps only attempts to bind every field name of the external format to the respectively internal format. Just
as with the in-maps, no additional formats or fields are created. Like the in-maps, out-maps support explicit mappings.
As for in-maps, specially named options can also be supplied in the out_map depending on the type of the external format. The type
specific options are:
Option Description
PER_aligned Only applicable for ASN.1 based formats. Specifies that PER encoding (ALIGNED version) is to be used.
PER_unaligned Only applicable for ASN.1 based formats. Specifies that PER encoding (UNALIGNED version) is to be used.
Optional Fields
There are some additional considerations for the case where optional external fields are encoded.
An internal field can be defined as optional, enabling to encode the corresponding external field as not present. Internal fields with value
null may still be considered present and are encoded as, for instance, an empty string. To override this, use the APL command
udrUnsetPresent prior to encoding.
Consider the following example, where an optional field within an incoming ASN.1 record will be encoded (the definition of myInt varies).
asn_block {
main_udr ::= SEQUENCE {
fieldA [APPLICATION 5] INTEGER OPTIONAL
};
};
in_map inM : external( main_udr ),
internal( myInt ) {
automatic;
};
out_map outM : internal( myInt ),
external( main_udr ) {
automatic;
};
decoder myDEC : in_map( inM );
encoder myENC : out_map( outM );
61
If fieldA is defined as optional in the internal format definition, it will be present in the encoded record if it was present in the
internal record, even if the value is null. It will not be present if it was not present in the internal record.
internal myInt {
int fieldA : optional;
};
If fieldA is defined as mandatory in the internal format definition, it will always be present in the encoded record.
internal myInt {
int fieldA ;
};
internal myInt {
};
62
14. Encoders
An encoder specifies how data is to be encoded. The syntax for the encoders is as follows:
Option Description
block_size(<size>) Specifies that this is a blocked format with a certain block size
terminated_by Specifies the block filler used. This option has no effect if the block_size has not been
(<terminator>) specified.
When encoding a record, the encoder tries each out-map in the order specified. If the out-map can encode the record, then this out-map is
used, otherwise the next out-map is tried.
1. The record type matches the internal type specified in the out-map.
2. All format specific requirements are met. At the moment this evaluation is performed only for sequential data with an
identified_by condition. Only data where the mapped fields meet the identification rule will be accepted. This is to support
mapping to different external record types from the same internal type.
Note!
There is no such thing as a constructed encoder. If the records are required to be forwarded in a specific order, an APL
agent handling the output logic must precede the Encoder.
63
15. A Constructed Decoder Example
In some cases, a so-called constructed decoder is useful. The main advantage is that it introduces some validation logic, making it
possible to evaluate the order of the arriving records. For instance, suppose the incoming files contain one header and one trailer which
must be present at file start and end, in order for the file to be accepted. In between, data records may or may not be present. The data
records can be of two types. Headers and trailers are considered being records as well, so there will actually be four record types in this
format definition.
This section includes a detailed description of all the code block parts that a constructed decoder might contain:
Headers and Trailers (which are included in the external code block)
external
internal
in_map
decoder
out_map
encoder
external
Both headers and trailers as well as record types should be included in the external code block.
external FileHeader {
ascii header : terminated_by(0xA);
};
Note!
No identified_by is needed, since the decoder will not evaluate the input stream to see if the next record is a leader or not.
This compared to whether to read a TypeA or TypeB record, when an identification test is called for.
64
external FileTrailer : identified_by( strStartsWith( trailer, "Date") ){
ascii trailer : terminated_by(0xA);
};
The identified_by for the trailer is not crucial, however, it provides additional validation during decoding, since it evaluates that the
trailer really starts with "Date".
Record Types
The definitions of TypeA and TypeB are fairly straight forward. No encode_value for RecordType is set, since this is evaluated from the
internal UDR during encoding (see the section below, internal).
internal
Suppose it is desired to output one record type as a replacement for the incoming types A and B the simplest way is to create a mutual
internal.
internal MyInternal {
string RecordType;
string SequenceNumber;
string A_number;
string B_number;
Both TypeA and TypeB records are mapped to MyInternal. The common fields will always be set. The others are defined as optional,
hence, their presence depends on the record type. The RecordType in the internal type is required for encoding, since the encoder needs
to evaluate the record type to decide whether to encode as TypeA or TypeB.
65
in_map
Both record types A and B are mapped to the same internal. This approach is useful to simplify APL syntax within processing (a lot of if-
statements used to determine the record type, can be eliminated), or in case one resulting output type is produced.
TypeA and TypeB are both mapped to MyInternal (see the section above, internal).
The headers are not wanted in processing, therefore discard_output is set. However, the target_internal is still useful since it
enables you to produce headers for encoding.
decoder
The following constructed decoder definition will expect all batches to start with a header, end with a trailer and have zero/one/several A
and B records in between. If not, the decoder will abort.
// The sub-decoders.
decoder Total {
decoder Header;
decoder Records *;
decoder Trailer;
};
out_map
Suppose you are required to encode back to the original format.
66
out_map TypeB_out: external(TypeB), internal( MyInternal ) {
automatic;
};
Note!
TypeA and TypeB both are encoded from MyInternal. Which type to use depends on the value of the RecordType field.
encoder
A constructed encoder cannot be created. Hence, the following encoder definition will not care for the order of arriving records, nor that all
types must be present in the output file.
67
16. A Sequential Format Example
The example illustrated in this appendix is a format definition for decoding a shortened version of EWSD AMA (Automatic Message
Accounting).
All incoming records are of the same record type, however their content varies. The first four fields are present in all records, the fifth field
varies depending on the content of the field RecordOwnerTypePresent. The last three fields are optional.
external
Since the last three optional fields (including RecordOwnerType and RecordOwnerDN) consist of several fields, each one will be defined
as its own type. That is, an external sequential format.
Note!
The FillerRecord_0x00_EXT construct. This is the padding which may be present between records. Hence, it is defined as a
record type identified by the decoder, however not routed on to the subsequent agent (see the in_map definitions).
If the format is only used for decoding (which is the normal case for switch output formats), the encoding instructions (encode_value) in
the following code is skipped.
external AMARecord_EXT:
identified_by(RecordIdentifier == 0x84),
dynamic_size(RecordLength)
{
int(little_endian) RecordIdentifier :static_size(1),
external_only, encode_value(0x84);
int(little_endian) RecordLength :static_size(2),
external_only, encode_value(udr_size);
This byte contains several flags, from which only one is of interest. Therefore, if RecordOwnerTypePresent is set, then the
RecordOwnerType is present, or else the RecordOwnerDN data is. See the presence specifications in the following code.
bit_block :static_size(1) {
int(little_endian) RecordOwnerTypePresent: msb(7),lsb(7),
external_only, encode_value(
(field_present(RecordOwnerType)?1:0));
};
Since three bytes of unwanted data is present, it is specified as external_only to stop the field from getting automatically generated in
the target internal. No encoding is specified (0 padding is used).
68
Either RecordOwnerType or RecordOwnerDN is present. To encode them, it is important to note that exactly one of these fields must be
present in the output data.
The rest of the record consists of optional packages with additional information. The full AMA format contains lots of other packages (and
additional information in the header), however in this example, only three packages are included. Any unrecognized package leads to
failure of the decoding, since the size of the set is specified (all the remaining data must be handled by the set decoding).
set: dynamic_size(remaining_size) {
Package_100_EXT DateTimeDuration : optional;
Package_101_EXT PartnerDirectoryNumber : optional;
Package_102_EXT ServiceInfo : optional;
};
};
external RecordOwnerDN_EXT
{
bit_block : static_size(1) {
int LACLength : msb(7), lsb(4);
int OwnerIDLength : msb(3), lsb(0),
external_only, encode_value( strLength( LACAndDN ));
};
The following is a typical construction for BCD data with a nibble length specification. Both nibble size (native_size) and field size (
dynamic_size) must be specified.
// Alternative syntax:
// dynamic_size((OwnerIDLength+1)/2)
native_size(OwnerIDLength);
};
69
external_only, encode_value( 0x66 );
int(little_endian) ServiceIndicator : static_size(1);
int(little_endian) AdditionalInformation : static_size(1);
int(little_endian) Flags : static_size(1);
};
Note!
The identified_by expression, which must be specified for any format used in a set construct.
};
Alternative Syntax
An alternative to use the set construct, in the external definition for AMARecord_ext, switched_set could be used. This will impact the
syntax for the Package_*_EXT types. Only the syntax differing from the original example is shown. The main reason for using
switched_set instead of set is when performance must be increased.
external AMARecord_EXT:
// ...
// All preceding fields according to the original specification.
// Only the set construct is replaced with switched_set.
// ...
switched_set(PackageNumber): dynamic_size(remaining_size) {
case( 0x64 ) {
Package_100_EXT DateTimeDuration;
};
case( 0x65 ) {
int(little_endian) NumberOfDigits_101: static_size(1),
external_only, encode_value( strLength( Digits_101 ));
external RecordOwnerDN_EXT
{
bit_block : static_size(1) {
int LACLength : msb(7), lsb(4);
int OwnerIDLength : msb(3), lsb(0),
external_only, encode_value( strLength( LACAndDN ));
};
The following is a typical construction for BCD data with a nibble length specification. Both nibble size (native_size) and field size (
dynamic_size) must be specified.
70
bcd LACAndDN : dynamic_size((OwnerIDLength+1)>>1),
native_size(OwnerIDLength);
};
Note!
internal
No internal is used. In this case, the target_internal is sufficient; all field names and field types are in order and there is only
one type of record present in the input, and no additional fields are required.
in_map
The padding in the records is recognized by the decoder, however it is not actually mapped in to the system due to the use of the
discard_output flag.
The AMARecord_Map contains sub-automatic specifications (the target_internal specifications within the automatic block), which
will give five additional internal formats (other than the AMARecord). This is useful when you want to route them as individual records.
in_map FillerRecord_0x00_Map :
external(FillerRecord_0x00_EXT),
target_internal(FillerRecord_0x00),
discard_output {
automatic;
};
in_map AMARecord_Map : external(AMARecord_EXT),
target_internal( AMARecord ) {
automatic {
RecordOwnerType_EXT : target_internal( RecordOwnerType );
RecordOwnerDN_EXT : target_internal( RecordOwnerDN );
Package_100_EXT : target_internal( Package_100 );
Package_101_EXT : target_internal( Package_101 );
Package_102_EXT : target_internal( Package_102 );
};
};
decoder
The padding pseudo-records and data records can arrive in any order, therefore there is no need to define a constructed decoder.
71
17. An ASN.1 Format Example
This appendix shows how incoming ASN.1 records can be encoded into a sequential external format.
An ASN.1 format definition can be pasted directly into an Ultra asn_block. Nested structures will be saved as they are in the
target_internal type, however the nested fields cannot easily be encoded to a different format without using an APL agent (Analysis
or Aggregation). In the example, the incoming ASN.1 record is encoded to a sequential record, mapping all the field values to
corresponding fields in the sequential format.
Mapping - nested structures to plain, sequential structures - can be accomplished in three ways:
By creating a constructed external format definition, that is, where the external record definition consists of sub-externals.
By extending the target_internal with first level temporary fields which will hold the values of the nested fields to be
encoded.
By creating a new UDR which is populated with values from the incoming nested UDR.
Constructed Internal
It is possible to encode to a constructed sequential external, that is, an external sequential definition containing other externals to represent
the nested fields. The disadvantage with this approach is that it is not possible to mix different level fields in the produced output record.
external
Name the fields in the outgoing external exactly as in the incoming ASN.1 structure. This allows the use of automatic mapping.
asn_block {
END
};
//-------------------------------------------------------
external out {
ascii duration : static_size(2);
ascii calledNumber : static_size(8);
subUDR1 callingNumber : static_size(8);
};
external subUDR1 {
ascii category : static_size(2);
subUDR2 adressString : static_size(6);
};
external subUDR2 {
72
ascii number : static_size(2);
ascii ton : static_size(2);
ascii npi : static_size(2);
};
asn_block {
:
main_udr
:
};
73
Note!
All following fields are declared optional. This is to enable differentiation between an absent value and a zero value (default for
int type). Thus, if no value is entered it will be encoded as empty in output format, as opposed to 0 (zero).
internal exchangeRec_Int {
int duration_i : optional;
string calledNumber_i : optional;
int category_i : optional;
string number_i : optional;
string ton_i : optional;
string npi_i : optional;
};
Note!
Since no automatic mapping specifications are given, no named internal types for SubUDR1 and SubUDR2 are received. This is
not a problem as long as referencing the types directly (for instance in APL) is unnecessary.
in_map exchangeRecord_MAP_IN:
external(MainUdr),
internal(exchangeRec_Int),
target_internal(exchangeRec_TI){
e:duration and i:duration_i;
e:calledNumber and i:calledNumber_i;
automatic;
};
A structure of sub-UDRs with the same field names as in the internal mapped from is created (that is, the target_internal which has
the same structure as the ASN.1 external). This will only produce a line-based comma separated output file.
out_map Constructed_Map:
external(ConstructedOut),
internal(exchangeRec_TI) {
e:duration and i:duration_i;
e:calledNumber and i:calledNumber_i;
automatic;
};
APL Code:
74
consume {
if ( udrIsPresent( input.callingNumber.adressString ) ) {
input.category_i = input.callingNumber.category;
input.number_i = input.callingNumber.adressString.number;
input.ton_i = input.callingNumber.adressString.ton;
input.npi_i = input.callingNumber.adressString.npi;
}
udrRoute( input );
}
consume {
outUDR.duration_i = input.duration;
outUDR.calledNumber_i = input.calledNumber;
if ( udrIsPresent( input.callingNumber.adressString ) ) {
outUDR.category_i = input.callingNumber.category;
outUDR.number_i = input.callingNumber.adressString.number;
outUDR.ton_i = input.callingNumber.adressString.ton;
outUDR.npi_i = input.callingNumber.adressString.npi;
75
}
udrRoute( outUDR );
}
external
The ASN.1 definition can be copied directly into an Ultra asn_block definition. An external for the sequential outgoing UDRs is created.
asn_block {
:
main_udr
:
};
internal
An internal, containing fields matching the external field names, is created in order to hold the values to be encoded.
internal exchangeRec_Int {
int duration_i : optional;
string calledNumber_i : optional;
int category_i : optional;
string number_i : optional;
string ton_i : optional;
string npi_i : optional;
};
in_map exchangeRecord_MAP_IN_II:
external(main_udr),
target_internal(exRec_TI){
automatic;
};
out_map exchangeRecord_MAP_OUT:
external(exchangeRecSEQ),
internal(exchangeRec_Int) {
automatic;
};
76
decoder and encoder
decoder exchangeRec: in_map(exchangeRecord_MAP_IN);
77
18. XML Schema Support
This chapter describes the XML addition to the Ultra Format Definition Language (UFDL). This addition enables you to compile a subset of
XML Schema element definitions, and to decode the XML input data.
18.1 Overview
MediationZone you manage XML parsing in UFDL by applying the xml_schema construct.
output_encoding - Use this option to specify the type of encoding used. See the official Java SE Documentation from Oracle for
information regarding supported encodings.
schemaLocation - Use this option to specify the location of a schema that contains qualified schema constructs.
Note!
simpleType
simpleType with restrictions
simpleType with union
complexType
complexType with sequence declarations
complexType with extension declarations
complexType with all declarations
Global element declarations and references
SimpleContent elements with extension declarations
Note!
If you want to use union type, you must set the property mz.ultra.xml.restrictions according to your requirements. If
you want to use unions and restrictions inside of unions, set this property to union. If you want to use restrictions everywhere,
including inside the union type, set this property to on. For further information, see 2.6.4 Platform Properties.
78
18.2 External - XML Records
XML Schema complex types are interpreted as UDR types. Elements and attributes within complex types are interpreted as UDR fields,
and field types vary according to the XML schema definitions.
<integer types> int, except for long and unsignedLong. These data types are mapped to bigint.
float float
double double
dateTime date
The mapping of the data types also depends on the element attribute maxOccurs. When the value of this attribute is greater than 1 (one)
or unbounded, the mapped field is of list type.
When the element attribute minOccurs is 0 (zero), the field is considered optional and can be omitted in the internal format.
Declared attributes are considered mandatory or optional, depending on the use attribute:
element name="REQUEST">
<complexType>
<!-- Mapped to string, mandatory -->
<attribute name="REQUEST_ID" type="string" use="required"/>
<sequence>
<!-- Mapped to string, mandatory -->
<element name="ITEM" type="string" minOccurs="1" maxOccurs="1"/>
79
18.2.2 AnyType UDR Type
The anyType data type specification in XML Schema is mapped to the AnyType UDR data type in the UltraXML namespace. This UDR
type contains information about all the elements and text contents of the mapped XML element.
attributeMap(map<string, A mapping, from an attribute name to a value, of all the attributes of an element.
string>)
elementMap(map<string, All the sub-elements within the "anyType" element. This is a mapping from the element name to a
list<AnyType(UltraXML)>>) list of all the occurrences. Each sub-element is also an "AnyType" UDR.
Note!
In APL, spaces between the closing angle brackets are required, or compilation will fail.
contentFieldName
ultraFieldName
contentFieldName Attribute
In an element that is defined to contain text, the text part is normally defined by the name content in the result Ultra type. Another Ultra
field name for this data can be specified by specifying the contentFieldName attribute in the containing element.
ultraFieldName Attribute
For any attribute or element specification that maps to an Ultra field, the Ultra field name is identical to the XML name (possible
namespace is removed). To create a different field name, specify the explicit Ultra field name by using the ultraFieldName attribute.
80
18.3 IPDR Compliance
MediationZone is fully IPDR compliant. UFDL also supports IPDR compact decoding and encoding. To apply decoding or encoding
specify the option ipdr_compact in the map definition.
list type
complexType defined as an extension of a simpleType
group
nillable declarations
include
redefine
substitutionGroup
81
Below is a description of the Ultra configuration that is used for XML encoding and decoding.
Example - ULTRA_XML
To decode or encode XML data, a format definition (an XML Schema syntax) is included in Ultra xml_schema block.
xml_schema {
<?xml version="1.0" encoding="ISO-8859-1"?>
<schema xmlns = " http://www.w3.org/2001/XMLSchema ">
<element name="TRANSACTION_LOG">
<complexType>
<sequence>
<element ref="TRANSACTION" maxOccurs="unbounded"/>
</sequence>
</complexType>
</element>
<element name="TRANSACTION">
<complexType>
<attribute name="TXID" type="string" use="required"/>
<sequence>
<element name="USER" type="string" minOccurs="1" maxOccurs="1"/>
<element name="IP" type="string" minOccurs="1" maxOccurs="1"/>
<element name="ITEM" type="string" minOccurs="1" maxOccurs="1"/>
<element name="VALUE" type="long" minOccurs="1" maxOccurs="1"/>
<element name="TIMESTAMP" type="dateTime" minOccurs="1" maxOccurs="1"/>
<element name="CURRENCY" type="string" minOccurs="1" maxOccurs="1"/>
<element name="MISC" type="string" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
</element>
</schema>
};
Collected XML UDRs are often terminated by one or several whitespace characters. When mapping, the whitespace temporary
record is identified. Although input data that includes trailing whitespace characters is valid in XML, it is recommended that you
eliminate them when decoding the data. To remove any excessive white spaces from the XML UDRs, the external format
WhiteSpace is used with the in_map of the deocder. For further information see 11. In-maps and 12. Decoders.
The internal and external formats can be mapped automatically but are mapped explicitly in the example. This is to demonstrate
how the interpretation of XML types works.
internal TransactionLog {
list<Transaction> Transactions;
};
internal Transaction {
string TxId;
string User;
string IP;
string Item;
long Value;
date Timestamp;
string Currency;
list<string> Misc;
};
82
i:Currency and e:CURRENCY;
i:Misc and e:MISC;
};
};
To get rid of white spaces, create a <literal>in_map</literal> for the external format WhiteSpace using the discard_output
option. For further information, see the 11. In-maps.
To remove as many white spaces as possible from the processed data, WS_map is set first in the deocder.
83
19. Google Protocol Buffer Support
This chapter describes the GPB (Google Protocol Buffers) addition to the Ultra Format Definition Language (UFDL). This addition enables
you to compile GPB definitions, and to decode the GPB input data as well as encode data into the GPB format.
Both the proto2 and proto3 versions of the google protocol buffers language are supported.
Overview
In MediationZone you manage GPB parsing in UFDL by applying the gpb_block construct. The syntax differs whether you are using
proto2 or proto3.
gpb_block {
<GPB message elements>
};
gpb_block {
syntax = "proto3";
<GPB message elements>
};
The full description of the GPB language for proto2 and proto3 can be found at: https://developers.google.com/protocol-buffers/docs/proto
or https://developers.google.com/protocol-buffers/docs/proto3.
required
optional
repeated
Type Notes
int32 Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values,
use sint32 instead.
int64 Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values,
use sint64 instead.
sint32 Uses variable-length encoding. Signed int value. This more efficiently encode negative numbers than regular int32s.
sint64
84
Uses variable-length encoding. Signed int value. This more efficiently encode negative numbers than regular int64s. In
MediationZone sint64 will be more efficient than uint64.
fixed32 Always four bytes. More efficient encoded than uint32 if values are often greater than 228.
fixed64 Always eight bytes. More efficient encoded than uint64 if values are often greater than 256.
bool
string
Limitations
The following limitations apply for the GPB support for proto2 in MediationZone:
The following limitations apply for the GPB support for proto3 in MediationZone:
The options that are supported are allow_alias in enums and packed for fields.
Importing definitions with the gpb_block is not supported.
Import public specifiers is not supported.
The parent message type is not supported.
The any type is not supported.
Packages are not supported.
Definitions of services are not supported, only messages.
Note!
The GPB message format is not self delimiting, which should be considered when decoding a stream of messages, or a file
containing several messages.
In this example M2 is nested inside M1. Depending on where you are inside the gbp_blockyou can refer to a message by its
relative nameM2 or its qualified name.M1.M2.
message M1 {
message M2 {
string f1 = 1;
}
M2 f2 = 2;
85
.M1.M2 f3 = 3;
}
In APL you can refer to M1 and M2 by their qualified names M1 and M1_M2, where an underscore is used instead of a point.
udrCreate(M1);
udrCreate(M1_M2);
86
Example - GPB format using proto2
gpb_block {
message MyData{
required string myName =1;
required string myText =2;
required string extraName =3;
message MyParam {
repeated string someField = 1;
}
message MyAdditional {
required uint32 action = 1;
required string alias = 2;
required int64 content = 3;
optional int32 newId = 4;
optional int32 newType = 5;
optional uint64 myKey = 6;
}
message FlashEx {
required string someField = 1;
}
message MyExtras {
repeated FlashEx ex = 1;
}
message MyList {
repeated string list = 1;
}
message SysmanData {
required string someField = 1;
}
};
external Wrapper {
int dataSize: static_size(4), encode_value(udr_size-4);
SysmanData data : dynamic_size(dataSize);
};
gpb_block {
syntax = "proto3";
message MyData{
string myName =1;
string myText =2;
string extraName =3;
enum AnEnum {
V0 = 0;
V1 = 1;
}
enum AnotherEnum {
option allow_alias = true;
V0 = 0;
V1 = 0;
}
message MyParam {
repeated string someField = 1;
}
message MyAdditional {
uint32 action = 1;
string alias = 2;
int64 content = 3;
int32 newId = 4;
int32 newType = 5;
uint64 myKey = 6;
}
message FlashEx {
string someField = 1;
}
message MyExtras {
repeated FlashEx ex = 1;
}
message MyList {
repeated string list = 1;
}
message SysmanData {
string someField = 1;
}
};
external Wrapper {
int dataSize: static_size(4), encode_value(udr_size-4);
SysmanData data : dynamic_size(dataSize);
};
Note!
Since GPB does not specify the size, this has to be done externally, which is why int dataSize has to be included in the
external unless the size is previously known.
20. Avro Support
This chapter describes the Avro support that has been added to the Ultra Format Definition Language (UFDL). This addition enables you to
compile Avro definitions, and to encode data into, and decode it from the Avro format. A schema in Avro is represented in JSON. You can
implement non-protocol data issues in an Analysis agent.
Overview
In MediationZone you manage Avro parsing in UFDL by applying the avro_block construct.
avro_block {
<avro json schema>
};
The output of an Avro encoder represents a single Avro record, not a complete Avro data file. To deserialize these records using a third
party tool, you must add the correct Avro header to the records based on the description of Avro provided in the link below.
The full description of the Avro language can be found at: https://avro.apache.org/docs/current/spec.html.
Note!
There are limitations to the implementation of the following elements. Refer to the the section below, Limitations, for further
information.
Complex Notes
Type
record Supports the attributes: name, namespace, doc (optional), aliases (optional), fields.
fields is an array of listing fields and supports the attributes: name, doc (optional), type, default, order
(optional), aliases (optional).
enum Supports the attributes: name, namespace, doc (optional), aliases (optional), symbols.
union Implemented as a record with all types set to optional. If two values are set, both are encoded. If no values are set,
none are encoded.
fixed
89
Supports the attributes: name, namespace, aliases (optional), size
Note!
Limitations
The following limitations apply for the Avro support in MediationZone:
avro_block {
{
"namespace": "example.avro",
"type": "record",
"name": "User3",
"fields": [
{"name": "name", "type": {
"name": "FullName2",
"type": "record",
"fields": [
{"name": "firstName", "type": "string"},
{"name": "lastName", "type": "string"}
]
}
},
{"name": "favorite_number", "type": ["int", "null"]},
{"name": "favorite_color", "type": ["string", "null"]},
{"name": "favorite_fotball_team", "type": {
"name": "teams",
"type": "enum",
"namespace": "example.avro.teams",
"symbols": ["Djurgården", "Hammarby", "Malmö", "Göteborg"]
}
},
{"name": "ipAddresses", "type": {
"type": "array",
"items": [
{
"name": "ipv4Address",
"type": "fixed",
"size": 4
},
{
"name": "ipv6Address",
"type": "fixed",
"size": 16
}
]
}
},
{"name": "favoriteFoodList", "type": {
"name": "favoriteFood",
90
"type": "record",
"fields": [
{"name": "dish", "type": "string"},
{"name": "next", "type": ["null", "favoriteFood"]}
]
}
},
{"name": "salary", "type": "long"},
{"name": "myFixed", "type": { "name": "myfixed", "type":"fixed", "size": 4 }},
{"name": "myFloat", "type": "float"},
{"name": "myDouble", "type": "double"},
{"name": "rootUsers", "type": {
"type": "map",
"values": {
"name": "RootUsers",
"type": "record",
"fields": [
{"name": "rootUser", "type": "string"},
{"name": "privileges", "type": "int"}
]
}
}
},
{"name": "maps", "type": {
"type": "array",
"items": {
"type": "map",
"values": {
"name": "Map2",
"type": "record",
"fields": [
{"name": "favoriteUser", "type": "string"},
{"name": "favoriteNumber", "type": "int"}
]
}
}
}
}
]
}
};
91
92