Change propagation
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 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 support 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.
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.
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).
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
atoband then back toaagain (within the same transaction), a Propagation Rule will never witness the valueb. -
Change Propagation may access metadata such as the
lastModifiedDateof an asset, a link, or an individual property value. However, as illustrated in the image above, the trigger which updates thelastModifiedDates occurs after the Change Propagation. So thelastModifiedDates observed by a Propagation Rule will be the previous change date, not the current one.
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
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 themessageobject to the log output. Please note that themessagecan be anything and does not need to be a string. Log messages produced bylog.debugwill be visible only in the rule editor. -
log.info(message)behaves in a similar fashion aslog.debug, except that log statemets produced bylog.infowill (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, preferlog.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 Name | Code Name | Comment on Code Name |
|---|---|---|
| Phone (Office) |
phoneOffice
|
Whitespaces, braces and special characters are eliminated in code names. |
eMail
|
Plus, minus and other related characters are also eliminated in code names. | |
EMail
|
Multiple successive uppercase letters are retained (note that
the property name uses no dash, but the two consecutive capital
letters EM).
|
|
| under_score |
under_score
|
The underscore character is allowed and retained. |
| Mobile |
mobile
|
All regular characters remain the same. Note that all properties start with a lower-case letter. |
| First name |
firstName
|
The 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. |
| B2B |
b2B
|
Numbers inside a name are allowed and are retained. |
| URL |
URL
|
Multiple 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 Range | Treatment |
|---|---|
| a-z, A-Z | Retained |
| 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 |
| Whitespace | Eliminated, next character is upper-cased |
| All other characters | Invalid 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.
asset.props
Signature:
OwnProperties
asset.props
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.
Returns: The own properties of the asset, limited to the ones specified in the rule.
Example:
asset.props.firstName
asset.links
Signature:
OwnReferences
asset.links
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.
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).
Example:
// restricts to the outgoing "runsOn" links
asset.links.out.runsOn
// restricts to the incoming "hosts" links
asset.links.in.hosts
asset.links.in
Signature:
IncomingReferences
asset.links.in
Returns an accessor to the incoming links of an asset. From there, you can specify a link name, and optionally restrict to a Type.
Returns: An accessor to the incoming links of an asset.
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
asset.links.out
Signature:
OutgoingReferences
asset.links.out
Returns an accessor to the outgoing links of an asset. From there, you can restrict by Type, or specify a link name.
Returns: An accessor to the outgoing links of an asset.
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
links.props
Signature:
NeighborProperties
links.props
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.
Returns: An accessor to the properties of the asset collection.
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
links.linkProps
Signature:
LinkProperties
links.linkProps
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.
Returns: An accessor to the properties of the asset collection.
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
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
Signature:
<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.
Returns: Nothing. This method will always raise an internal exception which will be caught by the rule engine, causing the script execution to abort.
Example:
if(asset.name == "Don't touch me"){
return asset.skip()
}
// proceed with regular rule code here
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.
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().
Filtering Links
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)
Signature:
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:
-
closure— The 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)
Signature:
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:
-
closure— The 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.
Iterating over connected Links and Assets
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)
Signature:
void
linkCollection.forEachAsset(closure:
Closure<Asset>)
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:
-
closure— The 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.
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
LinkCollection.forEachLink(closure)
Signature:
void
linkCollection.forEachLink(closure: Closure<Link>)
Executes the given closure operation for each link
in the collection.
Parameters:
-
closure— The 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.
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
Methods on Multiplicity-One Properties
General
The following methods are available on all multiplicity-one properties (regardless of the Property Type).
propertyValue.is(other)
Signature:
boolean
propertyValue.is(other: Object)
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:
-
other— The other object to compare with.
Returns:true if
the property value is equal to other, otherwise
false.
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)
propertyValue.isPresent()
Signature:
boolean
propertyValue.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.
Returns:true if
a property value is present, otherwise
false.
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()
Checking Metadata on Property Values
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()
Signature:
boolean
propertyValue.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.
Returns:true if
the last modification to the property value has been performed
manually by a Txture user, otherwise
false.
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()
propertyValue.containsManuallyMaintained()
Signature:
boolean
propertyValue.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.
Returns:true if
the last modification to any of the property values has been
performed manually by a Txture user, otherwise
false.
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()
propertyValue.allManuallyMaintained()
Signature:
boolean
propertyValue.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.
Returns:true if
the last modification to all of the property values has been
performed manually by a Txture user, otherwise
false.
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()
propertyValue.isImported()
Signature:
boolean
propertyValue.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.
Returns:true if
the last modification to the property value has been performed by
an Importer, otherwise false.
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()
propertyValue.containsImported()
Signature:
boolean
propertyValue.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.
Returns:true if
the last modification to any of the property values has been
performed by an Importer, otherwise
false.
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()
propertyValue.allImported()
Signature:
boolean
propertyValue.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.
Returns:true if
the last modification to all of the property values has been
performed by an Importer, otherwise
false.
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()
propertyValue.isInferred()
Signature:
boolean
propertyValue.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.
Returns:true if
the last modification to the property value has been performed by
an inference mechanism (e.g. Change Propagation), otherwise
false.
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()
propertyValue.containsInferred()
Signature:
boolean
propertyValue.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.
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.
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()
propertyValue.allInferred()
Signature:
boolean
propertyValue.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.
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.
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()
propertyValue.lastModifiedDate
Signature:
Date / List<Date>
propertyValue.lastModifiedDate
Returns the last modification date(s) of the property value.
This method will return:
-
a single
Date(ornullif unassigned) for properties returned byasset.props, or for properties returned bylinkPropsif 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.
Returns: The last modification date(s) of the property.
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()
propertyValue.creationDate
Signature:
Date / List<Date>
propertyValue.creationDate
Returns the creation date(s) of the property value.
This method will return:
-
a single
Date(ornullif unassigned) for properties returned byasset.props, or for properties returned bylinkPropsif the link is single-valued and uniquely named. -
a list of
Dates (potentially empty) forlinkPropson many-valued or non-uniquely named links.
Returns: The last modification date(s) of the property.
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()
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()
Signature:
String / List<String>
StringProperty.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
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.
Returns: The raw property value. Can be
null (not set), a single String or a
List of Strings, depending on your path and
structure.
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.
StringProperty.value(default)
Signature:
String
StringProperty.value(default: String)
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.
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");
StringProperty.contains(text)
Signature:
boolean
StringProperty.contains(text: String)
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.
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")
StringProperty.startsWith(text)
Signature:
boolean
StringProperty.startsWith(text: String)
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.
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")
StringProperty.endsWith(text)
Signature:
boolean
StringProperty.endsWith(text: String)
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.
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")
StringProperty.matches(regularExpression)
Signature:
boolean
StringProperty.matches(regularExpression: String)
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.
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.*")
StringProperty.is(other, caseSensitive)
Signature:
boolean
StringProperty.is(String other, Boolean caseSensitive)
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— Usetruefor case-sensitive comparison, orfalsefor case-insensitive comparison.
Returns:true if
the property value is equal to the given text (taking
the given case sensitivity into account), otherwise
false.
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)
StringProperty.length()
Signature:
boolean
StringProperty.length()
Returns the number of characters in the text at hand. Will return zero if the Property is unassigned.
Returns: The number of characters in the text property value, or zero if unassigned.
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()
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()
Signature:
Double
NumericProperty.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.
Returns: The raw value of this property as a
Double, null (unassigned) or a
List<Double> (for multi-valued properties).
Example:
// gets the number of cores as a double, or null if not set.
def cores = asset.props.cores.value();
NumericProperty.value(default)
Signature:
Double
NumericProperty.value(Double default)
Returns the raw primitive value of this Property. If the Property is not present, the given default value will be returned instead.
Parameters:
- 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.
Example:
// gets the cost associated with this asset, or 100.0 if no cost is assigned.
def cost = asset.props.cost.value(100.0);
NumericProperty.abs()
Signature:
Double
NumericProperty.abs()
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.
Returns: The absolute value of the stored number.
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)
NumericProperty.is(other, tolerance)
Signature:
Boolean
NumericProperty.is(Double other, Double tolerance)
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.
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)
NumericProperty.isApproximately(other,
tolerancePercent)
Signature:
Boolean
NumericProperty.is(Double other, Double
tolerancePercent)
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 theotherparameter), applied in both positive and negative direction.
Returns:true if
the property value is equal to other within the given
tolerancePercent, otherwise
false.
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)
NumericProperty.isInRange(lower, upper)
Signature:
Boolean
NumericProperty.isInRange(Double lower, Double upper)
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.
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)
NumericProperty.isLeq(other)
Signature:
Boolean
NumericProperty.isLeq(Double other)
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.
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)
NumericProperty.isGeq(other)
Signature:
Boolean
NumericProperty.isGeq(Double other)
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.
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)
NumericProperty.isLt(other)
Signature:
Boolean
NumericProperty.isLt(Double other)
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.
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)
NumericProperty.isGt(other)
Signature:
Boolean
NumericProperty.isGt(Double other)
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.
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)
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()
Signature:
Boolean
BooleanProperty.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.
Returns: The raw boolean value assigned to this
property, or null if unassigned.
Example:
// returns the active state of this asset, or null if no active state is assigned.
def isActive = asset.props.active.value()
BooleanProperty.value(default)
Signature:
Boolean
BooleanProperty.value(default: Boolean)
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.
Example:
// returns the active state of this asset, or false if no active state is assigned.
def isActive = asset.props.active.value(false)
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)
Signature:
Boolean
RangeProperty.value(number: Double)
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.
Example:
// checks if the value 12 is contained in the maintenanceTime range
def isInMaintenanceAtNoon = asset.props.maintenanceTime.contains(12)
RangeProperty.lower()
Signature:
Double
RangeProperty.lower()
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.
Returns: The lower bound of the property value range.
Example:
// checks if the value 0 is the lower bound of the maintenanceTime range
def maintenanceStartsAtMidnight = asset.props.maintenanceTime.lower().is(0)
RangeProperty.upper()
Signature:
Double
RangeProperty.upper()
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.
Returns: The upper bound of the property value range.
Example:
// checks if the value 0 is the upper bound of the maintenanceTime range
def maintenanceEndsAtMidnight = asset.props.maintenanceTime.upper().is(0)
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)
Signature:
Boolean Property.is(List
values)
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.
Example:
// checks if the maintainers are "John" and "Jack"
def maintainedByJohnAndJack = asset.props.maintainers.name.is(Lists.newArrayList("John", "Jack"))
Property.value()
Signature:
List
Property.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.
Returns: The property value as a raw list.
Example:
// checks if the maintainers are "John" and "Jack"
def maintainers = asset.props.maintainers.name.value()
Property.size()
Signature:
Integer
Property.size()
Returns the size (number of elements) of the list at hand. Will be zero if the Property is unassigned.
Returns: The number of elements in the property value list, or zero if unassigned.
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()
Property.first()
Signature:
Property
Property.first()
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.
Returns: The first element of the property values, wrapped in a property.
Example:
// checks if the first maintainer in the list is "Jack"
def firstMaintainerIsJack = asset.props.maintainers.first().is("Jack")
Property.last()
Signature:
Property
Property.last()
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.
Returns: The last element of the property values, wrapped in a property.
Example:
// checks if the last maintainer in the list is "Jack"
def lastMaintainerIsJack = asset.props.maintainers.last().is("Jack")
Property.filter(predicate)
Signature:
Property
Property.filter(Predicate predicate)
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 returnstruewill appear in the output list (i.e. will be kept), input values for which the predicate returnsfalsewill not appear in the output list (i.e. will be filtered out).
Returns: A multi-valued property containing the filtered values.
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()
Property.any(object)
Signature:
Boolean Property.any(T
object)
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.
Example:
// checks if any of the names in the maintainers property is "John Doe"
def johnDoeIsMaintainer = asset.props.maintainers.any("John Doe")
Property.anyHaving(predicate)
Signature:
Boolean
Property.anyHaving(Predicate predicate)
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 returntrue, thenanyHavingwill also returntrue.
Returns:true if
any value within the property values matches the given
predicate, otherwise
false. Always
false if unassigned.
Example:
// checks if any of the names in the maintainers property starts with "John"
def johnIsMaintainer = asset.props.maintainers.anyHaving({ it.startsWith("John") })
Property.all(object)
Signature:
Boolean Property.all(T
object)
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.
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")
Property.allHaving(predicate)
Signature:
Boolean
Property.allHaving(Predicate predicate)
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 returntrue, thenanyHavingwill also returntrue.
Returns:true if
all values within the property values matches the given
predicate, otherwise
false. Always
true if unassigned.
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 })
Property.atLeast(amount, object)
Signature:
Boolean Property.allHaving(int
amount, T object)
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 givenobjectin 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.
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")
Property.atLeast(percent, object)
Signature:
Boolean
Property.allHaving(double percent, T object)
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 givenobjectin 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.
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")
Property.atLeastHaving(amount, predicate)
Signature:
Boolean Property.allHaving(int
amount, Predicate predicate)
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 givenpredicatein 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.
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 })
Property.atLeastHaving(percent, predicate)
Signature:
Boolean
Property.allHaving(double percent, Predicate predicate)
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 givenpredicatein 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.
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 })
Property.atMost(amount,
object)
Signature:
Boolean Property.allHaving(int
amount, T object)
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 givenobjectin 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.
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")
Property.atMost(percentage, object)
Signature:
Boolean
Property.allHaving(double percentage, T object)
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 givenobjectin 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.
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")
Property.atMostHaving(amount, predicate)
Signature:
Boolean Property.allHaving(int
amout, Predicate predicate)
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 givenobjectin 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.
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 })
Property.atMostHaving(percentage, predicate)
Signature:
Boolean
Property.allHaving(double percentage, Predicate
predicate)
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 givenobjectin 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.
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 })
Property.exactly(amount, object)
Signature:
Boolean Property.allHaving(int
amount, T object)
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 givenobjectin 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.
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)
Property.exactly(percentage, object)
Signature:
Boolean
Property.allHaving(double percentage, T object)
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.
exactly(amount: int, object:
T): boolean instead.
Parameters:
-
percentage— The fraction of elements in the property value which must be equal to the givenobjectin 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.
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")
Property.exactlyHaving(amount, predicate)
Signature:
Boolean Property.allHaving(int
amount, Predicate predicate)
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 givenpredicatein 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.
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") })
Property.exactlyHaving(percentage, predicate)
Signature:
Boolean
Property.allHaving(double percentage, Predicate
predicate)
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.
exactlyHaving(amount: int,
predicate: Predicate): boolean instead.
Parameters:
-
percentage— The fraction of elements in the property value which must match the givenpredicatein 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.
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") })
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()
Signature:
NumberProperty
NumberProperty.avg()
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.
Returns: Returns the average of all numbers within this property value, as a numeric property.
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)
NumberProperty.avg(defaultForNull)
Signature:
NumberProperty
NumberProperty.avg(double defaultForNull)
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 ofnullvalues.
Returns: Returns the average of all numbers within this property value, as a numeric property.
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)
NumberProperty.sum()
Signature:
NumberProperty
NumberProperty.sum()
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.
Returns: Returns the sum of all numbers within this property value, as a numeric property.
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)
NumberProperty.sum(defaultForNull)
Signature:
NumberProperty
NumberProperty.sum(double defaultForNull)
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 ofnullvalues.
Returns: Returns the sum of all numbers within this property value, as a numeric property.
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)
NumberProperty.max()
Signature:
NumberProperty
NumberProperty.max()
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.
Returns: Returns the maximum of all numbers within this property value, as a numeric property.
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)
NumberProperty.min()
Signature:
NumberProperty
NumberProperty.min()
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.
Returns: Returns the minimum of all numbers within this property value, as a numeric property.
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)
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)
Signature:
Boolean
BooleanProperty.or(boolean defaultValue)
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 ofnullvalues.
Returns:true if
at least one property value is true,
otherwise false.
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)
BooleanProperty.and(defaultValue)
Signature:
Boolean
BooleanProperty.and(boolean defaultValue)
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 ofnullvalues.
Returns:false if
at least one property value is false,
otherwise true.
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)
BooleanProperty.xor(defaultValue)
Signature:
Boolean
BooleanProperty.xor(boolean defaultValue)
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 ofnullvalues.
Returns:true if
the number of true property values is odd, otherwise
false.
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)
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.