CodamAIDocs
Themafertig

Eigene Datenfilter

Wie ein Projekt eigene Sichtbarkeitsregeln einbaut und warum ein Pflichtfilter, der nicht aufgelöst werden kann, die Anfrage abbricht statt still zu verschwinden.

Ausprägungen
Filter liefert eine BedingungFilter liefert null → keine EinschränkungFilter wirft einen Fehler → Anfrage scheitertmehrere Filter an einem Modellunauflösbar → 500

Worum es geht

Eigene Daten und Attributfilter decken die häufigen Fälle ab. Manchmal braucht ein Projekt eine eigene Regel, etwa „Entwürfe sieht nur die Redaktion“ oder „Archivierte Verträge nur mit einem bestimmten Attribut“. Dafür schreibst du einen eigenen Datenfilter.

Ein eigener Datenfilter ist eine Spring-Bean, die CdmsFilterInterface<T> für das DTO eines Modells umsetzt. CDMS findet sie über den Typ und fragt sie bei jeder Anfrage auf dieses Modell nach einer Bedingung.

So sieht ein eigener Filter aus

@Service
public class ContractArchiveFilter implements CdmsFilterInterface<ContractDto> {

  @Override
  public ListSearchFilter get() {
    List<String> roles = RequestContextHolder.get().getEffectiveUserRoles();
    if (roles != null && roles.contains("contract-archive"))
      return null;                                   // no restriction
    return new ListSearchFilter("archived", "false", SearchLogicOperations.EQ);
  }
}

Mehr brauchst du nicht: keine Annotation für CDMS, keine Registrierung, kein fester Klassenname. Entscheidend ist nur der Typparameter, hier ContractDto.

Der Filter läuft einmal pro Anfrage, nicht pro Zeile. Er muss seine Regel deshalb als Bedingung ausdrücken, die die Datenbank prüfen kann. Feldpfade über Beziehungen sind erlaubt, z. B. company.id.

Was get() zurückgeben kann

Die drei Antworten eines Filters

Wann: get() liefert einen ListSearchFilter

CDMS hängt die Bedingung als Pflichtfilter an die Anfrage, verbunden mit UND.

Ergebnis: Die Person sieht nur Zeilen, die die Bedingung erfüllen.

Wann: get() liefert null

CDMS hängt für diesen Filter nichts an.

Ergebnis: Keine Einschränkung durch diesen Filter. Andere Filter gelten weiter.

Wann: get() wirft eine Exception

Die Anfrage scheitert mit dem Status der Exception. Der Attributfilter macht es so bei fehlendem Attribut: 422.

Ergebnis: Nichts wird gelesen oder geschrieben.

Der Filterbaum

CDMS baut jede Anfrage auf ein Modell aus einer UND-Wurzel. Darunter hängen deine Anfrage und alle Sicherheitsfilter nebeneinander.

flowchart TB
    W["UND"] --> C["Filter vom Client<br/>(aus query)"]
    W --> O["eigene Daten<br/>_userId = Person"]
    W --> A["Attributfilter"]
    W --> E1["eigener Filter 1"]
    W --> E2["eigener Filter 2"]

Gibt es mehrere eigene Filter für dasselbe Modell, gelten alle gleichzeitig. Eine Zeile muss jede Bedingung erfüllen.

Wo der Filter wirkt

AnfrageWirkung
POST /queryNur passende Zeilen, totalCount zählt nur sie.
POST /read/{id}Nicht passende Zeile → 404.
Listen und Referenzen in einer responseNicht passende Einträge fehlen, eine nicht passende Einzelreferenz ist null.
PUT, PATCH, DELETE, rollbackCDMS prüft vorher, ob die Zeile den Filter besteht; sonst 404.

Was du nicht lesen darfst, darfst du also auch nicht ändern. Siehe Warum Unsichtbares 404 liefert.

Wenn der Filter nicht passt

Ein Filter, der nicht passt, etwa mit einem Tippfehler im Feldnamen, fällt nie still weg: Ohne ihn kämen mehr Zeilen zurück, bei einem Sicherheitsfilter jede. Wer den Fehler beheben muss, hängt davon ab, woher der Filter kommt:

Filter vom Client und Pflichtfilter
Filter vom Client
aus query
  • unbekanntes Feld oder unpassender Operator → Anfrage abgelehnt
  • 400 unknown-search-key|…, unsupported-operator|…
  • der Client korrigiert seine Anfrage
Pflichtfilter
eigene Daten, Attributfilter, eigene Filter
  • unbekanntes Feld, unbekannter Pfadschritt oder unpassender Operator → Anfrage scheitert
  • 500 unresolvable-mandatory-filter|<feld>|…
  • lieber kein Ergebnis als zu viel

500 heißt hier: Das Projekt ist falsch eingerichtet, nicht die Anfrage. Der Client kann nichts daran ändern. Prüfe den Feldnamen in deinem Filter gegen das Modell. Einen Pflichtfilter kann der Client weder setzen noch abschalten.

Fallen

Wie es weitergeht

Quellen im Code und in der Wissensdatenbank
  • CDMS/cdms-commons – CdmsFilterInterface, ListSearchFilter (mandatory)
  • CDMS/cdms-system-layer – AbstractLayer (getCdmsFilter, addSecurityFilters, buildSearchRoot, assertVisibleForWrite, fetchAndSetModel, fetchAndSetList)
  • CDMS/cdms-persistence-database – DatabaseConditionBuilder (unresolvable-mandatory-filter)
  • CDMS/cdms-commons – SystemConfigurationException
  • CDMS/cdms-integrationtest – AbstractFilterTest, OrderFilter, VaultFilter
  • documentation/60-erweiterung/03-eigene-filter.md
Suchen