Model

Model

wCMF applications are based on a model. The model defines the key aspects of the application on a higher abstraction level than code does. You can think of it as a condensed description of the application.

A template based code generator transforms the model into source code that will run inside the wCMF framework. Where necessary, the code can then be enhanced manually inside pre-defined regions. Further generation runs will protect these manual additions.

We believe that this approach helps to develop a clear concept of the application and improves code quality and maintainability dramatically.

Modeling

Technically the model is an UML model that uses the Chronos profile from the Olympos project. It is stored in an Eclipse MDT/UML2 compatible XML file (e.g. model.uml). This file can be directly edited using Eclipse Papyrus or any other compatible UML modeling tool. Alternatively you can use the Chronos Web Modeler that allows browser based collaborative modeling. wCMF uses a minimized version of the code generator from the Olympos project with wCMF specific templates.

The following diagram shows the workflow of the generator.

generator.png
Generator workflow

Chronos profile

Profiles are used to extend UML for different domains. They consist of stereotypes and tags that are applied to model elements to express domain specific features. The following sections describe the stereotypes and tags of the Chronos profile that are used to define various aspects of a wCMF application. The complete Chronos profile is available on GitHub.

You will notice that only a small part of UML is used to define the application and not all aspects of the application are defined in the model. Especially the actual behavior of controllers and domain classes is omitted, since we believe that this is more efficiently expressed in code. For simplicity and compatibility reasons all aspects can be modeled in class diagrams using classes, attributes and associations.

Note
UML elements and concepts that are not mentioned in the following sections are most likely not supported by the generator and will be ignored.

Domain classes

The following stereotypes are used to model persistent domain classes and their relations.

Name UML meta class Description Example
ChiNode Class Persistent domain class, must inherit from the Node Article
ChiValue Attribute Persistent attribute in a ChiNode headline of Article
ChiValueRef Attribute ReadOnly-reference to an attribute of another ChiNode author_name in Article references name in Author
ChiManyToMany Class Connection class in a many to many relation between ChiNode classes, must inherit from Node One Author writes nultiple Articles and one Article has multiple Authors
ChiAssociation Association Optional, e.g. used to define a foreign key name in a relation between ChiNode instances author_id in Article as foreign key to Author table

ChiNode / ChiManyToMany

The following tags are defined on the ChiNode / ChiManyToMany stereotypes.

Tag Description Example Default value
initparams Name of the configuration section, which defines initialization parameters for the PersistenceMapper instance database database
display_value Attributes to display in a list view: A single attribute name or |-separated list of attribute names name|date
orderby Definition of default sorting: none (no order), sortkey (generates a sortkey column, that is used for explicit sorting) or the name of any attribute optionally followed by ASC or DESC name ASC none
is_searchable Boolean, indicating whether this type should be included in the default search true true
is_soap Boolean, indicating whether this type should be exposed to the SOAP interface true true
table_name The name of the database table in which instances will be stored Author Class name
pk_name The name of the primary key column: A single value or |-separated list of values (the generator will add this automatically, if there is no appropriate attribute) fk_user_id|fk_role_id id
child_order The order of the associated child types: A single type or |-separated list of types Image|Textblock|Attachment in Article type
parent_order The order of the associated parent types: A single type or |-separated list of types Author|Publisher in Article type
Note
Some of these tags are accessible in the application through the PersistentObject::getProperty method.

ChiValue

The following tags are defined on the ChiValue stereotype.

Tag Description Example Default value
app_data_type Application specific attribute tags: A single value or |-separated list of values (see Values, Properties and Tags) TAG_A|TAG_B DATATYPE_ATTRIBUTE
db_data_type The attribute's database type TEXT VARCHAR(255)
is_editable Boolean, indicating whether this attribute is editable true true
input_type Name of the attribute's input control as listed in the InputTypes configuration section and additional configuration encoded as JSON string filebrowser or ckeditor:{"toolbarSet":"full"} text
display_type Name of the attribute's display type as listed in the DisplayTypes configuration section image text
restrictions_match Name of the attribute's validation type as listed in the Validator configuration section (see Validation) and additional configuration encoded as JSON string regexp:{"pattern":"^[0-9]*$"} or image:{"height":[300,0]}
restrictions_not_match not used
restrictions_description Validation description used in case of a validation error The value must be an integer or empty
column_name The name of the database column in which the attribute will be stored name Attribute name
Note
Some of these tags are accessible in the application through the PersistentObject::getValueProperty method.

ChiValueRef

The following tags are defined on the ChiValueRef stereotype.

Tag Description Example Default value
reference_type Type, that owns the referenced attribute Author
reference_value Name of the references attribute name

ChiAssociation

The following tags are defined on the ChiAssociation stereotype.

Tag Description Example Default value
fk_name Name of the foreign key attribute (the generator will add this automatically, if there is no appropriate attribute) author_id fk_type_ id

Example class diagram

A simple data model is shown in the diagram below. Each of the domain classes Author, Article and Image is modeled with ChiNode stereotype, their attributes with ChiValue stereotype. The only exception is the author_name attribute, which is a reference to the name attribute of Author and therefore uses the stereotype ChiValueRef. As the relations between the classes show, one Author can own several Articles and each Article in turn can contain several Images.

All PersistenceMapper instances are initialized using the parameters defined in the database configuration section.

In list views Author instances are sorted by name while Article and Image instances get an attribute sortkey which is used to define an explicit order.

model.png
Example class diagram

Associations

Relations between domain classes - e.g. parent-child relations - are modeled as associations. Three different types of associations are supported: compositions, aggregations and one-directional associations as shown in the following diagram.

associations.png
Association types

It is important to understand how wCMF recognizes parents and children in an association. In case of compositions and aggregations the parent is always the class, that is connected with the diamond end of the association. Other associations are treated as parent-child relation, if they are only navigable in one direction, which is then defined as the child to parent direction.

The association types differ in the treatment of children in case of deletion of the parent. In aggregations and normal associations children are not deleted, while composite children are deleted on parent deletion. On the other hand the default application allows creation of child instances in a composition, while the other two types only allow adding existing instances.

The following table summarizes the behavior of the different association types regarding the operations allowed on child instances:

Association type Delete children Create children Associate children
Composition Yes Yes No
Aggregation No Yes Yes
Association No No Yes
Multiplicity

The multiplicity at the association ends limits the amount of instances that are allowed at that relation end. In a typical parent-child relation the parent end has a value of 1 and the child end has a value of 0..* meaning that a child instance is connected to exactly one parent instance, while any number of child instances may be connected to the parent instance (including zero). This kind of relation is called one-to-many relation and is easy to realize in a database by using a foreign key column.

Many-to-many relations on the other hand allow an arbitrary number of instances at both ends and are typically realized in an database using a junction table. The Chronos profile allows for this by providing the ChiManyToMany stereotype. The following diagram shows how to model a many-to-many relation:

many-to-many.png
Many-to-many relation

Using compositions ensures that many-to-many instances are deleted correctly, when the parent instances are deleted.

Navigability

Another aspect of associations is the use of arrow ends that define the navigability. If an arrow end is omitted on one end, instances at that end are not accessible from the other end. Regarding the database schema all three association types will result in the creation of a foreign key column in the child table that points to the parent table.

Role names

Each end of an association can have a role name assigned. It describes how the element at that end participates in the relation. Generally the role name defaults to the element's name, but there are two cases where it is necessary to assign a dedicated name:

  • Multiple associations
  • Self associations

Sometimes multiple associations have to be defined between two domain classes. For example if there are Person and Task domain classes and tasks should be associated with persons. If each task should have an owner and a creator, there will be two aggregations between the two domain classes. To allow wCMF to know which role a person has in relation to a given task, role names have to be assigned to the association ends.

The following diagram illustrates the given example:

multiple-associations.png
Role names in multiple associations

To build a hierarchy where one item contains items of the same type, an association from the domain class to itself is required. An example would be a file system with nested directories. In this case, role names are required at each end of this self association.

The following diagram illustrates the given example:

self-associations.png
Role names in self associations

Inheritance

If different domain classes should have the same attributes, a common base class can make these available to inheriting classes. An example may be an EntityBase type, which defines meta information like creation date and last modification date for all domain classes. The diagram below illustrates the concept.

inheritance.png
Inheritance

Inheritance will cause the generator to create new relations in the following cases:

Parent relations Child relations
inherited-relation1.png
Subclass B becomes parent of A
inherited-relation3.png
Subclass B becomes child of A
inherited-relation2.png
Parent class of B becomes parent of A
inherited-relation4.png
Child class of B becomes child of A

Application flow

Since a wCMF application is based on the Model-View-Controller pattern, application flow is defined in terms of controllers and views. Controller execution is triggered by actions which are initiated by the application user.

The following stereotypes are used to model user interaction.

Name UML meta class Description Example
ChiController Class Controller class, must inherit from the Controller LoginController
ChiView Class View assigned to a ChiController login
ChiActionKey Association Associates two ChiController instances (to define a control flow) or a ChiView with a ChiController (to define a view attachment), must be one directional
Note
ChiActionKey realizes the concept of action keys (see Action Key). Multiple action keys may be defined between controllers or controllers and views each one used in a different context and/or for a different action.

ChiController

No tags are defined on the ChiController stereotype.

ChiView

No tags are defined on the ChiView stereotype.

ChiActionKey

The following tags are defined on the ChiActionKey stereotype.

Tag Description Example Default value
action The action, which is triggered by this association. If empty, any action is valid save
context The context, in which this association is valid. If empty, any context is valid author
config The configuration, in which this association is defined config.ini config.ini

Example application flow

An example for a simple interaction model is given in the diagram below. The controllers are modeled with the stereotype ChiController, the associations with ChiActionKey stereotype. Each association's tagged values are displayed in an attached note. Since the association between AuthorController and author view does not define the tagged values action and context, AuthorController displays this view for every action and context. The same applies to ArticleController and the article view. SaveController does not display a view, it only stores the data passed to it and returns to the next controller.

For associations, which link controllers, at least the tagged value action is set. Since obviously all save actions result in the execution of SaveController, no context is necessary. The context is helpful, when we want to solve the ambiguousness of the action ok upon termination of SaveController. We define, that the context is author when editing the author and article when editing articles. By this the application always knows to which controller it should return to after executing SaveController.

flow.png
Example application flow
Note
If the controller value of the action key should be empty, meaning that the action can be triggered from any controller, the source of the ChiActionKey association must be the Controller base class.

Controller methods

By default the framework calls the method doExecute on the current controller instance for any context and action value. For this reason an empty implementation of this method will be added by the generator.

To distinguish different actions or contexts it is also possible to model several operations inside the controller class. To connect an action key to a controller method, the action key's end that points to the controller must be named like the method. The following diagram illustrates the concept:

controller-methods.png
Controller methods

Configuration

The following stereotypes are used to model the application configuration.

Name UML meta class Description Example
ChiSystem Class A configuration section, class members and their default values become key-value pairs inside the section Database

ChiSystem

The following tags are defined on the ChiSystem stereotype.

Tag Description Example Default value
platform The platform to which the configuration settings apply wcmf
config The configuration, in which the settings are defined config.ini config.ini

Example configuration

The following diagram shows the configuration of a database connection. The connection parameters can be accessed later using the Configuration::getSection method and passing database as section paramter.

config.png
Example configuration

Default model

The default application inlcudes a demo UML model located in model/model.uml. It is a good starting point for own experiments. For those who want to start from scratch there are also base models in model/base/cwm/ (for Chronos Web Modeler) and model/base/papyrus/ (for Eclipse Papyrus).

The default model has the following package structure:

  • model
    • wcmf test
      • Primitive types
      • root
        • configuration Application specific configuration
          • default
            • config.ini
              • «ChiSystem» Config
              • ...
            • ...
        • wcmf Framework packages with useful (base-)classes
          • application
            • controller Existing controllers
              • «ChiController» AssociateController
              • ...
          • lib
            • presentation
              • «ChiController» Controller Base class for all controller classes
            • model
              • «ChiNode» Node Base class for all domain classes
            • security
              • principal
                • impl
                  • AbstractUser Base class for custom user class
                  • AbstractRole Base class for custom role class
        • app Application specific packages
          • src
            • model Domain class package
              • wcmf Default framework classes
                • «ChiNode» DBSequence
                • ...
              • «ChiNode» EntityBase Base class for domain classes with audit info
              • ...
            • controller Controller package
            • views Views package

Application specific model elements will mostly reside in the emphasized packages.

Generator

wCMF uses the code generator from the Olympos project which is originally based on openArchitectureWare. The generator is a JAVA application that executes user defined workflows. Workflows are organized in cartridges one of which is the wCMF cartridge. Cartridges are written in the Xtent/Xpand language.

If you are using Composer, the generator will be installed as a dependency in the directory vendor/olympos/chronos-generator. It may also be downloaded from SourceForge.

Configuration

The configuration of the generator is stored as key-value pairs in a file called workflow.properties in the model directory. It contains the following variables:

Variable Description Default value
profilename Name of the used UML profile Chronos
profileUmlFile Path to the profile file ${basePath}/metamodel/chronos.profile.uml
modelUmlFile Model file to generate code from model.uml
transformedModelUmlFile Location for the model transformed into the generator's internal format (used for debug purposes) model-transformed
rootPackage Model package containing libraryPackage and applicationPackage. It's name will be stripped from paths to classes wcmf test::root
libraryPackage Model package, in which the wCMF framework is defined. From this package no files will be generated wcmf
applicationPackage Model package, in which the application is modeled app
doCheck Indicates whether the generator should run checks on the model true
preCheckFile Check file, that should be used before the transformation into the internal model format cartridge::Wcmf::checks::pre
postCheckFile Check file, that should be used after the transformation into the internal model format cartridge::Wcmf::checks::post
requiredControllerSuperclass Controller base class, from which all controllers must inherit, used in the checks model::${rootPackage}::${libraryPackage}::lib::presentation::Controller
requiredNodeSuperclass Domain base class, from which all domain classes must inherit, used in the checks model::${rootPackage}::${libraryPackage}::lib::model::Node
doBackup Indicates whether the generator should do a backup of the application, before generating any files false
expand Template definition to start the generation from cartridge::Wcmf::templates::Root::root
outputEncoding Encoding of the generated files UTF-8
configFileDefault Name of the default configuration file, general properties like type mapping are declared here config.ini
projectname Name of the application wcmf testapp
targetDir Directory, in which the application is created targetDir
prExcludes File patterns to be excluded when searching for protected regions *.svn-base, .git, vendor
printGenerateDate Indicates whether the generation date should be printed in generated file headers false
headerText Text to be prepended to generated files

The variables ${basePath} (generator location) and ${targetDir} (generated code location) must be provided as command line arguments when running the generator (see Running).

Running

The generator is started using the command

java -Djava.library.path=libPath -jar ChronosGenerator.jar workflowFile -basePath=basePath -propertyFile=propertyFile -targetDir=targetDir

The parameters are explained in the following table.

Parameter Description Default value
libPath Path to the generator libraries ../vendor/olympos/chronos-generator/lib
workflowFile Workflow definition file ../vendor/olympos/chronos-generator/cartridge/Wcmf/workflow/wcmf.oaw
basePath Path to the generator installation ../vendor/olympos/chronos-generator/
propertyFile Workflow configuration file ../model/workflow.properties
targetDir Path to the generated files ../

The default values apply, if the generator is run from the build directory of the default application.

Since the code generator is integrated into the ant deployment script of the application, it's also sufficient to run the following command in the build directory:

ant generate

Artefacts

The generator creates the following files:

Configuration

  • SQL scripts are generated in the install directory. They contain the table definitions for MySQL databases (install/tables_mysql.sql) and SQLite databases (install/tables_sqlite.sql). For each domain class one table is created, inherited attributes are stored in each table (Concrete Table Inheritance).
  • Configuration files in the INI file format are generated in the app/config directory. Configuration files are implicitly defined in the model by the ChiActionKey.config and ChiSystem.config tags. For each name mentioned in these tags, one configuration file will be created, containing all definitions related to it. Furthermore, the default configuration file (config.ini per default) contains the domain class mapping definitions.

PHP Code

  • Mapper classes are generated in directories corresponding to the model packages (app/src/model, if the default model packages are used). For each ChiNode/ChiManyToMany class one subclass of NodeUnifiedRDBMapper is created (e.g. AuthorRDBMapper).
  • Domain classes are generated in the same directories as the mapper classes. For each ChiNode/ChiManyToMany class two classes are created, one base class that contains all generated code (e.g. AuthorBase) and one empty subclass, that is used to add custom code (e.g. Author). The base class inherits from Node or one of it's subclasses.
  • Controller classes are generated in directories corresponding to the model packages (app/src/controller, if the default model packages are used). For each ChiController class one subclass of Controller will be created.
  • The SOAP interface is generated in the file app/public/soap-interface.php. SOAPController uses this file to configure the SoapServer.

Template Code

  • View templates are generated in directories corresponding to the model packages (app/src/views, if the default model packages are used). For each ChiView class one empty template file will be created.

JavaScript Code

  • Domain classes are generated in a subdirectory of public/js (app/public/js/app/src/model, if the default model packages are used). For each ChiNode/ChiManyToMany one subclass of Entity is created.
  • An AMD file referencing all domain classes is created in public/js/model (app/public/js/model/_TypeList.js, if the default model packages are used).

Protected regions

The generator creates functional code, but of course custom code must be added to implement domain specific functionality. For this reason the generator adds sections that are enclosed in PROTECTED REGION tags, between which the user is supposed to place custom code. When re-generating the code later (e.g. because of model changes), this custom code will be preserved.

An example of a class file containing protected regions is shown below.

<?php
/**
This file was generated by ChronosGenerator from model.uml.
Manual modifications should be placed inside the protected regions.
*/
namespace app\src\model;
use app\src\model\AuthorBase;
// PROTECTED REGION ID(app/src/model/Author.php/Import) ENABLED START
// PROTECTED REGION END
/**
Author description:
@author
@version 1.0
*/
class Author extends AuthorBase {
// PROTECTED REGION ID(app/src/model/Author.php/Body) ENABLED START
// PROTECTED REGION END
}
?>