Skip to content

Profiles & platforms (.profile)

This page explains how platform profiles are modeled in .profile files and how they interact with the canonical model (.cmn).

Application developers normally consume the profiles delivered by a facility. Defining a custom profile is an advanced, release-bound extension task; use the examples in this page as orientation for JoinedWorkz 1.3.80.

A platform profile typically defines:

  • stereotypes – reusable annotations for model elements
  • strategies – logic to compute derived property values
  • outlets – where generated artifacts are written
  • cartridges – groups of generators for a specific concern
  • settings – wiring for dependency injection / implementation classes
  • platforms – how cartridges, properties and conventions are combined

Platforms are packaged as normal Maven artifacts that also contain the Java/Xtend implementations of cartridges, strategies and settings, and often additional CMN base models (for example base types and resource method types).


1. Profile file structure

A .profile file is organised similarly to a CMN file:

  • a package declaration at the top
  • then groups of definitions: stereotypes, strategies, outlets, cartridges, settings and platforms

Minimal, syntactically complete example:

profile
package com.example.profile

stereotype entity applicable for complextype not propagated by specialization

abstract outlet StandardOutput
    createNotExistingDirectory=true
    overwriteExistingFiles=true

outlet generatedOpenApi specialization of StandardOutput
    directory='./src/generated/resources/openapi'

cartridge OpenApiCartridge
    implementation='org.joinedworkz.common.OpenApiCartridge'
    outlets=generatedOpenApi

setting CommonSetting
    implementation='org.joinedworkz.common.CommonSetting'

platform Base setting=CommonSetting {
    apply cartridge OpenApiCartridge
}

Concrete CMN models select a platform via the platform header, for example platform Base (see Model file structure).


2. Stereotypes

Stereotypes are reusable annotations you can attach to model elements in .cmn files. They:

  • have a name
  • declare for which model element types they are applicable
  • can have specialisation relationships
  • can define how they are propagated

2.1 Declaring stereotypes

In a profile, stereotypes are declared like this (Base platform examples):

profile
stereotype entity applicable for complextype not propagated by specialization
stereotype aggregate applicable for complextype not propagated by specialization
stereotype key     applicable for field       propagated by specialization, including
stereotype controller applicable for service

Key aspects:

  • applicable for restricts where the stereotype can be used (e.g. simpletype, complextype, field, service, operation, component, …).
  • specialization of expresses inheritance between stereotypes, for example integer and long specialising number.
  • propagated by ... controls how stereotypes propagate:
    • specialization – along type inheritance
    • referencing – when something references another element
    • including – when elements are included/embedded
  • not propagated by ... can be used to explicitly stop propagation, e.g. for entity so that subtypes are not automatically entities.

2.2 Using stereotypes in CMN

In CMN models, stereotypes are applied in angle brackets on the annotated element:

cmn
type<entity> Customer {
    id**: Id
    name*: String
}

Here:

  • Customer is a complex type with the entity stereotype.
  • id** marks the field as a key using CMN shorthand.
  • Platforms can use this information to decide how to treat the type (e.g. as a persisted entity, as a logical entity, etc.).

3. Outlets

Outlets define where generated files are written and how generation treats those directories.

The Base profile defines an abstract outlet and several concrete ones, for example:

profile
abstract outlet StandardOutput
    createNotExistingDirectory = true
    overwriteExistingFiles     = true
    markAsDerived              = true
    deleteFilesOnCleanBuild    = true
    cleanWholdDirectoryOnCleanBuild = false
    keepLocalHistory           = true

outlet generatedDiagram  specialization of StandardOutput
    directory = "./diagram"

outlet generatedOpenApi  specialization of StandardOutput
    directory = "./src/generated/resources/openapi"

outlet generatedOpenApiHtml specialization of StandardOutput
    directory = "./diagram/api"

Cartridges refer to outlets to decide where to write their outputs. The directories can later be overridden at project level via joinedworkz.properties (see Create a project with Maven).


4. Cartridges

A cartridge is a bundle of generators for a specific aspect of a platform. It declares:

  • a name
  • an implementation class
  • the outlets it writes to

Examples from the Base profile:

The following declarations are an excerpt that uses the outlets from the previous section:

profile
cartridge DiagramCartridge implementation="org.joinedworkz.common.DiagramCartridge"
           outlets=generatedDiagram

cartridge OpenApiCartridge implementation="org.joinedworkz.common.OpenApiCartridge"
           outlets=generatedOpenApi, generatedOpenApiHtml

Cartridges are not invoked directly from the CMN model. Instead, they are applied by platforms (see next section). A platform can also support disabling a cartridge at model level via the exclude clause in the CMN platform header, e.g.:

cmn
platform SpringBoot exclude DtoCartridge

This keeps the platform profile generic while allowing per-model control.


5. Settings

A setting connects a platform to its implementation classes, typically via dependency injection.

Example:

profile
setting CommonSetting implementation="org.joinedworkz.common.CommonSetting"

The implementation class usually registers cartridges, generators, strategies and other services with a DI container. Derived platforms can override settings or replace specific strategies or generators by wiring different implementations.

Settings are mostly relevant when implementing platforms, not when consuming them in CMN models.


6. Platforms

A platform combines cartridges, property contributions and conventions to define how a canonical model is interpreted for a specific technology stack.

6.1 Base platform example

The following excerpt from the Base platform shows the platform body. The referenced stereotypes, cartridges, outlets, and setting are declared earlier in the same profile:

profile
platform Base setting=CommonSetting {

    /* apply cartridges */
    apply cartridge DiagramCartridge
    apply cartridge OpenApiCartridge

    contribute to simpletype<string> {
        property minLength: INTEGER
        property maxLength: INTEGER
        property pattern:   STRING
        property javaType:  STRING
        property format:    STRING
    }

    contribute to complextype<entity> {
        property tableName: STRING not propagated by specialization
    }

    contribute to complextype<entity>.field {
        property columnName: STRING
    }
}

Key ideas:

  • setting=CommonSetting links the platform to the DI configuration.
  • apply cartridge ... lists the cartridges that belong to this platform.
  • contribute to ... adds or overrides properties on model elements that have certain stereotypes (e.g. simpletype<string>, complextype<entity>).
  • Properties can also define propagation rules (not propagated by specialization) and, in derived platforms, default values or overrides.

6.2 Platform inheritance

Platforms can inherit from other platforms:

profile
platform Java specialization of Base {
    apply cartridge DtoCartridge

    contribute to simpletype<decimal> {
        override javaType value="java.math.BigDecimal"
    }
}

Inheritance allows you to:

  • reuse common behaviour (e.g. diagram and OpenAPI cartridges from Base),
  • add platform-specific cartridges (e.g. Java or Spring Boot generators),
  • refine property contributions (override or extend properties).

6.3 Binding CMN models to platforms

In CMN files, the header selects the platform, for example:

cmn
platform Base

or, with cartridge exclusions:

cmn
platform SpringBoot exclude DtoCartridge

The generator then:

  • loads the selected platform from the available profile modules,
  • applies its cartridges to the model,
  • uses property contributions, stereotypes and strategies defined by the platform to drive generation.

7. Strategies

Strategies are used to compute values for derived or calculated properties during generation.

They are declared in the profile, for example (Java platform):

profile
strategy JavaNamingStrategy implementation="org.joinedworkz.common.java.Strategy"
strategy JavaTypeStrategy   implementation="org.joinedworkz.common.java.JavaTypeStrategy"

Strategies are then referenced in property contributions:

The contributions occur inside a platform declaration:

profile
platform ExampleJava {
    contribute to field {
        property javaName: STRING strategy=JavaNamingStrategy
    }

    contribute to type {
        property javaType: STRING strategy=JavaTypeStrategy
    }
}

At generation time, the strategy implementations:

  • receive the relevant model element (field, type, …),
  • compute the property value (e.g. a Java-friendly name or type),
  • write it into the model’s derived properties for further use by generators.

Because strategies are wired via DI, derived platforms can easily swap in alternative implementations if needed.


8. Packaging and reuse

Each platform is typically delivered as a Maven module that contains:

  • one or more .profile files (platform profiles),
  • Java/Xtend implementations of cartridges, generators, strategies, settings and other helpers,
  • optional CMN base models, such as:
    • base type definitions (e.g. String, numeric types),
    • resource method types (create, read, etc.).

You make a platform available to your model module by adding it as a normal Maven dependency. The JoinedWorkz Maven plugin then:

  • loads the platform profiles and implementations from the classpath,
  • uses them when executing the generator for your models.

Platforms provided by JoinedSystems (such as the Base platform) are published to Maven Central. A custom platform should live in its own Maven module and be treated as an advanced extension that is tested against the JoinedWorkz release it targets.


9. Next steps

From here you can: