Command Framework

General

The command framework provides an extensible command pattern based on the template design. The commands can be seen as templates providing a static workflow using single, atomic operations as execution step. Usually, the commands fit for nearly all data modification tasks we have. You can create new data objects, add or remove them to/from their parent, you can set single properties of a data object and you can trigger separate validation rules. Additionally to this, even new commands can be contributed to the framework - either for new purposes (e.g. import or merge command), or as a different implementation for specific entities.

The amount of flexibility comes not without the cost of complexity. A "simple" article.setDescriptionShort(english, "my description") is currently not provided by the platform, but we encourage you to build your own data access objects which themself use the generic command framework.

images/download/attachments/35915671/CommandPattern.png

Every operator which is part of a command follows a well known interface. This interface always provides access to the CommandContext and additional parameters which might be helpful to fulfill the tasks the operator is designed for. Some operators are contributed by default from the command framework, others have no default implementation and are usually only for entity or customizing specific implementations.

In case a CommandContext is cancelled, the following operators will not be executed and the command execution is aborted.

Command Context

images/download/attachments/35915671/CommandContext.gxml.png

The CommandContext is the central interface of the command framework. Clients must obtain an instance from the CommandContextFactory using the CommandContextParam object to parameterize the context. By using the CommandContext you can obtain the CommandFactory as well as the OperatorFactory which provides you the actual command and operator instances for an Entity or Field.

Feedback Processors

All operators have access to the CommandContext and can - at any time - provide feedback to the framework. Feedback can be an error or a warning. To provide feedback you need to create a CommandStatus object and call the corresponding addFeedback method. Depending on the severity of the CommandStatus the FeedbackProcessor will decide if the command context should be cancelled or not.

In general there are two kinds of FeedbackProcessor implementations possible. The one supports and enforces to have the possibility to interact with a user (e.g. through a dialog), the other doesn't. For example, when editing in the client's table view, the feedback processor which is used needsUserinteraction since it opens an error or warning dialog (depending on the severity of the command status). On the other hand, during the automated execution of an import or merge, we can not expect to have the possibility of a user interaction during the command run - therefore the used processor will only log the feedback and - in case of a warning - will always assume a "yes" - thus warnings will not cancel the command status.

You can define your own FeedbackProcessor in the CommandContextParams in case you're calling the command by yourself. Other areas in the system like Jobs (e.g. Import, Merge) use their own feedback processor implementation which can not be replaced as the job logic relies on them.

Commands

Platform commands are all commands which are used by the core platform. They build the fundamental set of data modification commands all other parts of the application use.

Create Command

Creates a new data object and initializes all it's direct properties with the default values from the repository.

Add Command

Adds a data object to it's parent data object. Prior before doing this it executes several validation operators including the validation for duplicates.

Put Command

Typically used to set values of single fields of a data object. But in contrast to only allow a simple set operation on a field, it also is able to navigate through the object model to find the correct data object on which to set a value. This operation is called put, of course it's far more complex.

Validate Command

Validates a single data object and it's children. The default operators for this command only validate for mandatory fields and mandatory children. Field legth and other field based validations are performed during the put or set operation of the PutCommand and must not be executed again. Customizing can contribute additional validation.

Remove Command

Removes a data object from it's parent. Before that, validations are executed. For example one could check if it is allowed to remove the "last price" of an item. By default there are no extra validations implemented for this command.

Operators

Most operators are used in multiple commands (like the PropertyInitializer which is used in the AddCommand as well as the CreateCommand)

Operators are a highly generic concept. The command implementations are free to decide which kind of operators they want to use. There is no common base interface for all operators at all. So how can you contribute your own operator? For this you need the operator's type information which is either documented here, or in the class javadoc of the operator interface. The operator type has meta information which are documented as follows:

  • Type Identifier
    Unique identifier of the operator type, usually equals to the simple class name of the operator interface.

  • Allows Combination
    When yes, this signals that the command can handle multiple contributions for the same property, but on different repository levels. For example: You could then contribute an operator for the field type, e.g. ArticleLangType.DescriptionShort as well as for the field (custom area in the repositry) ArticleLang.DescriptionShort. In this case, both operators will be executed in order of their repository level. That is: Type elements before Custom elements, Entities before Fields.

  • Allows Multiple
    When true, multiple contributions for the same repository identifier are possible. The operators will then be executed in the order of their order attribute

  • Generic Operator Identifier
    The identifier of the generic implementation of the operator (generic means, no repository specific contribution, thus this operator will be executed for every field/entity)

The list of supported operators can be found on each command page.