Attributes
From ControlTier
This page describes the purpose and functionality of Attributes, and how you can use them to define custom data values for your Resource model, share those values among related Resources, and use the values in your commands.
Contents |
What are Attributes?
Attributes are essentially a way of creating custom "named" properties.
All of the types in the ControlTier model have a set of properties associated with them, and every property has these features:
- it can have a specific value defined in an Resource
- it can have a default value defined in the Type, as well as constraints on the value
- it can be referenced in commands using a property reference syntax.
- Use the syntax:
${resource.PROPERTY}
- Use the syntax:
However, the set of available properties is predefined for each Type and can not be extended. Which properties a Type has is determined by its Order (Service, Node, Package, Setting, etc).
Attributes allow you to extend the set of properties that a Resource or Type has available to it. They provide the same effective set of features as Properties do, but allow you to define the semantics and names that are used.
When you view any Type, you can see the set of potential Attributes, which are "imported" into the Types resource context. Under the Constraints tab, scroll to the "Imported Attributes" section:
The list of Imported Attributes is the set of all Attributes defined for each Type that is allowed as a Resource under the resources constraint (see #Allowing the child resource Type). Thus the list you see may be very long if the resources constraint is very general. If you change that constraint to be much more specific, the list of potentially imported Attributes will get smaller.
You can see that an Attribute has the same set of features as a Property:
- it can have a specific value defined in an Resource
- Define a Setting subtype, create a Resource of that Setting, and add it as a child resource of another Resource, as shown in the Defining Attributes using a Setting section.
- it can have a default value defined in the Type, as well as constraints on the value
- Set default values in each Type that may import the attribute: Setting Attribute Defaults
- Set constraints on the resource property in each Type: Allowing the child resource Type
- Set constraints on the settingValue property of the Setting type, to constrain the value further
- it can be referenced in commands using a property reference syntax.
- Use the syntax:
${resource.attribute.ATTRIBUTE}: Using Attribute Values
- Use the syntax:
Additionally, using Settings to define Attributes provide a few more options that increase flexibility:
- Setting Resources can be used by multiple other Resources, allowing you to easily change the value of an Attribute across a set of Resources.
- Setting Types fit in the Type system, allowing you to define precisely which Resources are allowed to use specific Attributes, based on the Constraints mechanism.
What is the difference between Property Attributes and Imported Attributes?
The conjunction of the two lists in the GUI may cause some confusion. If this is somewhat confusing or hard to distinguish, here is a concise definition of the two:
- Property Attributes
- "Property Attributes", or just "Attributes", are custom names that you give to a specific Property of a Type. Think of it as a way of referring to that Property value. You don't define default values for the Property Attribute, but you can define default value constraints for the Property itself.
- Imported Attributes
- Imported Attributes are the set of all Property Attributes defined in other Types that are visible to the current Type. Additionally, you may define default values for Imported Attributes.
It is somewhat confusing because you will use both Property Attributes (of your current resource and Type) and Imported Attributes (from other Resources and Types) in the same manner, and with the same syntax.
Defining Attributes
Attributes can be defined by setting a custom ("exported") name for any property of a Type. For example, you can set the deployment-basedir property of a Service subtype to have an attribute name of my-basedir.
Defining Attributes in Workbench
Navigate to the Type, and click the Constraints tab. Next to the property name, click the "+" icon to add a new Attribute for the property:
Once you have defined the Attribute name for a property, the value of that property is available for reference using the Attribute name (in addition to the original property reference). The syntax for referencing an attribute is:
${resource.attribute.ATTRIBUTE-NAME}
Defining Attributes in type.xml
The Type-v10.xml reference has detailed information about the syntax used to define attributes and attribute-defaults.
To define an Attribute name for a property, use the following in your type.xml file, inside the <attributes> ... </attributes> section:
<attribute name="attr_name" type-property="property-name"/>
Set attr_name to the name of the Attribute, and property-name to the name of the property of your Type that you want to export.
For example, to define the Attribute name my-basedir for the deployment-basedir property as shown above, use this:
<type ... >
...
<attributes>
<attribute name="my-basedir" type-property="deployment-basedir"/>
</attributes>
...
</type>
Defining Attributes using a Setting
While it is common to set Attribute names on existing Type properties, this still limits you to the existing set of properties for Types, as new properties cannot be defined. Additionally, each Property in a Type already has a concrete semantic purpose, and breaking those semantics should be avoided.
However you can use the Setting type as a way to define any number of "custom properties" using Attributes. By creating a custom subtype of the Setting type, you can also imbue your Attributes with concrete semantics, which provides greater customization options, clear constraint configurations, and greater understandability of your model.
To create a custom Attribute using a Setting, first define a custom Setting subtype:
- Navigate to the Setting Type (or any existing subtype)
- Click the Create Subtype button
Once you have created your type, you can add an Attribute name to the settingValue property.
- Click the "Constraints" tab
- Click the "+" icon next to the settingValue property, enter a value, and click "Add":
Note: If you are creating a new Setting subtype, it is useful to examine existing Setting subtypes to see if they already fulfill the purpose you wish to achieve. Many of the built-in base Types already have an associated set of Setting subtypes, and many of them already define an Attribute name that can be used.
Using type.xml
To create a Setting subtype in a type.xml file, you must first have created a type.xml file for one of the Deployable types, e.g. Managed-Entity, Deployment, Service, Builder, etc. This is because Settings are not deployable, and so cannot be built into a Module archive. You can however define multiple Types in a single type.xml file, and it is useful to include Setting subtypes alongside the associated Type that will be using them, so in this example, we will create a new type.xml for the NewServiceSubType type, and add the new Setting subtype definition to the same file.
Run the ProjectBuilder create-type command, and enter the Name, description, and Supertype. You can select the default directory by pressing enter, or enter a new directory path to store the module definition.
Gozer:~ greg$ ctl -p demo -m ProjectBuilder -c create-type Name of type: NewServiceSubType Description of type: my service type Choose a supertype: ([Managed-Entity], Package, Builder, Deployment, Service) Service Directory where module files will be created: [/Users/greg/ctier3/ctl/src] Creating module definition files in directory: /Users/greg/ctier3/ctl/src ... ... Define commands and attributes in this file: /Users/greg/ctier3/ctl/src/modules/NewServiceSubType/type.xml
Now edit the type.xml file. You can add the definition of MyPortSetting to the end of the file, by adding another <type> element. Be sure to include the order attribute of the type, so that when building the type.xml it knows that the type definition doesn't require certain normally required elements.
Inside that element, add the <attributes> section, and define the my-port Attribute for the settingValue property:
<?xml version="1.0" encoding="UTF-8"?>
<types
xmlns:module="http://open.controltier.com/base/Modules#"
xmlns:type="http://open.controltier.com/base/Types#"
xmlns:cmd="http://open.controltier.com/base/Modules/Commands#">
<type name="NewServiceSubType" ...> ... </type>
<type name="MyPortSetting" role="concrete" uniqueInstances="true"
order="Setting">
<description>port for the server</description>
<supertype>
<typereference name="Setting"/>
</supertype>
<attributes>
<attribute name="my-port" type-property="settingValue"/>
</attributes>
</type>
</types>
Once you have saved the file, use the ProjectBuilder build-type command to build the type.xml definition. Optionally, use -upload -deploy options to upload the Module to Workbench, and then deploy it locally:
Gozer:~ greg$ ctl -p demo -m ProjectBuilder -c build-type -- -type NewServiceSubType -upload -deploy Base directory where module source files reside [/Users/greg/ctier3/ctl/src] Target directory where build files are generated [/Users/greg/ctier3/target] Building type using the buildmodule.xml via classloader converting type.xml for module: NewServiceSubType generating handlers... packaging module: NewServiceSubType Copying 1 file to /Users/greg/ctier3/ctl/src/modules/NewServiceSubType Copying 1 file to /Users/greg/ctier3/ctl/src/modules/NewServiceSubType Deleting: /Users/greg/ctier3/ctl/src/modules/NewServiceSubType/module.properties.temp Building jar: /Users/greg/ctier3/target/modules/NewServiceSubType-1.jar Uploading built module to server ... processing files in directory: /Users/greg/ctier3/target/modules scanning for files matching pattern: (NewServiceSubType)-([0-9]+)\.jar Uploading jar: /Users/greg/ctier3/target/modules/NewServiceSubType-1.jar to server: 'localhost' ... Installing new build of "NewServiceSubType" module from server ... Getting: http://localhost:8080/jackrabbit/repository/controltier/projects/demo/publish/modules/NewServiceSubType-head.jar To: /Users/greg/ctier3/ctl/var/tmp/downloads/demo/NewServiceSubType-head.jar Created dir: /Users/greg/ctier3/ctl/projects/demo/modules/NewServiceSubType Expanding: /Users/greg/ctier3/ctl/var/tmp/downloads/demo/NewServiceSubType-head.jar into /Users/greg/ctier3/ctl/projects/demo/modules/NewServiceSubType Attempting to get Service-head.jar ... Getting: http://localhost:8080/jackrabbit/repository/controltier/projects/demo/publish/modules/Service-head.jar To: /Users/greg/ctier3/ctl/var/tmp/downloads/demo/Service-head.jar Created dir: /Users/greg/ctier3/ctl/projects/demo/modules/Service Expanding: /Users/greg/ctier3/ctl/var/tmp/downloads/demo/Service-head.jar into /Users/greg/ctier3/ctl/projects/demo/modules/Service Attempting to get Deployment-head.jar ... Getting: http://localhost:8080/jackrabbit/repository/controltier/projects/demo/publish/modules/Deployment-head.jar To: /Users/greg/ctier3/ctl/var/tmp/downloads/demo/Deployment-head.jar Created dir: /Users/greg/ctier3/ctl/projects/demo/modules/Deployment Expanding: /Users/greg/ctier3/ctl/var/tmp/downloads/demo/Deployment-head.jar into /Users/greg/ctier3/ctl/projects/demo/modules/Deployment
Create an Resource
Once you have defined the Attribute name for the settingValue property, you can create a new Resource of your Setting subtype.
- Click the Resource tab, and click the "+" icon to create an new Resource.
- Enter a value for the Value field, and notice the "†" character next to the field. The "†" identifies that the property value has an Attribute name associated with it, and you can see the specific Attribute name by hovering over the character.
- Click the Save button
Once you have saved the Resource, you can see in the Properties tab that the value of the the settingValue property has been exported as the attribute named resource.attribute.my-port and has the value you set in the form:
Create a Resource in project.xml
If you are developing a resource model using the Project-v10.xml file, you would define your Setting resource in this way:
<!DOCTYPE project PUBLIC
"-//ControlTier Software Inc.//DTD Project Document 1.0//EN" "project.dtd">
<project>
<setting type="MyPortSetting" name="default-port"
description="default port value for the server"
settingValue="8080" settingType="port"/>
</project>
Load the project.xml file using the ProjectBuilder load-resources command:
Gozer:~ greg$ ctl -p demo -m ProjectBuilder -c load-resources -- -filename project.xml Loading "/Users/greg/project.xml" ... 1 file(s) have been successfully validated. Processing /Users/greg/project.xml to /Users/greg/ctier3/ctl/var/tmp/projectxml-1012385295.xml Loading stylesheet /Users/greg/ctier3/ctl/modules/ProjectBuilder/lib/load-resources/projectxml/project.xsl Mapping XML to properties ... Collecting object attributes ... Batching object attribute updates ... Batching resource and referrer updates ... Executing batch update ...
Sharing Attributes
Like other properties, Attributes are generated in the context of the Resource that they receive their value from. Attributes can be "imported" from one resource to another by adding that resource as a Child resource of the other.
Remember: it is always the case that a Resource can only be added as a child resource to another Resource whose Type allows that kind of child resource via it's resources constraint. (See Constraints.)
Attributes are "imported" to the Resource context under the same rules that all child resource properties are included in the Properties View. For each Type, that definition of how that View is generated can include all Child resources, all Parent resources, or both. And the view can extend up to 3 "degrees" away in the resource model. (See Type modeling.)
In the simplest model, and by default, each Type's property View includes all immediate Child resources (1 degree away).
Allowing the child resource Type
To allow resources of your new Setting type to be added as a child resource to other Resources you must make sure that the Constraints for your parent Type are configured to allow it.
- Navigate to the Type of the Resource you wish to add the Setting to.
- Click the Constraints tab
- for the resources property, click the pencil icon to Edit the constraint
In this example a subtype of Service called "NewServiceSubType":
In the form, click the "+" icon next to "Allowed Types":
In the (potentially very long!) list of available types, scroll to your Setting subtype and click the checkbox just to the left of it. Optionally, you may select the checkbox on the right-side which indicates that only a single resource of that type is allowed to be added, called a Singleton constraint.
Click the "Save" button when you have finished.
Your Type should show the Setting subtype under the resources constraint.
Now you can add your Setting resource as a resource to any resource of that Type.
Setting the allowed child resource constraint in type.xml
To set the allowed child constraint in type.xml, refer to the Type-v10.xml#constraints reference. In our example, we would add <dependency-constraint> to the <constraints> section of the NewServiceSubtype type definition:
<type name="NewServiceSubType" ...>
...
<constraints>
<!-- Define constraints of the Type here -->
<dependency-constraint kind="child" enforced="true">
<allowedtypes>
<typereference name="MyPortSetting"/>
</allowedtypes>
<singletontypes>
<typereference name="MyPortSetting"/>
</singletontypes>
</dependency-constraint>
</constraints>
...
</type>
Adding the Setting resource
- Navigate to the Resource you wish to add your Setting to.
- Click the "Child Resources" section, and the "Add..." button.
- Select your Setting resource.
- Click the "Save" button
Notice that under the Attributes section for the Resource, you can now see the name of the Attribute you defined in the Type, and the value that you set in your Setting resource.
Add the Setting Resource in project.xml
Add the setting resource you defined earlier to the Service resource by modifying your project.xml like so:
<!DOCTYPE project PUBLIC
"-//ControlTier Software Inc.//DTD Project Document 1.0//EN" "project.dtd">
<project>
<setting ... />
<deployment
type="NewServiceSubType"
name="myService"
description="my Service resource"
installRoot=""
basedir="">
<resources>
<resource name="default-port" type="MyPortSetting" />
</resources>
</deployment>
</project>
Setting Attribute Defaults
Like Properties, it is useful to be able to define a default value for Attributes as well. This will let you use the Attribute value in Commands and Command Options without fear that no Attribute value will be available, even if your Resource doesn't have an appropriate child resource.
When you view any Type, you can see the set of potential Attributes that that type "imports" into its resource context. Under the Constraints tab, scroll to the "Imported Attributes" section:
The list of Imported Attributes is the set of all Attributes defined for each Type that is allowed as a resource under the resources constraint (see #Allowing the child resource Type). Thus the list you see may be very long if the resources constraint is very general. If you change that constraint to be much more specific, the list of potentially imported Attributes will get smaller.
Each row in the list shows the Attribute Name, any Default value, and the list of Types from which the Attribute is imported. (Note that more than one Type may define the same Attribute name on one of its properties.)
To set a Default value for an attribute, find the Attribute name you wish to set the default for, and click the Pencil icon to edit the default, then click the Set button:
Once a default is set, you can click the "x" icon to remove it, or click on the textual value itself to edit it:
Note: If an Attribute Default value is inherited from the Parent type, a small "i" will be shown next to the value. You can override this value by editing the Default, but you cannot clear the default completely. It will revert to the inherited Default value.
Once you have set an Attribute Default value, any Resource of that Type will always see a value for the Attribute name, even if no child resource is attached that exports that Attribute.
Setting Attribute Defaults in type.xml
Add a <attribute-default> element to the <attributes> section of your type.xml:
<type name="NewServiceSubType" ...>
...
<attributes>
<attribute-default name="my-port" value="8080"/>
</attributes>
...
</type>
Using Attribute Values
Attributes are included in the resource.properties that are generated for each Resource.
In an Ant based command handler, you can refer to the value of an Attribute using the syntax: ${resource.attribute.ATTRIBUTE}, replacing "ATTRIBUTE" with the name of the attribute.
You can also use the value in the Execution String, or Argument String of a Shell command.
The most typical method of using Attribute values is to provide a default value for an Option for a command. For more information on this see: Option defaulting with an attribute or literal.
Using Multiple Values
If you have more than one child resource that exports the same Attribute name, you will see a slightly different set of Properties get generated:
-
resource.attribute.NAME- contains a single value (See Caveat below) -
resource.attribute.NAME.list- contains a comma-separated list of values -
resource.attribute.NAME.size- contains the size of the list (integer) -
resource.attribute.NAME.X- contains the value of list itemX
For example, if you added another MyPortSetting resource to the Service resource, you would see this set of properties:
This allows you to use multiple values, if you so desire.
- Caveat: multiple Attribute values should only be used when you are writing Ant based command handlers and want to explicitly operate on a list of values. The value of the normal property typically used in a single-value Attribute,
${resource.attribute.NAME}will evaluate to the first value in the list. The order of the items in the list is governed by proximity (i.e.. closeness based on the View Constraints), as well as the "startup-rank" property. If two Resources have the same startup rank value, then their order in the list is not defined. The order for Resources without this property (such as Settings), is not defined.
Appendix
Complete type.xml example
This is the complete type.xml example which includes the NewServiceSubType with its attribute default and dependency constraint, and the MyPortSetting type, with its attribute definition:
<?xml version="1.0" encoding="UTF-8"?>
<!--
This document is used to define one or more Types.
-->
<types
xmlns:module="http://open.controltier.com/base/Modules#"
xmlns:type="http://open.controltier.com/base/Types#"
xmlns:cmd="http://open.controltier.com/base/Modules/Commands#">
<type
name="NewServiceSubType"
role="concrete"
uniqueInstances="true">
<description>My service subtype</description>
<supertype>
<typereference name="Service"/>
</supertype>
<command-settings>
<notification notify="false"/>
<template-directory></template-directory>
<dependency-view parents="false" children="true" proximity="1"/>
<logger name="NewServiceSubType"/>
</command-settings>
<attributes>
<attribute-default name="my-port" value="80"/>
</attributes>
<constraints>
<!-- Define constraints of the Type here -->
<dependency-constraint kind="child" enforced="true">
<allowedtypes>
<typereference name="MyPortSetting"/>
</allowedtypes>
<singletontypes>
<typereference name="MyPortSetting"/>
</singletontypes>
</dependency-constraint>
</constraints>
<commands>
<!-- Define commands here -->
<!-- See the Documentation on the ControlTier Wiki: -->
<!-- http://apps.sourceforge.net/mediawiki/controltier/index.php?title=Type-v10.xml#commands -->
</commands>
</type>
<type name="MyPortSetting"
role="concrete"
uniqueInstances="true"
order="Setting">
<description>port for the server</description>
<supertype>
<typereference name="Setting"/>
</supertype>
<attributes>
<attribute name="my-port" type-property="settingValue"/>
</attributes>
</type>
</types>
Complete project.xml example
This is the complete project.xml example, defining a single Setting resource and a Deployment object which has the Setting as a child resource:
<!DOCTYPE project PUBLIC
"-//ControlTier Software Inc.//DTD Project Document 1.0//EN" "project.dtd">
<project>
<setting type="MyPortSetting" name="default-port"
description="default port value for the server"
settingValue="8080" settingType="port"/>
<deployment
type="NewServiceSubType"
name="myService"
description="my Service resource"
installRoot=""
basedir="">
<resources>
<resource name="default-port" type="MyPortSetting" />
</resources>
</deployment>
</project>
| ||||||||||||||














