NexJ Logo

Using facets to enhance metadata

You can use the facets feature to assign customizable properties to classes (including aspects), class attributes, and class events.

This allows you to organize and filter metadata. For example, you can create a facet called "ui_component" and assign it to all class attributes that are reflected in the user interface. You can later use the facet filter to quickly identify these attributes.

First, create a definition file that defines the facet you plan to use. You can add validation to the definition, so that the system checks whether the facet is valid when it is being assigned. Then, assign the facet to the classes, attributes, or events to which it applies. You can specify that any inherited facet values can be overridden.

Filtering using facets

After facets have been assigned to attributes or events, you can search for specific attributes or events based on the assigned facet names and, optionally, their values. In NexJ Studio, on the Attributes tab or Events tab for the class, enter the search criteria in the search field above the attribute list or events list. For example:

  • Enter facetName1 to find attributes or events with facetName1assigned.
  • Enter facetName1 facetName2 to find attributes or events with either facetName1 or facetName2 assigned.
  • Enter (facetName3 value1 value2) to find attributes or events with facetName3 assigned, where the value for the facet is either value1 or value2.
  • Enter facetName1 facetName2 (facetName3 value1 value2) to find attributes or events with either facetName1, facetName2, or facetName3 assigned, where the value for facetName3 is either value1 or value2.

Using facets programmatically

In addition to using facets to filter and organize metadata, you can access them programmatically by using the Scheme language.

There are two commands you can use to determine facet information.
findFacetValue
Returns the value of the specified facet. Format: (<obj>'findFacetValue "<FacetName>") where <obj> is a metaclass, attribute, or event.

hasFacet
Returns #t if the facet exists, regardless of facet value. Format: (<obj>'hasFacet "<FacetName>") where <obj> is a metaclass, attribute, or event.

Refering to facets in Scheme code

For example, to extract all attributes with the "ui_component" facet, use the following code:

(let ((attributeList (collection)))
   (for-each
      (lambda (class)
         (for-each
            (lambda (attribute)
               (if (attribute'hasFacet "ui_component") (attributeList'add attribute))
            )
            (class'attributeIterator)
          )
      )
      (((invocation-context)'metadata)'metaclassIterator)
    )
    attributeList
)

Source code for defining facets

Model-wide facet definitions are maintained in .facets files in the meta/facets/ directory.

Facets file format

The file containing facet definitions has the following format:

<Facets>
   <Facet
      name="facetName"
      description="<facetDescription>"
      values="<default_value>|list|()"
      validation="<facetValidationExpression>"
      ; Lambda, similar to a attribute validation. 'this' resolves to the faceted
      ; metadata object i.e. Metaclass, Attribute or Event that this facet
      ; is applied to
      ; Runs as last step of metadata loading after makeReadOnly()
      ; Errors should be captured by Studio validation
   />
   ...
</Facets>

name
The name of the facet.

description
The description of the facet.

values
The possible values for the facet. This value is a comprised of space-separated Scheme literals. The supported values are:

<default_value>
The property does not support custom values. The existence of the facet implies the specified default value.

For example:


<Facet name="FacetName1" description="Facet description"/>
<Facet name="FacetName2" description="Facet description" values="defaultValue"/
>


If the default value is not specified when defining the facet, the (attr'findFacetValue "FacetName1") command returns #t when the facet is assigned to a metadata object.
If a single value is specified when defining the facet, then the (attr'findFacetValue "FacetName2") command returns the default value when the facet is assigned to a metadata object.
<list>
The value can be set to zero or more of the values in the specified list. For example:

<Facet name="FacetName3" description="Facet description" values="value1 value2
 value3"/>


When assigning the facet to a metadata object, the specified value will be validated against the value list specified when defining the facet. The (attr'findFacetValue "FacetName3") command returns whatever valid values were specified when assigning the facet.
()
The value is free form and no validation is performed. For example:
<Facet name="FacetName4" description="Facet description" values="()"/>
Any value can be specified when assigning the facet to a metadata object. The specified value is returned when the (attr'findFacetValue "FacetName4") command is issued.

validation
The validation script against which the facet values are tested when the facet is assigned to the metadata object. This expression takes this and value as arguments, where this refers to the metadata object to which the facet is assigned and value refers to the value of the facet. The validation expression returns #f, a string ID, or a list of format arguments if the facet is invalid.
Example:

(if (not (number? value))
   '("ids.numericValueError", value)
) ; where ids.numericValueError is "Facet must be numeric. '{0}' is not valid."

Defining facets using NexJ Studio

Define facets in the Facets tab in the Business Model layer in NexJ Studio.

You can define multiple related facets in the same facet definition file.

To define one or more facets using NexJ Studio:

  1. In the Business Model layer, click the Facets tab.
  2. Right-click in the navigator and select New Facets.
  3. In the New Facets dialog, confirm the model for which you are creating the facets, specify the name for the facets file, and click Finish.
  4. In the Hierarchy tab, right-click Facets and select Insert Facet.
  5. In the Properties tab, specify the values for the properties that apply to the facet.

    • name
      The name of the facet.

    • description
      The description of the facet.

    • values
      The possible values for the facet. This value is a comprised of space-separated Scheme literals. The supported values are:

      • <default_value>
        The property does not support custom values. The existence of the facet implies the specified default value.
        If the default value is not specified when defining the facet, the (attr'findFacetValue "<FacetName>") command returns #t when the facet is assigned to a metadata object.
        If the values property is set to a single value, for example value1, then the (attr'findFacetValue "<FacetName>") command returns 'value1 when the facet is assigned to a metadata object.

      • <list>
        The value can be set to zero or more values in the specified list. When assigning the facet to a metadata object, the specified value will be validated against the value list specified when defining the facet. For example, if the values property is set to value1 value2 value3, then the (attr'findFacetValue "<FacetName>") command returns whichever valid values (one or more of value1, value2, or value3) was specified when assigning the facet.

      • ()
        The value is free form and no validation is performed. If the values property is set to (), then any value can be specified when assigning the facet to a metadata object. The specified value is returned when the (attr'findFacetValue"<FacetName>") command is issued.

    • validation
      The validation script against which the facet values are tested when the facet is assigned to the metadata object. This expression takes this and value as arguments, where this refers to the metadata object to which the facet is assigned and value refers to the value of the facet. The validation expression returns#f, a string ID, or a list of format arguments if the facet is invalid.
      Example:

      (if (not (number? value))
      '("ids.numericValueError", value)
      )
      ; where ids.numericValueError is "Facet must be numeric. '{0}' is not valid."
  6. You may add more facets to the facet list.

    1. In the Hierarchy tab, right-click Facets and select Insert Child.

    2. To add a facet to the start of the list, select Facet beginning. To add a facet as the last item of the list, select Facet end.

    3. In the Properties tab, specify the values for the properties that apply to the facet.

  7. Click the Save button to save your changes.

The facet definition file has been created.

You can now assign the facet to classes, aspects, attributes, or events to which it applies.

Source code for assigning facets

Once the facet have been defined in a facets definition file, you can assign the facet to a class, an aspect, an event, or an attribute.

Assigned facet formats

The facet is assigned in the following format:
<Class facets="(facetName facetValue overrideType)" ...>

<Aspect facets="(facetName facetValue overrideType)" ...>

<Attribute facets="(facetName facetValue overrideType)" ...>

<Event facets="(facetName facetValue overrideType)" ...>

<facetName>
The name of the facet.

<facetValue>
The value of the facet. If not specified, the default value is null.

<overrideType>
Facets inherit values from the base metadata object from which the metadata object was customized. You can override the inherited value by including an override type definition. Valid override types are:
value
Sets the facet value to whatever is specified, regardless of the inherited values. For example:

<Class name="BaseClass" facets="(facetName1 (value5) value)" />
<Class name="SubClass" base="BaseClass" facets="(facetName1 (value1) value)" />
;;; The (class'findFacetValue "FacetName1") command returns '(value1)

list
Appends the value to the facet value inherited from the base class, attribute, or event. For example:

<Class name="BaseClass" facets="(facetName2 (value1) value)" />
<Class name="SubClass" base="BaseClass" facets="(facetName2 (value2) list)" />
;;; The (class'findFacetValue "FacetName2") command returns '(value1 value2)

assoc
Substitutes the heads of an association list with the new values. For example,

<Class name="BaseClass" facets="(facetName3 ((a 1) (b 2) (c 3)) value)" />
<Class name="SubClass" base="BaseClass" facets="(facetName3 ((a 3) (b 5) (d 7))
 assoc)" />

;;; The (class'findFacetValue "FacetName3") command returns '((a 3) (b 5) (c 3)
 (d 7))

Assigning facets using NexJ Studio

Assign facets to classes, aspects, class attributes, or class events in the Classes tab of the Business Model layer in NexJ Studio.

The facet must be defined before you can assign it to a metadata object.

To assign a facet to a class, aspect, event or attribute:

  1. In the Business Model layer, click the Classes tab.
  2. In the navigator, double-click the name of the class or the aspect class to open it.
  3. Navigate to the Facets tab for the metadata object to which you want to assign the facet.
    • To assign a facet to the class or aspect, enter the facet name, with optional values and overrides, in the Facets field on the Overview tab for the class.
    • To assign a facet to an attribute, select the attribute on the Attributes tab. Then select the Facets subtab and enter the facet name, with optional values and overrides, in the Facets field.
    • To assign a facet to an event, select the event on the Events tab. Then select the Facets subtab and enter the facet name, with optional values and overrides, in the Facets field.
      To specify just the facet name, enter the facet name in the Facets field. For example, ui_component.
      Otherwise, specify the facet name, value, and override type, enclosed in parentheses, in the following format:
      (<facetName> <facetValue> <overrideType>)
      <facetName>
      The name of the facet.
      <facetValue>
      The value of the facet. If not specified, the default value is null.
      <overrideType>
      Facets inherit values from the base metadata object from which the metadata object was customized. You can override the inherited value by including an override type definition. Valid override types are:
      • value
        Sets the facet value to whatever is specified, regardless of the inherited values. For example, if the base class facet is (facetName1 (value5) value) and the customized class facet is (facetName1 (value1) value), then the assigned facet value is '(value1).
      • list
        Appends the value to the facet value inherited from the base class, attribute, or event. For example, if the base class facet is (facetName2 (value1) value) and the customized class facet is (facetName2 (value2) list), then the assigned facet value is '(value1 value2).
      • assoc
        Substitutes the heads of an association list with the new values. For example, if the base class facet is (facetName3 ((a 1) (b 2) (c 3)) value) and the customized class facet is (facetName3 ((a 3) (b 5) (d 7)) assoc), then the assigned facet value is '((a 3) (b 5) (c 3) (d 7)).
  4. Click the Save button to save your changes.

The facet has been assigned to the class, attribute, or event.