This chapter introduces the concept of domain-specific languages (DSLs) as well as a concise summary of important recommendations to keep in mind when working with Fabasoft app.ducx.
Developing use case-oriented software solutions requires managing different aspects and elements such as data structures, user interface design, the implementation of methods, and business rules.
In order to account for this concept in an optimal manner, Fabasoft app.ducx is comprised of several declarative modeling languages, each designed for covering a particular aspect of solution development. For example, Fabasoft app.ducx includes a modeling language that has been designed explicitly for the definition of an object model. In addition to this, Fabasoft app.ducx includes languages for defining resources, a user interface model, an implementation model, a process model, and an organizational structure model.
These modeling languages are referred to as domain-specific languages (DSLs), where each DSL was designed for addressing a certain aspect of use case-oriented software development. The modular concept makes Fabasoft app.ducx easily extensible as new DSLs can be added on demand for addressing additional aspects without affecting existing projects.
Currently, Fabasoft app.ducx is comprised of eight distinct DSLs:
Each of these DSLs is covered in detail in its own chapter.
Each DSL is an independent declarative modeling language having its own set of language constructs and keywords designed with a particular purpose in mind. However, all DSLs also share certain similarities. These common characteristics and language elements that are the same across all DSLs of Fabasoft app.ducx are presented in this section.
A DSL consists of a unique set of keywords for addressing a particular aspect of solution development. However, there are shared keywords that are common to all DSLs.
The Fabasoft app.ducx compiler is case-sensitive. All keywords must be in lower case.
Each expression must be terminated by a semicolon or be enclosed in a block. A block consists of one or more expressions enclosed in curly braces.
There are several kinds of operators and punctuators. Operators are used in expressions to describe operations involving one or more operands.
Examples for operators and punctuators are { } [ ] ( ) , . : ; + - * / % & | ^ ! ~ = < > ? ?? ++ -- && || == != <= >= <=> += -= *= /= ??= ->.
Two forms of comments are supported: single-line comments and delimited comments. Single-line comments start with the characters // and extend to the end of the source line. Delimited comments start with the characters /* and end with the characters */. Delimited comments may span multiple lines. Comments do not nest and are not processed within character and string literals.
Multilingual strings are not defined in the source code but in separate resource files in order to keep the source code free of any hard-coded strings. By default, the resource files holding multilingual strings are named mlnames.lang. For each language you want to support, a separate resource file must be created.
The main benefit of this approach is that all language-specific string resources are maintained in a single resource file for the particular language, which allows for a quick and hassle-free localization of your application.
Resource files are automatically updated whenever you add a new element requiring a multilingual name (e.g. object classes, properties, or use cases) or another form of multilingual string, such as the label text for an input field on a form page or the text displayed for enumeration items in a drop-down list.
The language resource editor (see figure) is invoked when opening the mlnames.lang file. It allows you to enter a language-specific string for each multilingual string resource in your app.ducx project.
To edit the multilingual strings for all elements that are part of your software component open the mlnames.lang file in the Eclipse Project Explorer.
If a language string is not yet translated, the background color of this line is changed and after a successful build of this project, a warning is generated.
Beside mlnames.lang files, explanations.userdoc files are provided for defining explanation texts for properties. Simple XHTML tags like <b></b>, <i></i> or <br/> may be used to format the strings. These explanation texts can be displayed as context-sensitive help in the Fabasoft Web Client.
Note: The format of these files is by default CSV, existing projects are not migrated automatically.
Multilingual strings and explanation texts are not removed automatically when the corresponding reference is removed from the source code. Thus, you do not lose strings when temporarily commenting out some source code. To clean up multilingual names and explanation texts use the “Clean up Language Files” context menu command.
In all DSLs, component objects can be addressed by their fully qualified reference.
Each component object has a unique programming name, which is described by its fully qualified reference that indicates a logical hierarchy. For example, COOSYSTEM@1.1:objsubject is the fully qualified reference of a component object with the reference objsubject that is part of software component COOSYSTEM@1.1.
In Fabasoft app.ducx, a software component is somewhat similar to a namespace in an object-oriented programming language: all component objects belonging to a particular software component are nested in this namespace.
The following example shows part of an object model containing the definition of object class Product. This object class is derived from object class COOSYSTEM@1.1:BasicObject. Furthermore, the existing property COOSYSTEM@1.1:mlname is assigned to the object class. Please note that fully qualified references are used for referring to both of these component objects belonging to software component COOSYSTEM@1.1.
Example |
objmodel APPDUCXSAMPLE@200.200 |
Using the import statement, a software component can be made known to the compiler in order to avoid the need for using the fully qualified reference when referring to a component object that is part of the imported software component.
Once a software component has been imported using an import statement, you can refer to component objects belonging to this software component with their reference only, instead of having to use the fully qualified reference. This allows for the software component prefix to be left out when referring to its component objects once a software component has been imported.
A list of import statements is referred to as import declarations. All import declarations have to be placed inside objmodel, resources, userinterface, usecases, processes or orgmodel blocks. The different types of models are described in greater detail in the following chapters.
Note: Software components listed in the import declarations must be referenced in your Fabasoft app.ducx project’s list of software component references. For further information on software component references, refer to chapter “Adding a Software Component Reference”.
Example |
objmodel APPDUCXSAMPLE@200.200 class Product : BasicObject { |
It should be noted that even when a software component is imported using an import statement it is still valid to refer to component objects of the imported software component using the fully qualified reference.
A reference that is not fully qualified may be ambiguous, because component objects belonging to different software components might have the same reference. References of the own software component are favored over references of other software components. In all other cases the fully qualified reference must be used to refer to these component objects.
Beyond the resolving strategy of not fully qualified references some more rules apply to app.ducx expressions.
As a general rule of thumb, whenever you use qualifiers provide a type for the qualifiers to avoid ambiguities.
In following cases special resolving rules apply:
Compound properties
In the following example GetTypeDefinition is resolved to a kernel interface method and isbn to a property of the compound property publication.
Example |
usecases APPDUCXSAMPLE@200.200 usecase ResolveCompoundProperty() { |
Objects
In the following example GetClass is resolved to a kernel interface method, orderpositions to a property of the object order and ResolveCompoundProperty to a use case of the object order.
Example |
usecases APPDUCXSAMPLE@200.200 usecase ResolveObject() { |
Item Scope
In the following example objname is resolved to COOSYSTEM@1.1:objname and name to a key in the local scope.
Example |
usecases APPDUCXSAMPLE@200.200 usecase ResolveObjectList(string name) { |
Dictionaries
In the following example key is resolved as dictionary key.
Example |
usecases APPDUCXSAMPLE@200.200 usecase ResolveDictionary() { |
Other data types
Fabasoft app.ducx allows you to include so-called generic assignment statements in your source code in order to assign values to properties. You may only reference properties that actually belong to the object class of the component object denoted by the Fabasoft app.ducx language element the assignment statement is nested in.
Syntax |
property = value; |
For initializing a property with a scalar value, the reference of the property must be denoted followed by the equality character, and the value. The assignment statement must be terminated by a semicolon.
In the following example, the COOSYSTEM@1.1:attrextension property of a content property should be initialized with the value “txt”. There is no language element provided by any of the Fabasoft app.ducx DSLs for defining the value for this property, thus, a generic assignment statement must be used for defining the value of this property as illustrated by the following example.
Example |
objmodel APPDUCXSAMPLE@200.200 class OrderRecord : Record { |
Syntax |
property = { |
When setting a scalar compound property, the commonly used syntax can be used.
Example |
objmodel APPDUCXSAMPLE@200.200 class OrderRecord : Record { |
Syntax |
property = [value, value, value] |
When setting array properties, the familiar expression syntax can be used, even with compound properties.
Example |
objmodel APPDUCXSAMPLE@200.200 class OrderRecord : Record { |
Syntax |
property = expression { |
When setting expression properties, the keyword expression is used to describe an expression block.
Example |
objmodel APPDUCXSAMPLE@200.200 instance Expression MyExpression { |
If the expression property does not specify parameters or a scope type, the keyword as and an expression property definition can be used to specify this information.
Example |
objmodel APPDUCXSAMPLE@200.200 instance FilterExpression MyFilterExpression { |
Syntax |
property<member, ...> = { |
When assigning a list of values to a compound property, a special syntax can be used to create a very compact, table like initialization form. The reference of the compound property to be initialized must be followed by angle brackets. In the angle brackets, the references of the properties belonging to the compound property’s type that should be initialized with values must be specified. The initialization values provided must be enclosed in curly braces and separated by commas. Null values can be defined using the null keyword. Additionally, multiple lines must be separated by commas as well.
Example |
objmodel APPDUCXSAMPLE@200.200 class OrderRecord : Record { |
Compound properties can also be nested within other compound properties. The following example demonstrates the initialization of nested compound properties.
Example |
objmodel APPDUCXSAMPLE@200.200 extend class WorkList { |
Initializations with null can be specified by using the keyword null and will result in an appropriate assign statement. The keyword null can be used to prevent default initializations or, using the keyword update, to clear already set properties.
Example |
objmodel APPDUCXSAMPLE@200.200 update instance MyFilterExpression { |
Component objects may be marked as public, internal, private, secured, or obsolete using the keywords public, internal, private, secured, securedreadonly, and obsolete.
Depending on the project settings component objects are by default public internal or private.
The following rules apply:
Private component objects can only be used within the software component the component object is created in and in friend components. For further information on how to create a friend relation, please consult chapter “Defining a Friend Component”.
The type of the parameters of a public action or a public attribute must be also public. The private constraint is enforced by Fabasoft app.ducx the following way:
Internal component objects can only be used within the base product.
Secured component objects expressions can be executed with the EF_SECURED flag. In secure expressions it is possible to read and write properties marked with secured.
In secure expressions, it is possible to read properties marked with securedreadonly.
Obsolete component objects should not be used anymore and are likely no longer available in prospective versions. To handle obsolete component objects Fabasoft app.ducx provides following support:
The file keyword is used to reference a resource such as an image or another type of binary or text file. It must be followed by parentheses holding the relative path to the resource file enclosed in double quotes. The path must be specified relative to your Fabasoft app.ducx project.
The file keyword can also be used to reference app.ducx expressions that have been defined in separate app.ducx expression language files.
Example |
// Referencing a symbol imported to the "resources/symbols" folder of the // Referencing an expression in an app.ducx expression language file |
The following table gives an overview of suggested naming conventions for component object references. These naming conventions are only recommendations, and you are free to define your own naming conventions.
Note: A valid reference must begin with a character and must not contain any special characters except the underscore character.
Element | Recommended reference |
Software component | The reference of a software component should be composed of upper-case characters only. Example: APPDUCXSAMPLE |
Object class | The reference of an object class should be in singular form. Use mixed case notation, starting with a capital first letter. Example: OrderRecord |
Enumeration type, | The reference of an enumeration type or a compound type should describe the purpose of a property of this type. If possible, do not include the word “Type”. Use mixed case notation, starting with a capital first letter. Example: OrderState |
Enumeration item | The reference of an enumeration item should be composed of upper-case characters only. Individual words should be separated by an underscore character. Each enumeration item should share a prefix common to all enumeration items of the enumeration type containing them. Example: OS_SHIPPED |
Property | The reference of a property should describe the purpose of the property. You may include an abbreviation of the object class the property belongs to. Use lower case characters only for a property reference. Example: orderdate |
Use case | The reference of a use case should be comprised of a verb describing the action performed followed by the object on which this action is carried out. Use mixed case notation, starting with a capital first letter. Example: PrintInvoice |
ACL | The reference of an ACL should be in mixed case notation, starting with a capital first letter, and ending with the postfix “ACL”. Example: OrderRecordACL |
Form | The reference of a form should be in mixed case notation, starting with the prefix “Form”. If you define different forms for administrators and end-users, you should use the postfixes “User” and “Admin”. Example: FormOrderRecord, FormOrderRecordUser, FormOrderRecordAdmin |
Form page | The reference of a form page should be in mixed case notation, starting with the prefix “Page”. Example: PageOrderRecord |
Other component objects | The reference of all other component objects should be in mixed case notation, starting with a capital first letter. An abbreviation of the object class may be used as a prefix. Example: ButtonBarOrderRecord |