interplay | mam swodl referenceresources.avid.com/supportfiles/attach/interplay_mam/... ·...

157
Interplay ® | MAM SWoDL Reference Release 5

Upload: others

Post on 14-Mar-2020

9 views

Category:

Documents


0 download

TRANSCRIPT

Interplay® | MAM SWoDL Reference

Release 5

Contents

Using This Reference ....................................................................... 6 Symbols and Conventions .......................................................................................... 6 If You Need Help ......................................................................................................... 7 Avid Training Services ................................................................................................ 7

1 Introduction ....................................................................................... 8

2 Basic Language Elements ................................................................ 9 Command Separator, Identifiers ................................................................................. 9 Comments ................................................................................................................. 10 Status Definitions ...................................................................................................... 10 Literals ....................................................................................................................... 11

String Literals ....................................................................................................... 11 Integer Literals ..................................................................................................... 12 Floating-Point Literals .......................................................................................... 12 Boolean Literals ................................................................................................... 12

Variables and Constants ........................................................................................... 13 Variable Declaration ............................................................................................. 14 Assigning a Value to a Variable ........................................................................... 15 Constants ............................................................................................................. 16 System Variables ................................................................................................. 16

Structs and Arrays ..................................................................................................... 19 Structs .................................................................................................................. 19 Arrays ................................................................................................................... 21 Combining Structs and Arrays ............................................................................. 23 Using Arrays and Structs to Parse XML Documents ........................................... 25

Expressions ............................................................................................................... 28 Operators ............................................................................................................. 28 Type Considerations ............................................................................................ 29 Cast Operators ..................................................................................................... 30 Pitfall: Variables May Change Operation Type .................................................... 30

Command Blocks ...................................................................................................... 31 Labels, Goto, Gosub, and Return ............................................................................. 32

Labels and Goto ................................................................................................... 32 Gosub and Return ................................................................................................ 32

Exit ............................................................................................................................ 33 Error .......................................................................................................................... 33 Delay ......................................................................................................................... 33 Suspend .................................................................................................................... 33 Try-catch, Throw, and Assert .................................................................................... 34

3

Conditional Command: If – Then – Else ................................................................... 35 Loops ......................................................................................................................... 36

While Loop ........................................................................................................... 36 Do-while Loop ...................................................................................................... 36 Retry-while Loop .................................................................................................. 36

3 Built-in Functions ............................................................................ 38 String Handling .......................................................................................................... 38

String Comparison: compare ............................................................................... 39 Extracting Part of a String: substr ........................................................................ 39 Length of a String: length ..................................................................................... 40 Find a Substring in a String: find .......................................................................... 40 Find Last Occurrence of a Substring: findreverse ............................................... 40 Trim a String: trim................................................................................................. 41 Replace Substrings: replace ................................................................................ 41 Converting a String to Lowercase: str_lower ....................................................... 41 Converting a String to Uppercase: str_upper ...................................................... 41

XML Functions .......................................................................................................... 41 XML Encoding and Decoding: xmlencode and xmldecode ................................. 42 Parsing XML Documents ..................................................................................... 43 Creating XML Documents .................................................................................... 54

Array Functions ......................................................................................................... 60 Aggregating Elements: array_aggregate ............................................................. 60 Checking a Condition on all Elements: array_all ................................................. 61 Checking if any Element Fulfills a Condition: array_any...................................... 62 Transforming an Array: array_select.................................................................... 63 Filtering Elements with a Condition: array_where ............................................... 64

JSON Functions ........................................................................................................ 65 Converting JSON Documents to SWoDL Datatypes ........................................... 66 Converting a Complex SWoDL Type to a JSON Document ................................ 66 Parsing JSON Documents ................................................................................... 67 Creating JSON Documents .................................................................................. 72

Regular Expressions ................................................................................................. 76 Regular Expression Match: regex_ismatch ......................................................... 77 Finding Regular Expression Matches: regex_find ............................................... 77 Replacing Using Regular Expressions: regex_replace ....................................... 77 Defining Match Options ........................................................................................ 79

Configuration Settings ............................................................................................... 79 Common References ................................................................................................ 80 Handling Lists: getelement, getnumberofelements ................................................... 82 Random Number Generation .................................................................................... 83 Floating-Point Functions ........................................................................................... 83 Empty Operation: nop ............................................................................................... 84

4

4 HTTP POST Web Methods .............................................................. 85 Declaration of HTTP POST Methods ........................................................................ 85

Declaration of Input Parameters .......................................................................... 87 Declaration of Return Parameter ......................................................................... 87 Renaming HTTP POST Methods ......................................................................... 91 Declaration Modifier const ................................................................................... 92 Defining the Target in the Declaration of a Method ............................................. 92

Calling HTTP POST Methods ................................................................................... 93 Methods without Return Parameters ................................................................... 93 Methods with Return Parameters ........................................................................ 94 Using an Explicit URL .......................................................................................... 95 Lists as Parameters of an HTTP POST Method .................................................. 95

5 SOAP Web Methods ........................................................................ 96 Declare and Call SOAP Methods .............................................................................. 96

Method Name and Input Parameters ................................................................... 97 Calling a SOAP method ....................................................................................... 99 Input Parameters ............................................................................................... 100 Declaration of Return Parameter ....................................................................... 108

Renaming SOAP Methods ...................................................................................... 117 Declaration Modifier const ....................................................................................... 117 Defining the Target in the Declaration of a Method ................................................ 118

6 ACS Bus Messages ....................................................................... 119 Declaration and Sending of Bus Messages ............................................................ 119

Asynchronous Bus Messages ............................................................................ 119 Message Name and Input Parameters .............................................................. 120 Sending Bus Messages ..................................................................................... 121 Declaration of Input Parameters ........................................................................ 122 Declaration of Return Parameters ..................................................................... 129

Error Handling ......................................................................................................... 133

7 HTTP and HTTPS Web Requests ................................................. 135 Simple Web Requests: web_request ...................................................................... 135

Example: Getting Data from a Web Service ...................................................... 136 Example: Passing HTTP Headers ..................................................................... 137 Example: Passing Cookies ................................................................................ 137 Example: Sending a Body .................................................................................. 137 HTTPS Requests ............................................................................................... 138

Advanced Web Requests: web_request_ex ........................................................... 138 Example: Getting Data from a Web Service ...................................................... 140 Example: Getting Binary Data from a Web Service ........................................... 141 Example: POST Call with Request Body, HTTP Headers, and Cookies ........... 141

5

Example: Calling a Web Service with Authentication ........................................ 142 HTTPS Requests ............................................................................................... 143

8 Compatibility ................................................................................. 145 Web Methods .......................................................................................................... 145

Expressions as Arguments to Web Method Calls .............................................. 145 SOAP Calls: Automatic Handling of Structs and Arrays .................................... 145 Duplicate Web Method Declarations.................................................................. 146 SOAP Calls: Parsing WSDL .............................................................................. 146

Structs and Arrays ................................................................................................... 147 Structs ................................................................................................................ 147 Arrays ................................................................................................................. 148

9 MAP_Delete: An Interplay | MAM Workflow ................................ 149

Disclaimer ...................................................................................... 153

Using This Reference

Congratulations on your purchase of Avid® Interplay® | Media Asset Manager (Interplay | MAM), a powerful system for archiving and managing media in a shared storage environment. This documentation is about Simple Workflow Definition Language (SWoDL). SWoDL is a script language that describes workflows in the Interplay MAM WorkflowEngine.

Symbols and Conventions Avid documentation uses the following symbols and conventions:

Symbol or Convention Meaning or Action

A note provides important related information, reminders, recommendations, and strong suggestions.

A caution means that a specific action you take causes you to lose data.

Courier Courier on gray background indicates code examples.

Courier blue font Courier blue font on gray background emphasizes code in examples.

The arrow indicates that line breaks in code examples are not allowed when using or writing comparable code.

Italic font Italic font is used to emphasize certain words.

Courier bold font Courier bold font identifies text that you type.

> This symbol indicates menu commands (and subcommands) in the order you select them. For example, File > Import means open the File menu and then select the Import command.

This symbol indicates a single-step procedure. Multiple arrows in a list indicate that you perform one of the actions listed.

<placeholder, variable> Angle brackets indicate placeholders or variables.

UPPER CASE Indicates names of processes, process classes, data model attributes, legal lists, legal list values, states of tasks, and templates.

7

If You Need Help

If you are having trouble using your Avid product:

1. Retry the action, carefully following the instructions given for that task in this guide. It is especially important to check each step of your workflow.

2. Check the latest information that might have become available after the documentation was published.

You should always check online for the most up-to-date documentation because the online version is updated whenever new information becomes available. To view the online versions, visit the Knowledge Base at www.avid.com/support.

3. Check the documentation that came with your Avid application or your hardware for maintenance or hardware-related issues.

4. Visit the online Knowledge Base at www.avid.com/support. Online services are available 24 hours a day, 7 days a week. Search this online Knowledge Base to find answers, view error messages, access troubleshooting tips, download updates, and read or join online message-board discussions.

Avid Training Services

Avid makes lifelong learning, career advancement, and personal development easy and convenient. Avid understands that the knowledge you need to differentiate yourself is always changing, and Avid continually updates course content and offers new training delivery methods that accommodate your pressured and competitive work environment.

For information on courses/schedules, training centers, certifications, courseware, and books, please visit www.avid.com/support and follow the Training links, or call Avid Sales at 800-949-AVID (800-949-2843).

1 Introduction

The following topics provide information about the use of SWoDL in Interplay | MAM:

• Basic Language Elements

• Built-in Functions

• HTTP POST Web Methods

• SOAP Web Methods

• ACS Bus Messages

• Compatibility

• MAP_Delete: An Interplay | MAM Workflow

2 Basic Language Elements

The following table contains links to the topics that describe the basic SWoDL element.

Topics “ Topics continued

Command Separator, Identifiers Labels, Goto, Gosub, and Return

Comments Exit

Status Definitions Error

Literals Delay

Variables and Constants Suspend

Structs and Arrays Try-catch, Throw, and Assert

Arrays Conditional Command: If – Then – Else

Expressions Loops

Command Blocks

Command Separator, Identifiers

Commands are separated by a semicolon.

An identifier in SWoDL consists of a leading letter or underscore followed by any number of alphanumeric characters or underscores.

Examples:

myvar _some_variable CurrentOrderStatus var4711 ASoapFunction

Status Definitions

10

Comments

Comments are used in the same way as in C# or C++. There are two kinds of comments:

• Line comments start with double slashes and end at the current line.

Examples:

// some comment goto somelabel; // another comment

• Block comments start with /* and end with */. A Block comment can cover more than one line.

Example:

/* a large comment explaining for example the semantics of a function call */

Nested block comments are not allowed.

Status Definitions

When writing a workflow it is good practice to use states and transitions to specify basic behavior. In a second step you refine the basic behavior to the actual SOAP calls and loops and expressions. SWoDL allows you to keep the original state information in the workflow. For this purpose you can include a status definition statement.

Example:

[[Waiting for analysis]]

When executing the workflow, the status changes to “Waiting for analysis” as soon as the execution passes that definition; then you can see the new workflow status in the Workflow Monitor.

If you use status definitions wisely, you can easily monitor the progress of your workflows.

Literals

11

Literals

The following sections describe SWoDL literals:

• String Literals

• Integer Literals

• Floating-Point Literals

• Boolean Literals

String Literals

A string literal is any set of characters enclosed in double quotes.

Example:

"some test string"

Double Quotes in String Literals

To add double quotes to a string literal:

Escape the double quotes with a single backslash.

Example:

"some \"quoted\" string"

This is a string literal containing the string: some "quoted" string

Backslashes in String Literals

To add backslashes in string literals:

Escape the backslash with another backslash.

Example:

"a string with one slash \\ and two slashes \\\\ and three slashes \\\\\\"

Literals

12

Each double backslash represents one single slash in the string; that is, the string literal in the example defines the string: a string with one slash \ and two slashes \\ and three slashes \\\

Integer Literals

Integer literals consist of any number of decimal digits.

Examples:

42 4711 3

Beginning with WorkflowEngine V2.3.2, all integer calculations use signed 64-bit integer variables. This limits the range of values from –9.223.372.036.854.775.808 to 9.223.372.036.854.775.807. Versions before 2.3.2 used signed 32-bit integer variables, limiting the range from –2.147.483.648 to 2.147.483.647 (with the known bug: “–2147483648” could not be used as literal).

Floating-Point Literals

SWoDL has supported floating-point literals and operations since Interplay MAM 3.3. Floating-point literals consist of any number of decimal digits followed by a decimal point, followed by any number of decimal digits.

Examples:

42.5 0.234 -4.5

Boolean Literals

The following keywords are reserved for Boolean values.

true false

In expressions, the following values evaluate to true:

Variables and Constants

13

• the Boolean literal true

• the string “true,” case-insensitive

• all integer literals except 0

• all floating point literals except 0.0

• all strings containing an integer or floating point number that is not equal to 0

All other values evaluate to false.

Example:

// True: if(true) { } if("True") { } if(1) { } if(-5) { } if(-0.01) { } if("17") { } // False: if(false) { } if("false") { } if("tanstaafl") { } if(0) { } if(0.0) { } if(-0.0) { } if("0") { }

Variables and Constants

Any valid identifier is assumed to be a variable.

Examples:

myvar _some_variable CurrentOrderStatus var4711

SWoDL requires that all variables are defined before use.

SWoDL variables are not type-safe. All variables are treated as strings. Cast operators are available. This is vital for operators like + or compare operators. See “Type Considerations” on page 29 for details.

Variables and Constants

14

The following sections describe SWoDL variables and constants:

• Variable Declaration

• Assigning a Value to a Variable

• Constants

• System Variables

Variable Declaration

Variables must be declared before use. This informs WorkflowEngine clients about the workflow parameters that are available so that they can be set. A variable declaration uses either the var or the in keyword.

Examples:

var myvar1; in DMGUID; var myvar2 = "initial value";

The third variant initializes the variable with the given value.

SWoDL does not support the concept of a visibility scope. All variables are global variables and visible anywhere in the workflow, no matter where they are declared.

You can declare variables using the keyword in instead of var. Variables declared using in are input variables to the workflow. They are shown differently on the Workflow Monitor when starting a workflow:

Variables and Constants

15

The four variables shown in the upper section are in variables, those in the lower section are var variables. Apart from that, both types are handled in exactly the same way.

Interplay MAM 3.3.2 introduced a comma-separated list of variables with one declaration.

Example:

var v1, v2, v3; var v1 = "Example", v2 = "Hello, world!";

Assigning a Value to a Variable

Assigning a value to a variable works as in C# or C++.

Examples:

myvar = 5; myvar = "text"; myvar2 = myvar; myvar = 5 + 7; myvar += 3.5; myvar2 = "myvar contains " + myvar myvar3 = "9"; myvar4 = (int)myvar3 * 7; myvar = substr(myvar2, 10);

For information about operators, see “Operators” on page 28.

Variables and Constants

16

Constants

Interplay MAM 3.3.2 introduced the definition of constants. You can define a constant by using the keyword const.

Example:

const pi = 3.14159265; const productname = "Interplay MAM";

Constants are used exactly like variables, with the following restrictions:

• A constant must be initialized with a value.

• The value must be a literal of any type.

• Expressions are not allowed as values.

• Other assignments to a constant are not allowed.

The Workflow Monitor shows a checkbox to show or hide constants in the details of a workflow.

System Variables

Variable names that begin with an underscore are reserved for internal use by WorkflowEngine. Unless you want to access one of these system variables, you should not use variable names that begin with an underscore. It is possible that future SWoDL versions will require additional internal WorkflowEngine variables.

The following list of system variables is only a snapshot, and may be extended in the future.

Variables Used in Workflows

If the variable is not marked as “modifiable” you should never try to set the variable. Setting the variable may cause serious damage.

Variable Modifiable Description

_DebugMode yes Enables the debug mode. If set to “1”, the workflow is suspended after each step. Default is “0”.

_ExceptionReason yes Exception reason (if set) — for example, “Client.DataManagerWS.UnknownObject”. The value can be used to distinguish different specific exceptions.

Variables and Constants

17

Variable Modifiable Description

_HistorySize yes Maximum size of the _SWoDLHistory variable containing the history of executed SWoDL lines. Default is 2000. Setting the variable to very large values may result in memory shortage and performance issues.

_JobID no The ID of the workflow.

_Priority yes Scheduling priority for the workflow. Workflows with higher priority are executed more quickly than those with lower priority. Default is “100”.

_RetryDelay yes Gives the delay in seconds in retry loops. Default is “30”.

_SoapTimeout yes Defines the timeout, in seconds, for following SOAP calls. Default is the number defined in the configuration setting “WorkflowEngine/SoapCallTimeoutInSeconds”.

_UserGuid yes Not used by WorkflowEngineWS, but the value can be displayed in the “Browse” view of Workflow Monitor. The value is trimmed to 64 characters when it is stored in the database. It may have more than 64 characters while the workflow is running, but if the workflow is suspended or finishes, or if WorkflowEnigneWS is restarted, the value is trimmed to 64 characters.

Variables Used Internally or to Monitor Workflows

You should not set the following variables unless you know exactly what you are doing. This is only a snapshot of the meaning of the variables. Future versions might use variables in a different way, introduce new variables, or abandon the utilization of existing variables.

Variable Description

_ActivityLimiter Number of times the activity limiter was triggered. WorkflowEngine limits the number of steps a workflow may execute per second. This avoids congestion in the case of unintended endless loops.

_CallerIPAddress IP address of the PC that initially created the workflow.

_ErrorMessage Contains the error message set with the “error” statement.

_ErrorNumber Internal error number.

Variables and Constants

18

Variable Description

_ExceptionMessage Message of last SOAP exception.

_ExceptionOccured Contains 1 if a SOAP exception occurred recently. The variable is used internally to handle exceptions.

_LastModified Date and time of last modification to the workflow.

_SoapLimiter Number of times the SOAP limiter was triggered. WorkflowEngine limits the number of SOAP calls a workflow may execute per second. This avoids congestion of the entire Interplay MAM system in the case of unlimited loops with SOAP calls.

_State The status of the workflow. Possible values:

0: ready 1: ready for running 2: finished 3: suspended 4: error 5: ready with problems

Usually only the values 0, 2, 3, and 4 are used.

_Name Workflow template used for this workflow.

_NextActivity Number of next activity to be executed (only used internally).

_NextStartTime Next start time in case of delays.

_NumActivities Counter for number of executed activities (only used internally).

_Owner Name of the WorkflowEngineWS instance that currently owns the workflow.

_ReturnStack Stack of return addresses for gosub and return calls.

_RunTime Total runtime of workflow, in milliseconds.

_StartUpTime Time when the workflow was created.

_SWoDLHistory Execution history in terms of line numbers of the SWoDL description of the workflow.

_SWoDLLineNumber Number of the currently executed line in SWoDL description.

_WorkflowStatus Externally visible description of the workflow status, set using a “[[some text]]” statement.

Structs and Arrays

19

Structs and Arrays

SWoDL supports structs and arrays as built-in data types. Both are stored like any other variable, but with an XML document in a specific format as content.

Structs

Interplay MAM 3.4.3.2 introduced structs as a new concept in SWoDL. Structs are handled similarly to JavaScript. If you have an ordinary variable, you can introduce a new field with a dot notation.

Example:

var user; user.JobTitle = "Businessman"; user.Age = 55; user.FullName.FirstName = "Joe"; user.FullName.LastName = "Satriani";

This defines user as a struct that has the following members:

• JobTitle

• Age

• FullName

FullName in turn is a struct that has the members:

• FirstName

• LastName

The individual members of the struct do not appear in the list of variables in the Workflow Monitor. They are dynamically read from the XML content during runtime.

You can use a member of a struct like any regular variable — for example, in an expression or as parameter of a Web method.

Example:

var age = user.Age;

If you access a field that does not exist, it returns an empty string.

Structs and Arrays

20

Example:

var x = user.FieldThatDoesntExist; // returns an empty string

To avoid mistakes, you should be very careful with the exact spelling of your field names, including capitalization, as field names are case-sensitive.

You can also assign an entire struct to a variable.

Example:

var secondUser = user;

After that assignment, the variable secondUser contains a copy of the struct user. Structs are value types, not reference types.

Implementation of structs

This chapter explains the current implementation of structs. It is meant for informational purposes only. The implementation may be changed in future versions. You must not rely on the details of the implementation. For example, you should not pass an XML document for a struct to a Web method and parse it, relying on specifics of the XML format.

When you are defining a regular variable, its content is stored as a simple string. When you are using the “.” delimiter to introduce a field, the variable becomes a struct and the content of the struct is stored as an XML document, such as (referencing the previous example):

<struct> <JobTitle>Businessman</JobTitle> <Age>55</Age> <FullName>&lt;struct&gt;&lt;FirstName&gt;Joe&lt;/FirstName&gt; &lt;LastName&gt;Satriani&lt;/LastName&gt;&lt;/struct&gt;</FullName> </struct>

The root element of the XML document is “struct”. Each of the fields of the struct is represented by an XML element with the same name as the field — for example, <Age>55</Age> for the field Age.

The field FullName in the example is itself a struct that contains the fields FirstName and LastName. This inner struct is created using the same rules, resulting in the following XML:

Structs and Arrays

21

<struct> <FirstName>Joe</FirstName> <LastName>Satriani</LastName> </struct>

The XML document of that inner struct is then stored as text content in the outer struct:

<struct> <JobTitle>Businessman</JobTitle> <Age>55</Age> <FullName>&lt;struct&gt;&lt;FirstName&gt;Joe&lt;/FirstName&gt; &lt;LastName&gt;Satriani&lt;/LastName&gt;&lt;/struct&gt;</FullName> </struct>

Through Interplay MAM 4.2.x, the implementation was different. See “Structs” on page 147 for details.

Arrays

Interplay MAM 3.4.3.2 introduced arrays as a new concept in SWoDL. Arrays are implemented by a set of built-in functions. The content of an array is stored as an XML document. The following table lists the functions:

Function Description

x[i] Accesses the ith element of the array x.

array_create() Creates an array (returns an empty array XML). The call is often redundant, because SWoDL treats an empty string as an empty array when using the array functions.

array_add(array, value) Returns a copy of the given array with the new value added to the end of the array. The array given as first parameter is not changed.

array_get(array, index) Gets the value of the element with the given index in the array. If the index is not available in the array, the function returns an empty string.

array_isset(array, index) Returns true if the index is set in the array.

array_bounds_lower(array) Returns the lowest index in the array.

array_bounds_upper(array) Returns the highest index in the array.

array_size(array) Returns the size of the array (the number of elements that have been set).

Structs and Arrays

22

Function Description

array_set(array, index, value) Returns a copy of the given array, where the value of the item with the given index in the array is set to the given value.

For the array_get and array_set methods, the simpler and easier syntax with square brackets is available, as shown in the following examples:

Example 1:

var a = array_create(); a = array_set(a, 0, "astring"); a[0] = "astring"; // same as: a = array_set(a, 0, "astring"); var value = array_get(a, 0); value = a[0]; // same as: value = array_get(a, 0);

Example 2:

var a = array_create(); a[3] = "string #3"; a[5] = "string #5"; a[7] = "string #7"; // ------------------------ // bounds and size methods: // ------------------------ var bl = array_bounds_lower(a); // returns 3 var bu = array_bounds_upper(a); // returns 7 var size = array_size(a); // returns 3 // --------------------------- // typical loop over an array: // --------------------------- var i=array_bounds_lower(a); while( i<=array_bounds_upper(a) ) { // do something i += 1; }

Implementation of arrays

This chapter explains the current implementation of arrays. It is meant for informational purposes only. The implementation may be changed in future versions. Don’t rely on the

Structs and Arrays

23

details of the implementation. For example, you should not pass an XML document for an array to a Web method and parse it, relying on specifics of the XML format.

The content of an array is stored as an XML document with root element “itemsOfArray”. The root element has one “item” element for each item in the array. Each item has an XML attribute “index”, which gives the index number of the item.

Example:

var x; x[0] = "First item"; x[1] = "Second item";

This results in the following XML document:

<itemsOfArray> <item index="0">First item</item> <item index="1">Second item</item> </itemsOfArray>

Combining Structs and Arrays

You can combine structs and arrays in any way you want. The following example creates a struct that contains information about the movie Brazil, including an array of actors. The name and role name are stored for each actor.

Example:

var movie; movie.Title = "Brazil"; movie.Director = "Terry Gilliam"; movie.Actors[0].Name = "Jonathan Pryce"; movie.Actors[0].RoleName = "Sam Lowry"; movie.Actors[1].Name = "Robert De Niro"; movie.Actors[1].RoleName = "Harry Tuttle"; movie.Actors[2].Name = "Kim Greist"; movie.Actors[2].RoleName = "Jill Layton"; // Get name of the first actor: var firstActor = movie.Actors[0]; var nameOfFirstActor = firstActor.Name;

Structs and Arrays

24

// Get name of the second actor: var nameOfSecondActor = movie.Actors[1].Name;

The example shows that you can mix the square bracket operator that accesses an item of an array with the dot operator that accesses a field of a record.

Use of these operators was restricted in Interplay MAM through 4.2.x. See “Arrays” on page 148 for details.

Implementation of nested arrays and structs

An array is stored as an XML document with root element “itemsOfArray”. The root element has one “item” element for each item in the array. Each item has an XML attribute “index”, which gives the index number of the item.

If an item itself is a struct, the content of the struct is serialized as an XML document as explained in “Structs” on page 19. This inner document is then stored as the text value of the <item> node.

Example:

var x; x[0] = "First item"; x[1].a = "A value"; x[1].b = "A second value";

This results in the following XML document:

<itemsOfArray> <item index="0">First item</item> <item index="1">&lt;struct&gt;&lt;a&gt;A value&lt;/a&gt; &lt;b&gt;A second value&lt;/b&gt;&lt;/struct&gt;</item> </itemsOfArray>

The same happens if an item of an array is itself an array:

var a; a[0][0] = "First sub item of item 1"; a[0][1] = "Second sub item of item 1"; a[1] = "Item 2";

This results in the following XML document:

Structs and Arrays

25

<itemsOfArray> <item index="0">&lt;itemsOfArray&gt;&lt;item index="0"&gt;First sub item of item 1&lt;/item&gt;&lt;item index="1"&gt;Second sub item of item 1&lt;/item&gt;&lt;/itemsOfArray&gt;</item> <item index="1">Item 2</item> </itemsOfArray>

The item with index 0 contains an array with two elements. The XML representation of the inner element is stored as text content of the item 0.

Using Arrays and Structs to Parse XML Documents

When creating arrays and structs in SWoDL, the data is stored in the well-defined XML format described in the previous chapters. However, the implementation of arrays and structs is more flexible when parsing XML documents. It supports not only its own XML schema, but, in a lot of cases, also allows parsing XML documents using other schemas.

Example: The variable doc contains the following XML document:

<test> <a>1</a> <b> <f1>123</f1> <f2>456</f2> </b> <c> <x>0</x> <x>1</x> <x>2</x> </c> </test>

The following evaluation rules apply:

Access type Example Description

Struct doc.a Searches the first XML child element of the document node that has the same local name as the field name (here, “a”).

• If that element has sub-elements, the element is returned with all sub-elements. XML namespaces are kept.

• If that element has no sub-elements, the text content of the node is returned.

Examples:

• doc.a finds the XML element <a> in the document. <a> has

Structs and Arrays

26

Access type Example Description

no sub-elements, so the method returns the text content of a, which is “1”.

• doc.b finds the XML element <b> in the document. <b> has sub-elements, so the result is the XML fragment “<b><f1>123</f1><f2>456</f2></b>“.

Array doc[0]

If you use the square bracket operator on an XML document, SWoDL interprets all child elements of the document element as items, independent of the name of the element. In the example, the result is a total of three items, one for each of the child elements <a>, <b>, and <c>. doc[0] selects the first of the three elements. In the example, this is the XML element <a>.

• If that element has sub-elements, the element is returned with all sub-elements. XML namespaces are kept.

• If that element has no sub-elements, the text content of the node is returned.

Examples:

• doc[0] finds the first child element. In the example, this is the XML element <a>. The element has no sub-elements, so the method returns the text content of a, which is “1”.

• doc[1] finds the second child element. In the example, this is the XML element <b>. The element has sub-elements, so the result is the XML fragment “<b><f1>123</f1><f2>456</f2></b>“.

There’s one special case: If the root element is “itemsOfArray” and the child items have the name “item” and an XML attribute “index”, then the item is interpreted as an item with that index value. This corresponds to the format used to store an array in SWoDL.

Combined doc.b.f1

doc.c[0]

The evaluation rules ensure that you can combine the dot and square bracket operators in a natural way.

Examples:

• doc.b.f1 selects the element <f1> below the element <b> and returns the content, which is “123”.

• doc.c[0] selects the first element (index 0) below the element <c> and returns its content, which is “0”.

XML namespaces are ignored when evaluating the documents. In the end, you can parse most XML documents in a natural way.

Structs and Arrays

27

Example: The (abbreviated) result of a call to the EssenceManager method GetEMObjectWithLocations:

<GetEMObjectWithLocationsResult xmlns="http://www.blue-order.com/ma/essencemanagerws/EssenceManager"> <emobj> <emguid>262a3eb6-ddf8-4b52-acc5-4c126438c78d</emguid> <streamtype>MP4</streamtype> </emobj> <locations> <EMLocation> <locguid>c3ca04a3-ee21-482f-875d-7994d533b949</locguid> <carrierguid>1003</carrierguid> </EMLocation> <EMLocation> <locguid>f827c043-d6b3-433d-be71-0db03a2c1abf</locguid> <carrierguid>1001</carrierguid> </EMLocation> </locations> </GetEMObjectWithLocationsResult>

You can access the elements like this:

// declare method and call it var EssenceManagerWS_EssenceManager = "EssenceManagerWS/EssenceManager"; declare soap _auto GetEMObjectWithLocations(accesskey, emguid); var response = GetEMObjectWithLocations(AccessKey, "262a3eb6-ddf8-4b52-acc5-4c126438c78d") @ EssenceManagerWS_EssenceManager; // Get streamtype (sub element streamtype of element emobj): var streamType = response.emobj.streamtype; // Get number of locations below <locations> node: var numberOfLocations = array_size(response.locations); // Get first of the locations. The result is the XML fragment // <EMLocation>…<EMLocation> of the first returned EMLocation: var firstLocation = response.locations[0]; // Fetch the carrierguid from the first location: var carrierOfFirstLocation = firstLocation.carrierguid; // get carrierguid of second location: var carrierOfSecondLocation = response.locations[1].carrierguid;

Expressions

28

Expressions

The following sections describe SWoDL expressions:

• Operators

• Type Considerations

• Cast Operators

• Pitfall: Variables May Change Operation Type

Operators

SWoDL supports the usual operators that are available in most modern languages, and in the usual precedence.

Operator Name Operator Sign

Unary - !

Casts (int) (bool) (string) (float)

Multiplicative * / %

Additive + -

Shift << >>

Relational < > <= >=

Equality == !=

Logical AND &

Logical XOR ^

Logical OR |

Conditional AND &&

Conditional OR ||

Assignment = *= /= %= += -= <<= >>= &= ^= |=

Floating-point arithmetic was introduced in Interplay MAM 3.3.

The following operators have a different meaning when used with strings:

Expressions

29

Operator Name Operator Sign

Concatenation +

Relational: string comparison < > <= >=

Assignment with concatenation +=

You can also use parentheses to group your expressions.

Example:

3 * (4 + 5 – (4 * 7))

Type Considerations

All operators may be used for floating-point or integer arithmetic; some may additionally be used for string operations. The type of operation is defined by the type of operands.

It is very important to know that SWoDL variables are always treated like string variables. Even after assigning an integer value to a variable, it is treated as a string variable that contains the string representation of the integer value.

The basic rule for the selection of the type of operation works as follows:

1. If the operator is one of the string operators, and both operands are strings, the string operation is used.

2. If one of the operands is a double value or a string that can be interpreted as a double value (contains digits, followed by a dot, followed by digits), the double operation is used.

3. Otherwise, the integer operation is used.

Examples:

"a" + "b"// Rule 1: string operation (concatenation) 5.3 + "4"// Rule 2: double operation “5.3” + "4"// Rule 1: string operation (concatenation) 3 + "4"// Rule 3: integer operation 3 / "4.0"// Rule 2: double operation (“4.0” can be interpreted as // double) "3" / "4"// Rule 3: integer operation (“/” cannot be string op) "3" / "4.5"// Rule 2: double operation

Expressions

30

var x = 4.5; var y = 3; x + y;// Rule 1: string operation (because all variables are //treated as string) x / y;// Rule 2: double operation (because x contains "4.5" => //can be interpreted as double) y + 1;// Rule 2: integer operation (because 1 is not a string) y + (3 * x)// *: integer, +: integer

The last example shows that while evaluating an expression, the type is relevant. 3*x is evaluated using an integer operation, so the result is an integer. According to rule 3, the + operation in this case is also an integer operation, because the second operand (result of 3*x) is an integer value.

Cast Operators

You can always use cast operators to explicitly set the type of an operand.

Example:

(int) x + (int) y// integer operation (because of type casts) (float) 4 / 3// floating point operation 4 / (float) 3// floating point operation (float) 3 + "4"// string operation (bool) y

Pitfall: Variables May Change Operation Type

A very common mistake occurs when using loops in SWoDL. Consider the following examples:

Example 1:

var counter = 0; while( counter < 10 ) { // do something counter+=1; }

This works perfectly well. The “<” operation is an integer operation because 20 is an integer literal; “+=” is an integer operation because 1 is an integer literal.

Command Blocks

31

Example 2:

var counter = 0; var maxNumber = 10; while( counter < maxNumber ) { // BAD!!! // do something counter+=1; }

This fails, because now “<” is not an integer operation, but a string(!) operation, because both operands are strings. (Remember: all variables are treated as strings!) The loop aborts when counter has the value “2”, because when using a lexical comparison, the string “2” is larger than the string “10”. In this case you must use a cast operator (or better, use two, to clearly define what you want) as shown in the following example:

Example 3:

var counter = 0; var maxNumber = 10; while( (int)counter < (int)maxNumber ) { // OK // do something counter+=1; }

As a rule of thumb: If in doubt, use cast operators to clearly define which operation you want to use.

Command Blocks

A command block consists of a sequence of commands enclosed in brackets “{“ and ”}”. A command block is typically used in combination with an if command or a loop.

Example:

if( myvar == 1 ) { myvar = 4; goto farFarAway; }

Labels, Goto, Gosub, and Return

32

Labels, Goto, Gosub, and Return

Labels and Goto

SWoDL supports the goto command by means of definable labels. A label is defined by an identifier followed by a colon. A goto command consists of the keyword goto followed by a label and a semicolon.

Example:

goto mylabel; // do something mylabel: // do something else

Gosub and Return

SWoDL 2.2 supports the BASIC-like commands gosub and return in Interplay MAM 3.2.1. They are used for simple subroutines in a workflow.

Example:

// do some stuff gosub brewCoffee; // do more stuff brewCoffee: // do something useful return;

The gosub command jumps to a given label exactly as the goto call. The only difference is that the return address is stored in a system variable in the workflow. When the return command is executed, WorkflowEngine automatically continues with the next statement after the gosub call.

Suspend

33

Exit

The exit command terminates the workflow.

Example:

exit;

Error

The error command terminates the workflow with the status ERROR and sets the variable _ErrorMessage to the given text.

Example:

error "Somewith went wrong";

Delay

A delay command pauses the workflow for the given number of seconds. Argument can be either a literal or a variable.

Examples:

delay 10; delay delayInSeconds;

Suspend

The suspend command suspends the workflow.

Example:

suspend;

There is no timeout for the suspension. The workflow is reactivated when someone calls the wakeup method of WorkflowEngine for that workflow. Currently this is used in connection

Try-catch, Throw, and Assert

34

with OrderManagement. The workflow suspends itself and is reactivated by OrderManagement when the status of an order has changed.

Try-catch, Throw, and Assert

SWoDL can catch exceptions that occur when calling web or bus methods.

Starting with Interplay MAM version 5.7, SWoDL can also catch exceptions that happen in all other expressions, for example, when using division by zero, or when using “substr” to extract an invalid part of a string. This is only available if the feature toggle “DisableSwodlFunctions” is not enabled.

Example:

try { // commands... } catch { // handle exception }

If an exception occurs outside of a try-catch block, the workflow terminates with status “error”.

try-catch blocks can be nested. In this case the innermost exception handler is executed.

Interplay MAM 3.3 introduced the new throw command, allowing you to explicitly throw an exception.

Example:

try { throw "Some text"; } catch { // handle exception }

Interplay MAM 3.3 introduced the the assert command. It asserts a condition (in the example, myvar==42). If the condition is not met, the assert command throws an exception.

Example:

try {

Conditional Command: If – Then – Else

35

assert(myvar==42, "myvar is not 42"); } catch { // handle exception }

This is useful in cases where you “know” that some condition must be true, but you want to check the condition to be absolutely sure. You can also use it to simplify the structure of your workflow, and for SWoDL scripts that implement automated integration tests.

Conditional Command: If – Then – Else

SWoDL supports the typical if-then-else semantics in the same way as in C# or C++.

Example:

if( myvar == 1 ) goto labelA; if( myvar == 3 ) goto labelB; else goto labelC;

Usually, command blocks are used together with conditional commands.

Example:

if( myvar == 0 ) { p = 42; } else if( myvar == 3 ) { p = 23; } else { p = 0; }

Loops

36

Loops

The following sections describe SWoDL loops:

• While Loop

• Do-while Loop

• Retry-while Loop

While Loop

The while loop repeats a command as long as a condition is fulfilled. The condition is checked before the command is executed. The while loop is not entered if the condition is not fulfilled.

Examples:

var i=0; while(i < array_size(a)) { // do something i += 1; }

Do-while Loop

The do-while loop repeats a command as long as the condition is fulfilled. The condition is checked after the command has been executed.

Example:

do { myvar = SOAPCall() @ EM; } while(myvar != 0);

Retry-while Loop

The retry-while loop works like the do-while loop, with two differences:

• If the while condition is true, the next execution of the loop is delayed. This is useful when calling a SOAP method until the call succeeds, for example.

Loops

37

The delay is defined by the value of the variable _RetryDelay (unit: seconds). The initial value of _RetryDelay is 30.

• The retry-while loop includes a try-catch exception handler around the looped commands. All exceptions are simply ignored.

Example:

retry { result = OMA_SetOrderStatus(jobID, "newStatus"); } while( result != false);

It is possible to define a maximum number of tries for a retry-while loop.

Example:

retry(10) { result = OMA_SetOrderStatus(jobID, "newStatus"); } while( result != false);

After 10 tries the loop exits, regardless of the while condition. The number of tries can be any valid SWoDL expression, such as a variable.

If the loop has no maximum number of tries defined, the loop does not end until the while condition is met. If the while condition does not evaluate to true, an endless loop was created.

3 Built-in Functions

SWoDL supports a set of built-in functions to be used in expressions. They are described in:

• String Handling

• XML Functions

• Array Functions

• JSON Functions

• Regular Expressions

• Configuration Settings

• Common References

• Handling Lists: getelement, getnumberofelements

• Random Number Generation

• Floating-Point FunctionsEmpty Operation: nop

String Handling

Handling strings is described in the following sections:

• String Comparison: compare

• Extracting Part of a String: substr

• Length of a String: length

• Find a Substring in a String: find

• Find Last Occurrence of a Substring: findreverse

• XML Encoding and Decoding: xmlencode and xmldecode

• Trim a String: trim

• Replace Substrings: replace

String Handling

39

String Comparison: compare

The method compare compares two strings. It corresponds to the .NET method string.Compare.

Example:

result = compare(str1, str2);// case-sensitive result = compare(str1, str2, true); // case-insensitive

This call compares two strings lexicographically and according to case-sensivity. It returns -1 if the first string is less than the second, 0 if they are equal, and 1 if the first string is greater than the second.

The method can be called with an additional Boolean parameter: If the third parameter is set to false, the method behaves as the two-parameter method. If the third parameter is true, the strings are compared case-insensitive.

Extracting Part of a String: substr

The method substr extracts a part of a given string. It corresponds to the .NET method String.Substring.

Example:

str1 = "An example string"; s1 = substr(str1, 5); // returns "ample string" s2 = substr(str1, 5, 3); // returns "amp"

The first parameter is the source string. The second parameter is the start position (first character is position 0). The optional third parameter is the length of the extracted part. If the third parameter is missing, the method returns the rest of the string, beginning with the start position.

The method throws an exception if the start position or start position plus length are out of the bounds of the string str1. Starting with MAM 5.7, you can use the try-catch statement to handle those exceptions.

String Handling

40

Length of a String: length

The method length returns the length of a string.

Example:

len = length("test"); // returns 4

Find a Substring in a String: find

The method find returns the first occurrence of a pattern string in a string. It corresponds to the .NET method String.IndexOf.

Example:

str = "a large string"; pattern = "large"; pos = find(str, pattern); // returns 2 pos2 = find(str, "doesn’t exist in str"); // returns –1 -> not found

The strings are compared according to case-sensitivity. If the pattern string cannot be found the method returns –1.

You can provide a third parameter to determine the start position in the string.

Example:

pos3 = find(str, "a", 2); // returns 3

Find Last Occurrence of a Substring: findreverse

The method findreverse returns the last occurrence of a pattern string in a string. It corresponds to the .NET method String.LastIndexOf. In all other aspects the method works like find.

Example:

str = "a large string"; pattern = "a"; pos = findreverse(str, pattern); // returns 3 pos2 = findreverse(str, pattern, 2); // returns 0

XML Functions

41

Trim a String: trim

The trim method removes white space characters from the beginning and end of a string.

Example:

result = trim(" a string "); // returns "a string"

Replace Substrings: replace

The replace method replaces all occurrences of a pattern string by a string.

Example:

result = replace("hurliburli", "url", "ping"); // returns "hpingibpingi"

Converting a String to Lowercase: str_lower

The str_lower method returns a copy of a string converted to lowercase.

Example:

result = str_lower("Test"); // returns "test"

Converting a String to Uppercase: str_upper

The str_upper method returns a copy of a string converted to uppercase.

Example:

result = str_upper("Test"); // returns "TEST"

XML Functions

Handling XML documents is described in the following sections:

• XML Encoding and Decoding: xmlencode and xmldecode

• Parsing XML Documents

XML Functions

42

• Creating XML Documents

XML Encoding and Decoding: xmlencode and xmldecode

xmlecode

The method xmlencode encodes the XML special characters to their encoded counterparts, as shown in the table:

Character Character name XML encoding

& ampersand &amp;

" double quotation mark &quot;

' apostrophe &apos;

< less-than sign &lt;

> greater-than sign &gt;

Example:

result = xmlencode(“<sometag>”); // returns “&lt;sometag&gt;”

xmldecode

The method xmldecode is the counterpart of xmlencode. It converts encoded characters back to their original values.

Example:

result = xmldecode(“&lt;sometag&gt;”); // returns “<sometag>”

Both methods are supposed to be used when manually creating XML “strings” via string operations, and when creating XML documents using the xml_new_element method.

Example:

var metaValue = "Rock'n Roll"; var xml = "<myxml><title>" + xmlencode(metaValue) + "</title></myxml>";

XML Functions

43

Avid recommends using xmlencode for all variables when creating an XML document by means of string operations. It is a very common error to forget the encoding. SWoDL scripts frequently fail in production environments because XML special characters — such as the apostrophe in the example above — haven’t been properly encoded.

Parsing XML Documents

You can parse XML documents using the array and struct functionality of SWoDL. See “Using Arrays and Structs to Parse XML Documents” on page 25 for details. However, there are cases when it is better to use the XML parsing methods described in this chapter:

• If your XML document is very large and you need to access specific nodes, it is faster to use the xml_select method and an XPath expression, because it parses the XML document only once.

• If you want to handle XML elements that appear in different places in your XML document in one loop, it is easier and faster to use xml_select_multi and an XPath expression.

• The SWoDL code can be easier to read if you clearly state that you are working on XML elements.

• XML documents that contain lists of XML elements together with other XML elements on the same level cannot be handled properly with the struct and array functionality.

• If XML namespaces are important, you must use the built-in XML methods, because XML namespaces are ignored by the struct and array functionality.

The following sections describe functions to parse XML documents:

• XML namespace: xml_ns

• Getting text content: xml_text

• Getting a child element: xml_element

• Getting all child elements: xml_elements

• Getting all descendants: xml_descendants

• Getting an attribute value: xml_attribute

• Selecting a single node via XPath: xml_select

• Selecting multiple nodes via XPath: xml_select_multi

XML Functions

44

XML namespace: xml_ns The function xml_ns creates an XML namespace declaration:

var ns = xml_ns("http://services.avid.com");

Technically, the function only places curly brackets around the given parameter, but by using the function the code becomes much more readable. Typical use is the combination of an XML namespace with an element:

var result = xml_element(xmldoc, ns + "example");

This returns the first child element of the XML document that has the name “example” and is in the XML namespace “http://services.avid.com”.

Getting text content: xml_text The function xml_text returns the concatenated value of all text nodes below the root node of the given XML document.

Example:

<myxml> <example> <a>1</a> <b>2</b> </example> <example> <a>10</a> <b>11</b> </example> <description>Test XML</description> </myxml>

The function xml_text() returns the concatenated text values of the entire XML document:

var text = xml_text(xml); // returns the string "121011Test XML"

Encoded XML special characters like &amp;, &gt;, or &lt; are automatically decoded by this method.

XML Functions

45

Getting a child element: xml_element The function xml_element accepts an XML document and an element name as parameter. It returns the first child element of the root element that matches the given name.

XML namespaces are relevant. If the element has a non-empty XML namespace, you must ask for the element with the XML namespace.

If the first argument is not a valid XML document or if there is no child element with the given name in the given XML namespace, the method returns an empty string.

Example without namespaces: The variable xml contains the following XML document:

<myxml> <example> <a>1</a> <b>2</b> </example> <example> <a>10</a> <b>11</b> </example> <description>Test XML</description> </myxml>

The function xml_element is called like this:

var elem = xml_element(xml, "example");

The function returns the first element with name “example”:

<example> <a>1</a> <b>2</b> </example>

Of course, you can nest xml_element calls to traverse the XML document.

Example:

var a = xml_text( xml_element( xml_element(xml,"example"), "a"));

XML Functions

46

// returns textual content of node "a" within node "example"

Example with namespaces: The variable xmlWithNs contains the following XML document:

<myxml xmlns='http://services.avid.com' xmlns:test='http://www.test.org'> <example> <test:a>1</test:a> <b>2</b> </example> <example> <test:a>10</test:a> <b>11</b> </example> <description>Test XML</description> </myxml>

The function xml_element is called like this:

var avid = xml_ns("http://services.avid.com"); var elemWithNs = xml_element(xmlWithNs, avid + "example");

The function returns the first element with name “example” in the XML namespace “http://services.avid.com”:

<example xmlns="http://services.avid.com"> <test:a xmlns:test="http://www.test.org">1</test:a> <b>2</b> </example>

The XML namespaces of returned elements are preserved. For example, the node <a> is still in the XML namespace “http://www.test.org”, as in the original XML document.

Getting all child elements: xml_elements The function xml_elements accepts an XML document and, optionally, an element name as parameter.

• xml_elements(xmldoc) returns an array with all child elements of the root node of the XML document.

• xml_elements(xmldoc, elementName) returns an array with all child elements of the root node of the XML document that have the name given with the parameter elementName.

XML Functions

47

XML namespaces are relevant. If the element names have a non-empty XML namespace, add the XML namespace to the element name parameter.

If the first argument is not a valid XML document, or if there is no child element with the given name in the given XML namespace, the method returns an empty string.

Example without namespaces: The variable xml contains the following XML document:

<myxml> <example> <a>1</a> <b>2</b> </example> <example> <a>10</a> <b>11</b> </example> <description>Test XML</description> </myxml>

The function xml_elements is called like this:

// Return all elements: var allElems = xml_elements(xml); // Return the elements with the name "example": var exampleElems = xml_elements(xml, "example");

The first call xml_elements(xml) returns an array with the following elements:

Item #0: <example><a>1</a><b>2</b></example> Item #1: <example><a>10</a><b>11</b></example> Item #2: <description>Test XML</description>

The second call xml_elements(xml, “example”) returns an array with the following elements:

Item #0: <example><a>1</a><b>2</b></example> Item #1: <example><a>10</a><b>11</b></example>

Example with namespaces: The variable xmlWithNs contains the following XML document:

<myxml xmlns=’http://services.avid.com' xmlns:test='http://www.test.org'> <example>

XML Functions

48

<test:a>1</test:a> <b>2</b> </example> <example> <test:a>10</test:a> <b>11</b> </example> <description>Test XML</description> </myxml>

The function xml_elements is called like this:

// Namespace definition: var avid = xml_ns("http://services.avid.com"); // Getting all elements: var allElementsWithNs = xml_elements(xmlWithNs); // Getting all elements with name "example" in XML namespace // "http://services.avid.com": var allElementsWithNs = xml_elements(xmlWithNs, avid + "example");

The first call xml_elements(xmlWithNs) returns an array with the following elements:

Item #0: <example xmlns="http://services.avid.com"> <test:a xmlns:test="http://www.test.org">1</test:a> <b>2</b> </example> Item #1: <example xmlns="http://services.avid.com"> <test:a xmlns:test="http://www.test.org">10</test:a> <b>11</b> </example> Item #2: <description xmlns="http://services.avid.com">Test XML</description>

The items here are shown as a formatted and indented XML document. The elements returned by SWoDL are stored without any formatting or indentation.

The second call xml_elements(xml, avid + “example”) returns an array with the following elements:

Item #0: <example xmlns="http://services.avid.com">

XML Functions

49

<test:a xmlns:test="http://www.test.org">1</test:a> <b>2</b> </example> Item #1: <example xmlns="http://services.avid.com"> <test:a xmlns:test="http://www.test.org">10</test:a> <b>11</b> </example>

The XML namespaces of returned elements are preserved.

Getting all descendants: xml_descendants The function xml_descendants accepts an XML document and, optionally, an element name as parameter.

• xml_descendants (xmldoc) returns an array with all descendant elements of the document node of the XML document. This includes child nodes on any level below the document element, including child elements, grandchild elements, and so on.

• xml_elements(xmldoc, elementName) returns an array with all descendant elements of the document node of the XML document that have the name given with the parameter elementName. This includes child nodes on any level below the document element, including child elements, grandchild elements, and so on.

XML namespaces are relevant. If the element names have a non-empty XML namespace, add the XML namespace to the element name parameter.

If the first argument is not a valid XML document, or if there is no child element with the given name in the given XML namespace, the method returns an empty string.

Example: The variable xml contains the following XML document:

<myxml> <example> <a>1</a> <b>2</b> </example> <example> <a>10</a> <b>11</b> </example> <description>Test XML</description> </myxml>

XML Functions

50

The function xml_descendants is called like this:

// Return ALL descendant elements: var allDescendants = xml_descendants(xml); // Return all descendant elements having the name "a": var descendants = xml_descendants(xml, "a");

The first call xml_descendants(xml) returns an array with the following elements:

Item #0: <example><a>1</a><b>2</b></example> Item #1: <a>1</a> Item #2: <b>2</b> Item #3: <example><a>10</a><b>11</b></example> Item #4: <a>10</a> Item #5: <b>11</b> Item #6: <description>Test XML</description>

The result consists of all XML elements below the document, on any level.

The second call xml_descendants(xml, "a") returns an array with the following elements:

Item #0: <a>1</a> Item #1: <a>10</a>

If you use the second version with an XML document that contains XML namespaces, you must use a qualified element name using the xml_ns() function. The following example returns all elements that have the name “example” and are in the XML namespace “http://services.avid.com”.

var ns = xml_ns("http://services.avid.com"); var descendantsWithNs = xml_descendants(xmlWithNs, ns + "example");

Getting an attribute value: xml_attribute The function xml_attribute accepts an XML document and an attribute name as parameter. The method returns the value of the given XML attribute of the XML document’s root element.

If the first argument is not a valid XML document or if there is no attribute with the given name, the method returns an empty string.

XML Functions

51

Example: The variable xml contains the following XML document:

<myxml tag="value"> <description>Test XML</description> </myxml>

The function xml_attribute returns the value of the given attribute:

var v = xml_attribute(xmlDoc, "tag"); // returns the string "value"

You can use attribute names that are in XML namespaces by using the xml_ns function:

var avid = xml_ns("http://services.avid.com"); var v = xml_attribute(xmlWithNs, avid + "tag");

Selecting a single node via XPath: xml_select The method xml_select accepts at least two arguments:

• xmlDoc: an XML document

• xpath: an XPath expression, according to XPath version 1.0

• namespaces: an arbitrary number (0 or more) of additional parameters; each contains an XML namespace definition

The method extracts the first node that matches the XPath expression. If xmlDoc is not a valid XML document, or if no node matches the XPath expression, the method returns an empty string.

Example without namespaces: The variable xml contains the following XML document:

<myxml> <example> <a>1</a> <b>2</b> </example> <example> <a>10</a> <b>11</b> </example> <description>Test XML</description> </myxml>

XML Functions

52

The function xml_select returns the node selected by the given XPath expression:

var xpath = "/myxml/example/a"; var selNode = xml_select(xml, xpath); // returns "<a>1</a>"

Example with namespaces: The variable xmlWithNs contains the following XML document:

<myxml xmlns=’http://services.avid.com' xmlns:test='http://www.test.org'> <example> <test:a>1</test:a> <b>2</b> </example> <example> <test:a>10</test:a> <b>11</b> </example> <description>Test XML</description> </myxml>

The function xml_select is called with the following arguments:

• The XML document.

• The XPath expression. The XPath expression in the example below uses the namespace prefixes “avid” and “t”.

• Two parameters declaring the two namespaces, including the prefixes used in the XPath expression. You can provide an arbitrary number of namespace declarations. Each consists of a prefix like “avid”, followed by an equal sign, followed by the actual XML namespace name.

// XPath expression, using namespace declarations: var xpathNs = "/avid:myxml/avid:example/t:a"; // Selecting the node using the XPath expression: var selNodeNs = xml_select(xmlWithNs, xpathNs, "avid=http://services.avid.com", "t=http://www.test.org"); // returns "<test:a xmlns:test="http://www.test.org">1</test:a>"

Selecting multiple nodes via XPath: xml_select_multi The method xml_select_multi works like xml_select, but returns an array with all nodes that match the given XPath expression. The method expects at least two arguments:

• xmlDoc: an XML document

XML Functions

53

• xpath: an XPath expression, according to XPath version 1.0

• namespaces: an arbitrary number (0 or more) of additional parameters; each contains an XML namespace definition

The method extracts all nodes that match the XPath expression. If xmlDoc is not a valid XML document, or if no node matches the XPath expression, the method returns an empty array.

Example without namespaces: The variable xml contains the following XML document:

<myxml> <example> <a>1</a> <b>2</b> </example> <example> <a>10</a> <b>11</b> </example> <description>Test XML</description> </myxml>

The function xml_select_multi returns an array of all nodes selected by the given XPath expression:

var xpath = "/myxml/example/a"; var selNodes = xml_select_multi(xml, xpath);"

This returns an array with the following items:

Item #0: <a>1</a> Item #1: <a>10</a>

Example with namespaces: The variable xmlWithNs contains the following XML document:

<myxml xmlns=’http://services.avid.com' xmlns:test='http://www.test.org'> <example> <test:a>1</test:a> <b>2</b> </example> <example> <test:a>10</test:a> <b>11</b> </example>

XML Functions

54

<description>Test XML</description> </myxml>

The function xml_select_multi is called with the following arguments:

• The XML document.

• The XPath expression. The XPath expression in the example below uses the namespace prefixes “avid” and “t”.

• Two parameters declaring the two namespaces, including the prefixes used in the XPath expression. You can provide an arbitrary number of namespace declarations. Each consists of a prefix like “avid”, followed by an equal sign, followed by the actual XML namespace name.

var xpathNs = "/avid:myxml/avid:example/t:a"; var selNodesNs = xml_select_multi(xmlWithNs, xpathNs, "avid=http://services.avid.com", "t=http://www.test.org");

This call returns an array with the following items:

Item #0: <test:a xmlns:test="http://www.test.org">1</test:a> Item #1: <test:a xmlns:test="http://www.test.org">10</test:a>

Creating XML Documents

SWoDL supports methods to create an XML document in a similar way to .NET.

Example:

var newXml = xml_new_element("myxml", xml_new_attribute("tag", "value"), xml_new_element("example", xml_new_element("a", xmlencode("1")), xml_new_element("b", xmlencode("2"))), xml_new_element("description", xmlencode("Simon & Garfunkel")));

That code fragment creates the following XML document:

<myxml tag="value"> <example> <a>1</a>

XML Functions

55

<b>2</b> </example> <description>Simon &amp; Garfunkel</description> </myxml>

When creating an XML document, ensure that the text for text nodes is properly XML encoded. Avid recommends using the xmlencode() function for all text elements, as shown in the example above.

Only XML attributes that are created using the xml_attribute() method are automatically encoded properly.

The methods can be used with XML namespaces:

var avid = xml_ns("http://services.avid.com"); var t = xml_ns("http://www.test.org"); var newXmlNs = xml_new_element(avid + "myxml", xml_new_element(avid + "example", xml_new_element(t + "a", xmlencode("1")), xml_new_element(avid + "b", xmlencode("2"))), xml_new_element("description", xmlencode("Simon & Garfunkel")));

This results in the following XML document:

<myxml xmlns="http://services.avid.com"> <example> <a xmlns="http://www.test.org">1</a> <b>2</b> </example> <description xmlns="">Simon &amp; Garfunkel</description> </myxml>

The following sections describe functions to create XML documents:

• Create an XML element: xml_new_element

• Create a new XML attribute: xml_new_attribute

Create an XML element: xml_new_element

The method xml_new_element expects an arbitrary number of arguments. The first argument is the name of the new XML element. The following arguments can be one of the following:

XML Functions

56

• The result of another xml_new_element() call. The XML element created by the inner call is added as child element.

• The result of a call to xml_new_attribute(). The attribute is added as XML attribute.

• A string containing an XML document. The document is added as child element.

• A string that is not parseable as XML document. Avid strongly recommends only passing strings encoded using the xmlencode() method.

Example 1: Create a new XML element:

var newElem = xml_new_element("example"); // Returns: <example />

Example 2: Create a new XML element in an XML namespace:

var avid = xml_ns("http://services.avid.com"); var newElemNs = xml_new_element(avid + "example"); // Returns: <example xmlns="http://services.avid.com" />

Example 3: Create a new XML element with the following sub-elements:

• an XML attribute

• an inner XML element

• an embedded XML fragment

• a text node, properly encoded using xmlencode

var newElemWithSubElements = xml_new_element("example", xml_new_attribute("tag", "value"), xml_new_element("description"), "<myxml><a/></myxml>", xmlencode("Simon & Garfunkel")); // Returns (formatted for better readability): // <example tag="value"> // <description /> // <myxml> // <a /> // </myxml> // Simon &amp; Garfunkel // </example>

XML Functions

57

Example 4: Create a new XML element in the namespace “http://services.avid.com” with the following sub-elements:

• an XML attribute in the same namespace

• an inner XML element in the same namespace

• an embedded XML fragment in the empty namespace

• a text node, properly encoded using xmlencode

var avid = xml_ns("http://services.avid.com"); var newElemWithSubElementsNs = xml_new_element(avid + "example", xml_new_attribute(avid + "tag", "value"), xml_new_element(avid + "description"), "<myxml><a/></myxml>", xmlencode("Simon & Garfunkel")); // Returns (formatted for better readability): // <example p1:tag="value" xmlns:p1="http://services.avid.com" // xmlns="http://services.avid.com"> // <p1:description /> // <myxml xmlns=""> // <a /> // </myxml> // Simon &amp; Garfunkel // </example>

WorkflowEngineWS creates XML namespace prefixes like the “p1” in the example, as needed.

Example 5: This is the same as the previous example, but now we define the XML namespace prefix by adding an appropriate “xmlns:prefixName” attribute to the element:

var avid = xml_ns("http://services.avid.com"); var newElemWithSubElementsNs = xml_new_element(avid + "example", xml_new_attribute("xmlns:avid", "http://services.avid.com"), xml_new_attribute(avid + "tag", "value"), xml_new_element(avid + "description"), "<myxml><a/></myxml>", xmlencode("Simon & Garfunkel")); // Returns (formatted for better readability): // <avid:example xmlns:avid="http://services.avid.com" // avid:tag="value"> // <avid:description />

XML Functions

58

// <myxml> // <a /> // </myxml> // Simon &amp; Garfunkel // </avid:example>

Create a new XML attribute: xml_new_attribute The function xml_new_attribute() is used to create a new XML attribute to be added to an XML element. The function can only be used in connection with the xml_new_element() function.

Example 1: Create a new element with two attributes:

var newElem = xml_new_element("example", xml_new_attribute("tag", "value"), xml_new_attribute("performed_by", "Simon & Garfunkel")); // Returns: // <example tag="value" performed_by="Simon &amp; Garfunkel" />

Example 2: Create a new element with two attributes, one of them using an XML namespace:

var avid = xml_ns("http://services.avid.com"); var newElem = xml_new_element("example", xml_new_attribute(avid + "tag", "value"), xml_new_attribute("performed_by", "Simon & Garfunkel")); // Returns: // <example p1:tag="value" performed_by="Simon &amp; Garfunkel" // xmlns:p1="http://services.avid.com" />

Technically, the xml_attributes() method creates an XML fragment with a magic value as element name:

var xmlFragment = xml_new_attribute("tag", "value"); // Returns: // <__wfe_xml_attribute__ tag="value" /> var avid = xml_ns("http://services.avid.com"); var xmlFragmentNs = xml_new_attribute(avid + "tag", "value"); // Returns: // <__wfe_xml_attribute__ p1:tag="value" // xmlns:p1="http://services.avid.com" />

The implementation of the xml_new_element method transforms that fragment to an XML attribute.

XML Functions

59

Add child elements: xml_add

The function xml_add() adds child elements to the root element of an XML document. The first argument is the XML document. The following arguments are the child elements to be added. They can be one of the following:

• The result of an xml_new_element() call. The XML element created by the inner call is added as a child element.

• The result of a call to xml_new_attribute(). The attribute is set as an XML attribute to the root element of the XML document.

• A string containing an XML document. The document is added as a child element.

• A string that is not parseable as an XML document. Avid strongly recommends only passing strings that are encoded using the xmlencode() function.

The function does not modify the XML document that is given as the first argument. It returns the modified XML document as the result value.

Examples:

var xml = "<test><a>5</a></test>"; // 1.) Add a child element: var modifiedXml = xml_add(xml, xml_new_element("b", "abc")); // returns: <test><a>5</a><b>abc</b></test> // 2.) Add an attribute: var modifiedXml2 = xml_add(xml, xml_new_attribute("id", "1")); // returns: <test id="1"><a>5</a></test> // 3.) Add an XML fragment: var modifiedXml3 = xml_add(xml, "<c f='7'>xyz</c>"); // returns: <test><a>5</a><c f="7">xyz</c></test> // 4.) Add an XML text node: var modifiedXml4 = xml_add(xml, xmlencode("3<=4")); // returns: <test><a>5</a>3&lt;=4</test>

Array Functions

60

The method supports XML namespaces in the same way as xml_new_element().

Examples:

var ns = xml_ns("http://www.avid.com"); var xml = "<test><a>5</a></test>"; // 1.) Add a child element: var modifiedXml = xml_add(xml, xml_new_element(ns + "b", "abc")); // returns: // <test><a>5</a><b xmlns="http://www.avid.com">abc</b></test> // 2.) Add an attribute: var modifiedXml2 = xml_add(xml, xml_new_attribute(ns + "id", "1")); // returns: // <test p1:id="1" xmlns:p1="http://www.avid.com"><a>5</a></test> // 3.) Add an XML fragment: var modifiedXml3 = xml_add(xml, "<c f='7' xmlns='http://www.avid.eu'>xyz</c>"); // returns: // <test><a>5</a><c f="7" xmlns="http://www.avid.eu">xyz</c></test>

Array Functions

SWoDL supports a number of built-in functions for arrays which are inspired by LINQ. The following built-in functions are supported:

• array_aggregate: Aggregates the elements of an array using a given aggregation function

• array_all: Returns true if all elements of an array fulfill a given condition

• array_any: Returns true if any element of the array fulfills a given condition

• array_select: Transforms the elements of an array using a given transformation function

• array_where: Returns all elements of an array that fulfill a given condition

Aggregating Elements: array_aggregate

The array_aggregate function aggregates the elements of an array using a given aggregation function. The method accepts two parameters:

• An array

Array Functions

61

• An aggregation function

The aggregation function is a SWoDL expression that uses the special variables _a and _b.

Examples:

var numbers = array_create(); numbers[0] = 5; numbers[1] = 3; numbers[3] = 7; var sum = array_aggregate(numbers, (int)_a + (int)_b); // sum = 5 + 3 + 7 = 15 var product = array_aggregate(numbers, (int)_a * (int)_b); // product = 5 * 3 * 7 = 105

The array_aggregate function works as follows:

• If the array is empty, it returns an empty string.

• If the array has one element, it returns that element.

• If the array contains two or more elements, it assigns the value of the first element to _a and the value of the second element to _b. Then it executes the aggregation function and assigns the result to _a. If there are more elements, it assigns the value of the next element to _b, executes the aggregation function, and assigns the result to _a; and so on, until all entries are handled. Finally, the value of _a is returned.

The method only uses elements that are set in the array. In the example, only the indexes 0, 1, and 3 are set, but not 2. This means that only the elements with indexes 0, 1, and 3 are aggregated.

If there is a global variable _a or _b, the value is not visible while executing the array_aggregate function, but the values of the global variables are restored after the execution.

Checking a Condition on all Elements: array_all

The array_all function checks if all elements of an array meet a given condition. The method accepts two parameters:

• An array

• A condition function

Array Functions

62

The condition function is a SWoDL expression that uses the special variable _value and returns a boolean result value.

Examples:

var numbers = array_create(); numbers[0] = 5; numbers[1] = 3; numbers[3] = 7; var allAreLessThan10 = array_all(numbers, (int)_value < 10); // true, because all values are less than 10 var allAreLessThan6 = array_all(numbers, (int)_value < 6); // false, because 7 is not less than 10

The array_all function works ad follows:

• If the array is empty, it returns true (“1”).

• If the array is not empty, the method iterates over all elements in the array. It assigns the value of an element to _value and evaluates the condition function. If the result for an element is false, it terminates execution and returns false (“0”). If the result is true for all elements, it returns true (“1”).

The method only uses elements that are set in the array. In the example, only the indexes 0, 1, and 3 are set, but not 2. This means that only the elements with indexes 0, 1, and 3 are checked.

If there is a global variable _value, the value is not visible while executing the array_all function, but the values of the global variable are restored after the execution.

Checking if any Element Fulfills a Condition: array_any

The array_any can be called with one or two parameters:

• When called with one parameter, it returns true if the array is not empty.

• When called with two parameters, it checks if any element of an array fulfills a given condition.

The method accepts the following parameters:

• An array

• Optional: a condition function

Array Functions

63

The condition function is a SWoDL expression that uses the special variable _value and returns a boolean result value.

Examples:

var numbers = array_create(); numbers[0] = 5; numbers[1] = 3; numbers[3] = 7; var anyAtAll = array_any(numbers); // true, because the array is not empty var anyIsLessThan4 = array_any(numbers, (int)_value < 4); // true, because 3 is less than 4 var anyIsLessThan2 = array_all(numbers, (int)_value < 2); // false, because no element is less than 2

The array_any function works like this:

• If the array is empty, it returns false (“0”).

• If the array is not empty and no condition function is given, it returns true (“1”).

• If the array is not empty and a condition function is given, the method iterates over all elements in the array. It assigns the value of an element to _value and evaluates the condition function. If the result for an element is true, it terminates execution and returns true (“1”). If the result is false for all elements, it returns false (“0”).

The method only uses elements that are set in the array. In the example, only the indexes 0, 1, and 3 are set, but not 2. This means that only the element with indexes 0, 1, and 3 are checked.

If there is a global variable _value, the value is not visible while executing the array_any function, but the values of the global variable are restored after the execution.

Transforming an Array: array_select

The array_select function returns a new array that contains all elements of a given array, transformed by means of a transformation function.

The method accepts two parameters:

• An array

Array Functions

64

• A transformation function

The transformation function is a SWoDL expression that uses the special variable _value.

Example:

var numbers = array_create(); numbers[0] = 5; numbers[2] = 7; numbers[4] = 3; var squareRoots = array_select(numbers, (int)_value * (int)_value); // returns an array with three enries: // - entry #0 contains 5 * 5 = 25 // - entry #2 contains 7 * 7 = 49 // - entry #4 contains 3 * 3 = 9

The array_select function works as follows:

• If the array is empty, it returns an empty array.

• If the array is not empty, the method iterates over all elements in the array. It assigns the value of an element to _value, evaluates the transformation function and assigns the result to the resulting array. The result is a new array that contains all entries of the original array with their original index, but transformed using the transformation function.

The method only uses elements that are set in the array. In the example, only the indexes 0, 2, and 4 are set, but not 2. This means that only the elements with indexes 0, 2, and 4 are transformed and returned.

If there is a global variable _value, the value is not visible while executing the array_select function, but the values of the global variable are restored after the execution.

Filtering Elements with a Condition: array_where

The array_where function returns a new array that contains all elements of a given array that meet a given condition.

The method accepts two parameters:

• An array

• A condition function

JSON Functions

65

The condition function is a SWoDL expression that uses the special variable _value and returns a boolean result value.

Example:

var numbers = array_create(); numbers[0] = 5; numbers[2] = 7; numbers[4] = 3; var lessThan6 = array_where(numbers, (int)_value < 6); // returns an array with two enries: // - entry #0 contains 5 // - entry #1 contains 3 // The indexes of the resulting array are consecutive integer values // starting with 0.

The array_where function works as follows:

• If the array is empty, it returns an empty array.

• If the array is not empty, the method iterates over all elements in the array. It assigns the value of an element to _value and evaluates the condition function. The result is a new array that contains all elements that fulfill the given condition. The indexes of the items in the resulting array are consecutive integer values starting with 0.

The method only uses elements that are set in the array. In the example, only the indexes 0, 2, and 4 are set, but not 2. This means that only the elements with indexes 0, 2, and 4 are checked.

If there is a global variable _value, the value is not visible while executing the array_where function, but the values of the global variable are restored after the execution.

JSON Functions

Handling JSON documents is described in the following sections:

• Converting JSON Documents to SWoDL Datatypes

• Converting a Complex SWoDL Type to a JSON Document

• Parsing JSON Documents

• Creating JSON Documents

JSON Functions

66

Converting JSON Documents to SWoDL Datatypes

You can parse JSON documents into SWoDL variables using the json_to_swodl() method.

Example:

var json = "[" + " {" + " \"name\" : \"John Doe\"," + " \"benefits\": [" + " \"Life Insurance\"," + " \"Disability Insurance\"" + " ]" + " }," + " {" + " \"name\" : \"Bob Smith\"," + " \"benefits\": [" + " \"Life Insurance\"," + " \"Disability Insurance\"," + " \"401K\"" + " ]" + " }" + " ]"; var employees = json_to_swodl(json); // employees[0].name -> John Doe // employees[0].benefits[0] -> Life Insurance // employees[0].benefits[1] -> Disability Insurance // employees[1].name -> Bob Smith // employees[1].benefits[0] -> Life Insurance // employees[1].benefits[1] -> Disability Insurance // employees[1].benefits[2] -> 401K

Converting a Complex SWoDL Type to a JSON Document

You can create JSON documents from SWoDL variables using the swodl_to_json() method.

Example

var arr = array_create(); arr[0].name = "John Doe"; arr[0].benefits[0] = "Life Insurance"; arr[0].benefits[1] = "Disability Insurance"; arr[1].name = "Bob Smith"; arr[1].benefits[0] = "Life Insurance"; arr[1].benefits[1] = "Disability Insurance"; arr[1].benefits[2] = "401K"; var params;

JSON Functions

67

params.employees = arr; var json = swodl_to_json(params);

The swodl_to_json method is used to create a JSON fragment. The resulting JSON fragment looks like this:

{ "employees": [ { "name" : "John Doe", "benefits": [ "Life Insurance", "Disability Insurance" ] }, { "name" : "Bob Smith", "benefits": [ "Life Insurance", "Disability Insurance", "401K" ] } ] }

Parsing JSON Documents

Getting a JSON property The json_property method expects the string representation of a JSON object and returns the value of a given property.

var doc = "{ " + "\"name\" : \"John Doe\", " + "\"address\" : { " + " \"street\" : \"5th Street\", " + " \"city\" : \"New York\" " + " } " + "}"; // JSON: // { // "name": "John Doe", // "address": { // "street": "5th Street", // "city": "New York" // } // } var name = json_property(doc, "name");

JSON Functions

68

// returns John Doe var address = json_property(doc, "address"); // returns the JSON object: // { // "street": "5th Street", // "city": "New York" // } var example1 = json_property(doc, "doesnt_exist"); // returns an empty string var example2 = json_property("xyz", "abc"); // returns an empty string, because xyz is not a well-formed JSON // document

If the value of the property is a basic type, the value is returned. If the value is a JSON object or JSON array, the value is returned as string representation of the JSON object or array.

If you ask for a non-existing property or if the given JSON document is invalid, the method returns an empty string.

Getting all JSON properties The json_properties method expects the string representation of a JSON object and returns a SWoDL array with all properties of the JSON object. The items in the SWoDL array are structs with the fields name and value.

var doc = "{ " + "\"name\" : \"John Doe\", " + "\"address\" : { " + " \"street\" : \"5th Street\", " + " \"city\" : \"New York\" " + " } " + "}"; // JSON: // { // "name": "John Doe", // "address": { // "street": "5th Street", // "city": "New York" // } // } var props = json_properties(doc); // returns an array of size 2 var prop0_name = props[0].name; // returns "name" var prop0_value = props[0].value; // returns "John Doe"

JSON Functions

69

var prop1_name = props[1].name; // returns "address" var prop1_value = props[1].value; // returns the JSON object: // { // "street": "5th Street", // "city": "New York" // } var example1 = json_properties("xyz"); // returns an empty array

The array can be handled comfortably with the array functions. See Array Functions on page 60 for details.

If the value of a property is a basic type, the value is returned. If the value is a JSON object or JSON array, the value is returned as string representation of the JSON object or array.

If the given JSON document is invalid or does not contain a JSON object, the method returns an empty array.

Getting a JSON array as SWoDL array The json_array method expects the string representation of a JSON array and returns a SWoDL array with the items in the JSON array.

var doc = "[ " + "1, " + "\"Apple pie\", " + "{ " + " \"street\" : \"5th Street\", " + " \"city\" : \"New York\" " + "} " + "]"; // JSON: // [ // 1, // "Apple Pie", // { // "street": "5th Street", // "city": "New York" // } // } var arr = json_array(doc); // returns an array of size 2 var arrItem0 = arr[0]; // returns "1" var arrItem1 = arr[1]; // returns "Apple pie" var arrItem2 = arr[2];

JSON Functions

70

// returns the JSON object: // { // "street": "5th Street", // "city": "New York" // } var example1 = json_array("xyz"); // returns an empty array

The array can be handled comfortably with the array functions. See Array Functions on page 60 for details.

If the given JSON document is invalid or does not contain a JSON object, the method returns an empty array.

Selecting a JSON item with a JSONPath expression The json_select method expects the string representation of a JSON array and returns the first item that matches the given JSONPath expression. For a definition of JSONPath see http://goessner.net/articles/JsonPath/.

var doc = "{ " + "\"name\" : \"John Doe\", " + "\"address\" : { " + " \"street\" : \"5th Street\", " + " \"city\" : \"New York\" " + " } " + "}"; // JSON: // { // "name": "John Doe", // "address": { // "street": "5th Street", // "city": "New York" // } // } var name = json_select(doc, "$.name"); // returns "John Doe" var street = json_select(doc, "$.address.street"); // returns "5th Street" var example1 = json_select(doc, "$.doesnt_exist"); // returns an empty string

If the given JSON document is invalid or there is no item that matches the given JSONPath expression, the method returns an empty string.

JSON Functions

71

Selecting multiple JSON items with a JSONPath expression The json_select_multi method expects the string representation of a JSON array and returns a SWoDL array with all items that match the given JSONPath expression. For a definition of JSONPath see http://goessner.net/articles/JsonPath/.

var doc = "{ " + " \"actors\" : [ " + " \"Ingrid Bergman\", " + " \"Humphrey Bogart\", " + " \"Paul Henreid\" " + " ], " + " \"addresses\": [" + " { " + " \"street\" : \"5th Street\", " + " \"city\" : \"New York\" " + " } " + " ] " + "}"; // JSON: // { // "actors": [ // "Ingrid Bergman", // "Humphrey Bogart", // "Paul Henreid" // ], // "addresses": [ // { // "street": "5th Street", // "city": "New York" // } // ] // } var actors = json_select_multi(doc, "$.actors[*]"); // returns an array with three items var actor0 = actors[0]; // returns "Ingrid Bergman" var actor1 = actors[1]; // returns "Humphrey Bogart" var actor2 = actors[2]; // returns "Paul Henreid" var addresses = json_select_multi(doc, "$.addresses[*]"); // returns an array with one entry var address0 = addresses[0]; // returns the JSON object: // { // "street": "5th Street", // "city": "New York" // } var example1 = json_select_multi(doc, "$.doesnt_exist[*]"); // returns an empty array

JSON Functions

72

If the given JSON document is invalid or there is no item that matches the given JSONPath expression, the method returns an empty array.

Testing if a JSON document is an object or array The methods json_is_array and json_is_object expects the string representation of a JSON document and test if it is a JSON array or a JSON object.

var isArray1 = json_is_array("[ 1,2,3 ]"); // returns 1 (true) var isArray2 = json_is_array("{ \"xyz\": 42 }"); // returns 0 (false) var isArray3 = json_is_array("xyz"); // returns 0 (false) var isObject1 = json_is_object("[ 1,2,3 ]"); // returns 0 (false) var isObject2 = json_is_object("{ \"xyz\": 42 }"); // returns 1 (true) var isObject3 = json_is_object("xyz"); // returns 0 (false)

If the given JSON document is invalid, both methods return false.

Creating JSON Documents

Creating a JSON object The json_new_object method accepts an arbitrary number of parameters and creates a JSON object with the parameters as properties. The parameters must contain a JSON property, created with the json_new_property method.

var obj1 = json_new_object( json_new_property("name", json_encode("Cookie Monster")), json_new_property("address", json_new_object( json_new_property("street", json_encode("Sesame Street")), json_new_property("city", json_encode("New York"))))); // returns: // { // "name": "Cookie Monster", // "address": { // "street": "Sesame Street", // "city": "New York" // } // } try { var obj2 = json_new_object("abc"); // throws an exception } catch {} try { var obj3 = json_new_object(json_new_array(1,2,3)); // throws an exception

JSON Functions

73

} catch {}

If a parameter is invalid the method throws an exception.

Technically, the given parameters are parsed as JSON objects and all properties of those JSON objects are added. So, you could use json_new_object or the string representation of a JSON object as parameter but that could be confusing and should be avoided.

Creating a JSON array The json_new_array method accepts an arbitrary number of parameters and creates a JSON array with the parameters as items. The parameters can contain one of the following:

• The string representation of a JSON object, preferably created with the json_new_object method.

• A JSON string token, preferably created with the json_encode method. The string token contains of the string with escaped double quotes, surrounded in double quotes.

• An integer value.

• The strings “true” or “false” for boolean values.

var array1 = json_new_array(1,2,3); // returns the JSON: // [ 1, 2, 3 ] var array2 = json_new_array( 24, json_encode("Casablanca"), "true", json_new_object( json_new_property("actors", json_new_array( json_encode("Ingrid Bergman"), json_encode("Humphrey Bogart"))))); // returns the JSON: // [ // 24, // "Casablanca", // true, // { // "actors": [ // "Ingrid Bergman", // "Humphrey Bogart" // ] // } // ]

JSON Functions

74

If the JSON document would be invalid, the method throws an exception.

A typical error is a missing call of json_encode to properly encode strings. The method always interpret the parameters as JSON tokens. An unencoded string cannot be parsed as JSON token, causes an error and results in an empty string.

You can use the string representation of a JSON object as parameter if this simplifies your code. Example:

var array5 = json_new_array(42, "{ \"name\": \"John Doe\" }"); // returns the JSON: // [ // 42, // { // "name": "John Doe" // } // ]

Technically, you can also use json_new_property as parameter, because that method returns a valid JSON object with one property, but that can be misleading and is not recommended.

Creating a JSON property The json_new_property method accepts a property name and value and creates a JSON object with one JSON property with the given name and value. The value can be one of the following:

• The string representation of a JSON object, preferably created with the json_new_object method.

• A JSON string token, preferably created with the json_encode method. The string token contains of the string with escaped double quotes, surrounded in double quotes.

• An integer value.

• The strings “true” or “false” for boolean values.

The method itself is typically only useful in connection with the method json_new_object to create a JSON document programmatically.

var prop1 = json_new_property("test", 42); // returns the JSON: // { // "test": 42 // } var prop2 = json_new_property("name", json_encode("Cookie Monster")); // returns the JSON:

JSON Functions

75

// { // "name": "Cookie Monster" // } var prop3 = json_new_property("isCool", "true"); // returns the JSON: // { // "isCool": true // } var prop4 = json_new_property("address", json_new_object( json_new_property("street", json_encode("Sesame Street")), json_new_property("city", json_encode("New York")))); // returns the JSON: // { // "address": { // "street": "Sesame Street", // "city": "New York" // } // } try { var prop5 = json_new_property("example", "fdklsfkl"); // throws an exception, because "fdklsfkl" cannot be parsed as // JSON token } catch {}

If the value is invalid, the method throws an exception.

A typical error is a missing call of json_encode to properly encode strings. The method always interpret the parameters as JSON tokens. An unencoded string cannot be parsed as JSON token, causes an error and results in an exception.

Encoding a string to a JSON token The json_encode method accepts a string and returns a properly encoded JSON string token. Double quotes and backslashes in the string are escaped with a backslash.

The method itself is typically only useful in connection with the methods json_new_array and json_new_property to create a JSON document programmatically.

var test = json_encode("test"); // returns (including the double quotes): // "test" var encoded1 = json_encode("Hamlet: \"To be or not to be\""); // returns (including the double quotes): // "Hamlet: \"To be or not to be\""

Regular Expressions

76

var encoded2 = json_encode("C:\\test.txt"); // returns (including the double quotes): // "C:\\test.txt"

Decoding a JSON string token to a SWoDL string The json_decode method accepts a JSON string token and the value as regular SWoDL string. The JSON string consists of a string, where double quotes and backslashes that are escaped with a backslash, surrounded by double quotes.

var test = json_decode("\"test\""); // returns: // test var decoded1 = json_decode("\"Hamlet: \\\"To be or not to be\\\"\""); // returns: // Hamlet: "To be or not to be" var decoded2 = json_decode("\"C:\\\\test.txt\""); // returns: // C:\test.txt try { var ex = json_decode("test"); // throws an exception, because test is not a valid JSON string token } catch{}

In the last example, the argument is not a valid JSON string token. In this case, the method throws an exception.

Regular Expressions

SWoDL introduced regular expressions in Interplay MAM 3.3.2 to simplify handling of strings. Internally, WorkflowEngine uses the regular expression capabilities of Microsoft .NET. They are described in detail in http://msdn.microsoft.com/en-us/library/hs600312(VS.80).aspx .

The following sections describe regular expressions:

• Regular Expression Match: regex_ismatch

• Finding Regular Expression Matches: regex_find

Regular Expressions

77

• Replacing Using Regular Expressions: regex_replace

• Defining Match Options

Regular Expression Match: regex_ismatch

New in Interplay MAM 3.3.2: The method regex_ismatch checks if there is a match of a regular expression in a given string.

Example:

b1 = regex_ismatch("abcabc", "bc.*"); // returns true, because there is a match of the reg. expr. "bc.*" in // the string "abcabc" b2 = regex_ismatch("abcabc", "cb.*"); // returns false, because there is no match of the regular expression // "cb.*" in the string "abcabc"

The method supports an optional third parameter that defines special options. For information about special options, see “Defining Match Options” on page 79.

Finding Regular Expression Matches: regex_find

New in Interplay MAM 3.3.2: The method regex_find searches for the first occurrence of a regular expression in a string.

Example:

b1 = regex_find("abcabc", "bc.*"); // returns 1, because 1 is the position of the first match of // the regular expression "bc.*" in the string "abcabc". b2 = regex_find("abcabc", "xy.*"); // returns -1 to indicate that there is no match for the regular // expression "xy.*" in the string "abcabc"

The method supports an optional third parameter that defines special options. For information about special options, see “Defining Match Options” on page 79.

Replacing Using Regular Expressions: regex_replace

New in Interplay MAM 3.3.2: The method regex_replace replaces all matches of a regular expression with a replacement expression.

Regular Expressions

78

Example:

s1 = regex_replace("abacadabra", "b.", "xy"); // replaces all occurences of the regular expression "b." // with "xy", returning "axycadaxya"

This is especially useful when using groups (using parentheses) in the regular expression, and group references — “$<num>“, where <num> starts with 1 for the first group — in the replacement expression.

Example:

s2 = regex_replace("abacadabra", "b(.)", "x$1"); // Searches for all matches of the regular expression "b(.)". // The string matching the expression part in parentheses is stored // as match group 1, here the one character following the character // “b”. // This group can be used with “$1” in the replacement expression. // So, this example searches for all “b”s followed by a single // character and it replaces the matches with an “x” and the // character that followed the “b” in the original string. // Result is “axacadaxra”.

regex_replace performs very complex transformations of strings, comparable to the UNIX command line tool “sed”. A more complex example shows how to transform a line of a “dir” command.

Example:

var s = "02.03.2005 16:16 0 CONFIG.SYS"; // the line returned by “dir” with german date format var regex = "([0-9]*)\\.([0-9]*)\\.([0-9]*)\\s*[0-9]*:[0-9]*\\s*[0-9]*\\s* ([^\\s].*)"; // the regular expression ensures that the “02” of the date is in // group 1, the “03” of the date is in group 2, the “2005” in // group 3 and the filename “CONFIG.SYS” in group 4. var repl = "$4: $3-$2-$1"; // Replacement expression, puts the filename in front, followed by a // colon, followed by the date in ISO format:

Configuration Settings

79

var r = regex_replace(s, regex, repl); // returns “CONFIG.SYS: 2005-03-02”

The method supports an optional fourth parameter that defines special options. For information about special options, see see “Defining Match Options” on page 79.

Defining Match Options

All of the regular expression functions support an optional additional parameter that defines special matching options. The additional parameter is a string that contains any of the characters shown in the following table:

Character Enables the Option

i Ignore case: specifies case-insensitive matching.

m Multi line: Changes the meaning of ^ and $ so they match at the beginning and end, respectively, of any line, and not just the beginning and end of the entire string.

s Single line: Changes the meaning of the dot (.) so it matches every character (instead of every character except \n).

r Right to left: Specifies that the search will be from right to left instead of left to right.

Example:

b1 = regex_ismatch("AbcAbc", "ab.*", "i"); // returns true, because "AbcAbc" contains a match of the regular // expression "ab.*", when using case-insensitive matching

Configuration Settings

The following functions return the values of configuration settings as defined in Interplay MAM System Administrator.

• config_get (profile, key)

Returns the value of a key in a configuration profile. If the key or the profile does not exist, it returns an empty string.

• config_get (profile, key, defaultValue)

Common References

80

Returns the value of a key in a configuration profile. If the key or the profile does not exist, it returns the given default value.

Examples:

var loglevel = config_get("DataManagerWS", "Logging/File/Level", "Info"); var UserManagementWS_UM = "UserManagementWS/UM"; declare string Login(user, pwd); var sessionId = Login( config_get("DataManagerWS", "ServiceAccount/User"), config_get("DataManagerWS", "ServiceAccount/Password") ) @ UserManagementWS_UM;

The settings of type “password” in the System Administrator contain confidential information like passwords. These settings are displayed as password fields in the System Administrator. MAM stores the values in encrypted form.

The config_get method automatically handles settings of type password and returns the decrypted values.

This can be a security threat. If you store the value in a SWoDL variable, the decrypted value is visible in the Workflow Monitor in clear text!

To avoid revealing the value of the password setting, you should not assign it to a variable. Instead, use the config_get function directly when calling a web or bus method, as shown in the example above. If you cannot avoid storing the value in a variable, you should set the variable to an empty string as soon as possible after using the password.

Common References

The methods in this chapter simplify the handling of references as received in the context of Media Central. If you start a process with non-MAM assets in Media Central | UX the reference to the non-MAM assets is stored as a URN in the following format:

urn:com.avid:common-object:systemType:systemID:type:ID The variable elements are:

• systemType: type of the object’s source system

• systemID: unique identifier of the object’s source system in the scope of systemType

• type: type of the object

Common References

81

• ID: unique identifier of the object in the source system identified by systemID

The following methods simplify parsing and generating the URN representation of a common reference. The methods care about escaping and unescaping special characters properly.

• commonref_systemtype(urn)

• accepts the URN representation of a common reference

• returns the system type

• if the URN is not valid, the method returns an empty string

• commonref_systemid(urn)

• accepts the URN representation of a common reference

• returns the system ID

• if the URN is not valid, the method returns an empty string

• commonref_type(urn)

• accepts the URN representation of a common reference

• returns the type

• if the URN is not valid, the method returns an empty string

• commonref_id(urn)

• accepts the URN representation of a common reference

• returns the ID

• if the URN is not valid, the method returns an empty string

• commonref_urn(systemType, systemID, type, ID)

• accepts the four elements of a common reference

• returns the URN representation of the common reference

• in case of an error, the method returns an empty string

Examples:

var urn = "urn:com.avid:common-object:interplay-mam:2348238472398: asset.VIDEO:23434-23F32-4234234-3243423"; var systemType = commonref_systemtype(urn); // interplay-mam var systemId = commonref_systemid(urn); // 2348238472398 var type = commonref_type(urn); // asset.VIDEO

Handling Lists: getelement, getnumberofelements

82

var id = commonref_id(urn); // 23434-23F32-4234234-3243423 var newUrn = commonref_urn("interplay", "12345", "asset", "ABCD"); // urn:com.avid:common-object:interplay:12345:asset:ABCD

Handling Lists: getelement, getnumberofelements

The methods getelement and getnumberofelements support handling of strings that contain a list of values separated by a comma or any other delimiter.

getnumberofelements returns the number of elements in the list. It accepts the following arguments:

1. The string containing the list of values.

2. An optional argument that defines the separator. If the argument is missing, a comma is used as separator.

3. A Boolean flag. If the flag is true, empty values are ignored. If the argument is missing, empty values are not ignored.

If the third parameter is false or missing, getnumberofelements() returns 1 if the first argument is an empty string! An empty string is interpreted in this case as a comma-separated list with one element: an empty string.

getelement returns one element from the list. It accepts the following arguments:

1. The string containing the list of values.

2. The zero-based index of the value to be returned.

3. An optional argument that defines the separator. If the argument is missing, a comma is used as separator.

4. A Boolean flag. If the flag is true, empty values are ignored. If the argument is missing, empty values are not ignored.

Example 1: Handling a comma-separated list:

var s="value1,value2,value3"; var element; var i=0; while( (int)i < getnumberofelements(s) ) { element = getelement(s,i); i += 1; }

Floating-Point Functions

83

The loop iterates through the elements “value1”, “value2”, and “value3”.

Example 2: The values are separated by “##” instead of a comma:

var s="value1##value2##value3"; var element; var i=0; while( (int)i < getnumberofelements(s,"##") ) { element = getelement(s,i,"##"); i += 1; }

Example 3: Handling of empty elements:

var s = "value1,,value2,"; elems = getnumberofelements(s, ",", true); // returns 2 elems = getnumberofelements(s, ",", false); // returns 4 elem = getelement(s, 1, ",", true); // returns "value2" elem = getelement(s, 1, ",", false); // returns "" elems = getnumberofelements("", ",", true); // returns 0

You must specify the separator (here, “,”) if you want to eliminate empty elements.

Random Number Generation

Interplay MAM 3.3 introduced the random function to generate random numbers.

Example:

x = random(25);

This assigns a random integer value in the range from 0 through 24.

Floating-Point Functions

Interplay MAM 3.3 introduced a series of floating-point functions.

Example:

x = sqrt(25); // square root (result: 5.0) x = abs(-2.0);// absolute value (result: 2.0) x = floor(2.5);// floor (result: 2.0)

Empty Operation: nop

84

x = ceil(2.5);// ceiling (result: 3.0) x = pow(3.0, 4.0);// power (result: 81.0) x = round(3.5);// rounding (result: 4.0)

round uses the common rounding method — for example, 3.5 is rounded to 4.0.

Empty Operation: nop

SWoDL supports an “empty” statement: nop (short for “no operation”). It basically does nothing at all, returns 0 if used in an expression, and is usually only used for internal purposes.

Example:

nop();

4 HTTP POST Web Methods

WorkflowEngine can call Web methods via HTTP POST. The calls must comply with the ASP.NET implementation. Declare Web service methods by providing the name of the method, the name of the parameters, and the name of the return parameters.

The following sections describe and explain calls via HTTP POST:

• Declaration of HTTP POST Methods

• Calling HTTP POST Methods

Declaration of HTTP POST Methods

A HTTP POST call declaration starts with the declare keyword.

Example:

declare boolean OMA_UpdateOrderState(orderID, state, accesskey);

This defines a method named OMA_ UpdateOrderState. The method has three input parameters: orderID, state, and accesseky. The return value is contained in the XML response in the element called boolean.

The best way to start, when declaring a Web service method, is by having a look at the automatically generated test page of the service, such as:

Declaration of HTTP POST Methods

86

The above declare statement needs to have the exact information from this page:

Declaration of HTTP POST Methods

87

Declaration of Input Parameters

WorkflowEngine supports call parameters of simple types like string, integer, or boolean in an HTTP POST call. The declaration for all types of input parameters is the same.

Example:

declare boolean OMA_UpdateOrderState(orderID, state, accesskey); var result = OMA_UpdateOrderState("123", "SendDone", "8924394729") @ OMA2;

The method has three input parameters: orderID, state, and accesskey. The example call will send an HTTP POST request to the service. The body is created using the declared input parameter names and the actual values of the parameters of the call:

orderID=123&state=SendDone&accesskey=8924394729

The input parameter names must correspond exactly to the names used in the HTTP POST method call’s definition! Upper- and lower-case characters do not matter, but Avid strongly recommends using the correct cases or you will run into trouble when switching to SOAP calls, because for SOAP calls the case does matter.

The only complex type supported for HTTP POST calls are lists or arrays of simple types. See “Lists as Parameters of an HTTP POST Method” on page 95 for details.

Declaration of Return Parameter

Explicit Return Parameter The typical declaration of an HTTP POST method consists of an identifier that selects an element in the response.

Example:

declare boolean OMA_UpdateOrderState(orderID, state, accesskey);

The section “HTTP POST” on the help page of the method shows the following format for the response of the call:

Declaration of HTTP POST Methods

88

WorkflowEngineWS parses the result and searches for the first XML element that has the same name as the return parameter declaration. In this example it finds the document element <boolean>. XML Namespaces are ignored. Then, WorkflowEngineWS returns the text content of that element.

The return parameter declaration does not really define the type of the result. It merely defines an XML element name within the response of the call.

The XML element can be anywhere in the response. The only limitation is that you can only access the first element with the declared name.

Example: The method GetEMGuidListWithFilter returns an XML in the following format:

With the following declaration, you will get the first of the returned <string> elements:

declare string GetEMGuildListWithFilter(accesskey, epguidlist, streamtype, streamclass, usage);

You can use the _auto return parameter declaration to access all elements of a response. See “Return Parameter _auto” on page 88 for details.

Return Parameter void If there is no return value the keyword void should be used.

Example:

declare void sendEmail(to);

Return Parameter _auto Instead of selecting an element in the resulting XML, you can use the _auto keyword in the declaration.

Example:

declare _auto GetDMLegalList(legalListID);

Declaration of HTTP POST Methods

89

The returned value depends on the result of the call:

• If the call returns a value of a simple type like string, integer, or boolean, that value is returned directly.

• If the call returns an XML document with a complex type, the entire XML response is returned. You can use the struct and array operators, or the XML built-in functions to parse the result. See “Using Arrays and Structs to Parse XML Documents” on page 25 and “Parsing XML Documents” on page 43 for details.

Return Parameter _xml Instead of the _auto return parameter, you can also use the keyword _xml as return parameter declaration. The behavior is the same as for _auto, except that in case of _xml the returned XML document has an XML declaration node as first node.

Example:

declare _xml GetDMLegalList(legalListID);

The _xml return parameter declaration is deprecated. You should use _auto instead.

Declaration of HTTP POST Methods

90

Multiple Return Parameters You can declare a method with multiple return parameters for HTTP POST methods that return a complex type like a nested struct. The response of such a call is an XML document with various XML elements.

Example: Here’s an abbreviated version of the response format of the GetEMObjectWithLocations call of EssenceManagerWS:

An HTTP POST method declaration can have multiple return parameters as a comma-separated list of XML element names in square brackets:

var EssenceManagerWS_EssenceManager = "EssenceManagerWS/EssenceManager"; declare [orgpath,carrierguid] GetEMObjectWithLocations(accesskey, emguid);

This defines a method GetEMObjectWithLocations with two input parameters: accesskey and emguid. The call extracts two return parameters from the response:

• The text content of the first XML element with name “orgpath” in the document

• The text content of the first XML element with name “carrierguid” in the document

Declaration of HTTP POST Methods

91

XML namespaces are ignored. When calling this method you must provide an equal set of return variables that receive the values.

Example:

var path, carrier; [path, carrier] = GetEMObjectWithLocations(AccessKey, "262a3eb6-ddf8-4b52-acc5-4c126438c78d") @ EssenceManagerWS_EssenceManager;

This assigns the text content of the XML element with name “orgpath” to the variable path and the text content of the first XML element with name “carrierguid” to the variable carrier.

You cannot access the second or third element within the response. WorkflowEngineWS always uses the first XML element with the declared name.

When using multiple return parameters, you can only use explicit return parameters. You must not have _xml, _auto, or void in the list of declared return parameter names.

Renaming HTTP POST Methods

There are some cases where the name of a method is inconvenient:

• The name of a method is very long and unreadable.

• The name of a method is misleading.

• There are two methods with the same name but different call or return parameters, such as a "Create" call from two different Web services.

SWoDL allows you to rename a method in the declaration of the method using the as keyword.

Example:

declare boolean OMA_UpdateOrderState(orderID, state, accesskey as UpdateStateOfOrder;

Then you can call the method using the given name.

Example:

x = UpdateStateOfOrder(orderID, "SomeState", AccessKey) @ OMA;

Declaration of HTTP POST Methods

92

The original name (here, OMA_UpdateOrderState) is only used internally and cannot be used in the workflow.

Declaration Modifier const

If a method is only used to query information from an external system and does not modify the state of any external entity, you can declare the method as const method.

Example:

declare const string GetDMAttribute (dmguid, attribute, accesskey);

In this case, WorkflowEngine does not store the current status of the SWoDL script after the method has been called. This reduces the number of DB updates. However, in the case of a restart of WorkflowEngine, it is possible that the method is called twice, hence the restrictions mentioned above.

Defining the Target in the Declaration of a Method

Usually, the target of a Web method is defined when calling the method. See “Calling HTTP POST Methods” on page 93 for details. However, it is possible to define the target of the HTTP POST call in the declaration of the method.

Example: Defining the target in the declaration:

var OMA="OrderManagementWS/OMA"; // declaration defines the target of the operation: declare boolean OMA_UpdateOrderState(orderID, state, accesskey) @ OMA; // call without giving a target // => uses the target in the declaration (OMA) result = OMA_UpdateOrderState(jobID, "SendDone", AccessKey); // call with target // => uses the target of this call (OMA2) result = OMA_UpdateOrderState(jobID, "SendDone", AccessKey) @ OMA2;

Defining the target together with the declaration is only possible when using naming entries, not when using a direct URL.

Calling HTTP POST Methods

93

If you want to combine this feature with the rename feature method described in “Renaming HTTP POST Methods” on page 44, you must first use the as keyword to rename the function, and then the @ sign to define the target.

Example:

declare boolean OMA_UpdateOrderState(orderID, state, accesskey) as UpdateState @ OMA; // ok declare boolean OMA_UpdateOrderState(orderID, state, accesskey) @ OMA as UpdateState; // SYNTAX ERROR!

Calling HTTP POST Methods

Methods without Return Parameters

A declared method can be called like built-in functions. The only difference is that you must define the target of the invocation. Usually, this is done by adding an @ sign, followed by a naming entry in ConfigurationServiceWS.

Example:

var WFE="WorkflowEngineWS/WFE"; sendEmail("[email protected]") @ WFE;

This is a typical call to a method without return parameters. The value after the @ sign is a naming entry in ConfigurationServiceWS, as in the following illustration:

Calling HTTP POST Methods

94

In the example, the entry “WorkflowEngineWS/WFE” is used, which corresponds to the URL http://kl-doc-mam43:12100/WorkflowEngineWS/WFE.asmx. The example shows a call to WorkflowEngineWS itself, but of course, you can call any service configured in ConfigurationServiceWS.

Instead of a naming entry, you can use a URL directly. See “Using an Explicit URL” on page 95. However, Avid recommends using naming entries to allow an easier configuration if the location of a service changes.

If you want to call a third-party Web service, you can create an additional naming entry for the third-party system and use that naming entry for your call.

The example shows how to define the invocation target together with the call to the service. You can also define a default invocation target together with the declaration of the call. See “Defining the Target in the Declaration of a Method” on page 92 for details.

Methods with Return Parameters

A method that returns a value can be called by assigning the result to a variable.

Example:

var result; var OMA="OrderManagementWS/OMA"; result = OMA_UpdateOrderState(jobID, "SendDone", AccessKey) @ OMA;

Calling HTTP POST Methods

95

result is a variable that receives the return value. The arguments of the method can be literals, variables, or expressions. The returned value depends on the declaration of the method. See “Declaration of Return Parameter” on page 87.

Using an Explicit URL

It is possible to call a Web method of a service that has no naming entry in ConfigurationServiceWS. You can use two @ characters, followed by the URL of the service.

Example:

sendEmail("[email protected]") @@ "http://BOPC064:12100/WorkflowEngineWS/WFE.asmx";

Avid recommends using naming entries to allow an easier configuration if the location of a service changes.

If you want to call a third-party Web service, you can create an additional naming entry for the third-party system and use that naming entry for your call.

Lists as Parameters of an HTTP POST Method

It is possible to use lists as parameters in a method. The OMA_UpdateOrderState call declared above, for example, expects a list of strings in the nextStates parameter. Lists are declared exactly like simple parameters. The only difference is in the call of the method.

If you want to provide a list with exactly one element, the call looks as it does in this simple case:

result = OM_WFE_UpdateOrderState("job1", "SendDone", "nextState") @ OMA;

In all other cases you need to provide a list as argument, consisting of a comma-separated sequence of expressions, enclosed in square brackets.

Example:

result = OM_WFE_UpdateOrderState("job1", "SendDone", ["Allow", "Deny"] ) @ OMA;

The elements of the list can be a literal, a variable, or an expression.

Declare and Call SOAP Methods

96

5 SOAP Web Methods

WorkflowEngine supports calling SOAP Web service. The mechanism works much like the HTTP POST mechanism. The differences between HTTP POST and SOAP calls are described in the following sections:

• Declare and Call SOAP Methods

• Renaming SOAP Methods

• Declaration Modifier const

• Defining the Target in the Declaration of a Method

Declare and Call SOAP Methods

You declare SOAP methods the same way as POST methods: by giving the name of the method, the name of the parameters, and the name of the return parameters. The main difference is the additional keyword soap.

Example:

declare soap boolean OMA_UpdateOrderState(orderID, state, accesskey);

This defines the SOAP method named OMA_UpdateOrderState.

Declare and Call SOAP Methods

97

Method Name and Input Parameters

When declaring a SOAP method, the best way to start is by having a look at the automatically generated test page of the service, such as:

Declare and Call SOAP Methods

98

In case of a SOAP method, look at the SOAP 1.1 section when declaring the method and input parameter names. The identifiers must be exactly as they appear on the method’s information page. Here is an example with primitive data types:

The declaration looks like this:

declare soap boolean OMA_UpdateOrderState(orderID, state, accesskey);

The name of the method is used for the URL and the element name of the SOAP body (here, OMA_UpdateOrderState). The input parameters must be exactly the same as in the SOAP request body. In the example, the parameters are of primitive types. For input parameters with complex types, see the following chapters.

The declaration of the output parameter (here, “boolean”) defines which part of the result is returned. See “Declaration of Return Parameter” on page 108 for details.

Declare and Call SOAP Methods

99

Calling a SOAP method

A declared method can be called like a built-in function. The only difference is that you must define the target of the invocation. Usually this is achieved by adding an @ sign followed by a naming entry in ConfigurationServiceWS.

Example:

var OMA="OrderManagementWS/OMA"; var result = OMA_UpdateOrderState("theOrderID", "Completed", AccessKey) @ OMA;

WorkflowEngineWS resolves the naming entry in ConfigurationServiceWS and sends the request to that URL.

Instead of a naming entry, you can use a URL directly in the same way as for HTTP POST methods. See “Using an Explicit URL” on page 95. However, Avid recommends using naming entries to allow an easier configuration if the location of a service changes.

If you want to call a third-party Web service, you can create an additional naming entry for the third-party system and use that naming entry for your call.

The example shows how to define the invocation target together with the call to the service. You can also define a default invocation target together with the declaration of the call. See “Defining the Target in the Declaration of a Method” on page 118 for details.

When calling the method, WorkflowEngineWS creates the SOAP 1.1 request based on the method name and input parameters in the declaration. The XML namespace of the message is fetched by querying the WSDL of the service.

The method and parameter names must correspond exactly to the names used in the SOAP method call’s definition! Upper- and lower-case characters do matter for SOAP, in contrast to HTTP POST calls.

Declare and Call SOAP Methods

100

Input Parameters

Apart from primitive types, SWoDL supports using structs with fields of primitive types, arrays of primitive types, and arrays of structs with fields of primitive types:

Parameter type Declaration Description

Array of strings declare void F(p[]); Arrays as Input Parameters

Array of other primitive type declare void F(i p[]); Arrays as Input Parameters

Struct declare void F(s{}) Structs as Input Parameters

Array of Structs declare void F(s{} p[]); Arrays of Structs as Input Parameters

If you have other, more complex parameter types, you can create the entire request body yourself using the _body declaration.

SOAP headers can be added to the requests by using the _header keyword.

See the following chapters for details.

Arrays as Input Parameters Example:

The SOAP method GetHSMStatusList expects the parameter emguidList, which is an array of strings. The parameter can be declared like this:

declare soap _auto GetHSMStatusList(accesskey, string emguidList[]);

Declare and Call SOAP Methods

101

The declaration of the parameter consists of three elements:

• string: The inner XML element, used for each of the items of the array.

• emguidList: The outer XML element, used as the name of the parameter.

• []: an opening and closing square bracket, indicating that emguidList is an array parameter.

In case of an array of strings, you can omit the declaration of the inner XML element:

declare soap _auto GetHSMStatusList(accesskey, emguidList[]);

For arrays of other types, you must specify the inner XML element.

When using the declaration with two XML element names, you can omit the square brackets — but it’s recommended to use them to improve the readability.

The method can be called in two different ways. The first uses the square bracket syntax shown in “Lists as Parameters of an HTTP POST Method” on page 95:

var result = GetHSMStatusList(AccessKey, ["262a3eb6-ddf8-4b52-acc5-4c126438c78d", "7554b4d5-60b6-4ffb-b453-92b533ba52c3"]) @ EssenceManagerWS_EssenceManager;

The method is called with an array of the two elements given in square brackets.

The notation with square brackets is only valid if there are at least two values in the list. With only one value, the call will fail. Because of that, Avid recommends using the array functionality of SWoDL to call methods that have an array as input parameter.

The second method uses the array functionality of SWoDL. The script first creates an array with the items and passes the entire array as argument to the call:

var params = ""; params[0] = "262a3eb6-ddf8-4b52-acc5-4c126438c78d"; params[1] = "7554b4d5-60b6-4ffb-b453-92b533ba52c3"; var result = GetHSMStatusList(AccessKey, params) @ EssenceManagerWS_EssenceManager;

There is a third way to declare and use arrays in a SOAP call. This third way is deprecated and only available if the compatibility setting “ImpliedArraysAndStructsForSoap” in the section “WorkflowEngine/Compatibility” is activated. If the flag is enabled, WorkflowEngineWS tries to determine automatically if a parameter is an array or not. The

Declare and Call SOAP Methods

102

declaration looks like a primitive type declaration. The behavior depends on the value given when calling the method. See the following example for details. Avid recommends avoiding this type of declaration because it can lead to a rather confusing behavior.

declare soap _auto GetHSMStatusList(accesskey, emguidList); var params = ""; params[0] = "262a3eb6-ddf8-4b52-acc5-4c126438c78d"; params[1] = "7554b4d5-60b6-4ffb-b453-92b533ba52c3"; // params contains the XML representation of an array // => parameter is passed as array var result1 = GetHSMStatusList(AccessKey, params) @ EssenceManagerWS_EssenceManager; // More than one value is given in square brackets: // => parameter is passed as array var result2 = GetHSMStatusList(AccessKey, ["262a3eb6-ddf8-4b52-acc5-4c126438c78d", "7554b4d5-60b6-4ffb-b453-92b533ba52c3"]) @ EssenceManagerWS_EssenceManager; // If only one value is given in square brackets, the value is // passed a simple string and the method fails. // A string is given as value that is not the XML representation // of an array => passed as simple string and the call fails. var result3 = GetHSMStatusList(AccessKey, "x") @ EssenceManagerWS_EssenceManager;

Structs as Input Parameters SWoDL supports SOAP methods with structs as input parameter. An example is the method ISGetObjectDetails of the IntegrationServiceWS. It accepts an objectID parameter that has three fields: systemID, dmName, and guid:

Declare and Call SOAP Methods

103

This method can be declared and called by declaring the parameter as a struct parameter. A struct parameter consists of the name of the parameter followed by opening and closing curly brackets:

var IntegrationServiceWS_API = "IntegrationServiceWS/API"; declare soap string ISGetObjectDetails(accessKey, username, objectID{});

The method is called by creating a struct with proper field names and passing that as argument to the method:

var objID; objID.systemID=""; objID.dmName=""; objID.guid="30S_AVCI_720p_8_24"; var result = ISGetObjectDetails(AccessKey, "admin", objID) @ IntegrationServiceWS_API;

There is another way to use structs as input parameters in a SOAP call. This way is deprecated and only available if the compatibility setting “ImpliedArraysAndStructsForSoap” in the section “WorkflowEngine/Compatibility” is activated. If the flag is enabled, WorkflowEngineWS tries to determine automatically if a parameter is a struct or not. The declaration looks like a primitive type declaration. The behavior depends on the value given when calling the method. See the following example for details. Avid recommends avoiding this type of declaration.

var IntegrationServiceWS_API = "IntegrationServiceWS/API"; declare soap string ISGetObjectDetails(accessKey, username, objectID); var objID; objID.systemID=""; objID.dmName=""; objID.guid="30S_AVCI_720p_8_24"; // objID looks like a struct => pass it as struct var result = ISGetObjectDetails(AccessKey, "admin", objID) @ IntegrationServiceWS_API; // objID does not look like a struct => pass it as string => call fails var result2 = ISGetObjectDetails(AccessKey, "admin", "somevalue") @ IntegrationServiceWS_API;

Declare and Call SOAP Methods

104

Arrays of Structs as Input Parameters SWoDL supports arrays of structs as input parameters. The method ISObjectsGetLocalized of IntegrationServiceWS accepts an array with name objectID. Each element of the array is a struct with name ObjectID and the fields systemID, dmName, and guid:

The call can be declared using the following elements:

• ObjectID: the element name of the inner element

• {}: curly brackets to indicate that the ObjectID elements are structs

• objectID: the element name of the outer element

• []: square brackets to indicate that objectID is an array

In total: ObjectID{} objectID[]

Declare and Call SOAP Methods

105

var IntegrationServiceWS_API = "IntegrationServiceWS/API"; declare soap string ISObjectsGetLocalized(accessKey, ObjectID{} objectID[], includeAttributes, includeStrata, includeAssociations, includeEssencePackages, language, framerate);

The method can be called by creating an array. The items are structs with the proper field names. The entire array is passed as parameter to the call:

var ids = ""; ids[0].systemID = ""; ids[0].dmName = ""; ids[0].guid = "30S_AVCI_720p_8_24"; ids[1].systemID = ""; ids[1].dmName = ""; ids[1].guid = "30FPS_MP4"; var result = ISObjectsGetLocalized(AccessKey, ids, "true", "false", "false", "false", "en", "FPS:25") @ IntegrationServiceWS_API;

_xml as Input Parameter For SOAP methods that use more complex parameter types, you can create the SOAP request body yourself. To demonstrate this principle, the rather simple GetKey method of ConfigurationServiceWS is used:

You can declare the SOAP method with a single input parameter with the keyword “_xml”:

var ConfigurationServiceWS_Config = "ConfigurationServiceWS/Config"; declare soap _auto GetKey(_xml);

Declare and Call SOAP Methods

106

Then, the method can be called by creating the entire body, including the XML namespace, and passing that body as parameter to the call:

var profile = "DataManagerWS"; var key = "Logging/LogSQL"; var body = "<GetKey xmlns='http://www.blue-order.com/ma/configurationservicews/ config'>" + "<profile>" + xmlencode(profile) + "</profile>" + "<key>" + xmlencode(key) + "</key>" + "</GetKey>"; var value = GetKey(body) @ ConfigurationServiceWS_Config;

As this method is hard to read and error-prone, you should use it only when it is needed; that is, for methods with complex types.

The body must be a valid XML document. To avoid invalid XML characters in the body, Avid recommends using the xmlencode() method to all variable values, as shown in the example above.

SOAP Headers: _header as Input Parameter Some SOAP services expect additional parameters in the form of SOAP headers. Examples are the Interplay WebServices that expect the credentials of the caller as a SOAP header “UserCredentials”. Here is an example of a SOAP request for the GetAttribute method:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Header> <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none" /> <UserCredentials xmlns="http://avid.com/interplay/ws/assets/types"> <Username>username</Username> <Password>***</Password> </UserCredentials> </s:Header> <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <GetAttributes xmlns="http://avid.com/interplay/ws/assets/types"> <InterplayURIs> <InterplayURI>interplay://AvidWorkgroup/example</InterplayURI> </InterplayURIs> <Attributes /> </GetAttributes> </s:Body> </s:Envelope>

Declare and Call SOAP Methods

107

In SWoDL you can add custom SOAP headers by declaring the method with an input parameter with the keyword _header:

declare const soap _auto GetAttributes(_header,_xml);

The _header parameter does not need to be the first parameter. It can be in any position in the parameter list.

You can combine _header with all other input parameter types. This example uses _xml as second parameter, meaning that the caller creates the entire SOAP body as XML document. This is necessary in the example because the SOAP body is in a specific XML namespace.

The SWoDL code must create a string that contains one or more XML fragments. The XML fragments are added as SOAP headers. Here’s an example that creates the SOAP header using the built-in XML functions:

var ns = xml_ns("http://avid.com/interplay/ws/assets/types"); var credentialsHeader = xml_new_element(ns + "UserCredentials", xml_new_element(ns + "Username", pam_username), xml_new_element(ns + "Password", pam_password)); var callBodyInnerXml = xml_new_element(ns + "GetAttributes", xml_new_element(ns + "InterplayURIs", xml_new_element(ns + "InterplayURI", clipUri)), xml_new_element(ns + "Attributes")); var assetInfo = GetAttributes(credentialsHeader, callBodyInnerXml) @@ InterplayWebServicesUrl;

You can send more than one SOAP header by creating multiple XML fragments and concatenating them as a string. Example:

var credentialsHeader = xml_new_element(ns + "UserCredentials", xml_new_element(ns + "Username", pam_username), xml_new_element(ns + "Password", pam_password)); var exampleHeader = xml_new_element("example", 42); var assetInfo = GetAttributes(exampleHeader + credentialsHeader, callBodyInnerXml) @@ InterplayWebServicesUrl;

This results in the following SOAP message:

Declare and Call SOAP Methods

108

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Header> <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none" /> <UserCredentials xmlns="http://avid.com/interplay/ws/assets/types"> <Username>username</Username> <Password>***</Password> </UserCredentials> <example>42</example> </s:Header> <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <GetAttributes xmlns="http://avid.com/interplay/ws/assets/types"> <InterplayURIs> <InterplayURI>interplay://AvidWorkgroup/example</InterplayURI> </InterplayURIs> <Attributes /> </GetAttributes> </s:Body> </s:Envelope>

Declaration of Return Parameter

Explicit Return Parameter The typical declaration of an explicit return parameter for HTTP POST calls is explained in the chapter “Declaration of HTTP POST Methods” on page 85. The return parameter is declared as the name of the XML element within the response that contains the value that should be returned.

In case of a SOAP call, the declaration looks the same, but the behavior depends on the type of the response:

• If the method returns a primitive type, the declared result name is ignored and the value is returned.

• If the method returns a complex type, the declaration works the same as it does for HTTP POST methods: The declared return parameter defines the name of the XML element within the response that contains the value to be returned.

Declare and Call SOAP Methods

109

Methods that return a primitive type

In case a method returns a primitive type, the declared parameter name is ignored, unless it is a keyword like _auto, _xml, struct, or _array. The call returns the result value.

Example: The section “SOAP 1.1” on the help page of the method GetKey of ConfigurationServiceWS shows the following format for the response of the call:

WorkflowEngineWS parses the result and finds that the body contains the response in the element GetKeyResponse. That response contains a single result element called GetKeyResult. That is treated as a primitive type. So, the method can be declared like this:

var ConfigurationServiceWS_Config = "ConfigurationServiceWS/Config"; declare soap string GetKey(profile, key);

Actually, the declared name does not matter, as long as it is not one of the keywords _struct, _array, _xml, or _auto. For example, you can also declare the call like this:

var ConfigurationServiceWS_Config = "ConfigurationServiceWS/Config"; declare soap johnDoe GetKey(profile, key);

However, Avid recommends using a type name to improve the readability of the SWoDL script. Then, the method can be called like this:

var result = GetKey("DataManagerWS", "Logging/LogSQL") @ ConfigurationServiceWS_Config;

This returns the result value — for example, “true”.

Declare and Call SOAP Methods

110

Methods that return a complex type

In case of methods that return a complex type, the declared return parameter matters. In this case, WorkflowEngineWS parses the result and searches for the first XML element that has the same name as the return parameter declaration.

Example:

The method GetAccessPathEx returns a response in the following XML format:

To get the Uri element of the result, declare the method like this:

var EssenceManagerWS_EssenceManager = "EssenceManagerWS/EssenceManager"; declare soap Uri GetAccessPathEx(accesskey, emguid, protocol, mode);

The method can be called like this:

var uri = GetAccessPathEx(AccessKey, "d7dfc9ec-148e-42de-90e5-c1f37b89dd8d", "unc", "read") @ EssenceManagerWS_EssenceManager;

WorkflowEngineWS parses the result and finds the first XML element with name “Uri”. XML Namespaces are ignored. Then, WorkflowEngineWS returns the text content of that element.

The XML element can be anywhere in the response. The limitation is that you can only access the first element with the declared name. To access all elements of a response, use the _auto return parameter declaration. See “Return Parameter _auto” on page 111 for details.

Declare and Call SOAP Methods

111

Return Parameter void If there is no return value the keyword void should be used.

Example:

declare soap void sendEmail(to);

Return Parameter _auto Instead of selecting an element in the resulting XML, you can use the _auto keyword in the declaration.

Example:

declare soap _auto GetDMLegalList(legalListID);

The returned value depends on the result of the call:

• If the call returns a value of a simple type like string, integer, or boolean, that value is returned directly.

• If the call returns an XML document with a complex type, the entire XML response is returned. You can use the struct and array operators, or the XML built-in functions to parse the result. See “Using Arrays and Structs to Parse XML Documents” on page 25 and “Parsing XML Documents” on page 43 for details.

An example for a call that returns a complex type is GetAccessPathEx. It returns the following XML format:

Declare and Call SOAP Methods

112

You can declare the method using _auto as return parameter declaration:

var EssenceManagerWS_EssenceManager = "EssenceManagerWS/EssenceManager"; declare soap _auto GetAccessPathEx(accesskey, emguid, protocol, mode); var result = GetAccessPathEx(AccessKey, "d7dfc9ec-148e-42de-90e5-c1f37b89dd8d", "unc", "read") @ EssenceManagerWS_EssenceManager;

The returned value is the following XML document:

<GetAccessPathExResult xmlns="http://www.blue-order.com/ma/essencemanagerws/EssenceManager"> <Uri>\\kl-dev-vts01\InterplayMAMData\mediadata\30FPS_MP4.PF.2013032709 1051.PF.mp4</Uri> <HSMState>Online</HSMState> <Online>1000</Online> </GetAccessPathExResult>

You can get individual elements of the response using the struct functionality:

var hsmState = result.HSMState; var uri = result.Uri;

Return Parameter _xml (deprecated) The return parameter declaration _xml returns the entire response of the call, but wrapped in a <data> element and preceded by an XML declaration node.

The _xml return parameter declaration is deprecated. You should use _auto instead.

Example: Same method as above, but with _xml as return parameter:

var EssenceManagerWS_EssenceManager = "EssenceManagerWS/EssenceManager"; declare soap _xml GetAccessPathEx(accesskey, emguid, protocol, mode); var result = GetAccessPathEx(AccessKey, "d7dfc9ec-148e-42de-90e5-c1f37b89dd8d", "unc", "read") @ EssenceManagerWS_EssenceManager;

Declare and Call SOAP Methods

113

When called, it returns the following XML document:

<?xml version="1.0" encoding="utf-8"?> <data xmlns="http://www.blue-order.com/ma/essencemanagerws/EssenceManager"> <Uri>\\kl-dev-vts01\InterplayMAMData\mediadata\30FPS_MP4.PF.2013032709 1051.PF.mp4</Uri> <HSMState>Online</HSMState> <Online>1000</Online> </data>

Multiple Return Parameters You can declare a method with multiple return parameters for SOAP methods that return a complex type like a nested struct. The response of such a call is an XML document with various XML elements.

Example: Here’s an abbreviated version of the response format of the GetEMObjectWithLocations call of EssenceManagerWS:

Declare and Call SOAP Methods

114

A SOAP method declaration can have multiple return parameters as a comma-separated list of XML element names in square brackets:

var EssenceManagerWS_EssenceManager = "EssenceManagerWS/EssenceManager"; declare soap [orgpath,carrierguid] GetEMObjectWithLocations(accesskey, emguid);

This defines a method GetEMObjectWithLocations with two input parameters: accesskey and emguid. The call extracts two return parameters from the response:

• The text content of the first XML element with name “orgpath” in the document.

• The text content of the first XML element with name “carrierguid” in the document.

XML namespaces are ignored. When calling this method you must provide an equal set of return variables that receive the values.

Example:

var path, carrier; [path, carrier] = GetEMObjectWithLocations(AccessKey, "262a3eb6-ddf8-4b52-acc5-4c126438c78d") @ EssenceManagerWS_EssenceManager;

This assigns the text content of the XML element with name “orgpath” to the variable path, and the text content of the first XML element with name “carrierguid” to the variable carrier.

You cannot access the second or third element within the response. WorkflowEngineWS always uses the first XML element with the declared name.

When using multiple return parameters, use only explicit return parameters. You cannot have _xml, _auto, or void in the list of declared return parameter names.

Return Parameter _struct (deprecated) A SOAP call returning a struct can be declared using the _struct keyword:

declare soap _struct GetEMObjectWithLocations(accesskey, emguid);

Declare and Call SOAP Methods

115

Example: The GetEMObjectWithLocations call returns the following fields as the result:

If you declare the method using “_struct” as the return parameter, the response is stored as SWoDL struct and you can access all the fields directly.

Declare and Call SOAP Methods

116

Example:

declare soap _struct GetEMObject(accesskey, emguid); var emobj = GetEMObject(AccessKey, "daa5e727-d7dd-4f21-ab3b-f789ab428848") @ EssenceManagerWS_EssenceManager; var streamclass = emobj.streamclass; var som = emobj.som;

Avid recommends replacing the _struct.return parameter declaration with the _auto declaration. The _struct declaration works properly only if the fields contain only primitive types. If a field contains a sub-structure, the sub-structure is stored in a modified way. For example, in case a field contains an array of elements, all but the first of the elements in the array are removed.

Return Parameter _array (deprecated) A SOAP call that returns an array of values can be declared using the keyword “_array”. The result is stored as SWoDL array.

Example:

// GetEMObjectsInEP returns a list of EMGUIDs (type: string) declare soap _array GetEMObjectsInEP(accesskey, epguid); var emguids = GetEMObjectsInEP(AccessKey, "704de7dd-8362-48bf-9ec0-881c3a313bb7") @ EssenceManagerWS_EssenceManager; var numberOfEssences = array_size(emguids);

Avid recommends replacing the _array.return parameter declaration with the _auto declaration. The _array declaration works properly only if the items contain only primitive types or structs. If an item contains a sub-structure, the sub-structure is stored in a modified way. For example, in case an item contains an array of elements, all but the first of the elements in the inner array are removed.

Declaration Modifier const

117

Renaming SOAP Methods

There are some cases where the name of a method is inconvenient:

• The name of a method is very long and unreadable.

• The name of a method is misleading.

• There are two methods with the same name but different call or return parameters, such as a "Create" call from two different Web Services.

SWoDL allows you to rename a method in the declaration of the method using the as keyword.

Example:

declare soap boolean OMA_UpdateOrderState(orderID, state, accesskey) as UpdateStateOfOrder;

Then you can call the method using the given name.

x = UpdateStateOfOrder(orderID, "SomeState", AccessKey) @ OMA;

The original name (here, OMA_UpdateOrderState) is only referenced internally and cannot be used in the workflow.

Declaration Modifier const

If a method is only used to query information from an external system and does not modify the state of any external entity, you can declare the method as const method.

Example:

declare const string GetDMAttribute (dmguid, attribute, accesskey);

In this case, WorkflowEngine does not store the state of the workflow in the database after the call. This reduces the number of updates in the database. The risk is that after restarting WorkflowEngine, it is possible that the method is called twice, hence the restrictions mentioned above.

Defining the Target in the Declaration of a Method

118

Defining the Target in the Declaration of a Method

Usually, the target of a Web method is defined when calling the method. See “Calling HTTP POST Methods” on page 93 for details. However, it is possible to define the target of the HTTP POST call in the declaration of the method — the interface “OrderManagementWS/OMA” in the example above.

Example:

var OMA="OrderManagementWS/OMA"; declare soap boolean OMA_UpdateOrderState(orderID, state, accesskey) @ OMA; // declaration defines the target of the operation result = OMA_UpdateOrderState(jobID, "SendDone", AccessKey); // call without giving a target => uses the target in the declaration (OMA) result = OMA_UpdateOrderState(jobID, "SendDone", AccessKey) @ OMA2; // call with target => uses the target of this call (OMA2)

Defining the target together with the declaration is only possible when using naming entries, not when using a direct URL.

If you want to combine this feature with the rename feature method described in “Renaming SOAP Methods” on page 117, you must first use the as keyword to rename the function, and then the @ sign to define the target.

Example:

declare soap boolean OMA_UpdateOrderState(orderID, state, accesskey) as UpdateState @ OMA; // ok declare soap boolean OMA_UpdateOrderState(orderID, state, accesskey) @ OMA as UpdateState; // SYNTAX ERROR!

6 ACS Bus Messages

WorkflowEngine can send messages to any service that is connected to the ACS Message Bus (Avid Common Services Message Bus). The following sections describe and explain bus messages:

• Declaration and Sending of Bus Messages

• Error Handling

Declaration and Sending of Bus Messages

A bus message declaration starts with the declare keyword and the additional keyword bus.

Example:

declare bus lockInfo GetLockStatus(sessionToken, processId, taskId);

This defines a bus message named GetLockStatus. The method has three input parameters: sessionToken, processId, and taskId. The response from the bus service is parsed and the content of the element lockInfo is returned.

SWODL serializes ACS bus messages to the JSON data format before sending the message to the message bus. For details about the JSON data format refer to http://www.json.org.

In most cases the Workflow Engine is responsible to serialize the parameters for ACS Bus messages to the JSON data format and deserialize the result. To provide a maximum degree of control over the serialization process SWODL also offers options to work with the JSON data directly.

Asynchronous Bus Messages

In addition to synchronous messages, the Workflow Engine also supports sending asynchronous messages. An asynchronous bus message declaration starts with the declare keyword followed by the bus keyword and the additional keyword async.

Declaration and Sending of Bus Messages

120

Example:

declare bus async void StartProcess( sessionId, spec{});

Asynchronous bus calls must not have a return type other than void.

Message Name and Input Parameters

The bus message declaration defines the name of the bus message, the names of the parameters of the bus message and the name of the response parameter.

The following example shows how a bus message is serialized to the JSON data format. The message has three input parameters, sessionToken, processId, and taskId. Each of the parameters is of a simple type. All three parameters are represented as name/value pairs of the paramSet object.

Example:

{ "serviceType": "com.avid.orchestration", "serviceRealm": "global", "serviceVersion": 0, "op": "GetLockStatus", "paramSet": { "sessionToken": "9137180332947516705", "processId": "12275ee1-5400-4a6f-bc53-920923b7a3a5", "taskId": "e0171d87-abdc-474e-a295-d032570548e4" } }

The message returns the struct lockInfo in the response. The struct has three elements of simple types, LockStatus, LockOwnerId, LockOwnerName.

{ "serviceType": "com.avid.orchestration", "serviceRealm": "global", "op": "GetLockStatus", "resultSet": { "lockInfo": { "LockStatus": "CheckOut", "LockOwnerId": "admin", "LockOwnerName": "administrator" } } }

Declaration and Sending of Bus Messages

121

Sending Bus Messages

You can use a declared method like a built-in function. The only difference is that you also must provide the target of the invocation. Usually this is achieved by adding the @ sign; followed by the target for the invocation. SWODL needs this information to address the target service correctly.

Example:

const Bpm = ”bus://com.avid.orchestration”; declare bus lockInfo GetLockStatus(sessionToken, processId, taskId); var lockInfo = GetLockStatus(_SessionToken, _ProcessId, _TaskId) @ Bpm;

In SWODL the invocation target of a bus message is given as a URI, where serviceType defines the name of the service you want to address:

bus://<serviceType>

This requests version 0 of the service interface and uses the default realm of the MAM system.

Optionally, you can use query parameters to set the service realm, the interface version, and the encoding style:

bus://<serviceType>?realm=<serviceRealm>&version=<version>&encoding=<encoding>

The following elements can be part of the bus URI:

• serviceType: The service type is the registration name used by a particular service.

• realm: The service realm defines the realm of the service within the entire installation. If the realm parameter is not given, the default realm of the MAM system (setting “Bus/DefaultRealm” in the “Global” profile) is used.

• version: The version parameter defines the version of the service interface. The version is given as an integer value. If no version is given, the call requests version 0 of the interface.

• encoding: The encoding style of the message. Interplay MAM 5.0 supports “json” to select JSON as the message format.

The Workflow Engine uses the configuration data from the Bus section in the Global profile to locate the ACS Message Bus itself.

Declaration and Sending of Bus Messages

122

By default, a workflow uses the timeout defined by the configuration setting WorkflowEngine/BusTimeoutInSeconds. After a fresh installation of Interplay MAM, this is set to 30 seconds. You can override the timeout for each call by setting the variable _BusTimeout within the SWoDL script.

Declaration of Input Parameters

The declaration of a bus method accepts the following parameter definitions:

Parameter type Example Description

simple type declare bus void F(a,b) a and b are parameters of simple types. In JSON these parameters are transmitted as strings.

arrays declare bus void F(a[], b) a is an array of strings

structs declare bus void F(a{}, b) a is a struct

arrays of structs declare bus void F(a{}[], b) a is an array of structs

_json declare bus void F(_json a, b) a is a string containing preformatted JSON data

_json declare bus void F(_json) The full JSON data for the paramSet field are passed into the method.

_context declare bus void F(_context, a) Sends the given JSON object in the context section of the bus request.

Simple Types as Input Parameter A parameter with a simple type is added to the message’s paramSet object as a JSON parameter with a string value.

Example:

declare bus void SomeMethod(a,b,c); SomeMethod("x", 5, "something") @ ...;

The serialized message looks like this:

{ "serviceType": "com.avid.SomeService",

Declaration and Sending of Bus Messages

123

"serviceRealm": "global", "op": "SomeMethod", "paramSet": { "a": "x", "b": "5", "c": "something" } }

Arrays as Input Parameter An array parameter is declared using square brackets. The value used when calling the method should be a SWoDL array.

Example:

declare bus void SomeMethod(employees[],b); var arr = array_create(); arr[0] = "John Doe"; arr[1] = "Bob Smith"; SomeMethod(arr, "something") @ ...;

The serialized message looks like this:

{ "serviceType": "com.avid.SomeService", "serviceRealm": "global", "op": "SomeMethod", "paramSet": { "employees": [ "John Doe", "Bob Smith" ], "b": "something" } }

Structs as Input Parameter

A struct parameter is declared using curly brackets. The value used when calling the method should be a SWoDL struct. The field names of the JSON struct are the same as defined for the SWoDL struct.

Example:

declare bus void SomeMethod(employee{},b);

Declaration and Sending of Bus Messages

124

var p; p.name = "John Doe"; p.placeOfBirth = "New York"; p.dateOfBirth = "1980-08-25"; SomeMethod(p, "something") @ ...;

The serialized message looks like this:

{ "serviceType": "com.avid.SomeService", "serviceRealm": "global", "op": "SomeMethod", "paramSet": { "employee": { "name": "John Doe", "placeOfBirth": "New York", "dateOfBirth": "1980-08-25" }, "b": "something" } }

Arrays of Structs as Input Parameter

An array of structs parameter is declared using curly brackets followed by square brackets. The value used when calling the method should be a SWoDL array of structs. The field names of the JSON structs are the same as defined for the SWoDL structs.

Example:

declare bus void SomeMethod(employees{}[],b); var arr = array_create(); arr[0].name = "John Doe"; arr[0].placeOfBirth = "New York"; arr[0].dateOfBirth = "1980-08-25"; arr[1].name = "Bob Smith"; arr[1].placeOfBirth = "Denver"; arr[1].dateOfBirth = "1975-10-14"; SomeMethod(arr, "something") @ ...;

The serialized message looks like this:

{ "serviceType": "com.avid.ime.someservice", "serviceRealm": "global", "op": "SomeMethod",

Declaration and Sending of Bus Messages

125

"paramSet": { "employees": [ { "name" : "John Doe", "placeOfBirth": "New York", "dateOfBirth": "1980-08-25" }, { "name" : "Bob Smith", "placeOfBirth": "Denver", "dateOfBirth": "1975-10-14" } ], "b": "something" } }

Complex Types as Input Parameter

In case you have a more complicated parameter type, you can create a JSON fragment in your code and use that as value of a parameter. You achieve this by using the _json keyword. The JSON parameter is added to the message, using the declared parameter name employees. The value is the parsed JSON document.

Example:

declare bus void SomeMethod(_json employees,b); var json = "[" + " {" + " \"name\" : \"John Doe\"," + " \"benefits\": [" + " \"Life Insurance\"," + " \"Disability Insurance\"" + " ]" + " }," + " {" + " \"name\" : \"Bob Smith\"," + " \"benefits\": [" + " \"Life Insurance\"," + " \"Disability Insurance\"," + " \"401K\"" + " ]" + " }" + " ]"; SomeMethod(json, "something") @ ...;

The serialized message looks like this:

Declaration and Sending of Bus Messages

126

{ "serviceType": "com.avid.SomeService", "serviceRealm": "global", "op": "SomeMethod", "paramSet": { "employees": [ { "name" : "John Doe", "benefits": [ "Life Insurance", "Disability Insurance" ] }, { "name" : "Bob Smith", "benefits": [ "Life Insurance", "Disability Insurance", "401K" ] } ], "b": "something" } }

Complete paramSet For maximum flexibility SWoDL allows to create the complete paramSet object of the message by using a single input parameter declaration with the keyword _json.

Example:

declare bus void SomeMethod(_json); var arr = array_create(); arr[0].name = "John Doe"; arr[0].benefits[0] = "Life Insurance"; arr[0].benefits[1] = "Disability Insurance"; arr[1].name = "Bob Smith"; arr[1].benefits[0] = "Life Insurance"; arr[1].benefits[1] = "Disability Insurance"; arr[1].benefits[2] = "401K"; var params; params.employees = arr; params.b = "something"; var json = swodl_to_json(params); SomeMethod(json) @ ...;

Declaration and Sending of Bus Messages

127

The swodl_to_json method is used to create a JSON fragment. The resulting JSON fragment looks like this:

{ "employees": [ { "name" : "John Doe", "benefits": [ "Life Insurance", "Disability Insurance" ] }, { "name" : "Bob Smith", "benefits": [ "Life Insurance", "Disability Insurance", "401K" ] } ], "b": "something" }

If the method is declared with the keyword _json as in the example above, then the JSON fragment is copied to the paramSet parameter of the request.

{ "type": "request", "serviceType": "com.avid.Someservice", "serviceRealm": "global", "op": "SomeMethod", "paramSet": { "employees": [ { "name" : "John Doe", "benefits": [ "Life Insurance", "Disability Insurance" ] }, { "name" : "Bob Smith", "benefits": [ "Life Insurance", "Disability Insurance", "401K" ] } ], "b": "something" } }

Declaration and Sending of Bus Messages

128

Sending message context Some bus message expect information in the context section of a bus request message. Typical examples are services that are usually called via the Upstream Service and read for example the identitiy of the caller from the messge context.

You can set the message context by adding a parameter with the keyword _context in the declaration of the method. When calling the method, the WorkflowEngine expects a JSON object as value and adds the properties of that JSON object to the message context.

Example:

var avidMamAssetsAccess = "bus://avid.mam.assets.access?realm=" + config_get("global", "Bus/DefaultRealm"); // Declaration: declare bus _message assetExists(_context, id); // Create context: var idContext = json_new_object( json_new_property("identity", json_new_object( json_new_property("identityId", json_encode( "2016012509175620101291571800050569B5B3A0000012392B00000D0D000003")), json_new_property("identityMasterRegion", json_encode("region-0")), json_new_property("masterRegion", json_encode("region-0"))))); // Call: var exists = assetExists(idContext, "123") @ avidMamAssetsAccess; /* Sends the following request: { "serviceType": "avid.mam.assets.access", "serviceRealm": "1A8699074E2D491C859669D76D52D350", "serviceVersion": 0, "op": "assetExists", "context": { "identity": { "identityId": "2016012509175620101291571800050569B5B3A0000012392B00000D0D000003", "identityMasterRegion": "region-0", "masterRegion": "region-0" } },

"paramSet": { "id": "123" } } */

Declaration and Sending of Bus Messages

129

Declaration of Return Parameters

Return Parameter void If a method does not return a result it should be defined as void.

Example:

declare bus void SomeMethod(); SomeMethod(json) @ ...;

Single Return Parameter If you are interested in a single value from the response, you can declare the method with the name of the JSON parameter that contains that value.

Example:

We assume that we have received the following result from a message call:

{ "serviceType": "com.avid.SomeService", "serviceRealm": "global", "op": "GetEmployee", "resultSet": { "result": { "name": "John Doe", "placeOfBirth": "New York", "dateOfBirth": "1980-08-25", "benefits": [ "Life Insurance", "Disability Insurance" ] }, "otherResult": "done" } }

If you are interested only in the “name” of the employee, you can declare and call the method like this:

declare bus name GetEmployee(); var theName = GetEmployee() @ ...; // returns John Doe

This call fetches the first JSON parameter called “name” from the response (recursively, on any level). Depending on the content of the JSON parameter, you may get different results:

Declaration and Sending of Bus Messages

130

If the resultSet object contains a string or integer, that value is returned.

If the resultSet object contains a complex type like an array or struct, a corresponding SWoDL struct is returned.

If you are interested in the entire value of the “result” parameter you can use the following declaration:

declare bus result GetEmployee(); var r = GetEmployee() @ ...; // returns a SWoDL struct with the fields name, placeOfBirth, // dateOfBirth and benefits // r.benefits is an array of strings var name = r.name; // value: John Doe var placeOfBirth = r.placeOfBirth; // value: New York var dateOfBirth = r.dateOfBirth; // value: 1980-08-25 var firstBenefit = r.benefits[0]; // value: Life Insurance

Return Parameter _auto

SWoDL allows you to get the SWoDL representation of the entire JSON fragment of the resultSet object. You achieve this by using the keyword _auto in the declaration.

Example:

We assume that we have received the following result from a message call:

{ "serviceType": "com.avid.SomeService", "serviceRealm": "global", "op": "GetEmployee", "resultSet": { "result": { "name": "John Doe", "placeOfBirth": "New York", "dateOfBirth": "1980-08-25", "benefits": [ "Life Insurance", "Disability Insurance" ] }, "otherResult": "done" } }

Declaration and Sending of Bus Messages

131

You can access the result of the message as follows:

declare bus _auto GetEmployee(); var r = GetEmployee() @ ...; // r contains the SWoDL representation of the entire JSON fragment // in the resultSet object, i.e. a struct with two fields: // result and otherResult // r.result is a struct with the fields name, placeOfBirth, // dateOfBirth and benefits var name = r.result.name; // value: John Doe var nameBorn = r.result.placeOfBirth; // value: New York var dateBorn = r.result.dateOfBirth; // value: 1980-08-25 var firstBenefit = r.result.benefits[0]; // value: Life Insurance // r.otherResult is a string: var other = r.otherResult; // value: done

The _auto return parameter works only if the JSON does not contain properties with special characters like colons in the name. HAL interfaces typically fall into this category. In that case you have to use either _json or _message as response parameter and handle the JSON response manually with the JSON methods. For details, see “Parsing JSON Documents” on page 67.

Return Parameter _json

SWoDL allows you to get the entire JSON fragment of the resultSet object as a string. You achieve this by using the keyword _json in the declaration.

Example:

We assume that we have received the following result from a message call:

{ "serviceType": "avid.mam.assets.access", "serviceRealm": "1A8699074E2D491C859669D76D52D350", "serviceVersion": 0, "op": "serviceStatus", "context": { "sender": { … } }, "resultSet": { "timestamp": "2016-08-18T12:37:09.572Z", "status": { "code": "ok" } } }

Declaration and Sending of Bus Messages

132

You can access the resultSet of the message as follows:

var avidMamAssetsAccess = "bus://avid.mam.assets.access?realm=" + config_get("global", "Bus/DefaultRealm"); declare bus _json serviceStatus(); var x = serviceStatus() @ avidMamAssetsAccess; /* returns the following JSON object as string: { "timestamp": "2016-08-18T12:37:09.551Z", "status": { "code": "ok" } } */

Return Parameter _message

SWoDL allows you to get the entire JSON response message as a string. You achieve this by using the keyword _message in the declaration.

Example:

We assume that we have received the following result from a message call:

{ "serviceType": "avid.mam.assets.access", "serviceRealm": "1A8699074E2D491C859669D76D52D350", "serviceVersion": 0, "op": "serviceStatus", "context": { "sender": { … } }, "resultSet": { "timestamp": "2016-08-18T12:37:09.572Z", "status": { "code": "ok" } } }

You can access the resultSet of the message as follows:

var avidMamAssetsAccess = "bus://avid.mam.assets.access?realm=" + config_get("global", "Bus/DefaultRealm"); declare bus _message serviceStatus(); var x = serviceStatus() @ avidMamAssetsAccess; // returns the entire response message

Error Handling

133

Multiple Return Parameters If a response contains more than one return parameter, you can use square brackets and a list of return parameters.

Example:

We assume that we have received the following result from a message call:

{ "serviceType": "com.avid.SomeService", "serviceRealm": "global", "op": "GetEmployeeData", "resultSet": { "name": "John Doe", "placeOfBirth": "New York", "dateOfBirth": "2980-08-25" } }

The message result has three result parameters, name, placeOfBirth and dateOfBirth. You can declare and call this message like this:

declare bus [name, placeOfBirth, dateOfBirth] GetEmployeeData(); var n, p, d; [n,p,d] = GetEmployeeData() @ ...;

In the declaration you can define a comma-separated list of result parameter names in square brackets. When calling the method, you have to use the same number of parameters to receive the corresponding result values.

Error Handling

When an error occurs during the execution of a bus message the client receives a respone that contains an errorSet object.

Example:

{ "serviceType":"com.avid.SomeService", "serviceRealm":"global", "serviceVersion":0,"op":"login", "errorSet": [ "error": { "level": "ERR", "code": "com.avid.SomeService.UnauthorizedException",

Error Handling

134

"details": "Invalid credentials" } ] }

The errorSet object contains an array of error objects, each having an error level, a machine-readable code and human-readable details. If such an error message is received, the WorkflowEngineWS treats it like a SOAP exception. This means that the following variables are set:

SWoDL variable Value Description

_ExceptionOccured 1 Set to 1 to trigger the exception handling in the following SWoDL code.

_ExceptionReason com.avid.SomeService. UnauthorizedException

Value of the code field

This is the machine-readable error code that can be used in the SWoDL script to react on specific errors.

_ExceptionMessage com.avid.SomeService. UnauthorizedException - Invalid credentials

Value of the code field, followed by a dash, followed by the value of the details field.

This is the message for the administrative that is displayed for example in the Interplay MAM Workflow Monitor.

7 HTTP and HTTPS Web Requests

SWoDL allows calling web services via HTTP and HTTPS. This is useful to access RESTful services or to just download data from a web server. The following sections explain web requests:

• Simple Web Requests: web_request

• Advanced Web Requests: web_request_ex

Simple Web Requests: web_request

The easiest way to call a web service is by means of the web_request method. The method has 5 overloads:

Signature Description

web_request(URL) Uses GET to call the given URL.

web_request(verb, URL) Uses the given verb to call the URL.

web_request(verb, URL, headers) Passes HTTP headers with the request.

web_request(verb, URL, headers, cookies) Passes HTTP headers and cookies with the request.

web_request(verb, URL, headers, cookies, body)

Passes HTTP headers, cookies, and a body with the request. The body is sent as a string.

The call parameters have the following format:

Call parameter Description

verb The HTTP verb. The most frequently used verbs are GET, PUT, POST, PATCH, DELETE, HEAD, and OPTIONS. If an empty string is given as verb, then GET is used.

URL The URL of the web request.

headers A SWoDL array of strings. Each item in the array contains the definition of an HTTP header in the form “headername: value”. See Example: Passing HTTP Headers on page 137 for details.

Simple Web Requests: web_request

136

Call parameter Description

cookies A SWoDL array of strings. Each item in the array contains the definition of a cookie entry in the form “key=value”. See Example: Passing Cookies on page 137 for details.

body The body of the HTTP or HTTPS message. Not all verbs support a message body. For example, GET, HEAD, and DELETE should not be called with a body. See RFC7231 for details.

The result of the call is the body of the reponse message.

If the web request fails, the method throws an exception. This can happen if the URL is invalid, the called service is not available, or the called service actively returns an HTTP error status (anything outside of 200 through 299). You should use try-catch to handle the exception, otherwise the workflow terminates.

The web_request call is easy to use but has a number of limitations:

• It supports only strings as body of a request, not a binary request body.

• It supports only strings as body of the response, not a binary response body.

• You cannot access the HTTP headers of the response message.

• You cannot access cookies sent by the server.

• You cannot access the HTTP status code of the response. HTTP response codes others than 200 through 299 cause an exception. You cannot react differently on specific codes.

Use web_request_ex if you need more control over the call. See “Advanced Web Requests: web_request_ex” on page 138 for details.

Example: Getting Data from a Web Service

The example fetches the HTML code of a web page:

var result = web_request("http://www.avid.com");

It uses GET as verb and does not pass cookies, headers, or a body. The same call can be used to query a resource from a REST service.

Optionally, you can use the overload with HTTP GET verb for the same request:

Simple Web Requests: web_request

137

var result = web_request("GET", "http://www.avid.com");

Example: Passing HTTP Headers

The example calls a web request with two HTTP headers in the request message:

var headers = ""; headers[0] = "X-Example: 42"; headers[1] = "Accept: application/json"; var result = web_request("GET", "https://httpbin.org/headers", headers);

For this overload you must pass the HTTP verb as first parameter, here GET.

Example: Passing Cookies

The example calls a web request with two cookies in the request message:

var headers = ""; // no headers var cookies = ""; cookies[0] = "X=42"; cookies[1] = "Y=Avadacadavra"; result = web_request("GET", "https://httpbin.org/get", headers, cookies);

For this overload you must pass an HTTP verb and a value for the HTTP headers. The example uses an empty string for the headers to indicate that no headers are sent.

Example: Sending a Body

The example calls a web request with two cookies in the request message:

var result = web_request( "POST", // verb "https://httpbin.org/post", // URI "", // no headers "", // no cookies "A quick brown fox jumps over the lazy dog"); // body

Advanced Web Requests: web_request_ex

138

HTTPS Requests

The web_request method can be used to call HTTP and HTTPS services.

For HTTPS services, you can configure how the call reacts to invalid HTTPS certificates. A common use case is a self-signed certificate. You may want to accept an invalid certificate or let the call fail.

The configuration setting WorkflowEngine/CheckHttpsCertificates in the profile WorkflowEngine defines the behavior for the web_request method:

If the value is true, the call fails if HTTPS certificate validation fails.

If the value is false, the call succeeds even if HTTPS certificate validation fails. This is the default value.

The configuration setting WorkflowEngine/CheckHttpsCertificates is used for web_request and web_request_ex.

If you want to define the behavior for an individual call in your SWoDL script, you have to use the web_request_ex method. See “HTTPS requests” on page 143 for details.

Advanced Web Requests: web_request_ex

The method web_request_ex gives you more control over the handling of web requests. It accepts a SWoDL struct as parameter. The fields of the struct define the details of the web request. The following fields are supported.

Field name Description

verb The HTTP verb used for the request. If not set or set to an empty string, the verb GET is used.

The most frequently used verbs are GET, PUT, POST, PATCH, DELETE, HEAD, and OPTIONS.

url The URL of the web request. If not given, the request fails.

body A string to be sent as body of the request message. If not given, the request is either sent with a binary body (see bodyBinary) or sent without a body.

Not all verbs support a message body. For example, GET, HEAD, and DELETE should not be called with a body. See RFC7231 for details.

bodyBinary Only used if body is not set or empty.

A string containing the base64 encoded representation of a binary. The

Advanced Web Requests: web_request_ex

139

Field name Description

binary is sent as body of the request message. If not given, the request is sent without a body.

Not all verbs support a message body. For example, GET, HEAD, and DELETE should not be called with a body. See RFC7231 for details.

headers A SWoDL array of strings. Each item in the array contains the definition of an HTTP header in the form “headername: value”.

cookies A SWoDL array of strings. Each item in the array contains the definition of a cookie entry in the form “key=value”.

binaryResponse If set to true, the body of the response message is treated as binary data. In this case, the response body is returned as a base64 encoded string.

If set to false, the body of the response message is returned as text. This is the default if the value is not given.

checkCertificate The field is only used if an HTTPS service is called.

If set to true, the call fails if the HTTPS certificate validation fails. This happens for example when using self-signed certificates.

If set to false, the call ignores the HTTPS certificate validation. In this case, self-signed certificates are accepted. But this also means that the call is insecure and not safe against attacks.

If the value is not set or set to an empty string, the call evaluates a configuration setting. See “HTTPS requests” on page 143 for details.

user The user name used for authentication against the web service. Authentication supports Basic Authentication and Windows Authentication (NTLM).

password The password used for authentication against the web service. Authentication supports Basic Authentication and Windows Authentication (NTLM).

useDefaultCredentials The field is only used if “user” is not set.

If set to true, the call uses the default authentication. In this case, SWoDL uses the Windows credentials of WorkflowEngineWS.

If set to false, the call does not use the default authentication.

The field names must be used with the precise notation, including upper and lower casing.

The result of the call is a SWoDL struct with information about the response of the web request. It contains the following fields:

Advanced Web Requests: web_request_ex

140

Field name Description

success 1 if the call succeeded.

0 if the call failed.

status The HTTP status code of the response. The value is only set if the called service actively responds with an error.

statusText The text for the HTTP status code of the response. The value is only set if the called service actively responds with an error.

body The body of the response message as string. The field is only set if binaryResponse was not set or set to false in the request.

bodyBinary The body of the response message as base64 encoded string. The field is only set if binaryResponse was set to true in the request.

headers The headers of the response message as a SWoDL array. Each item in the array contains an HTTP header in the form “headername: value”.

cookies The cookies received with the response message as a SWoDL array. Each item in the array contains a cookie in the form “key=value”.

The web_request_ex method only throws an exception if the call cannot be sent at all, for example, because the URL is invalid or the called service is not available.

If the request is sent and the called web service responds with an HTTP error, then the method does not throw an exception. Instead it sets success to false, stores the HTTP status code to status, and sets statusText to the textual representation of that HTTP status code.

It is up to the SWoDL script to react on errors.

Example: Getting Data from a Web Service

The example fetches the HTML code of a web page, including proper error handling. It sets only the field url in the request.

try { var request = ""; request.url = "http://www.avid.com"; var result = web_request_ex(request); if(!result.success) {

Advanced Web Requests: web_request_ex

141

throw "Failed to call " + request.url + ": " + result.status + " " + result.statusText; } // handle result... var body = result.body; } catch { // error handling... error _ExceptionMessage; }

Example: Getting Binary Data from a Web Service

The example requests binary data (an SVG graphics object), including proper error handling. It sets request.binaryResponse to true and fetches the result using result.bodyBinary.

try { var request = ""; request.url = "https://httpbin.org/image/svg"; request.binaryResponse = true; var result = web_request_ex(request); if(!result.success) { throw "Failed to call " + request.url + ": " + result.status + " " + result.statusText; } // handle result... var image = result.bodyBinary; } catch { // error handling... error _ExceptionMessage; }

The result in image is a base64 encoded string that represents the requested binary data.

Example: POST Call with Request Body, HTTP Headers, and Cookies

The example calls a web service with verb POST with a request body, HTTP headers, and cookies. It sets the fields verb, headers, cookies, and body in the request.

Advanced Web Requests: web_request_ex

142

try { var request = ""; request.verb = "POST"; request.url = "https://httpbin.org/post"; request.headers = ""; // clear headers request.headers[0] = "X-Example: 42"; request.headers[1] = "Accept: application/json"; request.cookies = ""; // clear cookies request.cookies[0] = "X=42"; request.cookies[1] = "Y=Avadacadavra"; request.body = "A quick brown fox jumps over the lazy dog"; var result = web_request_ex(request); if(!result.success) { throw "Failed to call " + request.url + ": " + result.status + " " + result.statusText; } // handle result... var body = result.body; } catch { // error handling... error _ExceptionMessage; }

Example: Calling a Web Service with Authentication

The example calls a web service that requires authentication. It sets the fields user and password in the request.

try { var request = ""; request.url = "https://httpbin.org/basic-auth/test/123"; request.user = "test"; request.password = "123"; var result = web_request_ex(request); if(!result.success) { throw "Failed to call " + request.url + ": " + result.status + " " + result.statusText; } // handle result... var body = result.body;

Advanced Web Requests: web_request_ex

143

} catch { // error handling... error _ExceptionMessage; }

The example uses a publicly available test service that allows testing different aspects of HTTP calls. The URL https://httpbin.org/basic-auth/test/123 simulates a web service that requires authentication and accepts the user “test” with password “123”.

HTTPS Requests

The web_request_ex method can be used to call HTTP and HTTPS services.

For HTTPS services you can define if the HTTPS certificate is validated or not. A common use case is a self-signed certificate. You may want to accept an invalid certificate or let the call fail.

You can define the behavior for every individual request to an HTTPS service by using the field checkCertificate:

If set to true, the call fails if HTTPS certificate validation fails. This happens, for example, when using self-signed certificates.

If set to false, the call ignores HTTPS certificate validation. In this case, self-signed certificates are accepted. But this also means that the call is insecure and not safe against attacks.

If the value is not set or set to an empty string, the call reads the configuration setting WorkflowEngine/CheckHttpsCertificates in the profile WorkflowEngine:

If the value is true, the call fails if HTTPS certificate validation fails.

If the value is false, the call succeeds even if HTTPS certificate validation fails. This is the default value.

The configuration setting WorkflowEngine/CheckHttpsCertificates is used for web_request and web_request_ex.

Example: Force validation of the HTTPS certificate by setting checkCertificate to true.

try { var request = ""; request.url = "https://self-signed.badssl.com/"; request.checkCertificate = true; var result = web_request_ex(request);

Advanced Web Requests: web_request_ex

144

if(!result.success) { throw "Failed to call " + request.url + ": " + result.status + " " + result.statusText; } // handle result... var body = result.body; } catch { // error handling... error _ExceptionMessage; }

8 Compatibility

This chapter contains information about compatibility with previous versions of WorkflowEngineWS.

• Web Methods

• Structs and Arrays

Web Methods

Expressions as Arguments to Web Method Calls

Through MAM 4.2.x, you could not use an expression as argument of a Web method call. This restriction was lifted in MAM 4.3.

Example:

var OMA="OrderManagementWS/OMA"; declare boolean OMA_UpdateOrderState(orderID, state, accesskey); result = OMA_UpdateOrderState(jobID, "SendDone", AccessKey) @ OMA; // OK result = OMA_UpdateOrderState(a[0], "SendDone", AccessKey) @ OMA; // OK in MAM 4.3, ERROR in MAM 4.2.x result = OMA_UpdateOrderState(x + 1, "SendDone", AccessKey) @ OMA; // OK in MAM 4.3, ERROR in MAM 4.2.x

SOAP Calls: Automatic Handling of Structs and Arrays

Through Interplay MAM 4.2.x, WorkflowEngineWS tried to automatically determine if a given value for a parameter is a struct or array, or a simple type.

• If the value given for a parameter contains an XML document that looks like the XML representation of a struct, the value is passed in the SOAP body as a struct.

• If the value given for a parameter contains an XML document that looks like the XML representation of an array, the value is passed in the SOAP body as an array.

Web Methods

146

• In all other cases, the value is passed as a string.

So, the creation of the SOAP message depends on the value given as argument to the call. This can be very misleading. For example, if the SOAP call expects a string and by chance you provide a string that contains an XML document, WorkflowEngineWS might interpret that as struct or array and create a wrong SOAP body.

To avoid that, SWoDL now requires that you define the parameter types in the declaration of the call. See “Arrays as Input Parameters” on page 100, “Structs as Input Parameters” on page 102, and “Arrays of Structs as Input Parameters” on page 104 for details.

If you have existing SWoDL scripts that you don’t want to modify, you can enable the compatibility switch “WorkflowEngine/Compatibility/ImpliedArraysAndStructsForSoap” in the configuration profile of WorkflowEngineWS. For new projects, Avid recommends not to enable this flag.

Duplicate Web Method Declarations

Through Interplay MAM 4.2.x, you could declare SOAP and HTTP POST methods multiple times in your SWoDL script. WorkflowEngineWS used one of the declarations and ignored the other declarations.

Interplay MAM 4.3 fixes this compiler bug and correctly detects duplicate Web method declarations as errors.

If you have existing SWoDL scripts that you don’t want to modify, you can enable the compatibility switch “WorkflowEngine/Compatibility/AllowDuplicateMethodDeclarations” in the configuration profile of WorkflowEngineWS. As this is most likely a bug in the script, Avid recommends you do not enable this flag.

SOAP Calls: Parsing WSDL

To create the SOAP message for a SOAP call, WorkflowEngineWS fetches the description of the Web service and extracts the necessary information. Through Interplay MAM 4.2.x, WorkflowEngineWS fetched the WSDL of the service for each SOAP call. It parsed the WSDL, extracted the targetNamespace attribute of the WSDL, and used that as namespace for the SOAP message. This works well with ASP.NET Web services, but causes problems with other Web service frameworks like WCF.

Structs and Arrays

147

Since Interplay MAM 4.3, WorkflowEngineWS caches the WSDL of a Web service for a configurable time. The setting “/Performance/WsdlCacheLifeTime” configures the cache life time. The default value is 60 seconds.

Since Interplay MAM 4.3, the WSDL is not parsed using XML methods, but by using the ServiceDescription class of the Microsoft .NET framework. Now, the namespace of the SOAP operation is used as namespace of the SOAP message. This increases the compatibility with SOAP services that were developed using different frameworks such as WCF.

If the new WSDL parsing methods cause unexpected problems, you can reenable the old parsing methods using the compatibility switch “WorkflowEngine/Compatibility/TargetNameSpaceEvaluationForSoap” in the configuration profile of WorkflowEngineWS. Avid recommends you do not enable this flag unless it is really necessary.

Structs and Arrays

Structs

Through Interplay MAM 4.2.x, nested structs were stored in a different way. The fields of inner structs were added directly as XML elements. Example:

var user; user.JobTitle = "Businessman"; user.Age = 55; user.FullName.FirstName = "Joe"; user.FullName.LastName = "Satriani";

The XML representation of the example above looked like this:

<?xml version=”1.0”?> <struct> <JobTitle>Businessman</JobTitle> <Age>55</Age> <FullName> <FirstName>Joe</FirstName> <LastName>Satriani</LastName> </FullName> </struct>

Structs and Arrays

148

The format was changed in Interplay MAM 4.3 to support mixed-use of structs and arrays. In the new format, the struct FullName is serialized to an XML document and that XML document is stored as text content of the field FullName. See “Structs” on page 19 for an example.

This is only relevant if you parse such an XML document using XML functions. If you access it using the dot operator, both the old and the new XML documents can be accessed in the same way.

Arrays

Combining Structs and Arrays

Through Interplay MAM 4.2.x, you could not combine the square bracket notation with dot notation, as shown in the following example.

Example:

x[0].FirstName = "Joe"; // WRONG! // You must first create the struct and then assign it to an item in the // array. i = x[0].FirstName; // WRONG! // You must first assign the struct to a variable and then access the // fields.

Using Array Items for Web Calls

Through Interplay MAM 4.2.x, it was also not possible to use an array expression as parameter of a Web call:

declare string GetKey(profile, key); var result = GetKey(array[0], "SystemInfo/SystemVersion") @ ConfigService; // WRONG!

This restriction has been lifted.

Storage of Arrays

Through Interplay MAM 4.2.x, an item of an array was XML encoded twice in the XML document that represented the array. This has been fixed.

9 MAP_Delete: An Interplay | MAM Workflow

/////////////////////////////////////////////////////////////////////// // MAP_Delete Workflow // Version: 1.1.7 /////////////////////////////////////////////////////////////////////// // The workflow deletes an entire media object, including all essences and // associations. /////////////////////////////////////////////////////////////////////// // Details: // 1.) If the object doesn't exist, the workflow terminates immediately. // 2.) The workflow removes all essence packages and essences, aborting // running video analysis processes if necessary. // 3.) The workflow removes all associations of the given object // 4.) The workflow removes the DM object itself. /////////////////////////////////////////////////////////////////////// // Call parameters: in dmguid; // the DMGUID of the object to delete in UserAccessKey; // accesskey of the calling user /////////////////////////////////////////////////////////////////////// // WARNING: Please don't change anything below this line unless you // know exactly what you are doing. /////////////////////////////////////////////////////////////////////// ////////////////////////////////// // Definition of the web service methods // ////////////////////////////////// // DatamanagerWS - DMObjectAccess - Calls declare string GetDMAttribute (dmguid, attribute, accesskey); declare void DeleteDMObject (DMGUID, accesskey); declare boolean ExistsDMObject (dmguid, mdclass, accesskey); // DatamanagerWS - DMAssociations - Calls declare void RemoveAllAssociations (accesskey, dmguid); // DataManagerWS - DMEssencePackages - Calls declare EPGuid ListAllEssencePackages (accesskey, dmguid); declare void DeleteEssencePackage (accesskey, epguid); // VideoAnalysisServiceWS - VideoAnalysisService - Calls declare void AbortVideoAnalysis (accesskey, emguid); // EssenceManagerWS - EM - Calls declare boolean DeleteAllEMObjectsInEP (accesskey, epguid, removeFiles); declare string GetEMObjectsWithFilter (accesskey, epguid, streamType,

150

streamclass, usage); // Naming entries var DMAssociations = "DataManagerWS/DMAssociations"; var DMObjectAccess = "DataManagerWS/DMObjectAccess"; var DMEssencePackages = "DataManagerWS/DMEssencePackages"; var VAService = "VideoAnalysisServiceWS/VideoAnalysisService"; var EM = "EssenceManagerWS/EssenceManager"; var accesskey; // old name of accesskey parameter // Variables var accessKeyToUse; var AccessKey; // the accesskey as given by the workflow engine (system account) var DMObjectExists = "false"; var VAJobKilled = "false"; var EMDeleted = "false"; var EPDeleted = "false"; var DMDeleted = "false"; var ErrorMessage = "no error"; var SOAP_Call_Success = "true"; ////////////////////////////////////////////////////////////////////// // Activities //////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // If access key of user is given, use that. Otherwise use the one of the WFE. accessKeyToUse = AccessKey; if( accesskey != "" ) accessKeyToUse = accesskey; if( UserAccessKey != "" ) accessKeyToUse = UserAccessKey; //----------------------------------------------------------------------- // 1. check if DM object exist //----------------------------------------------------------------------- [[Checking if DM object exists]] retry(10) { DMObjectExists = ExistsDMObject (dmguid, "", accessKeyToUse) @ DMObjectAccess; if (!DMObjectExists) { [[Object doesn't exist => no action necessary]] exit; // object doesn't exist => no action necessary } } while (false); //-----------------------------------------------------------------------

151

// 2. delete all essence packages and essences (stopping running video analysis processes // if necessary) //----------------------------------------------------------------------- // Note: ListAllEssencePackages returns a list(!) of packages. The return value contains only // the EPGUID of the first of them. But the call is repeated after deleting this first package // so the list should become smaller in each loop, so the loop terminates eventually. var epguid = ""; do { [[Deleting essence packages]] SOAP_Call_Success = false; retry(10) { epguid = ListAllEssencePackages (accessKeyToUse, dmguid) @ DMEssencePackages; SOAP_Call_Success = true; } while ( !SOAP_Call_Success); if (!SOAP_Call_Success) error "Failed to get essence packages"; if (epguid != "") { try { var emguid; emguid = GetEMObjectsWithFilter (accessKeyToUse, epguid, "", "VIDEO", "BROWSE") @ EM; if (emguid != "") { VAJobKilled = false; retry(10) { [[Abort running video analysis if necessary]] AbortVideoAnalysis (accessKeyToUse, emguid) @ VAService; VAJobKilled = true; } while ( !VAJobKilled); if (!VAJobKilled) error "Failed to kill video analysis for " + emguid; } } catch { // ignore exception when query EMGuid for BROWSE VIDEO ErrorMessage = "exception when query EMGuid for BROWSE VIDEO “ + “for essence package " + epguid; } // Löschen aller Essencen die in dem Essence Package enthalten sind [[Deleting all em objects in essence package]] EMDeleted = "false"; retry(10) { EMDeleted = DeleteAllEMObjectsInEP (accessKeyToUse, epguid, "true") @ EM;

152

} while ( !EMDeleted); if (!EMDeleted) error "Failed to delete essences in essence package " + epguid + ": " + _ExceptionMessage; [[Deleting essence package]] EPDeleted = "false"; retry(10) { DeleteEssencePackage (accessKeyToUse, epguid) @ DMEssencePackages; EPDeleted = "true"; } while ( !EPDeleted); if (!EPDeleted) error "Failed to delete essence package " + epguid + ": " + _ExceptionMessage; } } while (epguid != ""); //----------------------------------------------------------------------- // 3. Delete all associations [DatamanagerWS:RemoveAllAssociations] //----------------------------------------------------------------------- [[Deleting associations]] DMDeleted = false; retry(10) { RemoveAllAssociations (accessKeyToUse, dmguid) @ DMAssociations; DMDeleted = true; } while ( !DMDeleted ); //----------------------------------------------------------------------- // 4. Delete DM object [DatamanagerWS:DeleteDMObject] //----------------------------------------------------------------------- [[Deleting DM object]] DMDeleted = false; retry(10) { DeleteDMObject (dmguid, accessKeyToUse) @ DMObjectAccess; DMDeleted = true; } while ( !DMDeleted ); if (!DMDeleted) error "Failed to delete object " + dmguid + ": " + _ExceptionMessage; [[Object deleted]] nop();

Disclaimer

Product specifications are subject to change without notice and do not represent a commitment on the part of Avid Technology, Inc.

This product is subject to the terms and conditions of a software license agreement provided with the software. The product may only be used in accordance with the license agreement.

This product may be protected by one or more U.S. and non-U.S. patents. Details are available at www.avid.com/patents.

This document is protected under copyright law. An authorized licensee of Avid Interplay | Media Asset Manager may reproduce this publication for the licensee’s own use in learning how to use the software. This document may not be reproduced or distributed, in whole or in part, for commercial purposes, such as selling copies of this document or providing support or educational services to others. This document is supplied as a guide for Avid Interplay | MAM. Reasonable care has been taken in preparing the information it contains. However, this document may contain omissions, technical inaccuracies, or typographical errors. Avid Technology, Inc. does not accept responsibility of any kind for customers’ losses due to the use of this document. Product specifications are subject to change without notice.

Copyright © 1998-2016 Avid Technology, Inc. and its licensors. All rights reserved.

The following disclaimer is required by Apache Commons Logging: Copyright © 2003-2013 The Apache Software Foundation Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)

The following disclaimer is required by Apache Commons Net: Copyright © 2001-2013 The Apache Software Foundation Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)

The following disclaimer is required by Apache Jakarta Commons HttpClient: Copyright © 2004 The Apache Software Foundation Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)

The following disclaimer is required by Apache log4net: Copyright © 2004-2011 The Apache Software Foundation Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)

The following disclaimer is required by Apache Xerxes: Copyright © 2008 Apache Software Foundation Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)

The following disclaimer is required by Behaviour.js: This product includes software developed by Ben Nolan and his contributors. Copyright © 2006, 2007 Ben Nolan. All rightsreserved.

The following disclaimer is required by CFlatToolbar: Portions of this product are Copyright © 2002 Roger Onslov, all rights reserved.

The following disclaimer is required by Cross-Browser X Library: Copyright © 2000-2009 Michael Foster, distributed under the terms of LGPL (http://cross-browser.com/license.html)

The following disclaimer is required by CSXButton: Copyright © 1998 Michael Santoro, all rights reserved

The following disclaimer is required by CVersionInfo: Portions of this product are Copyright © 1997 Roberto Rocco, all rights reserved.

The following disclaimer is required by Assisted Solutions InputMask:

154

Portions of this product are Copyright © Data Reasearch Group. All rights reserved.

The following disclaimer is required by dicas: Portions of this product are Copyright © dicas digital image coding GmbH. All rights reserved.

The following disclaimer is required by DirectShowLib: Copyright (C) 2007 http://sourceforge.net/projects/directshownet, distributed under the terms of LGPL V2.1 (http://www.gnu.org/licenses/lgpl-2.1.html)

The following disclaimer is required by Divelements: Portions of this product are Copyright © 2003-2011 Divelements Limited.

The following disclaimer is required by DockPanelSuite: This product includes software developed by Mark Twombley, Steve Overton, and Weifen Luo and their contributors. Copyright © 2009 Mark Twombley, Steve Overton, and Weifen Luo.

The following disclaimer is required by FFmpeg: FFmpeg is Copyright © 2000-2003 Fabrice Bellard and is licensed under the terms of the GNU Lesser General Public License, which is included with this product.

The following disclaimer is required by GDCL Sample Parser: Copyright 2004 GDCL (http://www.gdcl.co.uk)

The following disclaimer is required by getElementsByAttribute: Copyright © 2006 Robert Nyman (http://www.robertnyman.com)

The following disclaimer is required by GoXam: Portions of this product are Copyright © 1995-2011 Northwoods Software. All rights reserved.

The following disclaimer is required by IC#Code #ZipLib: Copyright © 2000-2009 Michael Foster, distributed under the terms of GNU GPL with the following exception: As a special exception, the copyright holders of this library give you permission to link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this library, you may extend this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version.

The following disclaimer is required by IFilter Text Extracter: IFilter Text Extracter Microsoft Public License (Ms-PL)

The following disclaimer is required by ImageMagick: Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization dedicated to making software imaging solutions freely available. (http://www.imagemagick.org/script/license.php)

The following disclaimer is required by Interplay Common Playback Service: This product includes FFmpeg, which is covered by the GNU Lesser General Public License. This product includes software that is based in part of the work of the FreeType Team. This software is based in part on the work of the Independent JPEG Group. This product includes libjpeg-turbo, which is covered by the wxWindows Library License, Version 3.1. Portions copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 by Cold Spring Harbor Laboratory. Funded under Grant P41-RR02188 by the National Institutes of Health. Portions copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 by Boutell.Com, Inc. Portions relating to GD2 format copyright 1999, 2000, 2001, 2002 Philip Warner. Portions relating to PNG copyright 1999, 2000, 2001, 2002 Greg Roelofs. Portions relating to gdttf.c copyright 1999, 2000, 2001, 2002 John Ellson ([email protected]). Portions relating to gdft.c copyright 2001, 2002 John Ellson ([email protected]). Portions relating to JPEG and to color quantization copyright 2000, 2001, 2002, Doug Becker and copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, Thomas G. Lane. This software is based in part on the work of the Independent JPEG Group. See the file README-JPEG.TXT for more information. Portions relating to WBMP copyright 2000, 2001, 2002 Maurice Szmurlo and Johan Van den Brande. Permission has been granted to copy, distribute and modify gd in any context without fee, including a commercial application, provided that this notice is present in user-accessible supporting documentation.This does not affect your ownership of the derived work itself, and the intent is to assure proper credit for the authors of gd, not to interfere with your productive use of gd. If you have questions, ask. "Derived works" includes all programs that utilize the library. Credit must be given in user-accessible

155

documentation.This software is provided "AS IS." The copyright holders disclaim all warranties, either express or implied, including but not limited to implied warranties of merchantability and fitness for a particular purpose, with respect to this code and accompanying documentation.Although their code does not appear in gd, the authors wish to thank David Koblas, David Rowley, and Hutchison Avenue Software Corporation for their prior contributions.

The following disclaimer is required by Interplay Entertainment Corp.: The Interplay name is used with the permission of Interplay Entertainment Corp., which bears no responsibility for the product.

The following disclaimer is required by JavaZoom: Portions of this product are Copyright © JavaZoom. All rights reserved.

The following disclaimer is required by JQuery: Copyright 2013 jQuery Foundation and other contributors (http://jquery.com/)

The following disclaimer is required by JQuery Plugin Autocomplete: Copyright (c) 2009 Jörn Zaefferer. (http://www.opensource.org/licenses/mit-license.php)

The following disclaimer is required by jquery.contextMenu: Copyright © 2008 A Beautiful Site, LLC

The following disclaimer is required by jquery.jqDnR: Copyright © 2007 Brice Burgess (<[email protected]>, http://www.iceburg.net)

The following disclaimer is required by Ui.dropdownchecklist: Copyright © 2008-2010 Adrian Tosca, Copyright (c) 2010-2011 Ittrium LLC

The following disclaimer is required by jquery.json: Copyright © 2009 Brantley Harris

The following disclaimer is required by jquery.metadata: Copyright © 2006 John Resig, Yehuda Katz, Jörn Zaefferer, Paul McLanahan

The following disclaimer is required by jquery.jqModal: Copyright © 2007,2008 Brice Burgess (<[email protected]>)

The following disclaimer is required by jquery.jTemplates: Copyright © 2009 Tomasz Gloc

The following disclaimer is required by jquery.treeview: Copyright © 2007 Jörn Zaefferer

The following disclaimer is required by jquery UI: Copyright © 2011, Scott Gonzalez et al. (http://jqueryui.com/about)

The following disclaimer is required by JScape: Portions of this product are Copyright © JScape. All rights reserved.

The following disclaimer is required by JScript Hashtable: Copyright © 2003 Michael Synovic This is a Javascript implementation of the Java Hashtable object.

The following disclaimer is required by JScript Table Sorter: © 2010 Michael Leigeber. All Rights Reserved This script has been tested in all major browsers and is available free of charge for both personal or commercial projects under the creative commons license.

The following disclaimer is required by Libjpeg-turbo: libjpeg-turbo is Copyright © 1998-2005 Julian Smart, Robert Roebling et al and is licensed under the terms of the wxWindows Library Licence, Version 3.1, which is included with this product.

The following disclaimer is required by Limited Concurrency Task Scheduler: Portions Copyright © Microsoft Corporation Inc. All Rights Reserved. Microsoft Limited Public License version 1.1

The following disclaimer is required by MediaLooks:

156

Portions of this product are Copyright MediaLooks. All rights reserved.

The following disclaimer is required by Microsoft Corporation: Portions of this product are Copyright © Microsoft Corporation. All rights reserved.

The following disclaimer is required by Microsoft.Net Framework Base Class Libraries, BigRational: Portions of this product are Copyright © Microsoft Corporation. All rights reserved.

The following disclaimer is required by Microsoft Prism: Microsoft patterns & practices License; Creative Commons Attribution License 3.0 Unported

The following disclaimer is required by MOG Solutions: Portions of this product are Copyright © MOG Solutions. All rights reserved.

The following disclaimer is required by MPEG Audio: MPEG Audio technology may be included with this product. Audio MPEG, Inc. and S.I.SV.EL., S.P.A. require this notice: This product contains MPEG Audio technology licensed by Audio MPEG and SISVEL only for use in accordance with Avid's EULA. Last Updated: March 2010

The following disclaimer is required by MSTS-adapter: Copyright © 2008 Will Ballard / Duane Fields / ExactMagic

The following disclaimer is required by MVVM Lite: Copyright (c) 2009 - 2011 Laurent Bugnion

The following disclaimer is required by nUnit: Copyright (c) 2004-2009 Charlie Poole

The following disclaimer is required by Obout Software: Portions of this product are Copyright © Obout Software. All rights reserved.

The following disclaimer is required by OpenSSL: This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/)

The following disclaimer is required by PixieLib: Portions of this program borrowed from PixieLib.NET, Copyright 2005 Paul DiLascia.

The following disclaimer is required by FilterCode: Copyright © 2011 phpleo

The following disclaimer is required by PlainIt Works JeeGooContext: Copyright © 2009 - 2010 by Erik van den Berg

The following disclaimer is required by Prototype JavaScript Framework: Copyright © 2005-2008 Sam Stephenson

The following disclaimer is required by ScintillaNET: Copyright © 1998-2006 by Neil Hodgson ([email protected]) All Rights Reserved ScintillaNET bindings are Copyright © 2002-2006 by Garrett Serack ([email protected]) All Rights Reserved

The following disclaimer is required by RabbitMQ: Copyright © 2013 GoPivotal, Inc. All rights reserved

The following disclaimer is required by Script.Aculo.Us Web 2.0 JavaScript: Copyright © 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)

The following disclaimer is required by Search Highlighter: Copyright (c) 2002, 2007, 2008 Stuart Langridge ([email protected])

The following disclaimer is required by Silverlight Menu: Microsoft Public License (Ms-PL) http://sl3menu.codeplex.com/license

157

The following disclaimer is required by Silverlight Serializer: Copyright © Mike Talbot, Microsoft Public License (Ms-PL)

The following disclaimer is required by tipsy: Copyright (c) 2008 Jason Frame ([email protected]). The software and documentation is released under the MIT license. https://github.com/jaz303/tipsy/blob/master/LICENSE

The following disclaimer is required by WPF Themes: Licensed under the Microsoft Public License (Ms-PL) http://wpf.codeplex.com/license

The following disclaimer is required by WPF Toolkit: Microsoft Public License (MS-PL)

The following disclaimer is required by Xmlextras.js: Copyright © 2006 Erik Arvidsson Licensed under the Apache License, Version 2.

The following disclaimer is required by XNView: Portions of this product are Copyright © XNView. All rights reserved.

Attn. Government User(s). Restricted Rights Legend U.S. GOVERNMENT RESTRICTED RIGHTS. This Software and its documentation are “commercial computer software” or “commercial computer software documentation.” In the event that such Software or documentation is acquired by or on behalf of a unit or agency of the U.S. Government, all rights with respect to this Software and documentation are subject to the terms of the License Agreement, pursuant to FAR §12.212(a) and/or DFARS §227.7202-1(a), as applicable.

Trademarks

Avid, the Avid Logo, Avid Everywhere, Avid DNXHD, Avid DNXHR, Avid Nexis, AirSpeed, Eleven, EUCON, Interplay, iNEWS, ISIS, Mbox, MediaCentral, Media Composer, NewsCutter, Pro Tools, ProSet and RealSet, Maestro, PlayMaker, Sibelius, Symphony, and all related product names and logos, are registered or unregistered trademarks of Avid Technology, Inc. in the United States and/or other countries. The Interplay name is used with the permission of the Interplay Entertainment Corp. which bears no responsibility for Avid products. All other trademarks are the property of their respective owners. For a full list of Avid trademarks, see: http://www.avid.com/US/about-avid/legal-notices/trademarks.

Adobe and Photoshop are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other countries. Apple and Macintosh are trademarks of Apple Computer, Inc., registered in the U.S. and other countries. Windows is either a registered trademark or trademark of Microsoft Corporation in the United States and/or other countries. All other trademarks contained herein are the property of their respective owners.

Avid Interplay | MAM SWoDL Reference v5.7, Created 9/23/2016. This document is distributed by Avid in online (electronic) form only, and is not available for purchase in printed form.