Content modeling in Alfresco ECM and Citeck ECOS

What is content modeling

Systems of ECM class allow work with any content: documents, images, audio and video files, as well as files of any other types. Along with these files, such systems can save certain amount of additional information (metadata, attributes). In general case, an enterprise has its own set of document types (e.g. incoming documents, office memorandums, orders, …), and each type has its set of attributes (registration number, contractor, branch, responsible person, …). That's why an ECM system shall allow addition of new data types and attributes.

Alfresco ECM system allows it by the means of content modeling function. Alfresco administrator sets models (XML files), in which data types and their attributes are defined. The attributes also have some characteristics (mandatory status, default value etc.), which are also set during the modeling.

Who is engaged in content modeling

In ECOS system models for a wide range of applications are already available. However, during the implementation of the system at any company it may occur that any types and attributes are lacking in standard models. In this case, implementing engineers shall know how to define new types and attributes and set required characteristic values for them.

Standard modeling options in Alfresco

The following can be defined in Alfresco models:

  • Name spaces (namespaces)
  • Object classes: types and aspects (types, aspects)
  • Properties and associations (properties, associations)
  • Constraints (constraints)

The models are XML files with following structure:


<model name="letters:lettersModel"
       xmlns="http://www.alfresco.org/model/dictionary/1.0">
    <description>Citeck EcoS letters</description>
    <author>Citeck</author>
    <version>1.0</version>
    <imports> … </imports>
    <namespaces> … </namespaces>
    <constraints> … </constraints>
    <types> … </types>
    <aspects> … </aspects>
</aspect>

Mandatory elements of a model are name, xmlns and namespaces. Practically, each model also has imported name spaces (imports) and type (types) or aspect (aspects) definitions, for which this model is intended.

Types

The model allows definition of data types (types). For example, ”Incoming document” type can be defined. For the type properties (e.g. reference number) and associations (e.g. contractor), as well as aspects (e.g. classified) can be defined.

Each object is defined by one (and only one) type (i.e. an object cannot be an incoming document and an order simultaneously). However, parent type (parent) is always specified for the type, which inherits all its properties, associations and aspects.

Types are allocated in types section of the model. name is a mandatory element for type definition; practically, each definition includes also parent, other elements can be omitted. Each type definition has the following aspect:

  

  <type name="letters:income">
    <title>Incoming</title>
    <description>Incoming Document</description>
    <parent>idocs:doc</parent>
    <properties> ... </properties>
    <associations> ... </associations>
    <overrides> ... </overrides>
    <mandatory-aspects> ... </mandatory-aspects>
</type>


Properties and associations

Properties and associations can be regarded as type attributes. The difference consists in the fact that properties refer to a primitive data type (string, number, date, …), and associations refer to data types defined in the models (incoming, legal entity, user, …).

Along with data type, it can be specified in a model, if the property (association) is mandatory (mandatory) and if the property (association) can contain multiple values (multiple, many). For properties, default values (default), constraints (constraints) and index control directives (index) can be specified.

Definitions of the properties are listed in properties section of the model. Mandatory elements of property definition are name and type, other elements can be omitted. Example:


<property name="letters:deliveryMethod">
    <title>Delivery Method</title>
    <type>d:text</type>
    <mandatory>true</mandatory>
    <multiple>false</multiple>
    <default>express</default>
    <constraints> ... </constraints>
    <index enabled="true"> … </index>
</property>



Definitions of the associations are listed in associations section of the model. Mandatory elements of each association are name and target.class. In the field target.class the required type or aspect of the target object shall be specified. Practically, absence of constraints for a source object (mandatory=false, many=true) are also specified.


<association name="letters:addressee">
    <title>Destinee</title>
    <source>
        <mandatory>false</mandatory>
        <many>true</many>
    </source>
    <target>
        <class>idocs:contractor</class>
        <mandatory>false</mandatory>
        <many>false</many>
    </target>
</association>


Elements source and target in an association definition stand for two linked objects. An association can be represented as an arrow linking two objects, then source is from where the arrow comes and target is where the arrow points. As it is clear from the definition, class shall be assigned for a target object and shall not be assigned for a source object. The reason is the fact that class for source object is type or object, in which this association is defined.

Mandatory and Many settings determine arity of the link on each end. Example:

  • if mandatory = true and many = true, than link arity is: 1…*;
  • if mandatory = false and many = true, than link arity is: 0…*;
  • if mandatory = false and many = false, than link arity is: 0…1;
  • if mandatory = true and many = false, than link arity is: 1...1.

Child associations

Each association sets a link between two objects, and this link can be hierarchical of non-hierarchical. Associations that set a hierarchical link are called child associations, others are called peer associations. In child associations linked objects are parent and child, in peer associations they are just source and target object.

Child associations are an essential element of Alfresco system. In particular:

  • if parent is deleted, all its children are deleted too;
  • for child objects name uniqueness can be controlled (it can be deactivated during the definition of child association);
  • over child association object access privileges are propagated (it can be deactivated for individual objects);
  • over child association change time stamps are propagated (it can be deactivated during the definition of child association).

In the model, child associations are located in associations section, like common associations, but instead of association child-association is written:


<child-association name="cm:contains">
    <source>
        <mandatory>false</mandatory>
        <many>true</many>
    </source>
    <target>
        <class>sys:base</class>
        <mandatory>false</mandatory>
        <many>true</many>
    </target>
    <duplicate>false</duplicate>
    <propagateTimestamps>true</propagateTimestamps>
</child-association>



In case of child associations, source object stands for parent, and target object for child. The setting duplicate=false allows activation of name uniqueness control, and the setting propagateTimestamps=true allows activation of change time stamp propagation.

Aspects

Aspects allow adding supplementary properties and associations, as well as other aspects to the objects. In this respect, they are similar to types, but, unlike the types, an object can have multiple various aspects. An aspect can also have parent aspect, but, unlike the types, it is not mandatory. If type names are usually a noun (order, contract), aspect names are adjectives or verbs (classified, has an author).

Definitions of the aspects are listed in aspects section of the model. Each definition looks similar to type definition:


<aspect name="letters:hasDelivery">
    <title>…</title>
    <description>…</description>
    <parent>…</parent>
    <properties> ... </properties>
    <associations> ... </associations>
    <overrides> ... </overrides>
    <mandatory-aspects> ... </mandatory-aspects>
</aspect>



The only mandatory element of aspect definition is the name. An aspect can be created, which only has a name; such aspect is called marker aspect.  By means of this, objects can be distinguished by presence or absence of such marker aspect. For example, standard model has an aspect cm:personDisabled, which is superposed to the object cm:person (user), if it is not active.

Names and name spaces

Each object determined in the model – including types, aspects, properties and associations, as well as the model itself – shall have a unique name (name). In order to prevent name conflicts, Alfresco uses name spaces (namespace): each name (of type, aspect, …) consists of two parts: name space and local name, and local name shall only be unique within its name space. Each model can define multiple name spaces, and each name within the model shall be contained in these name spaces.

Name spaces are specified in a long string (URI), for example: http://www.alfresco.org/model/content/1.0. Names are also long enough, e.g. «folder» type name: {http://www.alfresco.org/model/content/1.0}folder. In order to shorten the entry, name space prefixes are used, e.g. the above mentioned name space has a prefix cm (which means content model), and the above mentioned name is shorter in prefix entry: cm:folder.

Name spaces are defined in namespaces section as follows:

<namespace uri="http://www.citeck.ru/model/letters/1.0" prefix="letters" />

If the model uses names from other models (it is an ordinary case), they are imported in the similar manner in imports section:


<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d" />
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm" />


Constraints

Constraints can be specified for property values (constraints). The following constraint types are supported in the models:

  • LIST – the property shall have a value from the list of allowable values (allowedValues)
  • MINMAX – the property shall have a value not less than (not more than) the preset one (for numeric properties)
  • LENGTH – the property shall have a length not less than (not more than) the preset one (for string properties)
  • REGEX – the property shall correspond to a regular expression

Example of a constraint set in the model:


<constraint name="letters:deliveryMethod" type="LIST">
    <parameter name="allowedValues">
        <list>
            <value>snailmail</value>
            <value>courier</value>
            <value>fax</value>
            <value>express</value>
        </list>    
    </parameter>
</constraint>
 

Constraints can be specified both within the model and within the property, the value of which is to be constrained. If a constraint is specified within the model, a name is set for it, so that this constraint can be referred to using this name:

<property name="letters:deliveryMethod">
    ...
    <constraints>
        <constraint ref="letters:deliveryMethod" />
    </constraints>
</property>


Redefinitions

Redefinitions allow specification of properties in child types or aspects.

For example, if we have ”document” data type, for which a “number” property is defined, we can set this property as mandatory in “order” child data type, set a default value for it or add a constraint for it.

Example of a redefinition that sets the property as mandatory:       


<overrides>
    <property name="letters:deliveryMethod">
        <mandatory>true</mandatory>
    </property>
</overrides>

Localization of models

If model operation in one language is sufficient, attributes title and description can be used; they can be set for all named objects of the model: types, aspects, properties and associations.


<type name="letters:income">
    <title>Incoming</title>
    <description>Incoming Document</description>
    ...
 

If translations of the model to other languages are required, these translations are located in individual files with extension *.properties – one file for each target language.

Properties files are also required for localization of LIST type constraints.

Example of a properties file:

listconstraint.letters_deliveryMethod.snailmail=Mail
letters_lettersModel.type.letters_income.title=Incoming
letters_lettersModel.property.letters_deliveryMethod.title=Delivery Method
letters_lettersModel.association.letters_addressee.title=Destinee

Heritage

It is a frequently appearing task to create the same property (association) in multiple various types. However, the mechanism of the models allows only one definition of each property (association), in any type or aspect. Therefore, in order to solve this problem, we have to involve heritage mechanism.

There are two options of property (association) heritage: inheriting from parent type (aspect) with specification of parent element, or inheriting from mandatory aspects, specifying mandatory-aspects.

The main difference is that the parent type can be only one, and mandatory aspects can be multiple; that is why aspects are more convenient option for data structuring.

Downloading models

Actual Alfresco models are stored in RAM memory of the repository, so an XML file shall be downloaded in Alfresco in order to begin to work. The system offers two options to do this:

  • dictionarybootstrap – downloading the model during server start;
  • dynamicmodels – downloading the model during server operation.

To use dictionarybootstrap option, the following is required:

  1. put the model (e.g. file lettersModel.xml) in folder tomcat/shared/classes/alfresco/extension/model;
  2. put the localization (e.g. files letters*.properties) in folder tomcat/shared/classes/alfresco/extension/messages;
  3. create file tomcat/shared/classes/alfresco/extension/lettersModel-bootstrap-context.xml with the following content:


<?xml version='1.0' encoding='UTF-8'?>
<beans xmlns="http://www.springframework.org/schema/beans">
  <bean id="letters.dictionaryBootstrap" parent="dictionaryModelBootstrap">
    <property name="models">
      <list>
        <value>alfresco/extension/model/lettersModel.xml</value>
      </list>                   
    </property>
    <property name="labels">
      <list>
        <value>alfresco/extension/messages/letters</value>
      </list>
    </property>
  </bean>
</beans>


     4. reboot Alfresco repository.

To use dynamic models option, the following is required:

  1. put the model (e.g. file lettersModel.xml) in folder tomcat/shared/classes/alfresco/extension/model;
  2. put the localization (e.g. files letters*.properties) in folder tomcat/shared/classes/alfresco/extension/messages;
  3. visit the link http://localhost:8080/alfresco/faces/jsp/login.jsp
  4. log on as administrator;
  5. visit the link http://localhost:8080/alfresco/faces/jsp/admin/repoadmin-console.jsp
  6. execute the command to download the model:
    deploy model alfresco/extension/model/lettersModel.xml
  7. execute the command to download the localization:
    deploy messages alfresco/extension/messages/letters
  8. execute the command to unload the model:
    undeploy model lettersModel.xml
  9. execute the command to unload the localization:
    undeploy messages letters

Dynamic downloading of a model (during repository operation) can be a little unstable. For example, nothing can be deleted from the model (types, properties etc.), only new ones can be added, and new constraints cannot be imposed (e.g. properties and associations cannot be set as mandatory and the list of mandatory objects cannot be completed). In order to do that, the model shall be unloaded and then deployed again. However, the model cannot be unloaded, if the repository contains objects with types or aspects set in this model; all these objects shall be deleted at first.

Official Alfresco documentation

You can find detailed information on content modeling by the means of Alfresco in official documentation of Alfresco and other resources.

http://docs.alfresco.com/4.2/concepts/content-modeling-about.html

http://wiki.alfresco.com/wiki/Data_Dictionary_Guide

http://wiki.alfresco.com/wiki/Constraints

http://ecmarchitect.com/images/articles/alfresco-content/content-article.pdf

In the section below we give some recommendations on modeling based on our experience.

Rules and recommendations

Name spaces

  • A model can set multiple name spaces.

A good classification of names in spaces contributes to better code quality (it is more readable etc.)

  • Different models cannot set the same name space

An attempt to download a model which sets an already set name space leads to error.

  • One name space, one prefix

Prefix is used in the major part of the system as a substitute for name space, so they shall be interchangeable. Herewith a prefix is used, that is set in the model which defines the name space. It is recommended to use the same prefix in all other models, as it improves code quality.

  • In a model names can be defined only with the name space defined in the same model.

It is allowed to define a name from an imported name space, but it can lead to conflicts, if an object (e.g. property) with the same name is added in other model.

Naming

  • Names should contain only Latin letters.
  • Names of type and aspect should differ.
  • It is recommended not to duplicate names of type (aspect) and associations.

Otherwise CMIS search and therefore integration with many applications wouldn’t work.

  • It is recommended not to duplicate names of properties and associations

In some parts of the system (for example, on the forms) there are name-related references to properties and associations, so it is assumed that the name of some property and association is unique. In case this tacit assumption is not implemented, unpredictable behavior of such components might be expected.

  • Conclusions from the above-mentioned information: it’s better to make all names unique. In order to achieve this you can develop some system for names formation.
  • It is recommended to avoid creating mandatory constraints (mandatory), especially for associations.

Constraints

In case some mandatory association is programmed in a model, it is impossible to create an object without this association. If this constraint is applied after the creation of object (i.e. model has been updated), one might be totally unable to work with objects without this association.

  • It is recommended to avoid applying constraints on a source-object of an association.

Target-object of an association is usually regarded as an attribute. If constraints on a source-object are applied, it might make it impossible to create objects while some unclear messages about an error would be displayed. Absence of constraints on a source-object means that source.mandatory = false, source.many = true.

Inheritance

  • It is mandatory for parent type and should be represented by another type.

Formally it is permitted to create a type without parent type but system will work improperly with such an object, in the worst case such objects are not available even for a system administrator.

  • Parent is not mandatory for aspect. If it’s set, it should be some other aspect.
  • In case it’s necessary to use property (association) in several types, it’s better to place this property (association) into a separate aspect and define this aspect as mandatory.
  • Redefinitions (overrides) are effective only for properties inherited from a type

In order to make a property inherited from aspect mandatory you can use functional of Citeck ECOS modeling.

Other

  • Please don’t try to add new primitive data-type (data-type).

At the present moment it’s impossible to create an object that has a property with non-standard data-type, there is no exception for data-types which correspond with supported Java class (for example, a line).

  • Sequence order of elements plays an important role in models. For example, elements are placed in a model in the following order: imports, namespaces, constraints, types, aspects. Detailed information about elements order is in XSD-scheme of models, see the file modelSchema.xsd. If the order of elements is violated, you cannot read or download the model.

Modeling resources in Citeck ECOS

What do Alfresco models lack?

Alfresco models make it possible to define new types and attributes but have some drawbacks. Some of the main drawbacks:

  • a few attributes’ characteristics (mandatory, multiple, protected, default, title, description, constraints);
  • characteristics can be set only as constants (true/false, line, number), expressions are not applicable;
  • characteristics in associations are not fully supported (in particular, it’s impossible to set a default value or constraints);
  • redefinitions are not fully supported (associations cannot be redifined; properties can be redefined only if its properties inherited from parent type/aspect).

System Citeck ECOS includes modeling resources that remedy all these drawbacks:

  • extended list of attributes’ characteristics (characteristics such as relevant, value-title, value-description are supported in addition to the standard);
  • characteristics are properly supported in properties as well as in associations;
  • characteristics can be set in a form of expressions in several supported languages;
  • flexible redefining of any characteristics of properties and associations.

For this purpose functionality of invariants was developed in the Citeck ECOS.

Definition of invariants

Invariant is some kind of affirmation about the attribute’s characteristic that should be true. An example of invariant: “property Number is mandatory if status of the document is not New”. In this example attribute is “Number”, characteristic is “mandatory”, affirmation is “mandatory if …”.

With the help of invariants you can set the following attributes’ characteristic:

  • mandatory – obligation – an attribute is mandatory or not
  • multiple – plurality – an attribute can include several values or not
  • relevant – relevance – an attribute has a meaning or not (it isn’t displayed or considered if it has no meaning)
  • protected – systemic – in case an attribute is true, it is maintained by the system; in case an attribute is false, the user can set value of this attribute
  • valid – correctness – value of an attribute is correct or not
  • title – name of the attribute
  • description – description of the attribute
  • value – attribute’s value – attribute’s value can be set explicitly (computable values)
  • default – default attribute’s value
  • options – possible attribute’s values
  • value-title – name of the attribute’s value
  • value-description – description of the attribute’s value

Different characteristics have implicit connection. For example, an irrelevant attribute (relevant = false) is always correct (valid = true). Value (value) of a multiple attribute (multiple = true) is an array; value of a single attribute (multiple = false) is a unit value. This rule as well as some other logical rules is encoded in Citeck ECOS in order to assist modeling process.

In addition to characteristics of properties and associations you can control characteristics of such special attributes as:

  • parent – parent element
  • parentassoc – child association connecting with parent element

Thus, you can define where an object should be created (or where objects should be created on default).

Values of characteristics can be set in one of the supported languages:

  • javascript
  • freemarker
  • criteria
  • explicit

Languages JavaScript and FreeMarker are common for Alfresco; the system has quite diverse API for these languages. Criteria language is a search language, it’s added in ECOS in order to simplify search. It is an alternative for standard Alfresco languages that are used for search such as Lucene and FTS. Explicit language is just explicitly set constant values: true, false, free strings, numbers and values lists.

For example, invariant “property Number is mandatory if status of the document is not New” can be easily described in the language JavaScript:


<property name="idocs:registrationNumber">
    <invariant on="mandatory" language="javascript">
        node.properties['idocs:documentStatus'] != 'new'
    </invariant>
</property>

It’s quite easy to describe arbitrary values in javascript, including logical values, numeric values, repository objects and arrays of such values. Freemarker is more suitable for setting of strings, for example:

<invariant on="value" language="freemarker">
 Договор №${node.properties["idocs:registrationNumber"]!'б/н'} с  
 ${node.assocs['contracts:contractor'][0].properties['idocs:juridicalTitle']
</invariant>

At the present moment support of the language FreeMarker is still very limited that’s why it is recommended to use the language JavaScript.

For invariants description the subset JavaScript API and FreeMarker API is available:

  • Node API: nodeRef, typeShort, aspects, parent, properties, assocs, name, isSubType(), hasAspect(), hasPermission();
  • Utilities: message().

Description of these properties and methods you can find in the Alfresco documentation open for public:

http://docs.alfresco.com/4.2/concepts/API-JS-intro.html

http://docs.alfresco.com/4.2/references/API-FreeMarker-intro.html

Properties and methods of access available in invariants allow performing only reading operations, it is quite enough to set arbitrary expressions for invariants.

Files of invariants

Usage of invariants doesn’t mean that you don’t need to download models, vice versa, this option is extended. Invariants are downloaded to Alfresco as separate XML-files that accompany models’ files.

File of invariants has the following structure:


<?xml version="1.0" encoding="UTF-8"?>
<invariants xmlns="http://www.citeck.ru/ecos/invariants/1.0">
    <imports> ... </imports>
    <!—definitions of invariants -->
</invariants>
   <!—definitions of invariants -->

Instead of the comment <!-- definitions of invariants --> definitions of invariants are listed in the file in the following way:

<type name="letters:income">                
    <association name="idocs:legalEntity">
        <invariant on="default" language="javascript">
            node.assocs["letters:outcome"][0]
                .assocs["idocs:legalEntity"][0]
        </invariant>
    </association>
</type>

It is written in this invariant that the legal entity of the incoming document (receiver) is equivalent on default to the legal entity of the outgoing document (sender).

Invariants are placed in the definite area of action (scope) that can be restricted by special elements:

  • type – restricts invariant’s scope by the type that is defined by name (name);
  • aspect – aspect defined by name;
  • property – property defined by name;
  • association – association defined by name;
  • properties – all properties with the specified type (type), for example, all properties of strings or all properties in general if the type isn’t specified;
  • associations – all associations with the specified type, for example, all associations with users or all associations in general if the type isn’t specified.

In the invariant’s scope there should be one (and only one) attribute constraint (one of property, association, properties, associations). Several attribute constraints are prohibited. In the invariant’s scope there can be a class constraint (type or aspect), several class constraints are not to be supported. In case there are no class constraints for the invariant, it is applied to the specified attributes regardless to the class (type or aspect).

Scopes can be freely inserted into each other, for example:


<type name="type1">                         
    <association name="assoc1">
        <!—invariant definition for type1.assoc1 -->
    </association>
    <property name="prop1">
        <!-- invariant definition for type1.prop1 -->
    </property>
    <properties type="d:text">
        <!-- invariant definition for text properties in type1 -->
    </properties>
</type>
<property name="prop2">
    <!-- invariant definition for *.prop2 -->
    <type name="type2">
        <!-- invariant definition  for type2.prop2 -->
    </type>
    <aspect name="aspect2">
        <!-- invariant definition for aspect2.prop2 -->
    </ aspect >
</property>

All names defined in the attributes name and type should be from namespaces listed in the section imports. In this section namespaces are listed in a manner similar to the same of models:

<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d" />
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm" />
<import uri="http://www.citeck.ru/model/content/idocs/1.0" prefix="idocs" />
<import uri="http://www.citeck.ru/model/letters/1.0" prefix="letters" />


In the invariant itself you should specify for what characteristic (on) and in which language (language) this invariant is written. Expression in the specified language is placed as a text inside the element invariant.

The following objects are available for expressions’ description:

  • node – repository object for which the invariant sets the attribute’s characteristic;
  • value – current value of the attribute;

Other standard objects:

  • person – current user;
  • companyhome – root of the repository;
  • userhome – home folder of the user;
  • message – option for unnaming of localization codes.

Objects node, person, companyhome and userhome are the objects of the class Node that’s why these objects represent the same API for access (nodeRef, parent, properties, assocs, …).

Downloading of invariants

You can download invariants right after start of the server with the help of the bootstrap mechanism (similar to the models download method). In order to do so in the file *-context.xml please set the following strings:


<bean parent="invariantsDeployer">
    <property name="location" 
              value="alfresco/extension/invariants/letters-invariants.xml" />
    <property name="priority" value="EXTEND" />
</bean>

In the property location you define where the XML-file with invariants is located in relation to the classpath root (folder tomcat/shared/classes). In the property priority you define priority of the invariants’ file. The priority allows redefining of existing invariants in files having higher priority. The following priorities are supported in the invariants (from the lowest to the highest):

  • COMMON – most common priority, invariants for a wide variety of attributes;
  • MODULE – priority of modules ECOS – invariants for attributes of different types of documents;
  • EXTEND – extensions priority
  • CUSTOM – implementations priority

Developers of ECOS use priorities COMMON and MODULE, implementation engineers of ECOS – priorities EXTEND and CUSTOM.

You can use attribute final in the invariant in order to prohibit redefining. Though final-invariants can redefine other final-invariants.

<invariant on="…" language="…" final="true"> ... </invariant>

Invariants processing

Support of invariants means that in certain parts of the system their values are calculated and taken into consideration in the logic of documents processing.

For example, when you save a document the following invariants are taken into consideration:

  • value, default, multiple – to calculate attributes’ values;
  • relevant, mandatory, valid – to check relevance, obligation and correctness.

In case the system found out during the process of saving that some attribute is incorrect, saving is prohibited.

Invariants are also supported in the forms of the system ECOS. Besides, expressions of invariants are calculated when user fulfills the form, thus, user can see at work all rules written in a form of invariants.

When invariants for a certain attribute of a certain object are calculated improper invariants are cast out while proper ones are sorted out in the following way:

  • first invariants with attribute final, then without it;
  • first invariants for certain attributes (property, association), then for arbitrary attributes (properties, associations);
  • first invariants with priority CUSTOM, then EXTEND, then MODULE, and finally COMMON;
  • first invariants suitable for non-mandatory aspects of the object, then for type of the object, then for mandatory aspects of the type, then for parent type, then for mandatory aspects of the parent type, etc., and finally invariants without class constraints.

Criteria language

Criteria is a search language. It is very easy to specify invariants for characteristics value, default, options in attributes containing references to the repository objects (mainly they are associations) using this language. Expression in the criteria language is a search request that includes search criteria. Each criterion consists of three parts:

  • attribute – name of attribute (name) according to which a search should be launched or a special attribute (see below);
  • value – sought value of attribute;
  • predicate – predicate identifier that compares actual and sought values of attribute (value).

An example of the invariant defined in the criteria language:


<type name="letters:income">
    <property name="parent">
        <invariant on="default" language="criteria">
            <criterion attribute="path" predicate="path-equals" value="/app:company_home/st:sites/cm:letters/cm:documentLibrary/cm:income" />
        </invariant>
    </property>
</type>

In this case search is performed on the basis of the special attribute path, the predicate path-equals (equality of path) and value (value) and includes route to the folder income (Income). Thus, we determine in what folder incoming documents should be created on default.

Possible predicate values depend on the type of attribute:

  • line (d:text, d:mltext):
    • string-contains, string-starts-with, string-ends-with
    • string-equals, string-not-equals
    • string-empty, string-not-empty
  • numeric (d:int, d:long, d:float, d:double):
    • number-equals, number-not-equals
    • number-less-than, number-less-or-equal
    • number-greater-than, number-greater-or-equal
  • date and time (d:date, d:datetime):
    • date-equals, date-not-equals
    • date-greater-or-equal, date-less-than
  • logical (d:boolean):
    • boolean-empty, boolean-not-empty
    • boolean-true, boolean-false
  • associations:
    • assoc-contains, assoc-not-contains
  • special attribute type:
    • type-equals, type-not-equals
  • special attribute aspect:
    • aspect-equals, aspect-not-equals
  • special attribute path:
    • path-equals – равенство по пути
    • path-child –contained directly inside the defined path
    • path-descendant – contained inside (on any nesting depth)
  • special attribute parent:
    • parent-equals, parent-not-equals

Several criteria can be set in one invariant, in this case all of them should be executed (i.e. logic AND is used).

Insertions in the FreeMarker language can be added to the value, for example, the following invariants are set for the properties Type and Kind:


<property name="tk:type">
    <invariant on="options" language="criteria">
        <criterion attribute="type" predicate="type-equals"
                   value="cm:category" />
        <criterion attribute="parent" predicate="parent-equals"
                value="workspace://SpacesStore/category-document-type-root" />
    </invariant>
</property>
<property name="tk:kind">
    <invariant on="options" language="criteria">
        <criterion attribute="type" predicate="type-equals"
                   value="cm:category" />
        <criterion attribute="parent" predicate="parent-equals"
                   value="${node.properties['tk:type'].nodeRef}" />
    </invariant>
    <invariant on="relevant" language="javascript">
        node.properties["tk:type"] != null
    </invariant>
</property>

In other words the following values, possible for the property Type, are subcategories of the special category “category-document-root-type”; possible values for the property Kind are subcategories of the specified Type. In case a type isn’t specified, the property Kind isn’t relevant.