2022 April Release

app.ducx Customization LanguagePermanent link for this heading

The purpose of the app.ducx customization language is to define, customize and tailor your software component to project- or solution-specific requirements.

A customization block consists of import declarations, customization points and customizations. The customization keyword denotes a customization model block. It must be followed by the reference of your software component and curly braces.

Syntax

customization softwarecomponent
{
  // Import declarations
  import softwarecomponent;
  ...
  // Customization point
  customizationpoint CustomizationPointReference(parameter, ...);
  ...
  // Customization for the customization point
  customize CustomizationPointReference<keyparameter, ...> {
    ...
  }
  ...
}

Customization PointsPermanent link for this heading

Customization points are defined within a customization model block. To declare a customization point, use the optional keyword customizationpoint, followed by the reference of the customization point and by parentheses holding the list of parameters. The declaration is finished with a semicolon.

Example

customizationpoint GetObjHint (
  key ObjectClass objclass,
  string suffix,
  retval string hint
);

customizationpoint GetAllowedAttrDef (
  key ObjectClass objclass,
  key AttributeObjectDef attrdef,
  out direct AttributeObjectDef outattrdef
);

customizationpoint GetAllowedExpression (
  key ObjectClass objclass,
  key AttributeObjectDef attrdef,
  out direct cfggetallowedextensions
);

customizationpoint GetTransferedAttribute(
  key ObjectClass objclass,
  key AttributeObjectDef attrdef,
  out direct boolean transferred
) {
  typecpaction = GetMergedPropertyValue;
}

Parameters denoted with the keyword key are used in customizations to define key values used to specify the customization entries. If a key parameter can be left empty, it has to be marked as optional (optional key).

All input parameters are available in expression blocks (local scope) of customizations.

Output parameters (out, retval) normally are calculated by an expression. Using the keyword direct for output parameters gives the possibility to return the value directly without evaluating an expression.

It is also possible to specify a parameter by using a property definition.

By default, the action FSCCONFIG@1.1001:GetMergedPropertyValueEx is used for resolving the customization point, resulting in a single line result.

If there are only direct parameters, the resolving action is FSCCONFIG@1.1001:GetMergedPropertyEx, resulting in a sorted list of configuration lines. To return only one line, specify the action to be used.

It is possible to define a customization point without key parameters. This results in a single line customization point for the specified output parameter.

Defining Domain TypesPermanent link for this heading

With help of Domain Types (COOSYSTEM@1.1:DomainType) it is possible to define configurations and ACLs abstractly for domain types instead of concrete domains. This can be achieved by using the keyword instance followed by the object class DomainType and the name of the instance reference.

Syntax

objmodel APPDUCXSAMPLE@200.200
{
  // Import declarations
  import softwarecomponent;

  ...
  // Creates an instance of a domain type
  instance DomainType DomainTypeReference {
    configurationreference = configurationobjectreference
    ...
  }
  ...
}

All configurations that are defined in the domain type instance can be used for customization points in foreign software components.

To reuse a defined configuration in your own software component, the configuration object instance has to be created manually. The reference of the configuration object instance has to comply with the following rule: reference of the domain type followed by the software component of the configuration followed by “Config” (e.g. DomainTypeAppducxSampleFSCCONFIGConfig).

Example

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;
  import FSCSMTP@1.1001;
  import FSCCONFIG@1.1001;

  instance AdministrationConfiguration DomainTypeAppducxSampleFSCCONFIGConfig {}

  instance DomainType DomainTypeAppducxSample {
    clientsmtpconfig = DefaultConfiguration;
    clientconfiguration = DomainTypeAppducxSampleFSCCONFIGConfig;
  }
}

Generic Method Implementation for Customization PointsPermanent link for this heading

If a customization point needs additionally an implementation of a specified action with a specified method implementation for the object class defined in a customize statement, this can be defined in the customization point to reduce the effort in the customizing statements.

Example

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  extend instance NameBuild {
    typecpmethods<cpaction,cpmethdefinition> = {
      {
        EvaluateGenericNameBuild,
        MethodGenericNameBuild
      }
    }
  }
}

If this customization point is used for an object class in a customizing statement, the mapping is now created implicitly.

CustomizationsPermanent link for this heading

For each customization point several customizations may exist, distinguished by the key parameters. Optional keys may be set to null, if the customization should apply to any value in the optional key. The customization provides the concrete implementation of a customization point.

By default, customizations are implicitly stored in the default configurations of the software components the corresponding customization point belongs to. If you create your own customization points a configuration with reference DefaultConfig is implicitly generated for your software component.

Using Domain TypesPermanent link for this heading

If an installation consists of several tenants you might want to have an own configuration for each tenant. This can be achieved by defining a software solution (or software edition) for each tenant and using the target keyword followed by the reference of the domain type.

A domain type can be customized if:

  • A configuration object is already specified in the DomainType object.
  • Only the domain type without configuration exists but it is defined in the own software component. Then a configuration will be created and the domain type extended.
  • The customization point is defined in the own software component, but the configuration object is not yet defined. Then a configuration will be created and the domain type extended.
  • The customization point is defined in a component which specifies the own software component as friend, but the configuration object is not yet defined. Then a configuration will be created and the domain type extended.

In all other cases an error will be thrown.

Example

// Define the customization for the own software solution
// Create a new configuration object if it is not already created manually

target
DomainTypeAppducxSample {
  customize
GetAllowedAttrDef<Folder, objchildren> {
    // Assumes that outattrdef is defined as direct
    outattrdef = objsubject;
  }
}

// Define the customization for the software edition Folio
// Add an entry to an existing configuration object in the Folio configuration

target DomainTypeFolio {
  customize GetAllowedAttrDef<Folder, objchildren> {
    outattrdef = objsubject;
  }
}

ContextsPermanent link for this heading

Some customization points support an additional configuration context. This context is calculated dynamically by calling the action FSCTEAMROOM@1.1001:GetCPContext(ClientConfigurationObject cfg, retval ComponentObject context) on the room of the object the customization point is called for. To get a specific context for a room the action GetCPContext can be implemented as seen in the sample below.

Currently to following customization points can be used for context-specific configuration:

  • FSCCONFIG@1.1001:CPStateDisplay
  • FSCCONFIG@1.1001:NameBuild
  • FSCCONFIG@1.1001:cfgformatting
  • FSCCONFIG@1.1001:CPAllowedAttrDef
  • FSCPDFANNOTATIONS@1.1001:CPAnnotationFeatureEnabled
  • FSCPDFANNOTATIONS@1.1001:CPAnnotationFeatureEnabledClasses

Example

// Define the customization for the software edition Folio
// Add an entry to an existing configuration object in the Folio configuration,

// additionally specifying a context

target DomainTypeFolio.Art {
  customize GetAllowedAttrDef<Folder, objchildren> {
    outattrdef = objsubject;
  }
}

target DomainTypeFolio.[Art,Business] {
  customize GetAllowedAttrDef<Folder, objchildren> {
    outattrdef = objsubject;
  }
}

// Implement the GetCPContext action for your AppRoom class to be able to provide
// customizations which are only effective within instances of this AppRoom.

// Sample implementation
override GetCPContext {
  variant MyAppRoom {
    expression {
      context = #MyAppRoomCtx;
    }
  }
}

// Sample customization
target DomainTypeFolioCloud.MyAppRoomCtx {
  customize NameBuild<ContentObject> {
    build = expression {
      return "Name of any ContentObject in MyAppRoom"
    }
    namefixed = true;
  }
}

Contexts can be listed in the target definition.

It is only allowed to configure the contexts, when one of the following conditions hold true:

  • the domain type configuration object belongs to the current project or
  • the customization point belongs to the current project or
  • the context object belongs to the current project

Using CustomizationsPermanent link for this heading

Customizations can be used in expression blocks.

Example

// The result is assigned to @tmp
impl = expression {
  cooobj.GetObjHint(cooobj.objclass, @suffix, &@tmp);
}

// build is declared as retval, thus the result can be assigned directly
impl
= expression {
  string @tmp = cooobj.GetObjHint(cooobj.objclass, @suffix);
}

// The result is a list of matching customizations assigned to @result
impl
= expression {
  GetAllowedAttrDef[] @result = cooobj. GetAllowedAttrDef(cooobj.objclass, null)[...];
}

Note:

  • The key parameters are used to evaluate which customization should be used. If a parameter is an object class, the inheritance is considered (best match).
  • If a parameter is defined as retval direct assignments are possible.
  • If an output parameter is omitted, its value is not calculated due to performance reasons.
  • If you need to access all matching configuration entries you can access this list by using “[...]” to qualify the result of the customization point.

Concise Example

This concise example subsumes the concepts described in the above chapters. The goal is to customize the hint that is displayed when moving the mouse over a content object.

Example

app.ducx Customization Language

GetObjHint
(
  key ObjectClass objclass,
  string suffix,
  retval string hint
);

customize GetObjHint<ContentObject> {
  hint = expression {
    return
      cooobj.GetHTMLLine(#objname, cooobj.objname) +
      cooobj.GetHTMLLine(#objowner, cooobj.objowner.objname);
  }
}

app.ducx Use Case Language

// Override COOATTREDIT@1.1:GetObjectHint
override
GetObjectHint {
  variant ContentObject {
    impl = expression {
      // Call customization point
      cooobj.GetObjHint(cooobj.objclass, null, &text);
    }
  }
}

GetHTMLLine(AttributeDefinition attrdef, any value, retval string line) {
  variant Object {
    impl = expression {
      line  = "<b>";
      line += attrdef.objname;
      line += ":</b> ";
      line += STRING(value);
      line += "</br>";
      return line;
    }
  }
}

Predefined customization pointsPermanent link for this heading

Several customization points are defined by the base product itself. The predefined customization points are described in the reference documentation:

https://help.developer.fabasoft.com/index.php?topic=doc/Reference-Documentation/cps-overview.htm