User Script Data Source

Txture provides a wide array of flexible importers. However, In very specific scenarios, you may want to create a heavily customized import pipeline. For this purpose, Txture offers the Scripted Import Datasource. As the name implies, such a datasource stores a user-defined executable script which is executed by the Txture server to provide the raw data for the import. This script may contain arbitrary internal logic for data merging, filtering and cleaning. This approach is extremely flexible, but also requires a good understanding of Txture as well as the Groovy scripting language. This datasource is ideal for advanced use cases, such as:

  • Integrating an external API for which there is no dedicated support in Txture.
  • Combining data from several sources before importing the result.
  • Performing custom pre-processing on data before it is handed to an importer.
  • Implementing workflows that deviate from the standard importer workflow.

You can create a User Script Datasource in the "Data Sources" admin area.

Script Structure

Txture imposes as few constraints as possible on the script. Generally speaking, there are three phases to each script:

  • Schema definition In the first step, the script should define the schema of the data to be imported. The schema consists of a list of columns. Each column has a name (e.g. "ID", "Name", "Description"...), a type (Text, Number, Date, Boolean, Range), and a multiplicity (single valued / many valued).
  • Data retrieval & preparation After defining the schema, scripts usually fetch data from an external source. At the time of writing this document, HTTP-based retrieval and file retrieval are supported, but other types may be added in the future. Note that several individual requests may be made (for example, to fully resolve data from a paginated endpoint) and the results can be joined in the script. If needed, you can also query multiple different external services and join their data.
  • Result collection After the external data has been fetched and prepared, you can bring it into Txture by declaring rows. Each row corresponds to one object, and each row uses the columns defined in the schema.

Please note that the script is located inside the Data Source. This means that all regular facilities for importers, such as filters, dynamic columns and enhancers, are also available when working with scripted datasources. The main job of the script is to retrieve the raw information.

Script Workflow

While Txture doesn't explicitly enforce a specific script structure, the recommended structure consists of the following 3 steps:

  1. Define the schema of the objects which will be produced by your script. This is done via dataSource.declareSchema{ ... }. This is the schema any importer will "see" when operating on your User Script Datasource.
  2. Fetch and pre-process the desired data. Txture provides several script helpers to access common datasources easily.
  3. Convert the data into rows, following the schema defined in step 1.

A minimal example

When you create a new Scripted Importer Datasource, the code area will already contain some examples to guide you through the process. The following listing shows a minimal example of the workflow (using hard-coded data):

// schema definition
def receiver = dataSource.declareSchema {
    column("ID", ColumnType.Number, Multiplicity.Single)
    column("Name", ColumnType.Text, Multiplicity.Single)
}

// Txture passes the "limit" parameter to the script to
// indicate how many rows should be returned (e.g. for preview).
// If the limit is less than or equal to 0, only the schema
// should be defined.
if(limit <= 0){
  return;
}

// data retrieval
// -> we use hard-coded data here so nothing to do in this phase

// result collection
def row1 = receiver.addRow()
row1.setNumber("ID", 1)
row1.setString("Name", "John Doe")

def row2 = receiver.addRow()
row2.setNumber("ID", 2)
row2.setString("Name", "Jane Doe")

def row3 = receiver.addRow()
row3.setNumber("ID", 3)

The result of this script will be a table with 2 columns and three rows:

ID (Number, Single) Name (Text, Single)
1 John Doe
2 Jane Doe
3 < no value >
Tip: Use the Code Completion Templates:

When editing a Scripted Importer Datasource, you can press CTRL+Space to bring up a list of code templates. Those templates are generated dynamically and will always match your current Txture version. In case that this document and the template differ from each other, the template is always correct. Code Completion Templates After you've selected a template, either click on the entry in the list, or press Enter to insert the template into your code. In addition to templates for a variety of importer types, the completion also includes access to all enumerations and their values (e.g. type AWSRegion. and press CTRL+Space to see all possible AWSRegion values).

Retrieving Data via HTTP(s)

Txture provides a facility for easy access to any external HTTP(s) endpoint via request.http:

def response = request.http {
  method = HttpMethod.POST
  url = "https://www.example.org"
  body = """
    ["This", "is", "an", "example"]
  """
  headers {
    contentType("application/json")
    authorization("Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
    custom("my-special-header", "header value")
  }
}

The exact API for the REST request is outlined below in the API reference. The snippet above performs the actual REST request. To extract data from it, we need to inspect the result:

// 'statusCode' returns the HTTP status, as an integer.
if(response.statusCode != 200){
  // the REST call failed!
  return fail("Failed to perform REST call!")
}

// with 'bodyText' we access the UTF-8 encoded string result.
// we could also use 'bodyBytes' to access the raw bytes.
def text = response.bodyText

// let's assume we receive a JSON array in the response. Decode it.
// for details on JSON handling, please see the "Scripting Utils" documentation page.
def jsonArray = parseJsonArray(text)

// if you need to, you can check the response headers as well.
// "getFirst" returns the first value for the header
def contentType = response.headers.getFirst("content-type")
// "getAll" returns all values for the header as a List of strings
def cacheControls = response.headers.getAll("cache-control")


// now, we can iterate over it...
for(def entry : jsonArray) {
  // ... and create one row per entry
  def row = receiver.addRow()
  // use the "serialNumber" from the JSON as our ID
  row.setNumber("ID", (Number)entry["serialNumber"])
  // transfer the "name" from the json to our row
  row.setString("Name", (String)entry["Name"])
}

Retrieving Data from local Files

Similar to the Folder Datasource, a script can read the contents of a file which is stored on the Txture server. The script is limited to read-only access, and the exact path of the file must be known (i.e. directory listings are not supported).

// request access to the file
def response = request.file {
    path = "/home/john-doe/Documents/myFile.json"
}

// check if the file has been found
if(!response.found){
  return fail("file not found")
}

// get the content
def jsonContent = response.contentString

Please check the API reference below for details.

Limited access to server files:

Depending on the server configuration, Txture may prevent access to certain files when using request.file{ ... }. Files that reside within the Txture Home directory, as well as security-sensitive directories, may not be accessible. Furthermore, all file accesses are subject to the file system permissions granted to the Txture server process by the operating system. Please make sure your files reside in an accessible directory.

Retrieving Data via OData

Txture provides a facility for easy access to any external OData endpoint via request.odata:

def serviceURL = "https://www.example.org/"
// set Authorization for OData client
def client = request.odata {
  auth {
    basic("admin","password")
  }
}

def receiver = dataSource.declareSchema {
  // add schema columns for class 'Machine'
  // the last parameter is optional - if it's not set schema will be fetched from whole metadata model
  addAllODataSchemaColumns(client, serviceURL, "Machine")
}
// use the OData Client (Apache Olingo OData 4.0) to retrieve data
// https://olingo.apache.org/doc/odata4/tutorials/od4_basic_client_read.html
def response = client.retrieveRequestFactory.getEntitySetRequest(
  // most of the requests expect an URI, helper method is provided
  parseURI(serviceURL + "Machines")
).execute()

The exact API for the REST request is outlined below in the API reference. Also use the Tutorial for OData 4.0 Basic Client Read. We expose the OData client, so it can be used as in the Olingo Apache Documentation to retrieve data. The snippet above performs the actual OData request. To extract data from it, we need to inspect the result:

// 'statusCode' returns the HTTP status, as an integer.
if (response.statusCode != 200) {
  fail("Failed to perform REST call")
}

// the response body has to be assigned to it's regarding interface-/class - so all variables/methods can be accessed afterwards.
ClientEntitySet responseBody = response.body

def entities = responseBody.entities
for (entity in entities) {
  def row = receiver.addRow()
  // map the entity to the metadata model fetched above
  mapODataEntityToRow(entity,row)
}

Retrieving Data via Standard Importers

Txture provides a wide variety of standard importers in order to connect to cloud providers and tools. You can configure such importers in-place in a Scripted Import Datasource in order to make use of their functionality. This allows your script to work with a uniform API across all integrations. Txture internally handles all differences in protocols, performs pagination as required and produces a unified output format.

All importers that are accessed via request.importer... will produce the same result of type ImportResult. Please see the scripting API below for details.

Standard Importer: SQL

The following template shows how to fetch data from an SQL database:

def importResult = request.importer.sql.query {
 // check your JDBC provider manual for details on the connection URL
 jdbcUrl = "jdbc:postgresql://localhost/testdb"
 username = " ... my database username ...  "
 password = " ... my database password ...  "
 query = "SELECT * FROM MyTable WHERE 1 = 1"
 maxResults = 10
}

Standard Importer: AWS

The following template shows how to fetch instances from Amazon Web Services (AWS):

def importResult = request.importer.aws.instances {
 onlyRunning = false
 type = AWSType.NODE
 regions = [AWSRegion.EU_WEST_3]
 elasticSearchDomains = ["my-elastic-search-domain"]
 maxResults = 10
 // Repeat the 'credentials{ ... }' block to add multiple credentials
 credentials {
  name = "... service account name ..."
  accessKeyId = "... my access key ..."
  secretKey = "... my secret key ..."
 }
}

Link information can be fetched as follows:

def importResult = request.importer.aws.links {
 path = AWSPath.INSTANCE_TO_IMAGE
 regions = [AWSRegion.EU_WEST_3]
 elasticSearchDomains = ["my-elastic-search-domain"]
 maxResults = 10
 // Repeat the 'credentials{ ... }' block to add multiple credentials
 credentials {
  name = "... service account name ..."
  accessKeyId = "... my access key ..."
  secretKey = "... my secret key ..."
 }
}

Standard Importer: Google Cloud

The following template shows how to fetch instances from Google Cloud Platform (GCP):

def importResult = request.importer.googleCloud.instances {
 type = GoogleCloudType.INSTANCE
 onlyRunning = false
 billingProject = "my-billing-project"
 billingDataset = "my-billing-dataset"
 billingTable = "my-billing-table"
 accountKey = """ ... google account key JSON ... """
 projectId = "my-project-id"
 regions = [GoogleRegion.EUROPE_WEST3]
 maxResults = 10
}

Link information can be fetched as follows:

def importResult = request.importer.googleCloud.links {
 path = GoogleCloudPath.DISK_TO_INSTANCE
 accountKey = """ ... google account key JSON ... """
 projectId = "my-project-id"
 regions = [GoogleRegion.EUROPE_WEST3]
 maxResults = 10
}

Standard Importer: Azure

The following template shows how to fetch instances from Azure:

def importResult = request.importer.azure.instances {
 type = AzureType.VIRTUAL_MACHINE
 onlyRunning = false
 clientAppId = " ... my client app ID ... "
 tenant = " ... my tentant ... "
 password = " ... my password ... "
 subscriptionId = " ... my subscription ID ... "
 region = AzureRegion.GLOBAL
 maxResults = 10
}

Link information can be fetched as follows:

def importResult = request.importer.azure.links {
 path = AzurePath.LOAD_BALANCER_TO_VIRTUAL_MACHINE
 clientAppId = " ... my client app ID ... "
 tenant = " ... my tentant ... "
 password = " ... my password ... "
 subscriptionId = " ... my subscription ID ... "
 region = AzureRegion.GLOBAL
 maxResults = 10
}

Standard Importer: Alibaba

The following template shows how to fetch instances from Alibaba:

def importResult = request.importer.alibaba.instances {
 type = AlibabaType.INSTANCE
 onlyRunning = false
 accessKey = " ... my access key ... "
 secretKey = " ... my secret key ... "
 region = AlibabaRegion.HONG_KONG
 maxResults = 10
}

Link information can be fetched as follows:

def importResult = request.importer.alibaba.links {
 path = AlibabaPath.DISK_TO_INSTANCE
 accessKey = " ... my access key ... "
 secretKey = " ... my secret key ... "
 region = AlibabaRegion.HONG_KONG
 maxResults = 10
}

Standard Importer: Oracle Cloud

The following template shows how to fetch instances from Oracle Cloud:

def importResult = request.importer.oracleCloud.instances {
 type = OracleCloudType.INSTANCE
 onlyRunning = false
 userOCID = """ ... my OracleCloud OCID ..."""
 fingerprint = """ ... my OracleCloud Fingerprint ..."""
 privateKey = """ ... my OracleCloud private key ..."""
 passphrase = """ ... my OracleCloud passphrase ..."""
 tenancyOCID = """ ... my OracleCloud tenancy OCID ..."""
 compartmentId = """ ... my OracleCloud compartment ID ..."""
 region = OracleClouRegion.EU_FRANKFURT_1
 maxResults = 10
}

Link information can be fetched as follows:

def importResult = request.importer.oracleCloud.links {
 path = OracleCloudPath.INSTANCE_CREATED_BY_IMAGE
 userOCID = """ ... my OracleCloud OCID ..."""
 fingerprint = """ ... my OracleCloud Fingerprint ..."""
 privateKey = """ ... my OracleCloud private key ..."""
 passphrase = """ ... my OracleCloud passphrase ..."""
 tenancyOCID = """ ... my OracleCloud tenancy OCID ..."""
 compartmentId = """ ... my OracleCloud compartment ID ..."""
 region = OracleClouRegion.EU_FRANKFURT_1
 maxResults = 10
}

Standard Importer: OpenStack

The following template shows how to fetch instances from OpenStack:

def importResult = request.importer.openStack.instances {
 type = OpenStackType.VIRTUAL_MACHINE
 onlyRunning = false
 endpoint = "https://www.example.org/openstack"
 username = " ... my OpenStack username ..."
 password = " ... my OpenStack password ..."
 projectName = "my-project"
 domainName = "Default"
 projectDomainName = "Default"
 maxResults = 10
}

Link information can be fetched as follows:

def importResult = request.importer.openStack.links {
 path = OpenStackPath.VIRTUAL_MACHINE_TO_IMAGE
 endpoint = "https://www.example.org/openstack"
 username = " ... my OpenStack username ..."
 password = " ... my OpenStack password ..."
 projectName = "my-project"
 domainName = "Default"
 projectDomainName = "Default"
 maxResults = 10
}

Standard Importer: VMware VSphere / VCenter 6

The following template shows how to fetch instances from VMware VSphere / VCenter (Version 6.x). Please note that version 7.x has a different API (see below).

def importResult = request.importer.vmWare6.instances {
 type = VMware6Type.VIRTUAL_MACHINE
 username = " ... my VMware username ..."
 password = " ... my VMware password ..."
 ignoreCertificate = false
 serverAddress = "192.168.1.10"
 maxResults = 10
}

Link information can be fetched as follows:

def importResult = request.importer.vmWare6.links {
 path = VMware6Path.HOST_SYSTEM_RUNS_VIRTUAL_MACHINE
 username = " ... my VMware username ..."
 password = " ... my VMware password ..."
 ignoreCertificate = false
 serverAddress = "192.168.1.10"
 maxResults = 10
}

Standard Importer: VMware VSphere / VCenter 7

The following template shows how to fetch instances from VMware VSphere / VCenter (Version 7.x). Please note that version 6.x has a different API (see above).

def importResult = request.importer.vmWare7.instances {
 type = VMware7Type.VIRTUAL_MACHINE
 username = " ... my VMware username ..."
 password = " ... my VMware password ..."
 ignoreCertificate = false
 serverAddress = "192.168.1.10"
 maxResults = 10
}

Link information can be fetched as follows:

def importResult = request.importer.vmWare7.links {
 path = VMware7Path.HOST_SYSTEM_RUNS_VIRTUAL_MACHINE
 username = " ... my VMware username ..."
 password = " ... my VMware password ..."
 ignoreCertificate = false
 serverAddress = "192.168.1.10"
 maxResults = 10
}

Standard Importer: HyperV

The following template shows how to fetch instances from HyperV.

def importResult = request.importer.hyperV.instances {
 type = HyperVType.VIRTUAL_MACHINE
 host = "my-hyperv-host"
 user = " ... my HyperV username ..."
 password = " ... my HyperV password ..."
 authScheme = HyperVAuthScheme.BASIC
 useHttps = false
 maxResults = 10
}

Link information can be fetched as follows:

def importResult = request.importer.hyperV.links {
 path = VM_TO_HOST
 host = "my-hyperv-host"
 user = " ... my HyperV username ..."
 password = " ... my HyperV password ..."
 authScheme = HyperVAuthScheme.BASIC
 useHttps = false
 maxResults = 10
}

Standard Importer: RedHat Virtualization

The following template shows how to fetch instances from RedHat Virtualization.

def importResult = request.importer.redHatVirtualization.instances {
 type = RedHatVirtualizationType.VM
 onlyRunning = false
 url = "https://www.example.org/redhat"
 user = " ... my RedHat Virtualization username ..."
 password = " ... my RedHat Virtualization password ..."
 maxResults = 10
}

Link information can be fetched as follows:

def importResult = request.importer.redHatVirtualization.links {
 path = RedHatVirtualizationPath.DISK_TO_VM
 url = "https://www.example.org/redhat"
 user = " ... my RedHat Virtualization username ..."
 password = " ... my RedHat Virtualization password ..."
 maxResults = 10
}

Standard Importer: Kubernetes

The following template shows how to fetch instances from Kubernetes.

def importResult = request.importer.kubernetes.instances {
 type = KubernetesType.NODE
 onlyRunning = false
 vendor = KubernetesVendor.GOOGLE
 kubernetesMasterUrl = "https://example.com/kubernetes"
 caCertificate = " ... my ca certificate ... "
 googleAccessDataKey = " ... my google access data key ... "
 awsClusterName = " ... my aws cluster name ... "
 awsAccessKeyId = " ... my aws access key id ... "
 awsSecretKey = " ... my aws secret key ... "
 maxResults = 10
}

Link information can be fetched as follows:

def importResult = request.importer.kubernetes.links {
 path = KubernetesPath.NODE_TO_CLUSTER
 vendor = KubernetesVendor.GOOGLE
 kubernetesMasterUrl = "https://example.com/kubernetes"
 caCertificate = " ... my ca certificate ... "
 googleAccessDataKey = " ... my google access data key ... "
 awsClusterName = " ... my aws cluster name ... "
 awsAccessKeyId = " ... my aws access key id ... "
 awsSecretKey = " ... my aws secret key ... "
 maxResults = 10
}

Standard Importer: Azure Migrate

The following template shows how to fetch instances from Azure Migrate:

def importResult = request.importer.azureMigrate.instances {
 type = AzureMigrateType.MACHINES
 clientId = " ... my client ID ... "
 clientSecret = " ... my client secret ... "
 tenantId = " ... my tenant ID ... "
 subscriptionId = " ... my subscription ID ... "
 resourceGroup = " ... my resource group ... "
 migrateProject = " ... my migrate project ... "
 maxResults = 10
}

Link information can be fetched as follows:

def importResult = request.importer.azureMigrate.links {
 path = AzureMigratePath.MACHINE_TO_STORAGE
 clientId = " ... my client ID ... "
 clientSecret = " ... my client secret ... "
 tenantId = " ... my tenant ID ... "
 subscriptionId = " ... my subscription ID ... "
 resourceGroup = " ... my resource group ... "
 migrateProject = " ... my migrate project ... "
 maxResults = 10
}

Standard Importer: Jira

The following template shows how to fetch issues from Jira:

def importResult = request.importer.jira.issues {
 url = "http://www.example.com/jira"
 email = "john.doe@example.com"
 token = """ ... my JIRA token ..."""
 query = """project = "EXM" ORDER BY created DESC"""
 maxResults = 10
 additionalHeaders {
 }
}

Standard Importer: I-Doit

The following template shows how to fetch instances from I-Doit:

def importResult = request.importer.idoit.instances {
 objectType = 1 // consult your Idoit admin for information which value maps to which type.
 username = " ... my Idoit username ... "
 password = " ... my Idoit password ... "
 apiKey = """ ... my Idoit API Key ... """
 url = "www.example.com/idoit"
 requestLimit = 150
 maxResults = 10
}

Link information can be fetched as follows:

def importResult = request.importer.idoit.links {
 username = " ... my Idoit username ... "
 password = " ... my Idoit password ... "
 apiKey = """ ... my Idoit API Key ... """
 url = "www.example.com/idoit"
 requestLimit = 150
 maxResults = 10
}

Standard Importer: ServiceNow

The following template shows how to fetch instances from ServiceNow:

def serviceNowImport = request.importer.serviceNow.instances {
 type = ServiceNowType.SERVER_VIRTUAL
 serverAddress = "https://www.example.org/service-now"
 username = " ... my ServiceNow username ..."
 password = " ... my ServiceNow password ..."
 maxResults = 10
}

Link information can be fetched as follows:

def serviceNowImport = request.importer.serviceNow.links {
 serverAddress = "https://www.example.org/service-now"
 username = " ... my ServiceNow username ..."
 password = " ... my ServiceNow password ..."
 maxResults = 10
}

Standard Importer: LeanIX

The following template shows how to fetch instances from LeanIX:

def importResult = request.importer.leanIX.instances {
 type = LeanIXType.IT_COMPONENT
 onlyActive = 10
 basePath = "https://app.leanix.net/services/pathfinder/v1"
 apiToken = """ ... my LeanIX API token ... """
 tokenProviderHost = "app.leanix.net"
 maxResults = 10
}

Link information can be fetched as follows:

def importResult = request.importer.leanIX.links {
 path = LeanIXType.IT_COMPONENT
 basePath = "https://app.leanix.net/services/pathfinder/v1"
 apiToken = """ ... my LeanIX API token ... """
 tokenProviderHost = "app.leanix.net"
 maxResults = 10
}

Standard Importer: CAST

The following template shows how to fetch instances from CAST:

def importResult = request.importer.CAST.instances {
 type = CASTType.APPLICATION
 username = " ... my CAST username ... "
 password = " ... my CAST password ... "
 domains = [ "my-cast-domain" ]
 maxResults = 10
}

Standard Importer: LDAP

The following template shows how to fetch instances from an LDAP Server:

def importResult = request.importer.ldap.instances {
 searchScope = LdapSearchScope.SUBTREE
 baseDn = null
 filter = ""
 url = "http://www.example.com/ldap"
 managerUserDn = "CN=John Doe,L=Vienna,C=AT"
 managerPassword = " ... my manager password ... "
 defaultBaseDn = ""
 maxResults = 10
}

Standard Importer: Active Directory

The following template shows how to fetch instances from Active Directory (AD):

def importResult = request.importer.ldapAd.instances {
 resourceType = LdapAdResource.USERS
 baseDn = null
 filter = ""
 url = "http://www.example.com/ldap"
 managerUserDn = "CN=John Doe,L=Vienna,C=AT"
 managerPassword = " ... my manager password ... "
 defaultBaseDn = ""
 maxResults = 10
}

Logging

Your script may produce log output during its execution in order to assist in quick issue detection and help during API exploration. There are two methods:

// log.debug(message) is only printed when fetching a preview in
// the data source UI.
log.debug("I'm only visible in preview mode!")

// log.info(message) is always printed to the server console
log.info("Hello World! I'm always printed!")

The messages will be displayed in the scripted import data source UI. We recommend using log.debug over log.info to avoid bloating the server logs during importer executions.

Cancelling Script Execution

At any point in the script, you may cancel the execution via the return fail(...) statement:

return fail("Oh no, something went wrong!")

This will:

  • terminate the script execution
  • cancel the importer operating on the datasource
  • cancel the scheduling group in which the importer is running

Cancellation is useful in cases where an external API does not respond, e.g. due to network connectivity issues. You should always consider cancellation when the HTTP response status is something other than 200.

Scripting API

Global variables

The scripting API defines the following global variables for scripted import datasources:

  • DataSourceBuilder dataSource The dataSource is the main API entry point and only declares one method, which is defineSchema.
  • int limit This integer tells how many rows Txture expects at most from the script execution. There are three cases:
    • Schema Query: Txture queries for the defined schema. In this case, limit will be 0.
    • Data Preview: Txture previews the datasource for a user. In this case, limit will be a small (positive) value (e.g. 20, 30, ...). All returned rows that exceed this threshold will be dropped automatically for the purposes of the preview. For performance reasons, your script should not fetch more rows than required.
    • Import Execution: Txture performs the actual import. In this case, limit will be set to the maximum integer value (2147483647) to retrieve all rows. This indicates "no limit". The scripting API exposes this number as Integer.MAX_VALUE.
  • RequestBuilder request A helper for building requests to external data sources, such as HTTP endpoints.
  • Logger log The logger prints messages and can be used as a debugging facility.

DataSourceBuilder

dataSource.defineSchema

Signature: DataReceiver defineSchema(SchemaBuilder builder)

Defines the schema of the datasource. The script is expected to call the column(...) method on the builder.

Returns: The data receiver which can be used to produce new rows.

Example:

def receiver = dataSource.defineSchema {
  column("ID", ColumnType.Number, Multiplicity.Single)
  column("Name", ColumnType.Text, Multiplicity.Single)
  column("EndOfLife", ColumnType.Date, Multiplicity.Single)
  column("IsVirtualized", ColumnType.Boolean, Multiplicity.Single)
} 

SchemaBuilder

column

Signature: void column(String name, ColumnType type, Multiplicity multiplicity)

Defines one column in the schema. Can only be used within a dataSource.defineSchema { } context.

Parameters:

  • name — The name of the column.
  • type — The type of the column. The following values exist for ColumnType: - ColumnType.Text for textual values - ColumnType.Number for numeric values (can be integer or floating point values) - ColumnType.Date for date/time values - ColumnType.Boolean for boolean (true/false) values

Example:

def receiver = dataSource.defineSchema {
  column("ID", ColumnType.Number, Multiplicity.Single)
  column("Name", ColumnType.Text, Multiplicity.Single)
  column("EndOfLife", ColumnType.Date, Multiplicity.Single)
  column("IsVirtualized", ColumnType.Boolean, Multiplicity.Single)
} 

addAllODataSchemaColumns

Signature: void addAllODataSchemaColumns(ODataClient client, String serviceURL, String className)

Auto fetch the metadata model of a certain class from the given service url. Can only be used within a dataSource.defineSchema { } context.

Parameters:

  • client — The exposed OData client.
  • serviceURL — The root url of the OData service.
  • className — Only fetch the schema from given className e.g. "Machine", "Person".

Example:

def receiver = dataSource.declareSchema {
  addAllODataSchemaColumns(client, "https://example.org", "Machine")
}

addAllODataSchemaColumns

Signature: void addAllODataSchemaColumns(ODataClient client, String serviceURL)

Auto fetch the metadata model from the given service url. Can only be used within a dataSource.defineSchema { } context.

Parameters:

  • client — The exposed OData client.
  • serviceURL — The root url of the OData service.

Example:

def receiver = dataSource.declareSchema {
  addAllODataSchemaColumns(client, "https://example.org")
}

Data Receiver

The receiver object is returned by dataSource.defineSchema{ ... } after the schema has been built. It and can be used to define rows of data. Those rows must follow the defined schema, and define the raw data which is then picked up by a Txture importer.

receiver.addRow

Signature: Row DataReceiver.addRow()

Adds a new row to the result which can then be consumed by the Txture importer. The new row is initially empty. Use row.setString(...), row.setNumber(...) etc. to fill it with data.

Returns: The new, empty Data Row.

Example:

def row = receiver.addRow()
row.setString("ID", "my-id-1234")

mapODataEntityToRow

Signature: void mapODataEntityToRow(ClientEntity entity, ImportObjectRow row)

Maps the whole ClientEntity to an empty row, respecting the defined schema. Properties that are not defined in the schema are omitted.

Parameters:

  • entity — The single client entity retrieved from OData service.
  • row — The new empty row from DataReceiver.

Example:

def entities = responseBody.entities
for (entity in entities) {
  def row = receiver.addRow()
  mapODataEntityToRow(entity, row)
}

Data Row

A row is a collection of key-value-pairs that match the schema defined in this datasource. Rows are created by the Data Receiver using addRow().

row.setString

Signature: void DataRow.setString(String column, String text)

Sets the value of the given column to the given text in this row.

Parameters:

  • The name of the column to assign. Must be one of the columns defined in the schema.
  • The text value to assign to the column on this row.

Example:

def row = receiver.addRow()
row.setString("Name", "")

row.setStrings

Signature: void DataRow.setStrings(String columnName, String... strings)

Sets multiple string values for the given columnName in this row.

Parameters:

  • columnName — The name of the column to assign. Must be one of the columns defined in the schema.
  • strings — An array of string values to assign to the column on this row.

Example:

def row = receiver.addRow()
row.setStrings("Tags", "tag1", "tag2", "tag3")

row.setStrings

Signature: void DataRow.setStrings(String columnName, Iterable<String> strings)

Sets multiple string values for the given columnName in this row using an iterable of strings.

Parameters:

  • columnName — The name of the column to assign. Must be one of the columns defined in the schema.
  • strings — An iterable of string values to assign to the column on this row.

Example:

def row = receiver.addRow()
def tagList = ["tag1", "tag2", "tag3"]
row.setStrings("Tags", tagList)


#### `row.setNumber`

**Signature:** `void DataRow.setNumber(String column, Number number)`

Sets the value of the given `column` to the given `number` in this row.

**Parameters:**
- The name of the column to assign. Must be one of the columns defined in the schema.
- The numeric value to assign to the column on this row. Can be an integer or a floating point value.

**Example:**

```groovy
def row = receiver.addRow()
row.setNumber("AccountNumber", 112233)

row.setNumbers

Signature: void DataRow.setNumbers(String columnName, Number... numbers)

Sets multiple number values for the given columnName in this row.

Parameters:

  • columnName — The name of the column to assign. Must be one of the columns defined in the schema.
  • numbers — An array of number values to assign to the column on this row.

Example:

def row = receiver.addRow()
row.setNumbers("Values", 1, 2, 3, 4, 5)

row.setNumbers

Signature: void DataRow.setNumbers(String columnName, Iterable<Number> numbers)

Sets multiple number values for the given columnName in this row using an iterable of numbers.

Parameters:

  • columnName — The name of the column to assign. Must be one of the columns defined in the schema.
  • numbers — An iterable of number values to assign to the column on this row.

Example:

def row = receiver.addRow()
def numberList = [1, 2, 3, 4, 5]
row.setNumbers("Values", numberList)

row.setDate

Signature: void DataRow.setDate(String column, Date date)

Sets the value of the given column to the given date in this row.

Parameters:

  • The name of the column to assign. Must be one of the columns defined in the schema.
  • The numeric value to assign to the column on this row.

Example:

def row = receiver.addRow()
row.setNumber("AccountNumber", new SimpleDateFormat("yyyy-MM-dd").parse("2020-09-18"))

row.setDates

Signature: void DataRow.setDates(String columnName, Date... dates)

Sets multiple date values for the given columnName in this row.

Parameters:

  • columnName — The name of the column to assign. Must be one of the columns defined in the schema.
  • dates — An array of date values to assign to the column on this row.

Example:

def row = receiver.addRow()
def date1 = new Date()
def date2 = new Date()
def date3 = new Date()
row.setDates("EventDates", date1, date2, date3)

row.setDates

Signature: void DataRow.setDates(String columnName, Iterable<Date> dates)

Sets multiple date values for the given columnName in this row using an iterable of dates.

Parameters:

  • columnName — The name of the column to assign. Must be one of the columns defined in the schema.
  • dates — An iterable of date values to assign to the column on this row.

Example:

def row = receiver.addRow()
def dateList = [new Date(), new Date(), new Date()]
row.setDates("EventDates", dateList)

row.setBoolean

Signature: void DataRow.setBoolean(String column, Boolean bool)

Sets the value of the given column to the given bool in this row.

Parameters:

  • The name of the column to assign. Must be one of the columns defined in the schema.
  • The boolean value to assign to the column on this row.

Example:

def row = receiver.addRow()
row.setBoolean("IsVirtualized", true)

row.setBooleans

Signature: void DataRow.setBooleans(String columnName, Boolean... booleans)

Sets multiple boolean values for the given columnName in this row.

Parameters:

  • columnName — The name of the column to assign. Must be one of the columns defined in the schema.
  • booleans — An array of boolean values to assign to the column on this row.

Example:

def row = receiver.addRow()
row.setBooleans("IsAdmin", true, false, true)

row.setBooleans

Signature: void DataRow.setBooleans(String columnName, Iterable<Boolean> booleans)

Sets multiple boolean values for the given columnName in this row using an iterable of booleans.

Parameters:

  • columnName — The name of the column to assign. Must be one of the columns defined in the schema.
  • booleans — An iterable of boolean values to assign to the column on this row.

Example:

def row = receiver.addRow()
def booleanList = [true, false, true]
row.setBooleans("IsAdmin", booleanList)

row.setRange

Signature: void DataRow.setRange(String column, Range range)

Sets the value of the given column to the given range in this row.

Parameters:

  • The name of the column to assign. Must be one of the columns defined in the schema.
  • The range value to assign to the column on this row.

Example:

def row = receiver.addRow()
row.setNumber("WorkingHours", Range.createRange(8.00, 17.00))

row.setRanges

Signature: void DataRow.setRanges(String columnName, Range... ranges)

Sets multiple range values for the given columnName in this row.

Parameters:

  • columnName — The name of the column to assign. Must be one of the columns defined in the schema.
  • ranges — An array of range values to assign to the column on this row.

Example:

def row = receiver.addRow()
def range1 = new Range(1, 10)
def range2 = new Range(20, 30)
def range3 = new Range(50, 60)
row.setRanges("ValueRanges", range1, range2, range3)

row.setRanges

Signature: void DataRow.setRanges(String columnName, Iterable<Range> ranges)

Sets multiple range values for the given columnName in this row using an iterable of ranges.

Parameters:

  • columnName — The name of the column to assign. Must be one of the columns defined in the schema.
  • ranges — An iterable of range values to assign to the column on this row.

Example:

def row = receiver.addRow()
def rangeList = [new Range(1, 10), new Range(20, 30), new Range(50, 60)]
row.setRanges("ValueRanges", rangeList)

Request Builder

The request builder provides useful utilities for accessing external data sources. It is passed to the script as a global variable named request.

request.http

Signature: HttpResponse RequestBuilder.http(HttpRequest)

Performs a HTTP request. The details of the request are given in curly brackets { }.

Parameters:

  • builder — The request builder. You can configure this object between the curly brackets.

Returns: The result of the HTTP call.

Example:

def response = request.http {
    method = HttpMethod.GET
    url = "http://www.example.org"
    headers {
    contentType("text/plain")
    }
}

request.file

Signature: FileResponse RequestBuilder.file(FileRequest)

Requests a file from the server's local hard drive. The details of the request are given in curly brackets { }.

Parameters:

  • builder — The request builder. You can configure this object between the curly brackets.

Returns: The result of the file lookup.

Example:

def response = request.file {
    path = "/home/john-doe/Documents/my-file.json"
}

request.odata

Signature: ODataClient RequestBuilder.odata(ODataRequest)

Creates an OData client with specified authentication. The details of the request are given in curly brackets { }.

Parameters:

  • builder — The request builder. You can configure this object between the curly brackets.

Returns: The exposed OData client.

Example:

def client = request.odata {
    auth {
    basic("admin","password")
    }
}

HTTP Request Builder

The HTTP request builder configures a single HTTP request. A new request builder can be created via request.http { ... }.

url

Signature: HttpRequestBuilder.url = String

Sets the URL to call. For dynamic URLs, we recommend using template strings (e.g. for a dynamic port, use def myPort = ... and then url = "https://myhost:${myPort}"). Please note that no additional URL encoding is performed; the given string is used as-is.

Parameters:

  • value — The new value for the request URL as a String.

Example:

def response = request.http {
    url = "http://www.example.org"
}

method

Signature: HttpRequestBuilder.method = HttpMethod

Sets the HTTP method to use for the request.

Parameters:

  • value — The method to use. The available values are: - HttpMethod.POST - HttpMethod.PUT - HttpMethod.GET - HttpMethod.PATCH - HttpMethod.DELETE - HttpMethod.HEAD - HttpMethod.OPTIONS - HttpMethod.TRACE

Example:

def response = request.http {
    url = "http://www.example.org"
    method = HttpMethod.GET
}

body

Signature: HttpRequestBuilder.body = String

Sets the body for the HTTP call as a String.

Parameters:

  • value — The body to use. Please note that you can use Groovy Multi-Line strings (denoted by """ """) if you need to create a mult-line body.

Example:

def response = request.http {
    url = "http://www.example.org"
    method = HttpMethod.POST
    body = """
      {
        "name": "John Doe"
      }
    """
}

readTimeoutSeconds

Signature: HttpRequestBuilder.readTimeoutSeconds = int

Sets the read timeout for the request (in seconds) as an integer value.

A read timeout is applied from the moment the connection between a client and a target host has been successfully established. It defines a maximum time of inactivity between two data packets when waiting for the server's response.

The default value is 300 seconds (equals 5 minutes).

Parameters:

  • value — The value to assign to the read timeout.

Example:

def response = request.http {
    url = "http://www.example.org"
    method = HttpMethod.GET
    readTimeoutSeconds = 60
}

connectTimeoutSeconds

Signature: HttpRequestBuilder.connectTimeoutSeconds = int

Sets the connect timeout for the request (in seconds) as an integer value.

A connect timeout defines a time period in which our client should establish a connection with a target host.

The default value is 10 seconds.

Parameters:

  • value — The value to assign to the connect timeout.

Example:

def response = request.http {
    url = "http://www.example.org"
    method = HttpMethod.GET
    connectTimeoutSeconds = 20
}

callTimeoutSeconds

Signature: HttpRequestBuilder.callTimeoutSeconds = int

Sets the call timeout for the request (in seconds) as an integer value.

It defines a time limit for a complete HTTP call. This includes resolving DNS, connecting, writing the request body, server processing, as well as reading the response body.

The default value is 300 seconds (equals 5 minutes).

Parameters:

  • value — The value to assign to the call timeout.

Example:

def response = request.http {
    url = "http://www.example.org"
    method = HttpMethod.GET
    callTimeoutSeconds = 90
}

headers

Signature: HttpRequestBuilder.headers(HttpRequestHeaderBuilder builder)

Sets the headers for the HTTP request. This is a builder, so use curly braces { } to configure it.

Parameters:

  • builder — The builder for the request parameters. Configure it between the curly braces { }.

Example:

def response = request.http {
    url = "http://www.example.org"
    method = HttpMethod.GET
    headers {
    contentType("text/plain")
    }
}

HTTP Request Header Builder

Allows to set various HTTP headers. For standard headers, a setter method named after the header is available (e.g. authorization(String)). For non-standard headers, please use the custom(String, String) method.

The signature of all predefined setters is the same and is not repeated here.

authorization

Signature: HttpHeaderBuilder.authorization(String value)

Sets the standard HTTP authorization header to the given value.

The predefined header setters are:

  • accept(String value)
  • acceptCharset(String value)
  • acceptEncoding(String value)
  • acceptLanguage(String value)
  • acceptRanges(String value)
  • accessControlAllowCredentials(String value)
  • accessControlAllowHeaders(String value)
  • accessControlAllowMethods(String value)
  • accessControlAllowOrigin(String value)
  • accessControlExposeHeaders(String value)
  • accessControlMaxAge(String value)
  • accessControlRequestHeaders(String value)
  • accessControlRequestMethod(String value)
  • age(String value)
  • allow(String value)
  • authorization(String value)
  • cacheControl(String value)
  • connection(String value)
  • contentEncoding(String value)
  • contentDisposition(String value)
  • contentLanguage(String value)
  • contentLength(String value)
  • contentLocation(String value)
  • contentRange(String value)
  • contentType(String value)
  • cookie(String value)
  • date(String value)
  • etag(String value)
  • expect(String value)
  • expires(String value)
  • from(String value)
  • host(String value)
  • ifMatch(String value)
  • ifModifiedSince(String value)
  • ifNoneMatch(String value)
  • ifRange(String value)
  • ifUnmodifiedSince(String value)
  • lastModified(String value)
  • link(String value)
  • location(String value)
  • maxForwards(String value)
  • origin(String value)
  • pragma(String value)
  • proxyAuthenticate(String value)
  • proxyAuthorization(String value)
  • range(String value)
  • referer(String value)
  • retryAfter(String value)
  • server(String value)
  • setCookie(String value)
  • setCookie2(String value)
  • te(String value)
  • trailer(String value)
  • transferEncoding(String value)
  • upgrade(String value)
  • userAgent(String value)
  • vary(String value)
  • via(String value)
  • warning(String value)
  • wwwAuthenticate(String value)

Parameters:

  • value — The value to assign to the authorization header.

Example:

def response = request.http {
    url = "http://www.example.org"
    method = HttpMethod.GET
    headers {
    contentType("text/plain")
    }
}

custom

Signature: HttpHeaderBuilder.custom(String headerName, String value)

Sets the given custom headerName to the given value. If desired, standard header names can also be used. For example, the following is valid:

headers {
    custom("content-type", "application/json")
}

... and fully equivalent to:

headers {
    contentType("application/json")
}

Parameters:

  • headerName — The name of the header to set.
  • value — The value to assign to the custom header.

Example:

def response = request.http {
    url = "http://www.example.org"
    method = HttpMethod.GET
    headers {
    custom("my-header", "a value for the header")
    }
}

HTTP Response

The HTTP Response is the object returned by request.http { ... }. It contains the actual response, but also the HTTP status code as well as other auxilliary information.

statusCode

Signature: HttpResponse.statusCode

Returns the status code of the HTTP response. Notable codes include:

  • 200 (OK)
  • 400 (Bad Request)
  • 401 (Unauthorized)
  • 403 (Forbidden)
  • 404 (Not found)
  • 500 (Internal Server Error)

Please see the Mozilla Wiki for a full list of error codes and their descriptions.

Returns: The HTTP reponse status code, as an integer.

Example:

def response = request.http {
    url = "http://www.example.org"
    method = HttpMethod.GET
}

if(response.statusCode != 200){
    return fail("Request failed")
}

statusCode

Signature: HttpResponse.message

Returns the message of the HTTP response. This is mostly used for error reporting in cases where the response code is something other than 200. This is not the response body.

Returns: The message of the HTTP response, as a string.

Example:

def response = request.http {
    url = "http://www.example.org"
    method = HttpMethod.GET
}

log.debug("Response message: " + response.message)

statusCode

Signature: HttpResponse.bodyText

Returns the response body as UTF-8 text. Depending on the requested endpoint, this value may be in JSON format, XML format, HTML or any other plain-text format. Please consult the documentation of the requested endpoint for details.

Returns: The body of the HTTP response, as a UTF-8 string.

Example:

def response = request.http {
    url = "http://www.example.org"
    method = HttpMethod.GET
}

// let's assume we get a JSON array back
def array = parseJsonArray(response.bodyText)

statusCode

Signature: HttpResponse.bodyBytes

Returns the response body as a raw byte array. This is useful in cases where the response of the external system is not delivered as plain text (e.g. when downoading a file).

Returns: The raw byte array that represents the HTTP response body.

Example:

def response = request.http {
    url = "http://www.example.org"
    method = HttpMethod.GET
}

def bytes = response.bodyBytes

headers

Signature: HttpResponse.headers

Returns the response headers object. To access an individual header, please use response.headers.getFirst("my-header") to retrieve the assigned string value. As a single header in HTTP can have multiple values assigned to it, you can also get all of the assigned values as a list of strings by using response.headers.getAll("my-header") instead.

Returns: The headers object.

Example:

def response = request.http {
    url = "http://www.example.org"
    method = HttpMethod.GET
}

// retrieves the "content-type" header value as a string
def contentType = response.headers.getFirst("content-type")

// retrieves the "cache-control" headers as a list of strings
def cacheControls = response.headers.getAll("cache-control")

found

Signature: FileResponse.found

Checks if the requested file has been found on the file system.

Returns:true if the file has been found, otherwise false. If the file was a directory, or the file path was syntactically invalid, this method will also return false.

Example:

def response = request.file {
    path = "/home/john-doe/Documents/my-file.json"
}

if(response.found){
    return fail("file not found!")
}

contentString

Signature: FileResponse.contentString

Reads the contents of the requested file as a String (using UTF-8 encoding).

Returns: The contents of the file as String. If response.found is false, the empty String is returned.

Example:

    def response = request.file {
    path = "/home/john-doe/Documents/my-file.json"
    }

    def jsonText = response.contentString
    ```

  #### `contentBytes`

**Signature:** `FileResponse.contentBytes`

Returns the contents of the requested file as a raw Byte Array.
  If your file is known to contain plain text data, the method
  `contentString` is usually preferable over raw byte processing.

**Returns:** The contents of the file as Byte Array. If `response.found` is `false`, the empty array is returned.

**Example:**

```groovy
    def response = request.file {
    path = "/home/john-doe/Documents/my-file.json"
    }

    def bytes = response.contentBytes
    ```

### OData Request Builder

#### `auth`

**Signature:** `void ODataRequest.auth(ODataAuth)`

Sets the Authorization for accessing the OData service.

**Example:**

```groovy
    def client = request.odata {
    auth {
      none()
    }
    }
    ```

  ### OData Auth Builder

  #### `none`

**Signature:** `void ODataAuth.none()`

No Authorization given for accessing the OData service.

**Example:**

```groovy
    def client = request.odata {
    auth {
      none()
    }
    }
    ```

#### `basic`

**Signature:** `void ODataAuth.basic(String username, String password)`

Basic Authorization given for accessing the OData service.

**Parameters:**
- `username` — The username for basic authorization.
- `password` — The password for basic authorization.

**Example:**

```groovy
    def client = request.odata {
    auth {
      basic("admin", "password")
    }
    }
    ```

#### `ntlm`

**Signature:** `void ODataAuth.ntlm(String username, String password, String workstation, String domain)`

NTLM Authorization given for accessing the OData service.

**Parameters:**
- `username` — The username for NTLM authorization.
- `password` — The password for NTLM authorization.
- `workstation` — The workstation for NTLM authorization.
- `domain` — The domain for NTLM authorization.

**Example:**

```groovy
    def client = request.odata {
    auth {
      ntlm("admin", "password", "test", "example.org")
    }
    }
    ```

### ImportResult

The `ImportResult` class is the result of a
standard importer request. It provides uniform access
to the returned data.


#### `ImportResult.objects`

**Signature:** `List<UserScriptImportObject> objects`

Retrieves the objects retrieved by the import as a list.

**Returns:** The list of retrieved objects. May be empty.

**Example:**

```groovy
    def importResult = request.importer....
  
    for(def obj : importResult.objects){
     // ... analyze/process "obj" here ...
    }
    ```

#### `ImportResult.schema`

**Signature:** `UserScriptImportSchema schema`

Retrieves the schema of the retrieved objects and grants access to the property names.

**Returns:** The schema of the retrieved objects.

**Example:**

```groovy
    def importResult = request.importer....
  
    for(def propertyName : importResult.schema.propertyNames){
     // use the propertyName
    }
    ```

#### `UserScriptImportObject.getString`

**Signature:** `String getString(String property)`

Extracts the value of the given property from this object.

**Parameters:**
- `property` — The name of the property to retrieve, as a `String`.

**Returns:** The value of the given property as a `String`. Value conversion will be attempted accordingly (e.g. if the actual value is a number, it will automatically be converted into a `String`). If there is no property with the given name, `null` will be returned instead.

**Example:**

```groovy
    def importResult = request.importer....
  
    for(def obj : importResult.objects){
    // assuming that the returned objects have a "Name" property,
    // we can extract it like this:
    def name = obj.getString("Name")   
    }
    ```

#### `UserScriptImportObject.getStrings`

**Signature:** `List<String> getStrings(String property)`

Extracts the value of the given property from this object.

**Parameters:**
- `property` — The name of the property to retrieve, as a `String`.

**Returns:** The value of the given property as a `List<String>`. Value conversion will be attempted accordingly (e.g. if the actual value is single-valued, it will be wrapped in a singleton list). If there is no property with the given name, the empty list will be returned instead.

**Example:**

```groovy
    def importResult = request.importer....
  
    for(def obj : importResult.objects){
    // assuming that the returned objects have a "phoneNumbers" property,
    // we can extract it like this:
    def phoneNumbers = obj.getString("phoneNumbers")
    for(def phoneNumber : phoneNumbers){
      // ... do something with the phoneNumber
    }  
    }
    ```






#### `UserScriptImportObject.getNumber`

**Signature:** `String getNumber(String property)`

Extracts the value of the given property from this object.

**Parameters:**
- `property` — The name of the property to retrieve, as a `Double`.

**Returns:** The value of the given property as a `Double`. Value conversion will be attempted accordingly (e.g. if the actual value is a `String`, it will automatically be parsed into a `Double`). If there is no property with the given name, `null` will be returned instead.

**Example:**

```groovy
    def importResult = request.importer....
  
    for(def obj : importResult.objects){
    // assuming that the returned objects have a "cpuCores" property,
    // we can extract it like this:
    def cpuCores = obj.getNumber("cpuCores")   
    }
    ```

#### `UserScriptImportObject.getNumbers`

**Signature:** `List<String> getNumbers(String property)`

Extracts the value of the given property from this object.

**Parameters:**
- `property` — The name of the property to retrieve, as a `String`.

**Returns:** The value of the given property as a `List<Double>`. Value conversion will be attempted accordingly (e.g. if the actual value is single-valued, it will be wrapped in a singleton list). If there is no property with the given name, the empty list will be returned instead.

**Example:**

```groovy
    def importResult = request.importer....
  
    for(def obj : importResult.objects){
    // assuming that the returned objects have a "ports" property,
    // we can extract it like this:
    def ports = obj.getNumbers("ports")
    for(def port : ports){
      // ... do something with the port
    }  
    }
    ```






#### `UserScriptImportObject.getDate`

**Signature:** `Date getDate(String property)`

Extracts the value of the given property from this object.

**Parameters:**
- `property` — The name of the property to retrieve, as a `Date`.

**Returns:** The value of the given property as a `Date`. Value conversion will be attempted accordingly (e.g. if the actual value is a `String`, it will automatically be parsed into a `Date`). If there is no property with the given name, `null` will be returned instead.

**Example:**

```groovy
    def importResult = request.importer....
  
    for(def obj : importResult.objects){
    // assuming that the returned objects have a "goLiveDate" property,
    // we can extract it like this:
    def goLiveDate = obj.getNumber("goLiveDate")   
    }
    ```

#### `UserScriptImportObject.getDates`

**Signature:** `List<Date> getDates(String property)`

Extracts the value of the given property from this object.

**Parameters:**
- `property` — The name of the property to retrieve, as a `String`.

**Returns:** The value of the given property as a `List<Date>`. Value conversion will be attempted accordingly (e.g. if the actual value is single-valued, it will be wrapped in a singleton list). If there is no property with the given name, the empty list will be returned instead.

**Example:**

```groovy
    def importResult = request.importer....
  
    for(def obj : importResult.objects){
    // assuming that the returned objects have a "maintenanceDates" property,
    // we can extract it like this:
    def maintenanceDates = obj.getNumbers("maintenanceDates")
    for(def maintenanceDate : maintenanceDates){
      // ... do something with the maintenanceDate
    }  
    }
    ```






#### `UserScriptImportObject.getBoolean`

**Signature:** `Boolean getBoolean(String property)`

Extracts the value of the given property from this object.

**Parameters:**
- `property` — The name of the property to retrieve, as a `Boolean`.

**Returns:** The value of the given property as a `Boolean`. Value conversion will be attempted accordingly (e.g. if the actual value is a `String`, it will automatically be parsed into a `Boolean`). If there is no property with the given name, `null` will be returned instead.

**Example:**

```groovy
    def importResult = request.importer....
  
    for(def obj : importResult.objects){
    // assuming that the returned objects have a "isOnline" property,
    // we can extract it like this:
    def isOnline = obj.getBoolean("isOnline")   
    }
    ```

#### `UserScriptImportObject.getBooleans`

**Signature:** `List<Boolean> getBooleans(String property)`

Extracts the value of the given property from this object.

**Parameters:**
- `property` — The name of the property to retrieve, as a `String`.

**Returns:** The value of the given property as a `List<Boolean>`. Value conversion will be attempted accordingly (e.g. if the actual value is single-valued, it will be wrapped in a singleton list). If there is no property with the given name, the empty list will be returned instead.

**Example:**

```groovy
    def importResult = request.importer....
  
    for(def obj : importResult.objects){
    // assuming that the returned objects have a "flags" property,
    // we can extract it like this:
    def flags = obj.getBooleans("flags")
    for(def flag : flags){
      // ... do something with the flag
    }  
    }
    ```




#### `UserScriptImportObject.getRange`

**Signature:** `Range getRange(String property)`

Extracts the value of the given property from this object.

**Parameters:**
- `property` — The name of the property to retrieve, as a `Range`.

**Returns:** The value of the given property as a `Range`. Value conversion will be attempted accordingly (e.g. if the actual value is a `String`, it will automatically be parsed into a `Range`). If there is no property with the given name, `null` will be returned instead.

**Example:**

```groovy
    def importResult = request.importer....
  
    for(def obj : importResult.objects){
    // assuming that the returned objects have a "maintenanceWindow" property,
    // we can extract it like this:
    def maintenanceWindow = obj.getRange("maintenanceWindow")   
    def start = maintenanceWindow.lowerBound
    def end = maintenanceWindow.upperBound
    }
    ```

#### `UserScriptImportObject.getRanges`

**Signature:** `List<Range> getRanges(String property)`

Extracts the value of the given property from this object.

**Parameters:**
- `property` — The name of the property to retrieve, as a `String`.

**Returns:** The value of the given property as a `List<Range>`. Value conversion will be attempted accordingly (e.g. if the actual value is single-valued, it will be wrapped in a singleton list). If there is no property with the given name, the empty list will be returned instead.

**Example:**

```groovy
    def importResult = request.importer....
  
    for(def obj : importResult.objects){
    // assuming that the returned objects have a "maintenanceWindows" property,
    // we can extract it like this:
    def maintenanceWindows = obj.getBooleans("maintenanceWindows")
    for(def maintenanceWindow : maintenanceWindows){
      // ... do something with the maintenanceWindow
      def start = maintenanceWindow.lowerBound
      def end = maintenanceWindow.upperBound
    }  
    }
    ```




#### `UserScriptImportObject.getObject`

**Signature:** `Object getObject(String property)`

Extracts the value of the given property from this object without
  applying any type conversion. This method should be used as a fallback
  for cases where the other methods do not work as intended.

**Parameters:**
- `property` — The name of the property to retrieve, as a `Range`.

**Returns:** The value of the given property, with no type conversion applied to it. The raw object will be returned. The resulting object may be `null`, and will always be `null` if the given property does not exist on the object.

**Example:**

```groovy
    def importResult = request.importer....
  
    for(def obj : importResult.objects){
    // assuming that the returned objects have a "owner" property,
    // we can extract it like this:
    def owner = obj.getObject("owner")   
    // you will likely need to down-cast the object to the
    // expected type, e.g. (String)owner
    }
    ```

#### `UserScriptImportObject.getObjects`

**Signature:** `List<Object> getObjects(String property)`

Extracts the value of the given property from this object.

**Parameters:**
- `property` — The name of the property to retrieve, as a `String`.

**Returns:** The value of the given property as a `List<Object>`. Value conversion will be attempted accordingly (e.g. if the actual value is single-valued, it will be wrapped in a singleton list). If there is no property with the given name, the empty list will be returned instead.

**Example:**

```groovy
    def importResult = request.importer....
  
    for(def obj : importResult.objects){
    // assuming that the returned objects have a "neighbors" property,
    // we can extract it like this:
    def neighbors = obj.getObjects("neighbors")
    for(def neighbor : neighbors){
      // you will likely need to down-cast the object to the
      // expected type, e.g. (String)neighbor
    }  
    }
    ```


#### `UserScriptImportObject.toMap`

**Signature:** `Map<String, Object> toMap()`

Converts this object into a basic map object. The map will
  contain the property names as keys, and the corresponding
  property values as map values. No type conversion will be
  applied to the map values (also, no multiplicity conversion
  will be employed; the values will be inserted into the map
  as-is).

**Returns:** The object converted into a basic map.

**Example:**

```groovy
    def importResult = request.importer....
  
    for(def obj : importResult.objects){
    // convert the object into a basic map for maximum
    // flexibility. Please keep in mind that no type
    // conversion is applied in this case.
    def map = obj.toMap()
    for(def entry : map.entrySet()){
      // the key is the name of the property
      def key = entry.key
      // the value is the value assigned to the property
      def value = entry.value

    }
    }
    ```