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
tob
and then back toa
again (within the same transaction), a Propagation Rule will never witness the valueb
. -
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 thelastModifiedDate
s occurs after the Change Propagation. So thelastModifiedDate
s 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 themessage
object to the log output. Please note that themessage
can be anything and does not need to be a string. Log messages produced bylog.debug
will be visible only in the rule editor.log.info(message)
behaves in a similar fashion aslog.debug
, except that log statemets produced bylog.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, 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.
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
.
OwnProperties asset.props
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:
Returns:
The own properties of the asset, limited to the ones specified in the rule.
OwnReferences asset.links
// 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:
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).
IncomingReferences asset.links.in
// 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:
Returns:
An accessor to the incoming links of an asset.
OutgoingReferences asset.links.out
// 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:
Returns:
An accessor to the outgoing links of an asset.
NeighborProperties links.props
// 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:
Returns:
An accessor to the properties of the asset collection.
LinkProperties links.linkProps
// 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:
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.
<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.
if(asset.name == "Don't touch me"){
return asset.skip()
}
// proceed with regular rule code here
Parameters:
Returns:
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()
.
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 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 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.
void linkCollection.forEachAsset(closure: Closure<Asset>)
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:
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.
void linkCollection.forEachLink(closure: Closure<Link>)
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:
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.
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).
boolean propertyValue.is(other: Object)
// 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:
other | The other object to compare with. |
Returns:
true
if the property value is equal to other
, otherwise
false
.
boolean propertyValue.isPresent()
// 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:
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?
boolean propertyValue.isManuallyMaintained()
// 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:
Returns:
true
if the last modification to the property value has been
performed manually by a Txture user, otherwise false
.
boolean propertyValue.containsManuallyMaintained()
// 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:
Returns:
true
if the last modification to any of the property values has been
performed manually by a Txture user, otherwise false
.
boolean propertyValue.allManuallyMaintained()
// 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:
Returns:
true
if the last modification to all of the property values has been
performed manually by a Txture user, otherwise false
.
boolean propertyValue.isImported()
// 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:
Returns:
true
if the last modification to the property value has been
performed by an Importer, otherwise false
.
boolean propertyValue.containsImported()
// 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:
Returns:
true
if the last modification to any of the property values has been
performed by an Importer, otherwise false
.
boolean propertyValue.allImported()
// 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:
Returns:
true
if the last modification to all of the property values has been
performed by an Importer, otherwise false
.
boolean propertyValue.isInferred()
// 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:
Returns:
true
if the last modification to the property value has been
performed by an inference mechanism (e.g. Change Propagation), otherwise false
.
boolean propertyValue.containsInferred()
// 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:
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
.
boolean propertyValue.allInferred()
// 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:
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
.
Date / List<Date> propertyValue.lastModifiedDate
// 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
(ornull
if unassigned) for properties returned byasset.props
, or for properties returned bylinkProps
if the link is single-valued and uniquely named. - a list of
Date
s (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:
Returns:
The last modification date(s) of the property.
Date / List<Date> propertyValue.creationDate
// 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
(ornull
if unassigned) for properties returned byasset.props
, or for properties returned bylinkProps
if the link is single-valued and uniquely named. - a list of
Date
s (potentially empty) forlinkProps
on many-valued or non-uniquely named links.
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.
String / List<String> StringProperty.value()
// 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:
Returns:
The raw property value. Can be null
(not set), a single String
or a
List
of Strings, depending on your path and structure.
String StringProperty.value(default: String)
// 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.
boolean StringProperty.contains(text: String)
// 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
.
boolean StringProperty.startsWith(text: String)
// 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
.
boolean StringProperty.endsWith(text: String)
// 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
.
boolean StringProperty.matches(regularExpression: String)
// 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
.
boolean StringProperty.is(String other, Boolean caseSensitive)
// 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 |
Returns:
true
if the property value is equal to the given text
(taking the
given case sensitivity into account), otherwise false
.
boolean StringProperty.length()
// 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:
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.
Double NumericProperty.value()
// 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:
Returns:
The raw value of this property as a Double
, null
(unassigned) or
a List<Double>
(for multi-valued properties).
Double NumericProperty.value(Double default)
// 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.
Double NumericProperty.abs()
// 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:
Returns:
The absolute value of the stored number.
Boolean NumericProperty.is(Double other, Double tolerance)
// 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
.
Boolean NumericProperty.is(Double other, Double tolerancePercent)
// 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 |
Returns:
true
if the property value is equal to other
within the given tolerancePercent
,
otherwise false
.
Boolean NumericProperty.isInRange(Double lower, Double upper)
// 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
.
Boolean NumericProperty.isLeq(Double other)
// 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
.
Boolean NumericProperty.isGeq(Double other)
// 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
.
Boolean NumericProperty.isLt(Double other)
// 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
.
Boolean NumericProperty.isGt(Double other)
// 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.
Boolean BooleanProperty.value()
// 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:
Returns:
The raw boolean value assigned to this property, or null
if unassigned.
Boolean BooleanProperty.value(default: Boolean)
// 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.
Boolean RangeProperty.value(number: Double)
// 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
.
Double RangeProperty.lower()
// 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:
Returns:
The lower bound of the property value range.
Double RangeProperty.upper()
// 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:
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).
Boolean Property.is(List values)
// 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.
List Property.value()
// 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:
Returns:
The property value as a raw list.
Integer Property.size()
// counts the names of assets on which we run
def numberOfClusterMembers = asset.links.out.runsOn.props.name.size()
// 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:
Returns:
The number of elements in the property value list, or zero if unassigned.
Property Property.first()
// 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:
Returns:
The first element of the property values, wrapped in a property.
Property Property.last()
// 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:
Returns:
The last element of the property values, wrapped in a property.
Property Property.filter(Predicate predicate)
// 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 |
Returns:
A multi-valued property containing the filtered values.
Boolean Property.any(T object)
// 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.
Boolean Property.anyHaving(Predicate predicate)
// 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 |
Returns:
true
if any value within the property values matches the given predicate
,
otherwise false
. Always false
if unassigned.
Boolean Property.all(T object)
// 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.
Boolean Property.allHaving(Predicate predicate)
// 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 |
Returns:
true
if all values within the property values matches the given predicate
,
otherwise false
. Always true
if unassigned.
Boolean Property.allHaving(int amount, T object)
// 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 | 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
.
Boolean Property.allHaving(double percent, T object)
// 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 | 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
.
Boolean Property.allHaving(int amount, Predicate predicate)
// 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 | The predicate to apply. |
Returns:
true
if at least amount
elements in the property value match
the given predicate
, otherwise false
.
Boolean Property.allHaving(double percent, Predicate predicate)
// 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 | The predicate to apply. |
Returns:
true
if at least percent
% of elements in the property value match
the given predicate
, otherwise false
.
Boolean Property.allHaving(int amount, T object)
// 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 | 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
.
Boolean Property.allHaving(double percentage, T object)
// 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 | 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
.
Boolean Property.allHaving(int amout, Predicate predicate)
// 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 |
predicate | The predicate to apply. |
Returns:
true
if at most amount
elements in the property value match
the given predicate
, otherwise false
.
Boolean Property.allHaving(double percentage, Predicate predicate)
// 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 |
predicate | The predicate to apply. |
Returns:
true
if at most percentage
% of elements in the property value match
the given predicate
, otherwise false
.
Boolean Property.allHaving(int amount, T object)
// 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 | 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
.
Boolean Property.allHaving(double percentage, T object)
// 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 | 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
.
Boolean Property.allHaving(int amount, Predicate predicate)
// 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 | 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
.
Boolean Property.allHaving(double percentage, Predicate predicate)
// 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 | 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 NumberProperty.avg()
// 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:
Returns:
Returns the average of all numbers within this property value, as a numeric property.
NumberProperty NumberProperty.avg(double defaultForNull)
// 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 |
Returns:
Returns the average of all numbers within this property value, as a numeric property.
NumberProperty NumberProperty.sum()
// 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:
Returns:
Returns the sum of all numbers within this property value, as a numeric property.
NumberProperty NumberProperty.sum(double defaultForNull)
// 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 |
Returns:
Returns the sum of all numbers within this property value, as a numeric property.
NumberProperty NumberProperty.max()
// 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:
Returns:
Returns the maximum of all numbers within this property value, as a numeric property.
NumberProperty NumberProperty.min()
// 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:
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.
Boolean BooleanProperty.or(boolean defaultValue)
// 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 |
Returns:
true
if at least one property value is true
, otherwise false
.
Boolean BooleanProperty.and(boolean defaultValue)
// 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 |
Returns:
false
if at least one property value is false
, otherwise true
.
Boolean BooleanProperty.xor(boolean defaultValue)
// 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 |
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.