Skip to main content

Propagation Rules

Txture's Change Propagation feature allows to define Propagation Rules (Main Menu / Admin / Propagation Rules). The Change Propagation is a powerful customization tool which allows you to propagate changes across your Assets and Links, performing arbitrary calculations along the way.

Change Propagation is useful for several applications:

  • Root-Cause Analysis: propagate online status upwards the deployment stack
  • Calculate metrics: cost aggregation, energy consumption aggregation...
  • Location propagation: if a server is deployed in a specific security zone, it propagates this information to the applications deployed on it
  • Custom validation: an Application is only valid if there is a deployment stack for it

For a concrete example use case, please see the Propagating Online Status Example

Basic principles

When any change occurs in the Txture dataset (e.g. an import execution, a manual change on an asset...), the Change Propagation triggers for the affected element(s). The Change Propagation also triggers if a new rule is created or an existing one is updated.

The figure above shows the basic principles of Change Propagation in Txture. Each circle represents an asset. The asset in the center (drawn in red) has been modified (e.g. by a manual change). This element acts as the "source" of the propagation mechanism. All other elements which have propagation dependencies to this asset (highlighted in orange, labeled with 1) will be re-evaluated. In case that an asset labeled with 1 changes due to the Change Propagation, the assets which have dependencies on it (highlighted in yellow and labeled with 2) will be re-evaluated. All other assets (highlighted in gray) will remain unchanged. A propagation dependency is a dependency alongside a link. Propagation dependencies can either go in the same direction as the link, or in the inverse direction.

The evaluation of propagation rules works recursively. If an affected asset is modified by the propagation process, it is considered as changed, thus it may affect further assets.

Change Propagation overrides all other changes

Change Propagation is a trigger mechanism which is executed after every change. This includes manual changes as well as changes by automations, such as Importers and Consolidations.

This also means that the value inferred by change propagation rules will always overwrite any other change (on the target property of a rule) before the asset is saved into the repository.

For example, let's assume that there is a numeric Cost property, and there is a rule to compute this cost. The Cost of My Application is currently inferred to be 500. If a user manually changes this value to 700, then change propagation will trigger, and override the Cost to be 500 again. The value 700 is never saved in the repository.

Propagation Dependencies

The figure above shows two examples for propagation dependencies. In Example 1, we want to infer the online status of a Virtual Machine. To do so, we depend on the online status of the Physical Machine on which it runs. We therefore have a dependency on an outgoing link. Conversely, in Example 2, in order to determine the health status of a Business Service, we depend on the health status of an Application which supports the Business Service in order to determine its own health.

The direction of propagation dependencies is configurable in the Administration user interface. Please note that propagation dependencies can only exist along an existing link. It is not possible to define a propagation dependency between two assets which are not connected by a link.

Propagation Rules

The third and final element of Change Propagation is the actual Rule Set. The rules define the behavior of the Change Propagation mechanism. In more detail, each Propagation Rule specifies:

  • The Asset Type to which it applies
  • The Property on the Asset which will receive the result of the rule evaluation
  • The Propagation Dependencies required to evaluate the rule
  • The Rule Script which specifies the evaluation details

Every rule will be applied to all instances of the Type it is attached to! This is also true for instances which are created after the rule was saved.

The figure above shows an example for a rule configuration. This rule is attached to a Business Process and assigns a value to the Migrated property. In order to calculate the Migrated value for any given Business Process, we depend on the Migration Status property of the Applications which are used by the Business Process. This information is inferred from the content of the Rule Script. This groovy script defines how the value for the output property is determined.

New in Txture 22: Automatic Dependency Inference

In Txture 21 and below, the dependencies of a rule needed to be declared explicitly by the user via a dropdown menu. This is no longer necessary, the dependencies are inferred from the rule script and are then displayed in the rule editor.

Rule Management

The Propagation Rule Manager can be found in the Txture Admin Area.

The rule manager lists all Propagation Rules which are currently configured in Txture. The main area (1) is a tree view which lists all rules. The top layer (by default) groups the rules by asset type. This view can also be grouped by output property via the "Group by" dropdown (2). Each group lists the number of rules it contains, as well as how many of them are currently enabled (3). If any of your rules have compile errors, they are also displayed here. All rules in a group can be enabled or disabled in bulk by using the buttons in the group header. The innermost panels each display an individual rule (4). If your rule has a description assigned, it is also shown here. This area allows you to enable or disable the rule, to delete it and to edit it in the Rule Editor.

Finally, there are two Add buttons for creating new rules. The global Add button at the very top will ask you for an Asset Type as well as an output Property. By using the Add button found within each group, either the Asset Type (if your view is grouped by Asset Type) or the output Property (if grouped by Property) is inferred automatically from context.

One Rule per Asset Type and Output Property

For each Asset Type and Output Property, you can only define one Propagation Rule. The rule manager will not permit adding multiple rules with the same Asset Type and Output Property.

Rule Editor

The rule editor allows you to create, edit, debug and test Propagation Rules. The header shows the Asset Type as well as the output Property of the current rule (1). A rule description can be added in this section as well. Below is the actual Rule Script editor (2). The code entered in this area is automatically compiled by Txture, and any errors are shown in-line. If your code compiled successfully, a green checkmark is displayed below the text area. The next section lists the dependencies of your script (4). The final section allows you to perform a test run of the rule on a selected asset.

Rule Scripts

Txture's Change Propagation is based on Rule Scripts. Scripts are written in  Groovy and use the Txture API (more details below).

Statically Typed Groovy

Rule Scripts use the Groovy scripting language. However, in order to ensure a basic safety net that the rule will work as intended, the rules will be compiled with a static typechecker which will point out any errors such as misspelled names or non-existing properties. This also entails that dynamic features of the Groovy language cannot be used.

When configuring the Script Rules, you have the full Groovy ecosystem available. However, all Rule Scripts must be pure functions in the mathematical sense. This means:

  • A Rule Script must not contain any internal state.
    • You must not define static variables
    • You must not define or access member variables
  • A Rule Script must not modify any external state.
    • You must not modify any variables outside the scope of the Rule Script itself
    • You must not make calls to external services (e.g. REST services, XML web services...)
    • You must not halt the executing thread (e.g. via Thread.sleep(), waiting for locks or other methods)
    • You must not attempt to stop any concurrent thread, and in particular you must not shut down the executing process
  • A Rule Script must not depend on any data, except for the specified links and properties.
    • You must not make calls to external services (e.g. REST services, XML web services...)
    • You must not access any file on the hard drive
    • You must not access the network
    • You must not ask for user input (via command line or otherwise)
    • You must not access any functions on the operating system level
    • You must not make use of Reflection and related technologies
  • A Rule Script must be idempotent, i.e. it must deliver the same output for the same input.
    • You must not use algorithms based on random numbers
    • You must not use algorithms based on system time

Txture will invoke the Rule Script bodies as needed, which may entail several hundred or even thousand calls per propagation evaluation. The execution order of Rule Scripts is (intentionally) not defined. Rule Scripts will be executed until further runs produce no more changes.

The value which is returned by the Rule Script body will be assigned to the output property. Therefore, the type of the returned value has to be compatible with the Property Type of the output Property (for example, if the output Property has Property Type Number, then the Rule Script must ensure to return a numeric value).

Txture Transactions & Change Propagation

Change Propagation is a step embedded in the Txture transaction protocol, as shown in the image above. Please consider the following facts carefully:

  • Change Propagation is triggered after all regular changes have been submitted. If a property value of a given asset has been changed from a to b and then back to a again (within the same transaction), a Propagation Rule will never witness the value b.

  • Change Propagation may access metadata such as the lastModifiedDate of an asset, a link, or an individual property value. However, as illustrated in the image above, the trigger which updates the lastModifiedDates occurs after the Change Propagation. So the lastModifiedDates observed by a Propagation Rule will be the previous change date, not the current one.

Change Propagation and the Last Modified Date

While it is technically possible to create a Propagation Rule which operates on the lastModifiedDate of an asset, link or property value, it usually doesn't produce the expected outcome. The use of lastModifiedDate within a Propagation Rule is therefore strongly discouraged.

Debugging Rule Scripts

New in Txture 22

Debugging facilities for Propagation Rules are available since Txture 22.

Rule Scripts can be tested against an Asset of your choice. Select the desired Asset in the Rule Editor to execute the rule against it. It is important to note that the Asset will not be modified by this process; any changes to the output Property value which would normally be performed by the rule will instead be discarded during a test run.

After performing a test run, the rule editor shows the Execution Result (which would become the new property value for the tested Asset) as well as the Logs produced by the execution. We encourage you to make use of this feature extensively to make sure your rules behave as intended.

In order to produce Logs, you can use one of two methods in your rule script:

  • log.debug(message) will log the message object to the log output. Please note that the message can be anything and does not need to be a string. Log messages produced by log.debug will be visible only in the rule editor.
  • log.info(message) behaves in a similar fashion as log.debug, except that log statemets produced by log.info will (in addition to the rule editor log ouptut) also show up in your change propagation log files when the rule script is actually executed. This can be useful for field testing and debugging, but should be used with care as rules are potentially executed very often, leading to a large number of log statements. In general, prefer log.debug(message).

Scripting API

Txture provides a Scripting API for easy interoperability with the Txture assets. A global variable named asset is accessible in every Rule Script. It always refers to the current asset for which the script is being evaluated. Users with prior programming experience may think of this variable as the this reference in a Rule Script. Starting from the asset, you can specify a path to any of the specified dependencies.

Code Names

At several points in the Scripting API, you can refer to Link targets or Property values by specifying an identifier. This identifier is the code name. The following table provides an overview of how code names are inferred from plain names.

Plain Property or Link NameCode NameComment on Code Name
Phone (Office)phoneOfficeWhitespaces, braces and special characters are eliminated in code names.
E-MaileMailPlus, minus and other related characters are also eliminated in code names.
EMailEMailMultiple successive uppercase letters are retained (note that the property name uses no dash, but the two consecutive capital letters EM).
under_scoreunder_scoreThe underscore character is allowed and retained.
MobilemobileAll regular characters remain the same. Note that all properties start with a lower-case letter.
First namefirstNameThe first character in a Property or Link code name is always lower-cased (except for successive uppercase letters, see below). Whenever a character (including whitespace) is elminated, the next character is upper case.
B2Bb2BNumbers inside a name are allowed and are retained.
URLURLMultiple successive uppercase letters are retained.

Code names for Types follow the same rules, except that the first letter in a Type name is always a capital (upper-case) letter.

The following character groups are considered when determining the code name:

Character RangeTreatment
a-z, A-ZRetained
0-9 (at the start of a name)Invalid for all Txture Identifiers
0-9 (inside a name)Retained
äöüßÄÖÜRetained
_ (at the start of a name)Invalid for all Txture Identifiers
_ (inside a name)Retained
[]()<>.,:;-+#@&%/*!?§~|=^°Eliminated
WhitespaceEliminated, next character is upper-cased
All other charactersInvalid for all Txture Identifiers

Script Paths

Script Paths are provided by the Txture Scripting API. They allow you to easily access dependencies and their properties. All Script Paths start with the asset variable. All Script Paths exhibit one of the following structures:

  • Querying the Property values of the Assets itself
    • asset.props.<property name>.<conditional expression>
  • Querying the Property values of neighboring Assets
    • asset.links.<in / out>.<Link Name>.<Type Name>.props.<conditional expression>

Placeholders are written in italic. The available conditional expressions depend on the multiplicity of links and properties, as well as the Property Type used before in the path. For more information, please see the section on Conditional Expressions in Script Paths.

Propagation Rules can only depend on the Properties of an asset, or on Properties of its immediate neighbors. It is not possible to depend on assets (or their Properties) which are not directly linked to the current asset.

Terminology: asset vs. entity

In Txture versions 14 and earlier, Change Propagation scripts used the keyword entity to reference the current object. Since Txture 15, we use the new keyword asset (in alignment with our terminology). The old keyword entity still works as intended to preserve backwards compatibility; new scripts should be written using asset.

asset.props
OwnProperties asset.props
Example
asset.props.firstName

Returns an accessor to the properties of the current asset. From here, use a property code name (or a quoted identifier). Please note that you must declare required own properties as dependencies. Otherwise, a compile error will occur.

Parameters:

No Parameters

Returns:

The own properties of the asset, limited to the ones specified in the rule.

asset.links
OwnReferences asset.links
Example
// restricts to the outgoing "runsOn" links
asset.links.out.runsOn
// restricts to the incoming "hosts" links
asset.links.in.hosts

Returns an accessor to the links of the current asset. From there, you can constrain the set of links by using asset.links.in or asset.links.out to only the incoming or only the outgoing references, respectively.

Parameters:

No Parameters

Returns:

The own references of the asset, limited to the ones specified in the rule. This includes both incoming and outgoing references; they can be filtered afterwards (see example).

asset.links.in
IncomingReferences asset.links.in
Example
// restricts to the "runsOn" link incoming from "VirtualMachine"
asset.links.in.runsOn.VirtualMachine
// restricts to the incoming "runs on" link, regardless of opposite Type
asset.links.in.runsOn

Returns an accessor to the incoming links of an asset. From there, you can specify a link name, and optionally restrict to a Type.

Parameters:

No Parameters

Returns:

An accessor to the incoming links of an asset.

asset.links.out
OutgoingReferences asset.links.out
Example
// restricts to the "runsOn" links which lead to an instance of "VirtualMachine"
asset.links.out.runsOn.VirtualMachine
// restricts to the "runsOn" links, regardless of the opposite Type
asset.links.out.runsOn

Returns an accessor to the outgoing links of an asset. From there, you can restrict by Type, or specify a link name.

Parameters:

No Parameters

Returns:

An accessor to the outgoing links of an asset.

links.props
NeighborProperties links.props
Example
// accesses the collection of "status" properties on all entities which are reachable via the outgoing "runsOn" link
asset.links.out.runsOn.props.status
// accesses the collection of "cost" properties on all entities of type Service which are reachable via the incoming "depends on" link
asset.links.in.dependsOn.Service.props.cost

Returns an accessor to the properties of the current asset collection. Note that this collection will be multiplicity-many, even if the property is multiplicity-one, if the preceding link is multiplicity-many.

Parameters:

No Parameters

Returns:

An accessor to the properties of the asset collection.

links.linkProps
LinkProperties links.linkProps
Example
// accesses the collection of "port" Properties on all assets which are reachable via the outgoing "runsOn" link
asset.links.out.runsOn.linkProps.port
// accesses the collection of "protocol" Properties on all assets of type Service which are reachable via the incoming "depends on" link
asset.links.in.communicatesWith.Service.linkProps.protocol

Returns an accessor to the Link Properties of the current Link collection. Note that this collection will be multiplicity-many, even if the Property is multiplicity-one, if the preceding Link is multiplicity-many.

Parameters:

No Parameters

Returns:

An accessor to the properties of the asset collection.

Conditional Expressions in Script Paths

In order to allow for easy querying of the asset and its neighbors, both OwnProperties and NeighborProperties offer a variety of helper methods. Which methods are available depend on three factors:

  • The Property Type (Text, Number, Boolean) of the selected Property
  • The Multiplicity (single-valued or multi-valued) of the selected **Property **
  • The Multiplicity (single-valued or multi-valued) of traversed Links in the path

For example, if runsOn is a multiplicity-one Link, and the Property status is a multiplicity-one Text property, then the path

asset.links.out.runsOn.props.status

... will offer all conditional methods for single-valued Text Properties. However, if runsOn is a multiplicity-many Link, the same path expression will offer conditional methods for multiplicity-many Text Properties. Note that multiplicity-one Properties are also treated as multiplicity-many if there are multiple Links with the same name and no target Type restriction is specified. For example, if there are two multiplicity-one Links named runsOn which lead to PhysicalMachine and VirtualMachine respectively, then the following path

asset.links.out.runsOn.props.status

... will offer multiplicity-many conditional methods (because asset.links.out.runsOn refers to the union of the PhysicalMachine and the VirtualMachine on which we run on), even though both runsOn and status are multiplicity-one. However, asset.links.out.runsOn.PhysicalMachine.props.status will be multiplicity-one.

The following flowchart summarizes the decision logic for property multiplicity:

Skipping Assets

It can sometimes be useful to instruct a rule not to touch a particular asset under certain circumstances.

asset.skip
<Nothing> asset.skip()

Skips the asset for this rule only. The rule engine will treat the asset as if the rule had been executed on it and produced no changes. This method should always be used in conjunction with the return keyword.

Example

if(asset.name == "Don't touch me"){
return asset.skip()
}

// proceed with regular rule code here

Parameters:

No Parameters

Returns:

Nothing. This method will always raise an internal exception which will be caught by the rule engine, causing the script execution to abort.

skip() will always cancel the rule execution

Internally, skip() will throw an exception which is caught and handled by the rule engine. This means that your rule will never continue to be executed after calling skip(). It is therefore our convention to write return skip() instead of just skip() to indicate to a human reader of the rule body that the control flow exits the rule here. The actual results of writing just skip() or return skip() are exactly the same.

It is also highly recommended to call return skip() exclusively within an if statement. A rule which unconditionally calls skip() in its body will never produce any results.

Use skip() sparingly

While return skip() can be very useful, please be tentative in its usage. Overuse of skip() in your rules makes it a lot harder to reason about your rules and find issues within the rule code, because in many cases it will not be clear if your rule produced the wrong output, or did not run in the first place due to a (potentially misplaced) skip().

In addition to the conditional expressions at the end of each script path, it is also possible to pre-filter the set of links by using the having(...) clause. The basic structure is as follows:

asset.links.<in/out>.<link name>.<type restriction>.<having clause>.<props/linkprops>.<conditional expression>

Having clauses can either operate on the Link Properties or on the Asset Properties (of the asset at the other end of the link) and are placed after the Type Restriction (or directly after the Link name if no Type Restriction is present). Consider the following example:

Example: Filtering Links using the having(...) clause

// check if all applications that run on this server on port 8080 are online
asset.links.in.runsOn.Application.having({ it.port.is(8080) }).props.status.all("online")

Please note that in the example above, we make use of a  Groovy Closure inside the having(...) clause. The closure is denoted via curly braces. By using the keyword it, we can access the current Link. All Properties of the Link are available for filtering. They make use of the same methods as Properties on Assets (see below).

If you do not restrict the target Type of the Link (e.g. just runsOn.having(...) instead of runsOn.Application.having(...)) and you have multiple Links of the same name adjacent to the Asset, then only the Link Properties which all Links of this name have in common will be accessible. If you cannot access a desired Link Property in a having(...) clause, try to restrict the Type.

In all other parts of a Script Path, the multiplicity of a Property depends on the multiplicity of the owning Link (i.e. a Property on a many-valued Link will be treated as many-valued, even though your Structure describes it as single-valued). Inside a having(...) clause, the Properties always have their original multiplicity (as stated in your Structure).

LinkCollection.having(closure)
LinkCollection linkCollection.having(closure: Closure<Link>)

Applies the given filter criterion on the links in the collection, and returns a new, filtered link collection. Inside the closure, use it to refer to the current link.

Parameters:

closureThe filter condition to apply to the link.

Returns:

A new collection of links, filtered by the given predicate.

Example: Filtering other-end assets using the havingAsset(...) clause

// aggregate the number of CPU cores of servers which are currently online
asset.links.in.belongsTo.havingAsset({ it.isOnline.is(true)}).props.cores.sum()

In this example, we filter the assets residing at the "other end" of the specified links. We explicitly avoid the terminology "source" and "target" here, because which end is the source and which is the target would depend on whether you use links.in or links.out. Instead, we use the more general term havingAsset to refer to the other end.

Just like with the regular having(...), we use a closure (denoted by { }), and inside we have access to the asset via it. Also, since this closure is evaluated on a per-asset basis, the available properties will have their original multiplicity (as stated in your Structure).

LinkCollection.havingAsset(closure)
LinkCollection linkCollection.havingAsset(closure: Closure<Asset>)

Filters the links in the collection by applying the given condition to the asset at the other end of the link. Please note that the result will still be another link collection, therefore chaining multiple having and havingAsset calls together is valid. Inside the closure, use it to refer to the asset at the other end of the current link.

Parameters:

closureThe filter condition to apply to the asset at the other end of the link

Returns:

A new collection of links, filtered by the given predicate on the other-end asset.

In addition to filters, some use cases require more control than simple filtering. For example, you might want to multiply two property values on one asset, and then sum them all up. For such cases, you can use the forEachAsset and forEachLink APIs.

LinkCollection.forEachAsset(closure)
void linkCollection.forEachAsset(closure: Closure<Asset>)
Example
def sum = 0
// iterate over all assets connected via an incoming "belongsTo" link
entity.links.in.belongsTo.forEachAsset({
// if it (i.e. the asset) has the property "isOnline" set to true...
if(it.isOnline.is(true)) {
// sum up its CPU cores (using 0 if no value is assigned)
sum += it.cpuCores.value(0)
}
})
return sum

Executes the given closure operation for each asset that resides on the other side of a link. It is noteworthy that this closure will be executed once per link. If you have two links in the collection with the same other-end asset, the closure will be executed twice for this asset.

Parameters:

closureThe operation to apply for each other-end asset.

Returns:

The forEachAsset method itself returns nothing (void). However, you may modify script variables within the closure, as shown in the example.

LinkCollection.forEachLink(closure)
void linkCollection.forEachLink(closure: Closure<Link>)
Example
def usedProtocols = new HashSet<String>()
// iterate over all outgoing "runsOn" links
entity.links.out.runsOn.forEachLink({
// look at the protocol of the current link (it)
def protocol = it.protocol.value(null)
// if a protocol is assigned...
if(protocol != null){
// ... add it to the set of protocols.
usedProtocols.add(protocol)
}
})
return protocols

Executes the given closure operation for each link in the collection.

Parameters:

closureThe operation to apply for each link.

Returns:

The forEachLink method itself returns nothing (void). However, you may modify script variables within the closure, as shown in the example.

Deprecation warning for 'LinkCollection.forEach'

The method LinkCollection.forEach has existed in Txture 24 and below. It is equivalent to the new LinkCollection.forEachLink. However, the name did not reveal if it iterates over links or assets. Therefore, we have deprecated this method. It is still available for use and will work as specified, but will be removed eventually. Please use the newer LinkCollection.forEachLink instead of LinkCollection.forEach.

Methods on Multiplicity-One Properties

General

The following methods are available on all multiplicity-one properties (regardless of the Property Type).

propertyValue.is(other)
boolean propertyValue.is(other: Object)
Example
// checks if the asset we run on has its status set to "online"
def isServerOnline = asset.links.out.runsOn.props.status.is("online")
// checks if the number of cores of the asset we run on is exactly 4
def has4Cores = asset.links.out.runsOn.props.cores.is(4)

Checks if the stored value is equal to the given one. Will return false if the given property is not set (unassigned).

Please always prefer using is over using the equality (==) operator, because it may perform implicit conversions (specific to Txture) which are not present in the general-purpose Groovy equality operator.

Parameters:

otherThe other object to compare with.

Returns:

true if the property value is equal to other, otherwise false.

propertyValue.isPresent()
boolean propertyValue.isPresent()
Example
// checks if our asset has a business contact assigned
def hasBusinessContact = asset.props.businessContact.isPresent()
// checks if the asset we run on has a responsible person assigned
def hasResponsiblePerson = asset.links.out.runsOn.props.responsible.isPresent()

Checks if any value for the property is set (i.e. checks if the property is assigned or not). Returns true if a value is assigned to the property, otherwise returns false.

Important: If isPresent() is used on a Property after following a Link, then isPresent() will also return false if that Link had no target.

Parameters:

No Parameters

Returns:

true if a property value is present, otherwise false.

Checking Metadata on Property Values

New in Txture 20

This functionality has been introduced as a new feature in Txture 20.

In addition to the actual property values, it can be useful to check the metadata of the property values, most notably:

  • What's the maintenance mode of property X?
  • When was the last time property X was modified?
  • When was the value for property X created?
propertyValue.isManuallyMaintained()
boolean propertyValue.isManuallyMaintained()
Example
// checks if the business contact has been assigned manually
def isBusinessContactManuallyMaintained = asset.props.businessContact.isManullyMaintained()
// checks if the "port" property on the "runsOn" link has been manually maintained.
// this works only if "runsOn" is single-valued.
def isRunsOnPortManuallyMaintained = asset.links.out.runsOn.linkProps.port.isManuallyMaintained()

Returns true if the last modification to the property value has been performed manually by a Txture user.

When used on a property returned by linkProps, then this method will be available if and only if the link in question is uniquely named and single-valued. For multi-valued links, containsManuallyMaintained() and allManuallyMaintained() are offered as an alternative.

Parameters:

No Parameters

Returns:

true if the last modification to the property value has been performed manually by a Txture user, otherwise false.

propertyValue.containsManuallyMaintained()
boolean propertyValue.containsManuallyMaintained()
Example
// checks if any of the "port" properties on the "runsOn" links have been manually maintained.
// this works only if "runsOn" is multi-valued, or there are multiple links named "runsOn"
// (e.g. runsOn VM, runsOn PhysicalServer).
def isAnyRunsOnPortManuallyMaintained = asset.links.out.runsOn.linkProps.port.containsManuallyMaintained()

Returns true if the last modification to any of the property values has been performed manually by a Txture user.

This method is only available on properties returned by linkProps when:

  • the link in question is multi-valued
  • OR the link is not uniquely named and there has been no type restriction on the link target.

Parameters:

No Parameters

Returns:

true if the last modification to any of the property values has been performed manually by a Txture user, otherwise false.

propertyValue.allManuallyMaintained()
boolean propertyValue.allManuallyMaintained()
Example
// checks if all of the "port" properties on the "runsOn" links have been manually maintained.
// this works only if "runsOn" is multi-valued, or there are multiple links named "runsOn"
// (e.g. runsOn VM, runsOn PhysicalServer).
def areAllRunsOnPortManuallyMaintained = asset.links.out.runsOn.linkProps.port.allManuallyMaintained()

Returns true if the last modification to all of the property values has been performed manually by a Txture user.

This method is only available on properties returned by linkProps when:

  • the link in question is multi-valued
  • OR the link is not uniquely named and there has been no type restriction on the link target.

Parameters:

No Parameters

Returns:

true if the last modification to all of the property values has been performed manually by a Txture user, otherwise false.

propertyValue.isImported()
boolean propertyValue.isImported()
Example
// checks if the business contact has been assigned by an importer
def isBusinessContactImported = asset.props.businessContact.isImported()
// checks if the "port" property on the "runsOn" link has been imported.
// this works only if "runsOn" is single-valued.
def isRunsOnPortImported = asset.links.out.runsOn.linkProps.port.isImported()

Returns true if the last modification to the property value has been performed manually by an Importer.

When used on a property returned by linkProps, then this method will be available if and only if the link in question is uniquely named and single-valued. For multi-valued links, containsImported() and allImported() are offered as an alternative.

Parameters:

No Parameters

Returns:

true if the last modification to the property value has been performed by an Importer, otherwise false.

propertyValue.containsImported()
boolean propertyValue.containsImported()
Example
// checks if any of the "port" properties on the "runsOn" links have been imported.
// this works only if "runsOn" is multi-valued, or there are multiple links named "runsOn"
// (e.g. runsOn VM, runsOn PhysicalServer).
def isAnyRunsOnPortImported = asset.links.out.runsOn.linkProps.port.containsImported()

Returns true if the last modification to any of the property values has been performed by an Importer.

This method is only available on properties returned by linkProps when:

  • the link in question is multi-valued
  • OR the link is not uniquely named and there has been no type restriction on the link target.

Parameters:

No Parameters

Returns:

true if the last modification to any of the property values has been performed by an Importer, otherwise false.

propertyValue.allImported()
boolean propertyValue.allImported()
Example
// checks if all of the "port" properties on the "runsOn" links have been imported.
// this works only if "runsOn" is multi-valued, or there are multiple links named "runsOn"
// (e.g. runsOn VM, runsOn PhysicalServer).
def areAllRunsOnPortsImported = asset.links.out.runsOn.linkProps.port.allImported()

Returns true if the last modification to all of the property values has been performed by an Importer.

This method is only available on properties returned by linkProps when:

  • the link in question is multi-valued
  • OR the link is not uniquely named and there has been no type restriction on the link target.

Parameters:

No Parameters

Returns:

true if the last modification to all of the property values has been performed by an Importer, otherwise false.

propertyValue.isInferred()
boolean propertyValue.isInferred()
Example
// checks if the business contact has been assigned by by an inference mechanism
def isBusinessContactInferred = asset.props.businessContact.isInferred()
// checks if the "port" property on the "runsOn" link has been inferred.
// this works only if "runsOn" is single-valued.
def isRunsOnPortInferred = asset.links.out.runsOn.linkProps.port.isInferred()

Returns true if the last modification to the property value has been performed by an inference mechanism (e.g. Change).

When used on a property returned by linkProps, then this method will be available if and only if the link in question is uniquely named and single-valued. For multi-valued links, containsImported() and allImported() are offered as an alternative.

Parameters:

No Parameters

Returns:

true if the last modification to the property value has been performed by an inference mechanism (e.g. Change Propagation), otherwise false.

propertyValue.containsInferred()
boolean propertyValue.containsInferred()
Example
// checks if any of the "port" properties on the "runsOn" links have been inferred.
// this works only if "runsOn" is multi-valued, or there are multiple links named "runsOn"
// (e.g. runsOn VM, runsOn PhysicalServer).
def isAnyRunsOnPortInferred = asset.links.out.runsOn.linkProps.port.containsInferred()

Returns true if the last modification to any of the property values has been performed by an inference mechanism (e.g. Change Propagation).

This method is only available on properties returned by linkProps when:

  • the link in question is multi-valued
  • OR the link is not uniquely named and there has been no type restriction on the link target.

Parameters:

No Parameters

Returns:

true if the last modification to any of the property values has been performed by an inference mechanism (e.g. Change Propagation), otherwise false.

propertyValue.allInferred()
boolean propertyValue.allInferred()
Example
// checks if all of the "port" properties on the "runsOn" links have been inferred.
// this works only if "runsOn" is multi-valued, or there are multiple links named "runsOn"
// (e.g. runsOn VM, runsOn PhysicalServer).
def areAllRunsOnPortsInferred = asset.links.out.runsOn.linkProps.port.allInferred()

Returns true if the last modification to all of the property values has been performed by an inference mechanism (e.g. Change Propagation).

This method is only available on properties returned by linkProps when:

  • the link in question is multi-valued
  • OR the link is not uniquely named and there has been no type restriction on the link target.

Parameters:

No Parameters

Returns:

true if the last modification to all of the property values has been performed by an inference mechanism (e.g. Change Propagation), otherwise false.

propertyValue.lastModifiedDate
Date / List<Date> propertyValue.lastModifiedDate
Example
// get the last modification date of the asset name.
def nameLastModified = asset.props.name.lastModifiedDate

// get the last modification date of the emails property
// (multi-valued properties still only have a single last-modified date)
def emailLastModified = asset.props.emailAddresses.lastModifiedDate

// gets the last modification date of the "runsOn" link property "port".
// (note: this works only if "runsOn" is a single-valued, uniquely named link)
def portLastModified = asset.links.out.runsOn.linkProps.port.lastModifiedDate

// here, "usesStorage" is a many-valued (or non-uniquely named) link. Note that
// we can use the "max()" operator in the end to get the latest modification date
// among all the modification dates of the "capacity" properties on the connected storages.
def storageCapacityLastModified = asset.links.out.usesStorage.props.capacity.lastModifiedDate.max()

Returns the last modification date(s) of the property value.

This method will return:

  • a single Date (or null if unassigned) for properties returned by asset.props, or for properties returned by linkProps if the link is single-valued and uniquely named.
  • a list of Dates (potentially empty) for properties on many-valued or non-uniquely named links or their target assets.

WARNING: The value returned by lastModifiedDate will be referring to the previous modification, not the current modification which triggered the Change Propagation! The use of this property in Propagation Rules is generally discouraged.

Parameters:

No Parameters

Returns:

The last modification date(s) of the property.

propertyValue.creationDate
Date / List<Date> propertyValue.creationDate
Example
// get the creation date of the asset name.
def nameCreationDate = asset.props.name.creationDate

// get the creation date of the emails property
// (multi-valued properties still only have a single creation modified date)
def emailLastModified = asset.props.emailAddresses.creationDate

// gets the creation date of the "runsOn" link property "port".
// (note: this works only if "runsOn" is a single-valued, uniquely named link)
def portLastModified = asset.links.out.runsOn.linkProps.port.creationDate

// here, "usesStorage" is a many-valued (or non-uniquely named) link. Note that
// we can use the "min()" operator in the end to get the earliest creation date
// among all the creation dates of the "capacity" properties on the connected storages.
def storageCapacityLastModified = asset.links.out.usesStorage.props.capacity.creationDate.min()

Returns the creation date(s) of the property value.

This method will return:

  • a single Date (or null if unassigned) for properties returned by asset.props, or for properties returned by linkProps if the link is single-valued and uniquely named.
  • a list of Dates (potentially empty) for linkProps on many-valued or non-uniquely named links.

Parameters:

No Parameters

Returns:

The last modification date(s) of the property.

Text Methods

The following methods are available on multiplicity-one Properties which are of type Text, in addition to the methods available on all multiplicity-one Properties. 

StringProperty.value()
String / List<String> StringProperty.value()
Example
// gets the name of our asset as string (or null if not set)
def nameAsString = asset.props.name.value(); // returns the name of the asset as String, or null if not set.

Returns the raw primitive value of this Property.

Important: Please note that this method will return null if it is invoked on a Property where isPresent(): boolean returns false! If you are uncertain if a Property is present or not, please use value(defaultValue: String): String instead.

Please note that it is usually not necessary to ever use .value(), as the majority of operations (e.g. string concatenation) can be performed on the property itself.

Parameters:

No Parameters

Returns:

The raw property value. Can be null (not set), a single String or a List of Strings, depending on your path and structure.

StringProperty.value(default)
String StringProperty.value(default: String)
Example
// gets the name of the contact person of our asset, or "John Doe" if none is set
def contactPersonName = asset.props.contactPerson.value("John Doe");

Returns the raw primitive value of this Property, or the given default if it is unassigned.

Please note that it is usually not necessary to ever use .value(), as the majority of operations (e.g. string concatenation) can be performed on the property itself.

This method is only available on single-valued properties.

Parameters:

default

The default value to return if the property is unassigned.

Returns:

The raw property value, or the given default if unassigned.

StringProperty.contains(text)
boolean StringProperty.contains(text: String)
Example
// checks if the first name of our contact person contains "John"
def isJohn = asset.links.out.contactPerson.props.firstName.contains("John")
// checks if the name of our asset contains "My App"
def isMyApp = asset.props.name.contains("My App")

Checks if the value at hand contains the given text (case insensitive). Will return true if the text is contained, otherwise false. Please note that this method always returns false if no value is present.

Parameters:

text

The text to check if it is contained in the property value.

Returns:

true if the property value contains the given text, otherwise false.

StringProperty.startsWith(text)
boolean StringProperty.startsWith(text: String)
Example
// checks if the first name of our contact person starts with "John"
def isJohn = asset.links.out.contactPerson.props.firstName.startsWith("John")
// checks if the name of our asset starts with "My App"
def isMyApp = asset.props.name.startsWith("My App")

Checks if the text at hand starts with the given text (case insensitive). Will return true if the text starts with the given one, otherwise false. Please note that this method always returns false if no value is present.

Parameters:

text

The text to check if the property value starts with this string.

Returns:

true if the property value starts with the given text, otherwise false.

StringProperty.endsWith(text)
boolean StringProperty.endsWith(text: String)
Example
// checks if the first name of our contact person ends with "John"
def isJohn = asset.links.out.contactPerson.props.firstName.endsWith("John")
// checks if the name of our asset ends with "My App"
def isMyApp = asset.props.name.endsWith("My App")

Checks if the text at hand ends with the given text (case insensitive). Will return true if the text ebdswith the given one, otherwise false. Please note that this method always returns false if no value is present.

Parameters:

text

The text to check if the property value ends with this string.

Returns:

true if the property value ends with the given text, otherwise false.

StringProperty.matches(regularExpression)
boolean StringProperty.matches(regularExpression: String)
Example
// checks if the name of the operating system on which our asset runs contains the text "Windows"
def runsOnWindows = asset.links.out.runsOn.props.operatingSystem.matches(".*Windows.*")
// checks if the location name of our asset contains the text "Vienna"
def deployedInVienna = asset.props.location.matches(".*Vienna.*")

Checks if the text at hand matches the given Java Regular Expression. Returns true if the text matches the given regular expression, otherwise false.

Parameters:

regularExpression

The regular expression to check against.

Returns:

true if the property value ends with the given text, otherwise false.

StringProperty.is(other, caseSensitive)
boolean StringProperty.is(String other, Boolean caseSensitive)
Example
// checks if our asset is running on a machine which uses windows (case insensitive)
def runsOnWindows = asset.links.out.runsOn.props.operatingSystem.is("windows", false)
// checks if the location of our asset is vienna (case sensitive)
def deployedInVienna = asset.props.location.is("Vienna", true)

An extended version of the general is(other: Object): boolean method which accepts a second argument which indicates whether or not the match should be case sensitive. Setting the caseSensitive parameter to true is equivalent to calling is(other: Object): boolean (i.e. without a second parameter).

Parameters:

other

The other string to compare with.

caseSensitive

Use true for case-sensitive comparison, or false for case-insensitive comparison.

Returns:

true if the property value is equal to the given text (taking the given case sensitivity into account), otherwise false.

StringProperty.length()
boolean StringProperty.length()
Example
// gets the number of characters in the name of the operating system of the machine we run on
def length = asset.links.out.runsOn.props.operatingSystem.length()
// gets the number of characters in our location name
def locationNameLength = asset.props.location.length()

Returns the number of characters in the text at hand. Will return zero if the Property is unassigned.

Parameters:

No Parameters

Returns:

The number of characters in the text property value, or zero if unassigned.

Number Methods

The following methods are available on multiplicity-one Properties which are of type Number, in addition to the methods available on all multiplicity-one Properties. 

NumericProperty.value()
Double NumericProperty.value()
Example
// gets the number of cores as a double, or null if not set.
def cores = asset.props.cores.value();

Returns the raw primitive value of this Property.

Important: Please note that this method will return null if it is invoked on a Property where isPresent(): boolean returns false! If you are uncertain if a Property is present or not, please use isPresent(defaultValue: double): double instead.

Please note that it is usually not necessary to ever use .value(), as most operations (e.g. arithmetics, comparisons...) can be performed directly on the property value.

Parameters:

No Parameters

Returns:

The raw value of this property as a Double, null (unassigned) or a List<Double> (for multi-valued properties).

NumericProperty.value(default)
Double NumericProperty.value(Double default)
Example
// gets the cost associated with this asset, or 100.0 if no cost is assigned.
def cost = asset.props.cost.value(100.0);

Returns the raw primitive value of this Property. If the Property is not present, the given default value will be returned instead.

Parameters:

default

The default number to return if the property is unassigned.

Returns:

The raw value of this property as a Double, or the given default if unassigned.

NumericProperty.abs()
Double NumericProperty.abs()
Example
// checks if the absolute number of cores on our asset is 4
def isFourOrMinusFour = asset.props.cores.abs().is(4)
// checks if the absolute number of cores on the server we run on is 4
def isFourOrMinusFour = asset.links.out.runsOn.props.cores.abs().is(4)

Returns the absolute value of the stored number, as a number value (i.e. further conditional expressions can be chained). Has no effect if the Property is unassigned.

Parameters:

No Parameters

Returns:

The absolute value of the stored number.

NumericProperty.is(other, tolerance)
Boolean NumericProperty.is(Double other, Double tolerance)
Example
// checks if the cost on our asset is 100 with a tolerance of 0.50
def costIs100 = asset.props.cost.is(100, 0.50)
// checks if the rating on the asset we depend on is 4 with a tolerance of 0.3
def ratingIs4 = asset.props.out.dependsOn.props.rating.is(4, 0.3)

Compares the value at hand with other, and returns true if the difference between them is less than or equal to tolerance, otherwise returns false.

For instance, if the value 3.5 is stored in a Property, then is(3, 0.5) and is(4, 0.5) both return true (the tolerance is applied both in positive and negative directions). This method will always return false if the Property is unassigned. Please note that the tolerance is an absolute value. For a tolerance which is relative to the size of the first argument, please use the method boolean isApproximately(double other, double tolerancePercent) instead.

Parameters:

other

The other value to compare against.

tolerance

The equality tolerance (as an absolute value), applied in both positive and negative direction.

Returns:

true if the property value is equal to other within the given tolerance, otherwise false.

NumericProperty.isApproximately(other, tolerancePercent)
Boolean NumericProperty.is(Double other, Double tolerancePercent)
Example
// checks for equality with 100 with 1% tolerance
def costIs100 = asset.props.cost.isApproximately(100, 1)
// checks for equality with 4 with 5% tolerance
def ratingIs4 = asset.props.out.dependsOn.props.rating.isApproximately(4, 5)

Compares the value at hand with other, and returns true if the difference between them is less than tolerancePercent of the first parameter, otherwise returns false. This method will always return false if the Property is unassigned. The tolerancePercent parameter is given in percent (i.e. a value of 100 means 100% tolerance).

Parameters:

other

The other value to compare against.

tolerancePercent

The equality tolerance (as a fraction of the other parameter), applied in both positive and negative direction.

Returns:

true if the property value is equal to other within the given tolerancePercent, otherwise false.

NumericProperty.isInRange(lower, upper)
Boolean NumericProperty.isInRange(Double lower, Double upper)
Example
// checks if the cost is between 90 and 110
def costIsInRange = asset.props.cost.isInRange(90, 110)
// checks if the rating is between 3 and 5
def ratingIsBetween3And5 = asset.props.out.dependsOn.props.rating.isInRange(3, 5)

Checks if the value at hand is in between the given bounds (inclusive).

Parameters:

lower

The lower bound in the range to check (inclusive).

upper

The upper bound in the range to check (inclusive).

Returns:

true if the property value is within the given range, otherwise false. Unassigned values always produce false.

NumericProperty.isLeq(other)
Boolean NumericProperty.isLeq(Double other)
Example
// checks if the cost is less than or equal to 75
def costIsMax75 = asset.props.cost.isLeq(75)
// checks if the rating is less than or equal to 3
def ratingIsLessThan3 = asset.props.out.dependsOn.props.rating.isLeq(3)

Checks if the value at hand is less than or equal to other. This method will always return false if the Property is unassigned.

Parameters:

other

The value to check against.

Returns:

true if the property value is less than or equal to other, otherwise false. Unassigned values always produce false.

NumericProperty.isGeq(other)
Boolean NumericProperty.isGeq(Double other)
Example
// checks if the cost is greater than or equal to 60
def costIsMin60 = asset.props.cost.isGeq(60)
// checks if the rating is greater than or equal to 4
def ratingIs4OrMore = asset.props.out.dependsOn.props.rating.isGeq(4)

Checks if the value at hand is greater than or equal to other. This method will always return false if the Property is unassigned.

Parameters:

other

The value to check against.

Returns:

true if the property value is greater than or equal to other, otherwise false. Unassigned values always produce false.

NumericProperty.isLt(other)
Boolean NumericProperty.isLt(Double other)
Example
// checks if the cost is less than or equal to 75
def costIsMax75 = asset.props.cost.isLeq(75)
// checks if the rating is less than or equal to 3
def ratingIsLessThan3 = asset.props.out.dependsOn.props.rating.isLeq(3)

Checks if the value at hand is (strictly) less than to other. This method will always return false if the Property is unassigned.

Parameters:

other

The value to check against.

Returns:

true if the property value is (strictly) less than other, otherwise false. Unassigned values always produce false.

NumericProperty.isGt(other)
Boolean NumericProperty.isGt(Double other)
Example
// checks if the cost is strictly greater than 60
def costIsGreaterThan60 = asset.props.cost.isGt(60)
// checks if the rating is greater than 4
def ratingIsHigherThan3 = asset.props.out.dependsOn.props.rating.isGt(3)

Checks if the value at hand is (strictly) greater than other. This method will always return false if the Property is unassigned.

Parameters:

other

The value to check against.

Returns:

true if the property value is (strictly) greater than other, otherwise false. Unassigned values always produce false.

Boolean Methods

The following methods are available on multiplicity-one Properties which are of type Boolean, in addition to the methods available on all multiplicity-one Properties. 

BooleanProperty.value()
Boolean BooleanProperty.value()
Example
// returns the active state of this asset, or null if no active state is assigned.
def isActive = asset.props.active.value()

Returns the raw primitive value of this Property.

Important: Please note that this method will return null if it is invoked on a Property where isPresent(): boolean returns false! If you are uncertain if a Property is present or not, please use isPresent(defaultValue: boolean): boolean instead.

Please note that it is usually not necessary to call .value() at all; most operators on Booleans are already available on the property value itself.

Parameters:

No Parameters

Returns:

The raw boolean value assigned to this property, or null if unassigned.

BooleanProperty.value(default)
Boolean BooleanProperty.value(default: Boolean)
Example
// returns the active state of this asset, or false if no active state is assigned.
def isActive = asset.props.active.value(false)

Returns the raw primitive value of this Property. If the Property is not present, the given default value will be returned instead.

Parameters:

default

The default value to return if the property is unassigned.

Returns:

The raw boolean value assigned to this property, or the given default if unassigned.

Range Methods

The following methods are available on multiplicity-one Properties which are of type Range, in addition to the methods available on all multiplicity-one Properties. 

RangeProperty.contains(number)
Boolean RangeProperty.value(number: Double)
Example
// checks if the value 12 is contained in the maintenanceTime range
def isInMaintenanceAtNoon = asset.props.maintenanceTime.contains(12)

Checks if this range contains the given value. Returns true if the value is contained, otherwise false. If this Property is unassigned, this method will always return false.

Parameters:

number

The value to check if it is contained in the range property or not.

Returns:

true if the given number is contained within the range property, otherwise false. Unassigned properties will always return false.

RangeProperty.lower()
Double RangeProperty.lower()
Example
// checks if the value 0 is the lower bound of the maintenanceTime range
def maintenanceStartsAtMidnight = asset.props.maintenanceTime.lower().is(0)

Returns the lower bound of the range as a multiplicity-one Number Property. If this Property is unassigned, the returned Number Property will also be unassigned.

Parameters:

No Parameters

Returns:

The lower bound of the property value range.

RangeProperty.upper()
Double RangeProperty.upper()
Example
// checks if the value 0 is the upper bound of the maintenanceTime range
def maintenanceEndsAtMidnight = asset.props.maintenanceTime.upper().is(0)

Returns the upper bound of the range as a multiplicity-one Number Property. If this Property is unassigned, the returned Number Property will also be unassigned.

Parameters:

No Parameters

Returns:

The upper bound of the property value range.

upper(): NumberProperty

Returns the upper bound of the range as a multiplicity-one Number Property. If this Property is unassigned, the returned Number Property will also be unassigned.

Example

// checks if the value 0 is the upper bound of the maintenanceTime range
def maintenanceEndsAtMidnight = asset.props.maintenanceTime.upper().is(0)

Methods on Multiplicity-Many Properties

General

The following methods are available on all multiplicity-many properties (regardless of the Property Type).

Property.is(values)
Boolean Property.is(List values)
Example
// checks if the maintainers are "John" and "Jack"
def maintainedByJohnAndJack = asset.props.maintainers.name.is(Lists.newArrayList("John", "Jack"))

Checks if the values at hand are equal to the given list of values. Returns false if the Property is unassigned.

Parameters:

values

The list of values to compare against.

Returns:

true if the property values are equal to the given values, otherwise false. Always false for unassigned properties.

Property.value()
List Property.value()
Example
// checks if the maintainers are "John" and "Jack"
def maintainers = asset.props.maintainers.name.value()

Returns the raw value of this Property as a List. If the Property is unassigned, an empty list will be returned. The type of elements in this list depend on the Property Type.

Parameters:

No Parameters

Returns:

The property value as a raw list.

Property.size()
Integer Property.size()
Basic Example
// counts the names of assets on which we run
def numberOfClusterMembers = asset.links.out.runsOn.props.name.size()
Link Collections Example
// counts the assets on which we run
def numberOfClusterMembers = asset.links.out.runsOn.size()

Returns the size (number of elements) of the list at hand. Will be zero if the Property is unassigned.

Note: size() can also be called directly on link collections. This is especially useful to count the number of links attached to a particular asset.

Parameters:

No Parameters

Returns:

The number of elements in the property value list, or zero if unassigned.

Property.first()
Property Property.first()
Example
// checks if the first maintainer in the list is "Jack"
def firstMaintainerIsJack = asset.props.maintainers.first().is("Jack")

Returns the first entry from the list of present values. The returned Property has the same type as this Property, but is multiplicity-one. Note that the returned Property may be unassigned if this Property is unassigned.

Parameters:

No Parameters

Returns:

The first element of the property values, wrapped in a property.

Property.last()
Property Property.last()
Example
// checks if the last maintainer in the list is "Jack"
def lastMaintainerIsJack = asset.props.maintainers.last().is("Jack")

Returns the last entry from the list of present values as a Property. The returned Property has the same type as this Property, but is multiplicity-one. Note that the returned Property may be unassigned if this Property is unassigned.

Parameters:

No Parameters

Returns:

The last element of the property values, wrapped in a property.

Property.filter(predicate)
Property Property.filter(Predicate predicate)
Example
// filters the list of maintainers for all names starting with "John" and counts the result list
def maintainersNamedJohn = asset.props.maintainers.filter({ it.startsWith("John") }).size()

Returns a multiplicity-many Property which has the same values as the Property at hand, except that they are filtered by the given predicate. Predicates are formulated in Groovy by using curly braces { }. Inside the curly braces, use the keyword it to reference the current value. Please note that it will always be of the same type as the Property. For instance, if filter(...) is called on a Text Property, it will be of type String. If the Property is of type Number, it will be of type double, etc.

Parameters:

predicate

The predicate to filter by. Input values for which the predicate returns true will appear in the output list (i.e. will be kept), input values for which the predicate returns false will not appear in the output list (i.e. will be filtered out).

Returns:

A multi-valued property containing the filtered values.

Property.any(object)
Boolean Property.any(T object)
Example
// checks if any of the names in the maintainers property is "John Doe"
def johnDoeIsMaintainer = asset.props.maintainers.any("John Doe")

Checks if any element in the list is equal to the given object, i.e. checks if the list contains the given element. Note that the passed object must match with the Type of the Property at hand. For instance, when calling any(...) on a Text Property, the passed value must be of type String. This method will always return false if the Property is unassigned. If the list is empty, this method also returns false.

The method contains(object: T): boolean is an alias for any(object: T): boolean and has exactly the same semantics.

Parameters:

object

The object to look for in the property values list.

Returns:

true if the property values contains the given object, otherwise false. Always false if unassigned.

Property.anyHaving(predicate)
Boolean Property.anyHaving(Predicate predicate)
Example
// checks if any of the names in the maintainers property starts with "John"
def johnIsMaintainer = asset.props.maintainers.anyHaving({ it.startsWith("John") })

Evaluates the given predicate on every entry of the list at hand, and returns true if the predicate evaluated to true for at least one of the entries, or false otherwise. Please note that this method will always return false if the Property is unassigned. Predicates are formulated in Groovy by using curly braces { }. Inside the curly braces, use the keyword it to reference the current value. Please note that it will always be of the same type as the Property. For instance, if anyHaving(...) is called on a Text Property, it will be of type String. If the Property is of type Number, it will be of type double, etc. This method will always return false if the Property is unassigned. If the list is empty, this method also returns false.

Parameters:

predicate

The predicate to filter by. If any input value causes the predicate to return true, then anyHaving will also return true.

Returns:

true if any value within the property values matches the given predicate, otherwise false. Always false if unassigned.

Property.all(object)
Boolean Property.all(T object)
Example
// checks if all Server assets on which we run have their status set to "online"
def allServersOnline = asset.links.out.runsOn.Server.props.status.all("online")

Checks if all elements in the list at hand are equal to the given one, i.e. checks if the list contains only the given element (possibly multiple times). Note that the passed object must match with the Type of the Property at hand. For instance, when calling all(...) on a Text Property, the passed value must be of type String. This method will always return true if the Property is unassigned. If the list is empty, this method also returns true.

Parameters:

object

The object to look for in the property values list.

Returns:

true if all property values are equal to the given object, otherwise false. Always true if unassigned.

Property.allHaving(predicate)
Boolean Property.allHaving(Predicate predicate)
Example
// checks if all Server assets on which we run have their status set to something other than "offline"
def noServersOffline = asset.links.out.runsOn.Server.props.status.allHaving({ it.equals("offline") == false })

Evaluates the given predicate on all entries of the list at hand, and returns true if the predicate evaluated to true for all entries, or false otherwise. Predicates are formulated in Groovy by using curly braces { }. Inside the curly braces, use the keyword it to reference the current value. Please note that it will always be of the same type as the Property. For instance, if allHaving(...) is called on a Text Property, it will be of type String. If the Property is of type Number, it will be of type double, etc. This method will always return true if the Property is unassigned. If the list is empty, this method also returns true.

Parameters:

predicate

The predicate to filter by. If all input values causes the predicate to return true, then anyHaving will also return true.

Returns:

true if all values within the property values matches the given predicate, otherwise false. Always true if unassigned.

Property.atLeast(amount, object)
Boolean Property.allHaving(int amount, T object)
Example
// checks if at least 2 Server assets on which we run have their status set to "online"
def atLeast2ServersOnline = asset.links.out.runsOn.Server.props.status.atLeast(2, "online")

Checks if at least amount entries in the list at hand are equal to the given object and returns true if this is the case, otherwise returns false. In other words, this method checks if the list contains the given object at least amount times.  Note that the passed object must match with the Type of the Property at hand. For instance, when calling atLeast(...) on a Text Property, the passed value must be of type String. This method will return false if the Property is unassigned or empty (unless amount is in addition set to zero, in which case it will return true).

Parameters:

amount

The number of elements in the property value which must be equal to the given object in order for the check to succeed.

object

The element to look for in the property values list.

Returns:

true if at least amount elements in the property value are equal to the given object, otherwise false.

Property.atLeast(percent, object)
Boolean Property.allHaving(double percent, T object)
Example
// checks if at least 50% of all Server assets on which we run have their status set to "online"
def atLeastHalfTheServersAreOnline = asset.links.out.runsOn.Server.props.status.atLeast(0.5, "online")

Checks if at least percent percent of all entries in the list are equal to the given object and returns true if this is the case, or false otherwise. The percentage is given as a floating point number in a range between 0 (0%) and 1 (100%).  Note that the passed object must match with the Type of the Property at hand. For instance, when calling atLeast(...) on a Text Property, the passed value must be of type String. This method will return false if the Property is unassigned or empty.

Parameters:

percent

The fraction of elements in the property value which must be equal to the given object in order for the check to succeed.

object

The element to look for in the property values list.

Returns:

true if at least percent % of elements in the property value are equal to the given object, otherwise false.

Property.atLeastHaving(amount, predicate)
Boolean Property.allHaving(int amount, Predicate predicate)
Example
// checks if at least 2 Server assets on which we run have their status set to something other than "offline"
def atLeast2ServersNotOffline = asset.links.out.runsOn.Server.props.status.atLeastHaving(2, { it.equals("offline") == false })

Evaluates the given predicate on all entries of the list at hand, and returns true if the predicate evaluated to true for at least amount entries, or false otherwise. Predicates are formulated in Groovy by using curly braces { }. Inside the curly braces, use the keyword it to reference the current value. Please note that it will always be of the same type as the Property. For instance, if atLeastHaving(...) is called on a Text Property, it will be of type String. If the Property is of type Number, it will be of type double, etc. This method will return false if the Property is unassigned or empty (unless amount is in addition set to zero, in which case it will return true).

Parameters:

amount

The number of elements in the property value which must match the given predicate in order for the check to succeed.

predicate

The predicate to apply.

Returns:

true if at least amount elements in the property value match the given predicate, otherwise false.

Property.atLeastHaving(percent, predicate)
Boolean Property.allHaving(double percent, Predicate predicate)
Example
// checks if at least 50% of all Server assets on which we run have their status set to something other than "offline"
def atLeastHalfTheServersNotOffline = asset.links.out.runsOn.Server.props.status.atLeastHaving(0.5, { it.equals("offline") == false })

Evaluates the given predicate on all entries of the list at hand, and returns true if the predicate evaluated to true for at least percent percent of all entities, or false otherwise. The percentage is given as a floating point number in a range between 0 (0%) and 1 (100%). Predicates are formulated in Groovy by using curly braces { }. Inside the curly braces, use the keyword it to reference the current value. Please note that it will always be of the same type as the Property. For instance, if atLeastHaving(...) is called on a Text Property, it will be of type String. If the Property is of type Number, it will be of type double, etc. This method will return false if the Property is unassigned or empty.

Parameters:

percent

The fraction of elements in the property value which must match the given predicate in order for the check to succeed.

predicate

The predicate to apply.

Returns:

true if at least percent % of elements in the property value match the given predicate, otherwise false.

Property.atMost(amount, object)
Boolean Property.allHaving(int amount, T object)
Example
// checks if at most 2 Server assets on which we run have their status set to "offline"
def atMost2ServersNotOnline = asset.links.out.runsOn.Server.props.status.atMost(2, "offline")

Checks if at most amount entries in the list at hand are equal to the given object and returns true if this is the case, otherwise returns false. In other words, this method checks if the list contains the given object at most amount times. Note that the passed object must match with the Type of the Property at hand. For instance, when calling atMost(...) on a Text Property, the passed value must be of type String. This method will return true if the Property is unassigned or empty (unless amount is in addition set to zero, in which case it will return false).

Parameters:

amount

The number of elements in the property value which must be equal to the given object in order for the check to succeed.

object

The object to look for in the property values list.

Returns:

true if at most amount elements in the property value are equal to the given object, otherwise false.

Property.atMost(percentage, object)
Boolean Property.allHaving(double percentage, T object)
Example
// checks if at most 50% of the Server assets on which we run have their status set to "offline"
def atMostHalfTheServersOffline = asset.links.out.runsOn.Server.props.status.atMost(0.5, "offline")

Checks if at most percent percent of all entries in the list are equal to the given object and returns true if this is thie case, otherwise returns false. The percentage is given as a floating point number in a range between 0 (0%) and 1 (100%). Note that the passed object must match with the Type of the Property at hand. For instance, when calling atMost(...) on a Text Property, the passed value must be of type String. This method will return false if the Property is unassigned or empty.

Parameters:

percentage

The fraction of elements in the property value which may be equal to the given object in order for the check to succeed.

object

The object to look for in the property values list.

Returns:

true if at most percentage % of elements in the property value are equal to the given object, otherwise false.

Property.atMostHaving(amount, predicate)
Boolean Property.allHaving(int amout, Predicate predicate)
Example
// checks if at most 2 Server assets on which we run have their status set to something other than "online"
def atMost2ServersNotOnline = asset.links.out.runsOn.Server.props.status.atMostHaving(2, { it.equals("online") == false })

Checks if at most percent percent of all entries in the list are equal to the given object and returns true if this is thie case, otherwise returns false. The percentage is given as a floating point number in a range between 0 (0%) and 1 (100%). Note that the passed object must match with the Type of the Property at hand. For instance, when calling atMost(...) on a Text Property, the passed value must be of type String. This method will return false if the Property is unassigned or empty.

Parameters:

amount

The number of elements in the property value which may be equal to the given object in order for the check to succeed.

predicate

The predicate to apply.

Returns:

true if at most amount elements in the property value match the given predicate, otherwise false.

Property.atMostHaving(percentage, predicate)
Boolean Property.allHaving(double percentage, Predicate predicate)
Example
// checks if at most 50% of the Server assets on which we run have their status set to something other than "online"
def atMostHalfTheServersNotOnline = asset.links.out.runsOn.Server.props.status.atMostHaving(0.5, { it.equals("online") == false })

Evaluates the given predicate on all entries of the list at hand, and returns true if the predicate evaluated to true for at most percent percent of all entries, or false otherwise. The percentage is given as a floating point number in a range between 0 (0%) and 1 (100%). Predicates are formulated in Groovy by using curly braces { }. Inside the curly braces, use the keyword it to reference the current value. Please note that it will always be of the same type as the Property. For instance, if atMostHaving(...) is called on a Text Property, it will be of type String. If the Property is of type Number, it will be of type double, etc.  This method will return false if the Property is unassigned or empty.

Parameters:

percentage

The fraction of elements in the property value which may be equal to the given object in order for the check to succeed.

predicate

The predicate to apply.

Returns:

true if at most percentage % of elements in the property value match the given predicate, otherwise false.

Property.exactly(amount, object)
Boolean Property.allHaving(int amount, T object)
Example
// checks if exactly 1 of the databases we depend on has its active flag set to true
def exactlyOneDatabaseActive = asset.links.out.database.props.active.exactly(1, true)

Checks if exactly amount elements in the list at hand are equal to the given object. In other words, checks if the list at hand contains the given object exactly amount times. Note that the passed object must match with the Type of the Property at hand. For instance, when calling exactly(...) on a Text Property, the passed value must be of type String. This method returns false if the Property is unassigned or empty (unless amount is in addition set to zero, in which case it will return true).

Parameters:

amount

The number of elements in the property value which must be equal to the given object in order for the check to succeed.

object

The object to check if it is contained in the property values list.

Returns:

true if exaclty amount elements in the property value are equal to the given object, otherwise false.

Property.exactly(percentage, object)
Boolean Property.allHaving(double percentage, T object)
Example
// checks if exactly 50% of the databases on which we depend have their status set to "online"
def exactlyHalfTheDatabasesAreOnline = asset.links.out.database.props.status.exactly(0.5, "online")

Checks if exactly percent percent of all entries in the list are equal to the given object and returns true if this is thie case, otherwise returns false. The percentage is given as a floating point number in a range between 0 (0%) and 1 (100%). Note that the passed object must match with the Type of the Property at hand. For instance, when calling atMost(...) on a Text Property, the passed value must be of type String. This method will return false if the Property is unassigned or empty.

Important: due to floating point precision issues it is recommended to use exactly(amount: int, object: T): boolean instead.

Parameters:

percentage

The fraction of elements in the property value which must be equal to the given object in order for the check to succeed.

object

The object to check if it is contained in the property values list.

Returns:

true if exaclty amount elements in the property value are equal to the given object, otherwise false.

Property.exactlyHaving(amount, predicate)
Boolean Property.allHaving(int amount, Predicate predicate)
Example
// checks if the names in the contacts Property have at least one entry containing the text "John"
def exactlyHaving = asset.props.contacts.exactlyHaving(1, { it.contains("John") })

Evaluates the given predicate on all entries of the list at hand, and returns true if the predicate evaluated to true for exactly amount entries, or false otherwise. Predicates are formulated in Groovy by using curly braces { }. Inside the curly braces, use the keyword it to reference the current value. Please note that it will always be of the same type as the Property. For instance, if exactlyHaving(...) is called on a Text Property, it will be of type String. If the Property is of type Number, it will be of type double, etc.  This method will return false if the Property is unassigned or empty (unless amount is in addition set to zero, in which case this method will return true).

Parameters:

amount

The number of elements in the property value which must match the given predicate in order for the check to succeed.

predicate

The object to check if it is contained in the property values list.

Returns:

true if exaclty amount elements in the property value match the given predicate, otherwise false.

Property.exactlyHaving(percentage, predicate)
Boolean Property.allHaving(double percentage, Predicate predicate)
Example
// checks if exactly 50% of the databases we depend on are online
def exactlyHalfOfAllDatabasesAreOnline = asset.links.out.databases.props.status.exactlyHaving(0.5, { it.equals("online") })

Evaluates the given predicate on all entries of the list at hand, and returns true if the predicate evaluated to true for exactly percent percent of all entries, or false otherwise. The percentage is given as a floating point number in a range between 0 (0%) and 1 (100%). Predicates are formulated in Groovy by using curly braces { }. Inside the curly braces, use the keyword it to reference the current value. Please note that it will always be of the same type as the Property. For instance, if exactlyHaving(...) is called on a Text Property, it will be of type String. If the Property is of type Number, it will be of type double, etc.  This method will return false if the Property is unassigned or empty.

Important: due to floating point precision issues it is recommended to use exactlyHaving(amount: int, predicate: Predicate): boolean instead.

Parameters:

percentage

The fraction of elements in the property value which must match the given predicate in order for the check to succeed.

predicate

The object to check if it is contained in the property values list.

Returns:

true if exaclty percentage % of elements in the property value match the given predicate, otherwise false.

Multi-Text Methods

Multiplicity-many Text-typed Properties do not have additional methods other than the general ones which are always available.

Multi-Number Methods

The following methods are available on multiplicity-many Properties which are of type Number, in addition to the methods available on all multiplicity-many Properties. 

NumberProperty.avg()
NumberProperty NumberProperty.avg()
Example
// returns the average cost of all servers on which our asset runs (skipping null values), or zero if unspecified.
def averageCostOfServers = asset.links.out.runsOn.props.cost.avg().value(0)

Returns the average of all values as a multiplicity-one Number Property. Any null values in the list are skipped for this calculation. Please note that the returned Property will be unassigned if this Property is unassigned or contains no non-null entries.

Parameters:

No Parameters

Returns:

Returns the average of all numbers within this property value, as a numeric property.

NumberProperty.avg(defaultForNull)
NumberProperty NumberProperty.avg(double defaultForNull)
Example
// returns the average cost of all servers on which our asset runs (treating null values as zero), or 100 if unspecified.
def averageCostOfServers = asset.links.out.runsOn.props.cost.avg(0).value(100)

Returns the average of all values as a multiplicity-one Number Property. Any null values in the list will be replaced with defaultForNull for this calculation only. Please note that the returned Property will be unassigned if this Property is unassigned.

Parameters:

defaultForNull

The default value to use in the average calculation instead of null values.

Returns:

Returns the average of all numbers within this property value, as a numeric property.

NumberProperty.sum()
NumberProperty NumberProperty.sum()
Example
// returns the total cost of all servers on which our asset runs (skipping null values), or zero if unspecified.
def totalCostOfServers = asset.links.out.runsOn.props.cost.sum().value(0)

Returns the sum of all values as a multiplicity-one Number Propertry. Any null values in this list are skipped for this calculation. Please note that the returned Property will be unassigned if this Property is unassigned or contains no non-null entries.

Parameters:

No Parameters

Returns:

Returns the sum of all numbers within this property value, as a numeric property.

NumberProperty.sum(defaultForNull)
NumberProperty NumberProperty.sum(double defaultForNull)
Example
// returns the total cost of all servers on which our asset runs (treating null values as 1), or 100 if unspecified.
def totalCostOfServers = asset.links.out.runsOn.props.cost.sum(1).value(100)

Returns the sum of all values as a multiplicity-one Number Property. Any null values in the list will be replaced with defaultForNull for this calculation only. Please note that the returned Property will be unassigend if this Property is unassigned.

Parameters:

defaultForNull

The default value to use during sum calculation instead of null values.

Returns:

Returns the sum of all numbers within this property value, as a numeric property.

NumberProperty.max()
NumberProperty NumberProperty.max()
Example
// returns the maximum cost of all servers on which our asset runs, or 0 if unspecified.
def highestServerCost = asset.links.out.runsOn.props.cost.max().value(0)

Returns the maximum of all values in this list as a mulitplicity-one Number Property. Please note that the returned Property will be unassigned if this Property is unassigned or contains no non-null entries.

Parameters:

No Parameters

Returns:

Returns the maximum of all numbers within this property value, as a numeric property.

NumberProperty.min()
NumberProperty NumberProperty.min()
Example
// returns the minimum cost of all servers on which our asset runs, or 0 if unspecified.
def lowestServerCost = asset.links.out.runsOn.props.cost.min().value(0)

Returns the minimum of all values in this list as a multiplicity-one Number Property. Please note that the returned Property will be unassigned if this Property is unassigned or contains no non-null entries.

Parameters:

No Parameters

Returns:

Returns the minimum of all numbers within this property value, as a numeric property.

Multi-Boolean Methods

The following methods are available on multiplicity-many Properties which are of type Boolean, in addition to the methods available on all multiplicity-many Properties. 

BooleanProperty.or(defaultValue)
Boolean BooleanProperty.or(boolean defaultValue)
Example
// checks if any of the servers our asset runs on is active (returning false if the list is empty)
def anyServerActive = asset.links.out.runsOn.props.active.or(false)

Applies an or operation to all booleans in the list, returning the result. If the list is empty or unassigned, the given defaultValue will be used.

For instance, if the list at hand consists of [true, false, true], then the or operation resolves to ((true or false) or true) which is (true or true) which finally results in true.

Parameters:

defaultValue

The default value to use instead of null values.

Returns:

true if at least one property value is true, otherwise false.

BooleanProperty.and(defaultValue)
Boolean BooleanProperty.and(boolean defaultValue)
Example
// checks if all of our servers are active (returning false if the list is empty)
def allServersActive = asset.links.out.runsOn.props.active.and(false)

Applies an and operation to all booleans in the list, returning the result. If the list is empty or unassigned, the given defaultValue will be used.

For instance, if the list at hand consists of [true, false, true], then the and operation resolves to ((true and false) and true) which is (false and true) which finally results in false.

Parameters:

defaultValue

The default value to use instead of null values.

Returns:

false if at least one property value is false, otherwise true.

BooleanProperty.xor(defaultValue)
Boolean BooleanProperty.xor(boolean defaultValue)
Example
// checks if exactly one of our servers is active (returning false if the list is empty)
def exactlyOneServerActive = asset.links.out.runsOn.props.active.xor(false)

Applies an xor operation to all booleans in the list, returning the result. If the list is empty or unassigned, the given defaultValue will be used.

For instance, if the list at hand consists  [true, false, true], then the xor operation resolves to ((true xor false) xor true) which is (true xor true) which finally results in false.

Parameters:

defaultValue

The default value to use instead of null values.

Returns:

true if the number of true property values is odd, otherwise false.

Multi-Range Methods

Multiplicity-many Range-typed Properties do not have additional methods other than the general ones which are always available.


Limitations

  • Propagation Rules are always applied to all scenarios. It is not possible to write rules for only one separated scenario.

FAQ

How is the execution of propagation rules triggered?

A propagation rule always keeps the assets up to date:

  • When a new rule is created, the entire rule set is applied to all assets.
  • Every time a rule is changed, the rule set is reapplied to all assets.
  • Every change to an asset triggers the execution of the rule set again.