Zum Inhalt springen

Anwendung bauen und betreiben

Kurzantwort: Ihr Projekt ist ein gewöhnliches Maven-Projekt. Beim Build holt ein Plugin die Modellbeschreibung aus dem Hub, danach erzeugt der CDMS-Generator als Annotation-Processor den Code — Ergebnis ist ein ausführbares Spring-Boot-Artefakt. Zur Laufzeit brauchen Sie eine Datenbank, ein Verzeichnis für Dateien und einen OIDC-Anbieter.


JDK24 (für den nativen Build: GraalVM Community 24)
Maven3.9+
DatenbankMySQL 8 produktiv, H2 für Tests
IdentitätsanbieterKeycloak oder ein anderer OIDC-Anbieter
Zugang zur Artefakt-RegistryZugangsdaten für die CDMS-Bibliotheken, in ~/.m2/settings.xml
Generator-ZugangClient-ID, Secret und die UUID Ihres CDMS-Systems

Zugangsdaten und Registry-URL erhalten Sie vom Betreiber Ihres Hubs. Die UUID Ihres Systems finden Sie in der Modellierungsoberfläche oder über cdms_list_targets im MCP-Server.

flowchart TB
    subgraph "mvn generate-sources"
        F["Metadaten holen"] -->|Client-Credentials| K[(Identitätsanbieter)]
        F -->|Modelle, Felder, Endpunkte| API[(CDMS-Hub)]
        F --> Y["Modell-Cache<br/>models · folders · enumerations · system"]
    end
    subgraph "mvn compile"
        L[Lombok] --> MS[MapStruct] --> G[CDMS-Generator]
        Y --> G
        G --> GEN["target/generated-sources/annotations<br/>~20 Klassen je Modell"]
    end
    GEN --> PKG["mvn package<br/>ausführbares JAR"]
    PKG -.->|"Profil native"| BIN["natives Binary"]

Die CDMS-Bibliotheken liegen in einer Maven-Registry. Tragen Sie die Zugangsdaten in ~/.m2/settings.xml ein — die Server-IDs nennt Ihnen der Betreiber zusammen mit der Repository-URL.

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.4.1</version>
<dependencies>
<dependency>
<groupId>com.codamai.cdms</groupId>
<artifactId>cdms-generator</artifactId>
<version>${cdms.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>fetch-cdms-metadata</id>
<phase>generate-sources</phase>
<goals><goal>java</goal></goals>
</execution>
</executions>
<configuration>
<mainClass>com.codamai.cdms.remote.CdmsMetadataFetcher</mainClass>
<includePluginDependencies>true</includePluginDependencies>
<skip>${cdms.generator.fetch.skip}</skip>
</configuration>
</plugin>

includePluginDependencies ist nötig, damit das Generator-JAR im Classloader des Plugins landet. Über cdms.generator.fetch.skip schalten Sie den Abruf ab und arbeiten auf dem vorhandenen Cache.

Die Reihenfolge ist verbindlich: Lombok → MapStruct → CDMS-Generator. Lombok erzeugt die Accessoren, auf die MapStruct aufsetzt; der Generator kommt zuletzt.

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>24</source>
<target>24</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
<path>
<groupId>com.codamai.cdms</groupId>
<artifactId>cdms-generator</artifactId>
<version>${cdms.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-parameters</arg>
<arg>-Acdms.generator.cacheDir=${project.build.directory}/cache</arg>
<arg>-Acdms.generator.basePackage=com.example.meineapp</arg>
</compilerArgs>
</configuration>
</plugin>

-parameters behält die Parameternamen im Bytecode — Spring MVC und MapStruct brauchen sie.

Werte kommen aus Umgebungsvariablen, JVM-Properties oder einer lokalen cdms-generator.properties. Details unter Generierung.

cdms.generator.keycloakUrl=https://<ihr-idp>
cdms.generator.keycloakRealm=<realm>
cdms.generator.clientId=<client-id>
cdms.generator.clientSecret=<secret>
cdms.generator.cdmsUrl=https://<ihr-hub>
cdms.generator.systemId=<uuid-ihres-systems>
cdms.generator.cacheDir=target/cache

Das Secret gehört nicht ins Repository. Nehmen Sie die Datei in .gitignore auf und setzen Sie die Werte in der CI aus geschützten Variablen.

Terminal-Fenster
# vollständiger Build inklusive Tests
mvn clean package
# ohne erneuten Modell-Abruf, auf dem vorhandenen Cache
mvn clean package -Dcdms.generator.fetch.skip=true
# nur generieren und kompilieren
mvn clean compile
# natives Binary (benötigt GraalVM 24)
mvn clean package -Pnative -DskipTests

Nach einer Modelländerung im Hub den Abruf einmal mit -Dcdms.generator.fetch.skip=false laufen lassen, sonst baut Maven weiter gegen den alten Cache.

Offline arbeiten geht mit CODEGEN_OFFLINE=true, sofern die vier Cache-Dateien vorliegen. Fehlt eine, bricht der Build mit einer klaren Meldung ab.

OrtInhalt
target/generated-sources/annotations/Entities, DTOs, Payloads, Mapper, APIs, Service- und Persistenzschicht
src/main/java/einmalig erzeugtes Gerüst (Hauptklasse, OpenAPI, Native Hints) plus Ihr Code
target/*.jarausführbares Spring-Boot-Artefakt
target/<name>natives Binary, wenn mit -Pnative gebaut

Generierten Code niemals von Hand ändern — er wird bei jedem Build neu erzeugt. Fachlogik kommt über Hooks.

Datenbank, Betriebsart, Dateiablage und Identitätsanbieter werden über Spring-Properties bzw. Umgebungsvariablen gesetzt. Die vollständige Liste steht unter Konfiguration; das Minimum:

cdms:
database:
mode: MULTI # oder SINGLE ohne Mandantentrennung
driver: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://db:3306/{tenant}
user: ${DB_USER}
password: ${DB_PASSWORD}
codamai:
cdms:
persistence:
file:
basePath: /files/

Der Platzhalter {tenant} wird pro Mandant ersetzt — siehe Mandantentrennung.

ZweckWert
Anwendung8080
Management8081
LivenessGET :8081/actuator/health/liveness
REST-API/api/rest/**

Die Health-Indikatoren für Persistenz und Dateiablage sind aktiv, sobald Actuator im Projekt liegt — siehe Observability.

ModusVerhalten
HIBERNATE (Standard)Hibernate passt das Schema selbst an (hbm2ddl.auto=update)
FLYWAYversionierte Migrationen pro Ziel: db/migration/system und db/migration/tenant, danach nur noch Validierung

Für produktive Installationen ist FLYWAY die belastbarere Wahl: Änderungen sind nachvollziehbar und wiederholbar. Eine neue Mandantendatenbank wird beim ersten Zugriff angelegt (sofern freigegeben) und anschließend migriert. flyway-core ist optional und nur für diesen Modus nötig.

# JVM-Variante
FROM eclipse-temurin:24-jre
WORKDIR /app
COPY target/meineapp.jar app.jar
EXPOSE 8080 8081
VOLUME /files
ENTRYPOINT ["java", "-jar", "app.jar"]
# Native Variante — kleiner und schneller am Start
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends curl \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY target/meineapp .
RUN useradd -r -u 1001 appuser && chown -R appuser /app
USER appuser
EXPOSE 8080 8081
VOLUME /files
HEALTHCHECK CMD curl -fsS http://127.0.0.1:8081/actuator/health/liveness || exit 1
ENTRYPOINT ["./meineapp"]

Das Volume unter dem konfigurierten basePath ist Pflicht, sobald Sie Datei-Modelle nutzen: Ohne persistentes Volume sind die Inhalte nach einem Neustart verloren, während die Metadaten in der Datenbank bleiben.

  • Native Image senkt Startzeit und Speicherbedarf deutlich (Erfahrungswert: rund 400 MB auf unter 200 MB) — dafür dauert der Build länger und Reflexion muss registriert sein, siehe Native Image.
  • Verbindungspool: cdms.database.pool-size gilt pro Mandant. Bei vielen Mandanten ist das die Stellschraube, die zuerst knapp wird.
  • Parallelität bei abstrakten Abfragen: cdms_hub_query_parallelism muss zur Poolgröße passen; jeder Worker belegt ein bis zwei Verbindungen.
  • Dateigrößen: Downloads werden vollständig in den Speicher gelesen. Der Heap-Bedarf wächst mit Dateigröße mal gleichzeitiger Downloads.
Terminal-Fenster
mvn test # Unit- und Integrationstests gegen H2
mvn verify # inklusive nachgelagerter Phasen

Was sich zu testen lohnt: Create, Update, Patch, Read, Suche, Response Requests, Validierung, Beziehungen, Mandanten-Isolation, Rechte, Datei-Handling und Auditing.

Hinweise zu H2: Tests isolieren, die Datenbank vor jedem Test in FK-verträglicher Reihenfolge leeren, Transaktionsgrenzen prüfen, nicht unnötig parallelisieren und @DirtiesContext nur gezielt einsetzen.

SymptomUrsache und Abhilfe
Maven findet die cdms-*-Artefakte nichtRegistry-Zugang fehlt — Zugangsdaten in ~/.m2/settings.xml, Erreichbarkeit prüfen
Metadaten-Abruf schlägt fehl oder hängtZugangsdaten und URLs prüfen; ersatzweise -Dcdms.generator.fetch.skip=true mit vorhandenem Cache
Build bricht mit UnsupportedClassVersionError abEs läuft ein JDK < 24 — auch die IDE muss auf 24 laufen, wenn sie den Abruf im eigenen Prozess ausführt
Generierte Klassen fehlenReihenfolge der Annotation-Processors prüfen (Lombok → MapStruct → Generator)
Reflexionsfehler nur im nativen ImageNative Hints ergänzen, siehe Native Image
Beziehungen werden nicht persistiertBesitzende Seite beachten, siehe Beziehungen
Objekte ohne Beziehung fehlen im Suchergebnisimpliziter Inner Join — Pfadausdrücke prüfen, siehe Suche und Filter
CDMS_TENANT_REQUIRED im BetriebMandantenobjekt ohne effektiven Mandanten, siehe Mandantentrennung