Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a1ec9f9
Add audit to FeatureSchema
neiroukh Apr 30, 2026
d9e266a
feature: basic audit logging
neiroukh May 6, 2026
1368091
extract audit code
neiroukh May 12, 2026
e310c0c
inject AuditLogger
neiroukh May 15, 2026
4142a50
apply support for access-logging
neiroukh May 18, 2026
9e8338e
extract requestId from ApiRequestContext instead of LogContext
neiroukh May 19, 2026
ac5756e
apply updated AuditLogger api calls
neiroukh May 20, 2026
38aa8f9
apply AuditLog refactor
neiroukh May 21, 2026
a1ccdf8
apply AuditLog changes
neiroukh May 22, 2026
35c3c8b
keep property order by using LinkedHashMap
neiroukh May 26, 2026
57f6892
remove log-finalizing from onEnd
neiroukh May 27, 2026
627453c
apply audit-log module
neiroukh May 28, 2026
1261ed9
apply auditLog moving to xtraplatform-services
neiroukh May 29, 2026
0d172f3
optional property access
neiroukh Jun 5, 2026
b5feed7
replace throw by LOGGER.error
neiroukh Jun 8, 2026
5a6f28f
Merge branch 'master' into ldp-95-audit-logging-new-module
azahnen Jun 11, 2026
0551dc7
fix merge
azahnen Jun 11, 2026
8ad1830
api config: includePropertyValues
neiroukh Jun 11, 2026
14cc39e
audit in provider
neiroukh Jun 11, 2026
253ce8c
log properties also in error case
azahnen Jun 11, 2026
0eadcf4
log properties also in error case
azahnen Jun 11, 2026
63f2090
support array values and complex schemas
azahnen Jun 12, 2026
6c13971
fix explicit false bug
neiroukh Jun 12, 2026
2774d2c
audit docs
neiroukh Jun 12, 2026
ba53483
cleanup
azahnen Jun 24, 2026
49d6995
cleanup
azahnen Jun 24, 2026
0f05eb1
Merge branch 'master' into ldp-95-audit-logging-new-module
azahnen Jun 24, 2026
676d900
docs
azahnen Jun 24, 2026
b2dc88c
upgrade xtraplatform
azahnen Jun 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions xtraplatform-features-geoparquet/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ dependencies {
provided project(':xtraplatform-features-sql')
provided project(':xtraplatform-geometries')

//NOPMD - TODO: very big, only include binary for current platform
Comment thread
azahnen marked this conversation as resolved.
embedded(libs.duckdb)
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import de.ii.xtraplatform.features.sql.domain.SqlQueryBatch;
import de.ii.xtraplatform.features.sql.domain.SqlQueryOptions;
import de.ii.xtraplatform.features.sql.domain.SqlRow;
import de.ii.xtraplatform.services.domain.AuditLog;
import de.ii.xtraplatform.services.domain.Scheduler;
import de.ii.xtraplatform.streams.domain.Reactive;
import de.ii.xtraplatform.values.domain.ValueStore;
Expand Down Expand Up @@ -217,6 +218,7 @@ public FeatureProviderGeoParquet(
VolatileRegistry volatileRegistry,
Cache cache,
Scheduler scheduler,
AuditLog auditLog,
@Assisted FeatureProviderDataV2 data) {
super(
crsTransformerFactory,
Expand All @@ -231,6 +233,7 @@ public FeatureProviderGeoParquet(
volatileRegistry,
cache,
scheduler,
auditLog,
data,
Map.of());
}
Expand Down
2 changes: 1 addition & 1 deletion xtraplatform-features-gml/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

maturity = 'CANDIDATE'
maintenance = 'NONE'
description = 'WFS feature provider and GML features.'
Expand All @@ -9,6 +8,7 @@ dependencies {
provided 'de.interactive_instruments:xtraplatform-streams'
provided 'de.interactive_instruments:xtraplatform-values'
provided 'de.interactive_instruments:xtraplatform-web'
provided 'de.interactive_instruments:xtraplatform-services'
provided project(':xtraplatform-codelists')
provided project(':xtraplatform-cql')
provided project(':xtraplatform-crs')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import de.ii.xtraplatform.features.gml.domain.FeatureProviderWfsData;
import de.ii.xtraplatform.features.gml.domain.WfsConnector;
import de.ii.xtraplatform.features.gml.domain.XMLNamespaceNormalizer;
import de.ii.xtraplatform.services.domain.AuditLog;
import de.ii.xtraplatform.streams.domain.Reactive;
import de.ii.xtraplatform.streams.domain.Reactive.Stream;
import de.ii.xtraplatform.values.domain.ValueStore;
Expand Down Expand Up @@ -142,6 +143,7 @@ public FeatureProviderWfs(
Reactive reactive,
ValueStore valueStore,
ProviderExtensionRegistry extensionRegistry,
AuditLog auditLog,
VolatileRegistry volatileRegistry,
@Assisted FeatureProviderDataV2 data) {
super(
Expand All @@ -151,6 +153,7 @@ public FeatureProviderWfs(
crsInfo,
extensionRegistry,
valueStore.forType(Codelist.class),
auditLog,
data,
volatileRegistry);

Expand Down Expand Up @@ -227,10 +230,9 @@ protected FeatureQueryEncoder<String, QueryOptions> getQueryEncoder() {
private FeatureTokenDecoder<
byte[], FeatureSchema, SchemaMapping, ModifiableContext<FeatureSchema, SchemaMapping>>
getDecoder(Query query, Map<String, SchemaMapping> mappings, boolean passThrough) {
if (!(query instanceof FeatureQuery)) {
if (!(query instanceof FeatureQuery featureQuery)) {
throw new IllegalArgumentException();
}
FeatureQuery featureQuery = (FeatureQuery) query;
Map<String, String> namespaces = getData().getConnectionInfo().getNamespaces();
XMLNamespaceNormalizer namespaceNormalizer = new XMLNamespaceNormalizer(namespaces);
FeatureSchema featureSchema = getData().getTypes().get(featureQuery.getType());
Expand Down Expand Up @@ -376,6 +378,7 @@ public FeatureStream getFeatureStreamPassThrough(FeatureQuery query) {
nativeCrsIs3d,
getCodelists(),
this::runQuery,
false);
false,
auditLog);
}
}
1 change: 1 addition & 0 deletions xtraplatform-features-graphql/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ dependencies {
provided 'de.interactive_instruments:xtraplatform-streams'
provided 'de.interactive_instruments:xtraplatform-values'
provided 'de.interactive_instruments:xtraplatform-web'
provided 'de.interactive_instruments:xtraplatform-services'
provided project(':xtraplatform-codelists')
provided project(':xtraplatform-cql')
provided project(':xtraplatform-crs')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import de.ii.xtraplatform.features.domain.transform.OnlySortables;
import de.ii.xtraplatform.features.graphql.domain.FeatureProviderGraphQlData;
import de.ii.xtraplatform.features.graphql.domain.GraphQlConnector;
import de.ii.xtraplatform.services.domain.AuditLog;
import de.ii.xtraplatform.streams.domain.Reactive;
import de.ii.xtraplatform.streams.domain.Reactive.Stream;
import de.ii.xtraplatform.values.domain.ValueStore;
Expand Down Expand Up @@ -197,6 +198,7 @@ public FeatureProviderGraphQl(
Reactive reactive,
ValueStore valueStore,
ProviderExtensionRegistry extensionRegistry,
AuditLog auditLog,
VolatileRegistry volatileRegistry,
@Assisted FeatureProviderDataV2 data) {
super(
Expand All @@ -206,6 +208,7 @@ public FeatureProviderGraphQl(
crsInfo,
extensionRegistry,
valueStore.forType(Codelist.class),
auditLog,
data,
volatileRegistry);

Expand Down Expand Up @@ -271,10 +274,9 @@ protected FeatureQueryEncoder<String, QueryOptions> getQueryEncoder() {
protected FeatureTokenDecoder<
byte[], FeatureSchema, SchemaMapping, ModifiableContext<FeatureSchema, SchemaMapping>>
getDecoder(Query query, Map<String, SchemaMapping> mappings) {
if (!(query instanceof FeatureQuery)) {
if (!(query instanceof FeatureQuery featureQuery)) {
throw new IllegalArgumentException();
}
FeatureQuery featureQuery = (FeatureQuery) query;
FeatureSchema featureSchema = getSourceSchemas().get(featureQuery.getType()).get(0);
String name =
featureSchema.getSourcePath().map(sourcePath -> sourcePath.substring(1)).orElse(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import de.ii.xtraplatform.features.sql.domain.SqlQueryOptions;
import de.ii.xtraplatform.features.sql.domain.SqlRow;
import de.ii.xtraplatform.geometries.domain.transcode.wktwkb.WkbDialect;
import de.ii.xtraplatform.services.domain.AuditLog;
import de.ii.xtraplatform.services.domain.Scheduler;
import de.ii.xtraplatform.streams.domain.Reactive;
import de.ii.xtraplatform.values.domain.ValueStore;
Expand Down Expand Up @@ -126,6 +127,7 @@ public FeatureProviderOracle(
VolatileRegistry volatileRegistry,
Cache cache,
Scheduler scheduler,
AuditLog auditLog,
@Assisted FeatureProviderDataV2 data) {
super(
crsTransformerFactory,
Expand All @@ -140,6 +142,7 @@ public FeatureProviderOracle(
volatileRegistry,
cache,
scheduler,
auditLog,
data,
Map.of());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
import de.ii.xtraplatform.features.sql.domain.SqlQueryColumn.Operation;
import de.ii.xtraplatform.features.sql.infra.db.SourceSchemaValidatorSql;
import de.ii.xtraplatform.geometries.domain.transcode.wktwkb.WkbDialect;
import de.ii.xtraplatform.services.domain.AuditLog;
import de.ii.xtraplatform.services.domain.Scheduler;
import de.ii.xtraplatform.streams.domain.Reactive;
import de.ii.xtraplatform.streams.domain.Reactive.RunnableStream;
Expand Down Expand Up @@ -490,6 +491,7 @@ public FeatureProviderSql(
VolatileRegistry volatileRegistry,
Cache cache,
Scheduler scheduler,
AuditLog auditLog,
@Assisted FeatureProviderDataV2 data) {
this(
crsTransformerFactory,
Expand All @@ -504,6 +506,7 @@ public FeatureProviderSql(
volatileRegistry,
cache,
scheduler,
auditLog,
data,
decoderFactories.getConnectorDecoders());
}
Expand All @@ -521,6 +524,7 @@ protected FeatureProviderSql(
VolatileRegistry volatileRegistry,
Cache cache,
Scheduler scheduler,
AuditLog auditLog,
FeatureProviderDataV2 data,
Map<String, DecoderFactory> subdecoders) {
super(
Expand All @@ -530,6 +534,7 @@ protected FeatureProviderSql(
crsInfo,
extensionRegistry,
valueStore.forType(Codelist.class),
auditLog,
data,
volatileRegistry);

Expand Down Expand Up @@ -965,11 +970,7 @@ public boolean supportsMutationsInternal() {
if (!Objects.equals(getData().getConnectionInfo().getDialect(), SqlDbmsPgis.ID)) {
return false;
}
if (!getData().getDatasetChanges().isModeCrud()) {
return false;
}

return true;
return getData().getDatasetChanges().isModeCrud();
}

@Override
Expand Down Expand Up @@ -1367,7 +1368,7 @@ private MutationResult writeFeatures(
crsTransformerFactory,
getData().getNativeTimeZone(),
partial ? Optional.of(FeatureTransactions.PATCH_NULL_VALUE) : Optional.empty()))
.via(Transformer.map(feature -> (FeatureDataSql) feature));
.via(Transformer.map(feature -> feature));

if (partial) {
featureSqlSource =
Expand Down Expand Up @@ -1492,7 +1493,8 @@ public FeatureStream getFeatureStream(MultiFeatureQuery query) {
nativeCrsIs3d,
getCodelists(),
this::runQuery,
!query.hitsOnly());
!query.hitsOnly(),
auditLog);
}

@Override
Expand Down
3 changes: 2 additions & 1 deletion xtraplatform-features/build.gradle
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@

maturity = 'MATURE'
maintenance = 'FULL'
description = 'Feature providers and transformations.'
descriptionDe = 'Feature-Provider und Transformationen.'

dependencies {
provided 'de.interactive_instruments:xtraplatform-base'
provided 'de.interactive_instruments:xtraplatform-entities'
provided 'de.interactive_instruments:xtraplatform-streams'
provided 'de.interactive_instruments:xtraplatform-values'
provided 'de.interactive_instruments:xtraplatform-services'
provided project(':xtraplatform-codelists')
provided project(':xtraplatform-cql')
provided project(':xtraplatform-crs')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import de.ii.xtraplatform.features.domain.transform.WithScope;
import de.ii.xtraplatform.features.domain.transform.WithoutProperties;
import de.ii.xtraplatform.geometries.domain.GeometryType;
import de.ii.xtraplatform.services.domain.AuditLog;
import de.ii.xtraplatform.streams.domain.Reactive;
import de.ii.xtraplatform.streams.domain.Reactive.Runner;
import de.ii.xtraplatform.streams.domain.Reactive.Stream;
Expand Down Expand Up @@ -87,13 +88,16 @@ public abstract class AbstractFeatureProvider<
private boolean datasetChangedForced;
private String previousDataset;

protected AuditLog auditLog;

protected AbstractFeatureProvider(
ConnectorFactory connectorFactory,
Reactive reactive,
CrsTransformerFactory crsTransformerFactory,
CrsInfo crsInfo,
ProviderExtensionRegistry extensionRegistry,
Values<Codelist> codelistStore,
AuditLog auditLog,
FeatureProviderDataV2 data,
VolatileRegistry volatileRegistry) {
super(data, volatileRegistry);
Expand All @@ -103,6 +107,7 @@ protected AbstractFeatureProvider(
this.crsInfo = crsInfo;
this.extensionRegistry = extensionRegistry;
this.codelistStore = codelistStore;
this.auditLog = auditLog;
this.volatileRegistry = volatileRegistry;
this.changeHandler = new FeatureChangeHandlerImpl();
this.connector =
Expand Down Expand Up @@ -527,7 +532,8 @@ public FeatureStream getFeatureStream(FeatureQuery query) {
nativeCrsIs3d,
getCodelists(),
this::runQuery,
!query.hitsOnly());
!query.hitsOnly(),
auditLog);
}

// TODO: more tests
Expand Down Expand Up @@ -594,8 +600,7 @@ private FeatureTokenSource getFeatureTokenSource(

private Map<String, SchemaMapping> createMapping(
Query query, Map<String, PropertyTransformations> propertyTransformations) {
if (query instanceof FeatureQuery) {
FeatureQuery featureQuery = (FeatureQuery) query;
if (query instanceof FeatureQuery featureQuery) {

WithScope withScope =
featureQuery.getSchemaScope() == SchemaBase.Scope.RETURNABLE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ default List<CustomFunction> getCql2Functions() {
* definitions](#schema-definitions) with `type: OBJECT` and at least one property with `role:
* ID`.
* @langDe Definition von Feature-Types. Die Einträge sind
* [Schema-Definitionen](#schema-definitions) mit `type: OBJECT` und mindestens einem Property
* mit `role: ID`.
* [Schema-Definitionen](#schema-definitionen) mit `type: OBJECT` und mindestens einem
* Property mit `role: ID`.
* @default {}
*/
@JsonMerge
Expand All @@ -197,7 +197,7 @@ default List<CustomFunction> getCql2Functions() {
* `types`. The entries are arbitrary [schema definitions](#schema-definitions).
* @langDe Definition von wiederverwendbaren Schema-Fragmenten, die mittels `schema` in `types`
* referenziert werden können. Die Einträge sind beliebige
* [Schema-Definitionen](#schema-definitions).
* [Schema-Definitionen](#schema-definitionen).
* @default {}
*/
@JsonMerge
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,20 @@ public interface FeatureSchema
String CONCAT_ELEMENT = "_CONCAT_ELEMENT_";
String COALESCE_ELEMENT = "_COALESCE_ELEMENT_";

/**
* @langEn If set to `true` for properties of type `VALUE`/`VALUE_ARRAY`, these will be included
* in the audit log. If set to `true` for a feature type, all of its properties will be
* included in the audit log except for those explicitly excluded. Geometries are always
* excluded.
* @langDe Wenn für Eigenschaften vom Typ `VALUE`/`VALUE_ARRAY` auf `true` gesetzt, werden diese
* in das Audit-Log aufgenommen. Wenn für einen Feature-Type auf `true` gesetzt, werden alle
* seine Eigenschaften in das Audit-Log aufgenommen, außer diejenigen, die explizit
* ausgeschlossen sind. Geometrien sind immer ausgeschlossen.
* @default false
* @since v4.8
*/
Optional<Boolean> getAudit();

@JsonIgnore
@Override
String getName();
Expand Down Expand Up @@ -1244,8 +1258,7 @@ default FeatureSchema accept(FeatureSchemaTransformer visitor, List<FeatureSchem
.map(
entry ->
new SimpleEntry<>(
entry.getKey(),
(FeatureSchema) visit.apply(entry.getValue())))
entry.getKey(), visit.apply(entry.getValue())))
.collect(
ImmutableMap.toImmutableMap(
Map.Entry::getKey, Map.Entry::getValue)))
Expand Down
Loading
Loading