diff --git a/.gitignore b/.gitignore index f83efc97d..7d345ec52 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.sublime-workspace *.iml build/ +bin/ .idea/ .gradle/ node_modules/ diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/app/ConnectorFactoryImpl.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/app/ConnectorFactoryImpl.java index da02cd1b3..dca7df227 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/app/ConnectorFactoryImpl.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/app/ConnectorFactoryImpl.java @@ -22,6 +22,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.locks.ReentrantLock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,6 +37,7 @@ public class ConnectorFactoryImpl implements ConnectorFactory { private final Lazy>> connectorFactories; private final Map> disposeListeners; + private final ReentrantLock lock = new ReentrantLock(); @Inject public ConnectorFactoryImpl(Lazy>> connectorFactories) { @@ -44,45 +46,73 @@ public ConnectorFactoryImpl(Lazy>> connectorFacto } @Override - public synchronized FeatureProviderConnector createConnector( + public FeatureProviderConnector createConnector( String providerType, String providerId, ConnectionInfo connectionInfo) { - final String connectorType = connectionInfo.getConnectorType(); + lock.lock(); + try { + final String connectorType = connectionInfo.getConnectorType(); - if (getFactory(providerType, connectorType).isEmpty()) { - throw new IllegalStateException( - String.format( - "Connector with type %s for provider type %s is not supported.", - connectorType, providerType)); - } + if (getFactory(providerType, connectorType).isEmpty()) { + throw new IllegalStateException( + String.format( + "Connector with type %s for provider type %s is not supported.", + connectorType, providerType)); + } + + ConnectorFactory2 connectorFactory2 = getFactory(providerType, connectorType).get(); + + if (connectionInfo.isShared()) { + Optional> shared = + findSharedConnector(connectorFactory2, connectionInfo); - ConnectorFactory2 connectorFactory2 = getFactory(providerType, connectorType).get(); - - if (connectionInfo.isShared()) { - Optional> match = - connectorFactory2.instances().stream() - .filter(connector -> connector.canBeSharedWith(connectionInfo, false).first()) - .findFirst(); - - if (match.isPresent()) { - Tuple fullMatch = match.get().canBeSharedWith(connectionInfo, true); - - if (fullMatch.first()) { - LOGGER.debug("Joining shared pool."); - match - .get() - .getRefCounter() - .ifPresent(refs -> LOGGER.debug("Shared pool consumers: {}", refs.incrementAndGet())); - - return match.get(); - } else { - throw new IllegalStateException( - String.format( - "Connection pool cannot be shared with provider %s: %s", - match.get().getProviderId(), fullMatch.second())); + if (shared.isPresent()) { + return shared.get(); } } + + return createNewConnector( + connectorFactory2, providerId, connectorType, providerType, connectionInfo); + } finally { + lock.unlock(); } + } + private Optional> findSharedConnector( + ConnectorFactory2 connectorFactory2, ConnectionInfo connectionInfo) { + Optional> match = + connectorFactory2.instances().stream() + .filter(connector -> connector.canBeSharedWith(connectionInfo, false).first()) + .findFirst(); + + if (match.isEmpty()) { + return Optional.empty(); + } + + Tuple fullMatch = match.get().canBeSharedWith(connectionInfo, true); + + if (!fullMatch.first()) { + throw new IllegalStateException( + String.format( + "Connection pool cannot be shared with provider %s: %s", + match.get().getProviderId(), fullMatch.second())); + } + + LOGGER.debug("Joining shared pool."); + match + .get() + .getRefCounter() + .ifPresent(refs -> LOGGER.debug("Shared pool consumers: {}", refs.incrementAndGet())); + + return Optional.of(match.get()); + } + + @SuppressWarnings("PMD.AvoidCatchingGenericException") + private FeatureProviderConnector createNewConnector( + ConnectorFactory2 connectorFactory2, + String providerId, + String connectorType, + String providerType, + ConnectionInfo connectionInfo) { try { LOGGER.debug("Creating new pool."); FeatureProviderConnector connector = @@ -96,7 +126,7 @@ public ConnectorFactoryImpl(Lazy>> connectorFacto return connector; - } catch (Throwable e) { + } catch (Exception e) { throw new IllegalStateException( String.format( "Connector with type %s for provider type %s could not be created.", @@ -106,35 +136,44 @@ public ConnectorFactoryImpl(Lazy>> connectorFacto } @Override - public synchronized void disposeConnector(FeatureProviderConnector connector) { - int refs = 0; - if (connector.getRefCounter().isPresent()) { - LOGGER.debug("Leaving shared pool."); - refs = connector.getRefCounter().get().decrementAndGet(); - LOGGER.debug("Shared pool consumers: {}", refs); - } + public void disposeConnector(FeatureProviderConnector connector) { + lock.lock(); + try { + int refs = 0; + if (connector.getRefCounter().isPresent()) { + LOGGER.debug("Leaving shared pool."); + refs = connector.getRefCounter().get().decrementAndGet(); + LOGGER.debug("Shared pool consumers: {}", refs); + } - if (refs == 0) { - boolean deleted = - getFactory(connector.getType()).get().deleteInstance(connector.getProviderId()); - if (deleted && LOGGER.isDebugEnabled()) { - LOGGER.debug("Deleted unused pool."); + if (refs == 0) { + boolean deleted = + getFactory(connector.getType()).get().deleteInstance(connector.getProviderId()); + if (deleted && LOGGER.isDebugEnabled()) { + LOGGER.debug("Deleted unused pool."); + } } - } - if (disposeListeners.containsKey(connector.getProviderId())) { - disposeListeners.get(connector.getProviderId()).forEach(Runnable::run); - disposeListeners.get(connector.getProviderId()).clear(); + if (disposeListeners.containsKey(connector.getProviderId())) { + disposeListeners.get(connector.getProviderId()).forEach(Runnable::run); + disposeListeners.get(connector.getProviderId()).clear(); + } + } finally { + lock.unlock(); } } @Override - public synchronized void onDispose( - FeatureProviderConnector connector, Runnable runnable) { - if (!disposeListeners.containsKey(connector.getProviderId())) { - disposeListeners.put(connector.getProviderId(), new HashSet<>()); + public void onDispose(FeatureProviderConnector connector, Runnable runnable) { + lock.lock(); + try { + if (!disposeListeners.containsKey(connector.getProviderId())) { + disposeListeners.put(connector.getProviderId(), new HashSet<>()); + } + disposeListeners.get(connector.getProviderId()).add(runnable); + } finally { + lock.unlock(); } - disposeListeners.get(connector.getProviderId()).add(runnable); } private Optional> getFactory(String type, String subType) { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/app/FeatureChangeHandlerImpl.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/app/FeatureChangeHandlerImpl.java index 13faf5000..e25db91cd 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/app/FeatureChangeHandlerImpl.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/app/FeatureChangeHandlerImpl.java @@ -22,6 +22,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +@SuppressWarnings("PMD.DoNotUseThreads") public class FeatureChangeHandlerImpl implements FeatureChanges { private static final Logger LOGGER = LoggerFactory.getLogger(FeatureChangeHandlerImpl.class); @@ -30,6 +31,7 @@ public class FeatureChangeHandlerImpl implements FeatureChanges { private final List datasetListeners; private final List featureListeners; + @SuppressWarnings("PMD.CloseResource") public FeatureChangeHandlerImpl() { ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/app/LocalSchemaFragmentResolver.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/app/LocalSchemaFragmentResolver.java index 9af3fdd6a..e941f2076 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/app/LocalSchemaFragmentResolver.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/app/LocalSchemaFragmentResolver.java @@ -145,6 +145,7 @@ private Map merge( // property element names per object type (notably GML with `objectTypeNamespaces`) read this // tag at runtime; without it they'd inherit the containing feature's objectType, which is // wrong for properties that come from a different schema fragment than the feature itself. + @SuppressWarnings("PMD.CompareObjectsWithEquals") private static FeatureSchema tagOrigin(FeatureSchema property, String originType) { if (originType == null) { return property; @@ -153,9 +154,11 @@ private static FeatureSchema tagOrigin(FeatureSchema property, String originType Map taggedChildren = null; for (Map.Entry e : property.getPropertyMap().entrySet()) { FeatureSchema childTagged = tagOrigin(e.getValue(), originType); + // reference comparison is intentional here: tagOrigin returns the same instance + // when nothing changed, so this is a cheap way to detect an actual change if (childTagged != e.getValue()) { if (taggedChildren == null) { - taggedChildren = new LinkedHashMap<>(property.getPropertyMap()); + taggedChildren = copyOf(property.getPropertyMap()); } taggedChildren.put(e.getKey(), childTagged); } @@ -173,6 +176,10 @@ private static FeatureSchema tagOrigin(FeatureSchema property, String originType return b.build(); } + private static Map copyOf(Map propertyMap) { + return new LinkedHashMap<>(propertyMap); + } + private FeatureSchema resolve(String ref, FeatureProviderDataV2 data) { String key = getKey(ref); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/AbstractFeatureProvider.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/AbstractFeatureProvider.java index 4c955cbe6..e4f83fb68 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/AbstractFeatureProvider.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/AbstractFeatureProvider.java @@ -41,10 +41,12 @@ import de.ii.xtraplatform.streams.domain.Reactive.Stream; import de.ii.xtraplatform.values.domain.Values; import java.io.IOException; +import java.io.UncheckedIOException; import java.util.EnumSet; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; @@ -60,10 +62,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +@SuppressWarnings({ + "PMD.CouplingBetweenObjects", + "PMD.GodClass", + "PMD.CyclomaticComplexity", + "PMD.TooManyMethods", + "PMD.DoNotUseThreads" +}) public abstract class AbstractFeatureProvider< T, U, V extends FeatureProviderConnector.QueryOptions, W extends SchemaBase> extends AbstractPersistentEntity - implements FeatureProviderEntity, FeatureProvider, FeatureInfo, FeatureQueries { + implements FeatureProviderEntity, FeatureInfo, FeatureQueries { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractFeatureProvider.class); protected static final WithScope WITH_SCOPE_RETURNABLE = new WithScope(Scope.RETURNABLE); @@ -81,7 +90,6 @@ public abstract class AbstractFeatureProvider< private final Values codelistStore; private final FeatureChanges changeHandler; private final ScheduledExecutorService delayedDisposer; - private final VolatileRegistry volatileRegistry; private Reactive.Runner streamRunner; private final DelayedVolatile> connector; private boolean datasetChanged; @@ -108,12 +116,11 @@ protected AbstractFeatureProvider( this.extensionRegistry = extensionRegistry; this.codelistStore = codelistStore; this.auditLog = auditLog; - this.volatileRegistry = volatileRegistry; this.changeHandler = new FeatureChangeHandlerImpl(); this.connector = new DelayedVolatile<>( volatileRegistry, - String.format("connector.%s", data.getProviderSubType().toLowerCase())); + String.format("connector.%s", data.getProviderSubType().toLowerCase(Locale.ROOT))); this.delayedDisposer = MoreExecutors.getExitingScheduledExecutorService( (ScheduledThreadPoolExecutor) @@ -126,17 +133,13 @@ public String getType() { return ProviderData.ENTITY_TYPE; } - @Override - public FeatureProviderDataV2 getData() { - return super.getData(); - } - @Override protected State reconcileStateNoComponents(@Nullable String capability) { return State.AVAILABLE; } @Override + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) protected boolean onStartup() throws InterruptedException { onVolatileStart(); @@ -229,7 +232,7 @@ protected boolean onStartup() throws InterruptedException { LOGGER.error( "Feature provider with id '{}' could not be started: {} {}", getId(), - getData().getTypeValidation().name().toLowerCase(), + getData().getTypeValidation().name().toLowerCase(Locale.ROOT), "validation failed"); // TODO: volatile defective return false; @@ -253,7 +256,9 @@ protected void onStarted() { onStateChange( (from, to) -> { - LOGGER.info("Feature provider with id '{}' state changed: {}", getId(), getState()); + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Feature provider with id '{}' state changed: {}", getId(), getState()); + } }, true); @@ -262,7 +267,9 @@ protected void onStarted() { .map(map -> String.format(" (%s)", map.toString().replace("{", "").replace("}", ""))) .orElse(""); - LOGGER.info("Feature provider with id '{}' started successfully.{}", getId(), startupInfo); + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Feature provider with id '{}' started successfully.{}", getId(), startupInfo); + } if (datasetChangedForced) { LOGGER.info("Dataset has changed (forced)."); @@ -289,12 +296,14 @@ protected void onReloaded(boolean forceReload) { .map(map -> String.format(" (%s)", map.toString().replace("{", "").replace("}", ""))) .orElse(""); - LOGGER.info("Feature provider with id '{}' reloaded successfully.{}", getId(), startupInfo); + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Feature provider with id '{}' reloaded successfully.{}", getId(), startupInfo); + } if (datasetChanged || datasetChangedForced || (forceReload && allowForceReload())) { if (datasetChangedForced || forceReload) { LOGGER.info("Dataset has changed (forced)."); - } else { + } else if (LOGGER.isInfoEnabled()) { LOGGER.info( "Dataset has changed ({} -> {}).", previousDataset, @@ -311,7 +320,9 @@ protected void onStopped() { if (connector.isPresent()) { connectorFactory.disposeConnector(connector.get()); } - LOGGER.info("Feature provider with id '{}' stopped.", getId()); + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Feature provider with id '{}' stopped.", getId()); + } } @Override @@ -392,9 +403,10 @@ private String getConnectorId(boolean previousAlive, boolean isShared) { i -> { try { return Optional.of(Integer.parseInt(i)); - } catch (Throwable e) { + } catch (NumberFormatException e) { + // not a valid iteration number, fall back to 1 + return Optional.of(1); } - return Optional.of(1); }) : Optional.of(1) : Optional.empty(); @@ -411,10 +423,12 @@ private boolean validate() throws InterruptedException { try { for (Map.Entry> sourceSchema : getSourceSchemas().entrySet()) { - LOGGER.info( - "Validating type '{}' ({})", - sourceSchema.getKey(), - getData().getTypeValidation().name().toLowerCase()); + if (LOGGER.isInfoEnabled()) { + LOGGER.info( + "Validating type '{}' ({})", + sourceSchema.getKey(), + getData().getTypeValidation().name().toLowerCase(Locale.ROOT)); + } ValidationResult result = getTypeInfoValidator() @@ -432,10 +446,7 @@ private boolean validate() throws InterruptedException { checkForStartupCancel(); } - } catch (Throwable e) { - if (e instanceof InterruptedException) { - throw e; - } + } catch (IllegalArgumentException | IllegalStateException | UncheckedIOException e) { LogContext.error(LOGGER, e, "Cannot validate types"); isSuccess = false; } @@ -538,10 +549,9 @@ public FeatureStream getFeatureStream(FeatureQuery query) { // TODO: more tests protected final void validateQuery(Query query) { - if (query instanceof FeatureQuery) { - if (!getSourceSchemas().containsKey(((FeatureQuery) query).getType())) { - throw new IllegalArgumentException("No features available for type"); - } + if (query instanceof FeatureQuery featureQuery + && !getSourceSchemas().containsKey(featureQuery.getType())) { + throw new IllegalArgumentException("No features available for type"); } if (query instanceof MultiFeatureQuery) { for (TypeQuery typeQuery : ((MultiFeatureQuery) query).getQueries()) { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/AbstractFeatureProviderMetadataConsumer.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/AbstractFeatureProviderMetadataConsumer.java index e2223bf8c..2bd681d90 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/AbstractFeatureProviderMetadataConsumer.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/AbstractFeatureProviderMetadataConsumer.java @@ -10,6 +10,7 @@ /** * @author zahnen */ +@SuppressWarnings("PMD.TooManyMethods") public class AbstractFeatureProviderMetadataConsumer implements FeatureProviderMetadataConsumer { @Override public void analyzeStart() {} @@ -126,6 +127,7 @@ public void analyzeFeatureTypeAbstract(String featureTypeName, String abstrct) { public void analyzeFeatureTypeKeywords(String featureTypeName, String... keywords) {} @Override + @SuppressWarnings("PMD.UseObjectForClearerAPI") public void analyzeFeatureTypeBoundingBox( String featureTypeName, String xmin, String ymin, String xmax, String ymax) {} diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ApplyKeyToValueMap.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ApplyKeyToValueMap.java index 3a096dd7d..fbca41334 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ApplyKeyToValueMap.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ApplyKeyToValueMap.java @@ -11,12 +11,13 @@ import java.util.Map; import java.util.function.BiFunction; -public class ApplyKeyToValueMap extends ForwardingMap implements Map { +public class ApplyKeyToValueMap extends ForwardingMap { private final Map delegate; private final BiFunction applyKeyToValue; public ApplyKeyToValueMap(Map delegate, BiFunction applyKeyToValue) { + super(); this.delegate = delegate; this.applyKeyToValue = applyKeyToValue; } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ConstantsResolver.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ConstantsResolver.java index 5d20a9029..7ebdf5d78 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ConstantsResolver.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ConstantsResolver.java @@ -32,10 +32,12 @@ public FeatureSchema resolve(FeatureSchema schema, List parents) schema.getType() == SchemaBase.Type.STRING ? String.format("'%s'", schema.getConstantValue().get()) : schema.getConstantValue().get(); + int currentConstantCounter = constantCounter[0]; + constantCounter[0] = currentConstantCounter + 1; String constantSourcePath = String.format( "%sconstant_%s_%d{constant=%s}", - schema.getSourcePath().orElse(""), parentName, constantCounter[0]++, constantValue); + schema.getSourcePath().orElse(""), parentName, currentConstantCounter, constantValue); return new ImmutableFeatureSchema.Builder().from(schema).sourcePath(constantSourcePath).build(); } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/DatasetChange.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/DatasetChange.java index 9f311bc6f..c97847f6d 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/DatasetChange.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/DatasetChange.java @@ -13,6 +13,7 @@ import org.immutables.value.Value; @Value.Immutable +@FunctionalInterface public interface DatasetChange { List getFeatureTypes(); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/DatasetChangeListener.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/DatasetChangeListener.java index 3337367d5..3e1ccc01d 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/DatasetChangeListener.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/DatasetChangeListener.java @@ -7,6 +7,7 @@ */ package de.ii.xtraplatform.features.domain; +@FunctionalInterface public interface DatasetChangeListener { void onDatasetChange(DatasetChange change); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/DecoderFactory.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/DecoderFactory.java index b8b104c8d..280901166 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/DecoderFactory.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/DecoderFactory.java @@ -42,7 +42,8 @@ default Optional getConnectorString() { return Optional.empty(); } - default de.ii.xtraplatform.base.domain.util.Tuple parseSourcePath( + @SuppressWarnings("PMD.UseObjectForClearerAPI") + default Tuple parseSourcePath( String path, String column, String flags, String connectorSpec) { return Tuple.of(column, ""); } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/DeterminePipelineStepsThatCannotBeSkipped.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/DeterminePipelineStepsThatCannotBeSkipped.java index 0d3c2db23..8ed9c6f5a 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/DeterminePipelineStepsThatCannotBeSkipped.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/DeterminePipelineStepsThatCannotBeSkipped.java @@ -59,6 +59,7 @@ public DeterminePipelineStepsThatCannotBeSkipped( } @Override + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public Set visit( FeatureSchema schema, List parents, @@ -98,29 +99,19 @@ public Set visit( // already handled by including MAPPING for any objects or arrays); // if only value transformations are applied, and no other mapping is needed, just execute // the value transformations, but skip schema transformations and token slice transformers - if (!intermediateResult.contains(PipelineSteps.MAPPING_SCHEMA)) { - if (requiresPropertiesInSequence) { + if (intermediateResult.contains(PipelineSteps.MAPPING_SCHEMA)) { + steps.add(PipelineSteps.MAPPING_VALUES); + } else { + List transformations = + getSpecificTransformations(mergedTransformations); + + if (requiresPropertiesInSequence + || transformations.stream().anyMatch(pt -> !pt.onlyValueTransformations())) { steps.add(PipelineSteps.MAPPING_SCHEMA); steps.add(PipelineSteps.MAPPING_VALUES); - } else { - List transformations = - mergedTransformations.getTransformations().entrySet().stream() - .filter(entry -> !PropertyTransformations.WILDCARD.equals(entry.getKey())) - .map(Entry::getValue) - .flatMap(Collection::stream) - .toList(); - if (!transformations.isEmpty()) { - if (transformations.stream() - .allMatch(PropertyTransformation::onlyValueTransformations)) { - steps.add(PipelineSteps.MAPPING_VALUES); - } else { - steps.add(PipelineSteps.MAPPING_SCHEMA); - steps.add(PipelineSteps.MAPPING_VALUES); - } - } + } else if (!transformations.isEmpty()) { + steps.add(PipelineSteps.MAPPING_VALUES); } - } else { - steps.add(PipelineSteps.MAPPING_VALUES); } } else { @@ -132,7 +123,7 @@ public Set visit( // COORDINATES step restores the recorded axis order of such positions (see // FeatureTokenTransformerCoordinates) if (!targetCrs.equals(nativeCrs) - || (simplifyGeometries) + || simplifyGeometries || requiresOriginalCrsRestore(schema) || (!(OgcCrs.CRS84.equals(nativeCrs) || OgcCrs.CRS84h.equals(nativeCrs)) && supportSecondaryGeometry @@ -192,4 +183,13 @@ private static boolean requiresOriginalCrsRestore(FeatureSchema schema) { .filter(originalCrs -> !originalCrs.equals(schema.getNativeCrs().get())) .isPresent(); } + + private static List getSpecificTransformations( + PropertyTransformations mergedTransformations) { + return mergedTransformations.getTransformations().entrySet().stream() + .filter(entry -> !PropertyTransformations.WILDCARD.equals(entry.getKey())) + .map(Entry::getValue) + .flatMap(Collection::stream) + .toList(); + } } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ExtendableConfiguration.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ExtendableConfiguration.java index d1b7d37af..5d17cd2cb 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ExtendableConfiguration.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ExtendableConfiguration.java @@ -16,6 +16,7 @@ import java.util.stream.Collectors; import org.immutables.value.Value; +@FunctionalInterface public interface ExtendableConfiguration { List getExtensions(); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureChangeListener.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureChangeListener.java index efd244315..14c43b896 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureChangeListener.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureChangeListener.java @@ -7,6 +7,7 @@ */ package de.ii.xtraplatform.features.domain; +@FunctionalInterface public interface FeatureChangeListener { void onFeatureChange(FeatureChange change); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureConsumer.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureConsumer.java index 9c2f562c0..624d77e1a 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureConsumer.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureConsumer.java @@ -14,6 +14,7 @@ /** * @author zahnen */ +@SuppressWarnings("PMD.SignatureDeclareThrowsException") public interface FeatureConsumer { void onStart( OptionalLong numberReturned, OptionalLong numberMatched, Map additionalInfos) diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureEventEncoder.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureEventEncoder.java index 8c6cbedbf..c8cc700bc 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureEventEncoder.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureEventEncoder.java @@ -13,11 +13,11 @@ public abstract class FeatureEventEncoder implements TransformerCustomFuseableIn, FeatureEventConsumer { - private final FeatureTokenReader tokenReader; + private final FeatureTokenReader tokenReader; private Consumer downstream; protected FeatureEventEncoder() { - this.tokenReader = new FeatureTokenReader(this); + this.tokenReader = new FeatureTokenReader<>(this); } @Override diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureEventHandler.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureEventHandler.java index 2a2132855..fe49c315b 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureEventHandler.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureEventHandler.java @@ -18,6 +18,7 @@ import javax.annotation.Nullable; import org.immutables.value.Value; +@SuppressWarnings("PMD.TooManyMethods") public interface FeatureEventHandler< T extends SchemaBase, U extends SchemaMappingBase, V extends ModifiableContext> { @@ -228,6 +229,7 @@ interface ModifiableContext, U extends SchemaMappingBase // a @Value.Default is not cached on a Modifiable, so create the value, store it via the // setter and reuse that instance on subsequent calls + @Override @Value.Default default ModifiableCollectionMetadata metadata() { ModifiableCollectionMetadata collectionMetadata = ModifiableCollectionMetadata.create(); @@ -244,7 +246,7 @@ default FeaturePathTracker pathTracker() { // when tracking target paths, if present, use path separator from flatten transformation in // mapping().getTargetSchema() Optional pathSeparator = - Optional.ofNullable(mapping()).flatMap(u -> u.getPathSeparator()); + Optional.ofNullable(mapping()).flatMap(SchemaMappingBase::getPathSeparator); FeaturePathTracker pathTracker = pathSeparator.isPresent() @@ -288,13 +290,12 @@ private PathMemo currentMemo() { boolean useTargetPaths = isUseTargetPaths(); if (memo.version != version || memo.useTargetPaths != useTargetPaths) { - memo.version = version; - memo.useTargetPaths = useTargetPaths; - memo.path = pathTracker().asList(); - memo.schemas = null; - memo.positions = null; - memo.parentSchemas = null; - memo.parentPositions = null; + PathMemo refreshed = new PathMemo<>(); + refreshed.version = version; + refreshed.useTargetPaths = useTargetPaths; + refreshed.path = pathTracker().asList(); + setPathMemo(refreshed); + memo = refreshed; } return memo; @@ -355,11 +356,10 @@ default List> parentSchemasForPath() { @Value.Lazy default boolean shouldSkip() { - return schema().isEmpty() - || !shouldInclude(schema().get(), parentSchemas(), pathTracker().toString()); + return schema().isEmpty() || !shouldInclude(schema().get(), pathTracker().toString()); } - private boolean shouldInclude(T schema, List parentSchemas, String path) { + private boolean shouldInclude(T schema, String path) { return schema.isId() || (schema.isSpatial() && (typeQueries().isEmpty() diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureMetadata.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureMetadata.java index de9d718fd..77d581db0 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureMetadata.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureMetadata.java @@ -9,6 +9,7 @@ import java.util.Optional; +@FunctionalInterface public interface FeatureMetadata { String CAPABILITY = "metadata"; diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureMutationHookException.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureMutationHookException.java index 05465bb0d..f5e39d43a 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureMutationHookException.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureMutationHookException.java @@ -18,6 +18,8 @@ */ public class FeatureMutationHookException extends RuntimeException { + private static final long serialVersionUID = 1L; + private final List warnings; public FeatureMutationHookException(String message, Throwable cause, List warnings) { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureObjectEncoderBase.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureObjectEncoderBase.java index fa89e2881..319810fd6 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureObjectEncoderBase.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureObjectEncoderBase.java @@ -38,6 +38,7 @@ public void onStart(ModifiableContext context) {} public void onEnd(ModifiableContext context) {} @Override + @SuppressWarnings("PMD.NullAssignment") public final void onFeatureStart(ModifiableContext context) { if (context.schema().isEmpty()) { return; @@ -52,6 +53,7 @@ public final void onFeatureStart(ModifiableContext context) { } @Override + @SuppressWarnings("PMD.NullAssignment") public final void onFeatureEnd(ModifiableContext context) { onFeature(currentFeature); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureObjectTransformerBase.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureObjectTransformerBase.java index 64b824745..9c5b24535 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureObjectTransformerBase.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureObjectTransformerBase.java @@ -33,6 +33,7 @@ protected FeatureObjectTransformerBase() { } protected FeatureObjectTransformerBase(Optional nullValue) { + super(); this.nullValue = nullValue; } @@ -49,6 +50,7 @@ public void onStart(ModifiableContext context) {} public void onEnd(ModifiableContext context) {} @Override + @SuppressWarnings("PMD.NullAssignment") public final void onFeatureStart(ModifiableContext context) { if (context.schema().isEmpty()) { return; @@ -63,6 +65,7 @@ public final void onFeatureStart(ModifiableContext context) { } @Override + @SuppressWarnings("PMD.NullAssignment") public final void onFeatureEnd(ModifiableContext context) { onFeature(currentFeature); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeaturePathTracker.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeaturePathTracker.java index a3f95f800..733cc78ae 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeaturePathTracker.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeaturePathTracker.java @@ -82,25 +82,28 @@ public boolean isEmpty() { @Override public String toString() { - if (localPath.isEmpty()) return ""; + if (localPath.isEmpty()) { + return ""; + } return joiner.join(localPath); } public String toStringWithDefaultSeparator() { - if (localPath.isEmpty()) return ""; + if (localPath.isEmpty()) { + return ""; + } return DEFAULT_JOINER.join(localPath); } public List asList() { - if (localPath.isEmpty()) return ImmutableList.of(); + if (localPath.isEmpty()) { + return ImmutableList.of(); + } return ImmutableList.copyOf(localPath); } public boolean containedIn(List path) { - if (path.size() < localPath.size()) { - return false; - } - - return Objects.equals(path.subList(0, localPath.size()), localPath); + return path.size() >= localPath.size() + && Objects.equals(path.subList(0, localPath.size()), localPath); } } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeaturePropertyV2.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeaturePropertyV2.java index 1cec96ad5..9678797c6 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeaturePropertyV2.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeaturePropertyV2.java @@ -75,6 +75,7 @@ default Type getType() { // deserialization // (immutables attributeBuilder does not work with maps yet) @JsonMerge + @SuppressWarnings("PMD.LooseCoupling") BuildableMap getProperties(); Map getAdditionalInfo(); @@ -85,7 +86,7 @@ abstract class Builder implements BuildableBuilder { public abstract ImmutableFeaturePropertyV2.Builder putProperties( String key, ImmutableFeaturePropertyV2.Builder builder); - @JsonProperty(value = "properties") + @JsonProperty("properties") public ImmutableFeaturePropertyV2.Builder putProperties2( String key, ImmutableFeaturePropertyV2.Builder builder) { return putProperties(key, builder.name(key)); @@ -99,7 +100,7 @@ interface Constraints { Optional getCodelist(); - @JsonProperty(value = "enum") + @JsonProperty("enum") List getEnumValues(); Optional getRegex(); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderCapabilities.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderCapabilities.java index 2acb1c8da..77f166670 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderCapabilities.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderCapabilities.java @@ -51,18 +51,6 @@ public enum Cql2Class { ARITHMETIC } - @Value.Immutable - public interface Profile { - - Level getLevel(); - - List getQueryOps(); - - List getCql2Operators(); - - List getCql2Classes(); - } - private static final Profile PROFILE_MINIMAL = ImmutableProfile.builder() .level(Level.MINIMAL) @@ -96,6 +84,18 @@ public interface Profile { Level.DEFAULT, PROFILE_DEFAULT, Level.FULL, PROFILE_FULL); + @Value.Immutable + public interface Profile { + + Level getLevel(); + + List getQueryOps(); + + List getCql2Operators(); + + List getCql2Classes(); + } + public abstract Level getLevel(); protected abstract List getAdditionalQueryOps(); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderCommonData.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderCommonData.java index 512620064..6d81f869e 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderCommonData.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderCommonData.java @@ -10,7 +10,6 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import de.ii.xtraplatform.docs.DocIgnore; -import de.ii.xtraplatform.entities.domain.EntityDataBuilder; import de.ii.xtraplatform.entities.domain.EntityDataDefaults; import de.ii.xtraplatform.entities.domain.maptobuilder.encoding.BuildableMapEncodingEnabled; import javax.annotation.Nullable; @@ -34,8 +33,7 @@ public interface FeatureProviderCommonData ConnectionInfo getConnectionInfo(); abstract class Builder - extends FeatureProviderDataV2.Builder - implements EntityDataBuilder { + extends FeatureProviderDataV2.Builder { @Override public Builder fillRequiredFieldsWithPlaceholders() { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderConnector.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderConnector.java index ed4b5e7e6..294997c14 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderConnector.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderConnector.java @@ -56,6 +56,7 @@ interface QueryOptions {} String getDatasetIdentifier(); + @SuppressWarnings("PMD.LinguisticNaming") default Tuple canBeSharedWith( ConnectionInfo connectionInfo, boolean checkAllParameters) { return Tuple.of(false, null); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderDataV2.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderDataV2.java index cef9cee09..5c03ab51e 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderDataV2.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderDataV2.java @@ -39,6 +39,7 @@ default long getEntitySchemaVersion() { * @langEn Always `FEATURE`. * @langDe Stets `FEATURE`. */ + @Override String getProviderType(); /** @@ -190,6 +191,7 @@ default List getCql2Functions() { */ @JsonMerge @JsonProperty("types") + @SuppressWarnings("PMD.LooseCoupling") BuildableMap getTypes(); /** @@ -201,6 +203,7 @@ default List getCql2Functions() { * @default {} */ @JsonMerge + @SuppressWarnings("PMD.LooseCoupling") BuildableMap getFragments(); @DocIgnore @@ -222,7 +225,7 @@ abstract class Builder> implements EntityDataBuilder getTypes(); - @JsonProperty(value = "types") + @JsonProperty("types") public Map getTypes2() { Map types = getTypes(); @@ -231,7 +234,7 @@ public Map getTypes2() { public abstract T putTypes(String key, ImmutableFeatureSchema.Builder builder); - @JsonProperty(value = "types") + @JsonProperty("types") public T putTypes2(String key, ImmutableFeatureSchema.Builder builder) { return putTypes(key, builder.name(key)); } @@ -239,7 +242,7 @@ public T putTypes2(String key, ImmutableFeatureSchema.Builder builder) { @JsonIgnore public abstract Map getFragments(); - @JsonProperty(value = "fragments") + @JsonProperty("fragments") public Map getFragments2() { Map types = getFragments(); @@ -248,7 +251,7 @@ public Map getFragments2() { public abstract T putFragments(String key, ImmutableFeatureSchema.Builder builder); - @JsonProperty(value = "fragments") + @JsonProperty("fragments") public T putFragments2(String key, ImmutableFeatureSchema.Builder builder) { return putFragments(key, builder.name(key)); } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderMetadataConsumer.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderMetadataConsumer.java index ee5d40834..5e5948500 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderMetadataConsumer.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureProviderMetadataConsumer.java @@ -10,6 +10,7 @@ /** * @author zahnen */ +@SuppressWarnings("PMD.TooManyMethods") public interface FeatureProviderMetadataConsumer { void analyzeStart(); @@ -88,6 +89,7 @@ public interface FeatureProviderMetadataConsumer { void analyzeFeatureTypeKeywords(String featureTypeName, String... keywords); + @SuppressWarnings("PMD.UseObjectForClearerAPI") void analyzeFeatureTypeBoundingBox( String featureTypeName, String xmin, String ymin, String xmax, String ymax); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureQueriesExtension.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureQueriesExtension.java index 50b8dde12..46926e845 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureQueriesExtension.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureQueriesExtension.java @@ -137,10 +137,12 @@ @AutoMultiBind public interface FeatureQueriesExtension { + @SuppressWarnings("PMD.ClassNamingConventions") enum LIFECYCLE_HOOK { STARTED } + @SuppressWarnings("PMD.ClassNamingConventions") enum QUERY_HOOK { BEFORE, AFTER diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureReader.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureReader.java index ceb0a8b6f..53572fdb7 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureReader.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureReader.java @@ -15,6 +15,7 @@ /** * @author zahnen */ +@SuppressWarnings("PMD.SignatureDeclareThrowsException") public interface FeatureReader { void onStart(OptionalLong numberReturned, OptionalLong numberMatched, T context) throws Exception; diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureReaderGeneric.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureReaderGeneric.java index 2aaeb7034..7e7123e6a 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureReaderGeneric.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureReaderGeneric.java @@ -18,25 +18,35 @@ public interface FeatureReaderGeneric extends FeatureReader, Map> { + @Override void onStart(OptionalLong numberReturned, OptionalLong numberMatched, Map context) throws Exception; + @Override void onEnd() throws Exception; + @Override void onFeatureStart(List path, Map context) throws Exception; + @Override void onFeatureEnd(List path) throws Exception; + @Override void onObjectStart(List path, Map context) throws Exception; + @Override void onObjectEnd(List path, Map context) throws Exception; + @Override void onArrayStart(List path, Map context) throws Exception; + @Override void onArrayEnd(List path, Map context) throws Exception; + @Override void onGeometry(List path, Geometry geometry, Map context) throws Exception; + @Override void onValue(List path, String value, Map context) throws Exception; } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureSchema.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureSchema.java index acffd228d..47319fbef 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureSchema.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureSchema.java @@ -17,7 +17,6 @@ import com.google.common.collect.ImmutableMap; import de.ii.xtraplatform.crs.domain.EpsgCrs; import de.ii.xtraplatform.docs.DocIgnore; -import de.ii.xtraplatform.entities.domain.maptobuilder.Buildable; import de.ii.xtraplatform.entities.domain.maptobuilder.BuildableMap; import de.ii.xtraplatform.entities.domain.maptobuilder.encoding.BuildableMapEncodingEnabled; import de.ii.xtraplatform.features.domain.transform.PropertyTransformation; @@ -66,9 +65,9 @@ "constraints", "properties" }) +@SuppressWarnings("PMD.ExcessivePublicCount") public interface FeatureSchema extends FeatureSchemaBase, - Buildable, PropertiesSchema { Logger LOGGER = LoggerFactory.getLogger(FeatureSchema.class); @@ -76,6 +75,7 @@ public interface FeatureSchema String IS_PROPERTY = "IS_PROPERTY"; String CONCAT_ELEMENT = "_CONCAT_ELEMENT_"; String COALESCE_ELEMENT = "_COALESCE_ELEMENT_"; + String QUOTED_LIST_SEPARATOR = "', '"; /** * @langEn If set to `true` for properties of type `VALUE`/`VALUE_ARRAY`, these will be included @@ -350,6 +350,7 @@ default Type getType() { * Verwenden Sie stattdessen FEATURE_REF oder FEATURE_REF_ARRAY als Typ der Eigenschaft. * @default null */ + @Override Optional getObjectType(); /** @@ -362,6 +363,7 @@ default Type getType() { */ @JsonIgnore @DocIgnore + @Override Optional getOriginObjectType(); /** @@ -398,6 +400,7 @@ default Type getType() { * @langEn The unit of measurement of the value, only relevant for numeric properties. * @langDe Die Maßeinheit des Wertes, nur relevant bei numerischen Eigenschaften. */ + @Override Optional getUnit(); /** @@ -417,6 +420,7 @@ default Type getType() { * Feature-Provider eine Eigenschaft mit einem festen Wert zu belegen. * @default `null` */ + @Override Optional getConstantValue(); /** @@ -505,7 +509,7 @@ default boolean queryable() { return !isObject() && !isMultiSource() && !isInternal() - && !Objects.equals(getType(), Type.UNKNOWN) + && getType() != Type.UNKNOWN && !getExcludedScopes().contains(Scope.QUERYABLE); } @@ -519,8 +523,8 @@ default boolean sortable() { && !isArray() && !isMultiSource() && !isInternal() - && !Objects.equals(getType(), Type.BOOLEAN) - && !Objects.equals(getType(), Type.UNKNOWN) + && getType() != Type.BOOLEAN + && getType() != Type.UNKNOWN && !getExcludedScopes().contains(Scope.SORTABLE); } @@ -576,6 +580,7 @@ default boolean getIgnore() { * [Transformationen](../details/transformations.md). * @default [] */ + @Override List getTransformations(); /** @@ -801,8 +806,8 @@ default boolean isVirtualObject() { @Override default boolean isFeature() { return isObject() - && (!getEffectiveSourcePaths().isEmpty() - && getEffectiveSourcePaths().get(0).startsWith("/")) + && !getEffectiveSourcePaths().isEmpty() + && getEffectiveSourcePaths().get(0).startsWith("/") && !getAdditionalInfo().containsKey(IS_PROPERTY); } @@ -850,16 +855,16 @@ default void concatConstraints() { getIdProperties().stream() .map(FeatureSchema::getFullPathAsString) .distinct() - .collect(Collectors.joining("', '")), + .collect(Collectors.joining(QUOTED_LIST_SEPARATOR)), getName()); Preconditions.checkState( - getIdProperties().stream().allMatch(p -> p.getType().equals(first.getType())), + getIdProperties().stream().allMatch(p -> p.getType() == first.getType()), "All ID properties of concatenated objects must have the same type, but found '%s' in type '%s'.", getIdProperties().stream() .map(FeatureSchema::getType) .map(Enum::name) .distinct() - .collect(Collectors.joining("', '")), + .collect(Collectors.joining(QUOTED_LIST_SEPARATOR)), getName()); }); @@ -882,7 +887,7 @@ default void concatConstraints() { getPrimaryGeometries().stream() .map(FeatureSchema::getFullPathAsString) .distinct() - .collect(Collectors.joining("', '")), + .collect(Collectors.joining(QUOTED_LIST_SEPARATOR)), getName()); Preconditions.checkState( getPrimaryGeometries().stream().allMatch(SchemaBase::isSimpleFeatureGeometry), @@ -909,17 +914,16 @@ default void concatConstraints() { getPrimaryInstants().stream() .map(FeatureSchema::getFullPathAsString) .distinct() - .collect(Collectors.joining("', '")), + .collect(Collectors.joining(QUOTED_LIST_SEPARATOR)), getName()); Preconditions.checkState( - getPrimaryInstants().stream() - .allMatch(p -> p.getType().equals(first.getType())), + getPrimaryInstants().stream().allMatch(p -> p.getType() == first.getType()), "All primary instants of concatenated objects must have the same type, but found '%s' in type '%s'.", getPrimaryInstants().stream() .map(FeatureSchema::getType) .map(Enum::name) .distinct() - .collect(Collectors.joining("', '")), + .collect(Collectors.joining(QUOTED_LIST_SEPARATOR)), getName()); }); @@ -944,7 +948,7 @@ default void concatConstraints() { .map(Tuple::first) .map(FeatureSchema::getFullPathAsString) .distinct() - .collect(Collectors.joining("', '")), + .collect(Collectors.joining(QUOTED_LIST_SEPARATOR)), getName()); Preconditions.checkState( getPrimaryIntervals().stream() @@ -958,29 +962,29 @@ default void concatConstraints() { .map(Tuple::second) .map(FeatureSchema::getFullPathAsString) .distinct() - .collect(Collectors.joining("', '")), + .collect(Collectors.joining(QUOTED_LIST_SEPARATOR)), getName()); Preconditions.checkState( getPrimaryIntervals().stream() - .allMatch(p -> p.first().getType().equals(first.first().getType())), + .allMatch(p -> p.first().getType() == first.first().getType()), "All primary interval starts of concatenated objects must have the same type, but found '%s' in type '%s'.", getPrimaryIntervals().stream() .map(Tuple::first) .map(FeatureSchema::getType) .map(Enum::name) .distinct() - .collect(Collectors.joining("', '")), + .collect(Collectors.joining(QUOTED_LIST_SEPARATOR)), getName()); Preconditions.checkState( getPrimaryIntervals().stream() - .allMatch(p -> p.second().getType().equals(first.second().getType())), + .allMatch(p -> p.second().getType() == first.second().getType()), "All primary interval ends of concatenated objects must have the same type, but found '%s' in type '%s'.", getPrimaryIntervals().stream() .map(Tuple::second) .map(FeatureSchema::getType) .map(Enum::name) .distinct() - .collect(Collectors.joining("', '")), + .collect(Collectors.joining(QUOTED_LIST_SEPARATOR)), getName()); }); @@ -1003,7 +1007,7 @@ default void concatConstraints() { getSecondaryGeometries().stream() .map(FeatureSchema::getFullPathAsString) .distinct() - .collect(Collectors.joining("', '")), + .collect(Collectors.joining(QUOTED_LIST_SEPARATOR)), getName()); }); } @@ -1014,7 +1018,7 @@ default void warnOnConflictingGeometryTypes() { if (getGeometryType().isPresent() && !getGeometryTypes().isEmpty()) { List types = getGeometryTypes(); boolean consistent = types.size() == 1 && types.get(0) == getGeometryType().get(); - if (!consistent) { + if (!consistent && LOGGER.isWarnEnabled()) { LOGGER.warn( "Both 'geometryType' ({}) and 'geometryTypes' ({}) are set on property '{}'; 'geometryTypes' takes precedence.", getGeometryType().get(), @@ -1035,6 +1039,7 @@ default void disallowFlattening() { } @Value.Check + @SuppressWarnings("PMD.NPathComplexity") default void checkMappingOperations() { Preconditions.checkState( getConcat().isEmpty() || isArray() || getFullPath().isEmpty(), @@ -1197,7 +1202,7 @@ default void checkMappingOperations() { @Value.Check default void checkIsQueryable() { Preconditions.checkState( - !queryable() || (!isObject() && !Objects.equals(getType(), Type.UNKNOWN)), + !queryable() || (!isObject() && getType() != Type.UNKNOWN), "A queryable property must not be of type OBJECT, OBJECT_ARRAY or UNKNOWN. Found: %s. Path: %s.", getType(), getFullPathAsString()); @@ -1210,8 +1215,8 @@ default void checkIsSortable() { || (!isSpatial() && !isObject() && !isArray() - && !Objects.equals(getType(), Type.BOOLEAN) - && !Objects.equals(getType(), Type.UNKNOWN)), + && getType() != Type.BOOLEAN + && getType() != Type.UNKNOWN), "A sortable property must be a string, a number or an instant. Found %s. Path: %s.", getType(), getFullPathAsString()); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureSchemaExt.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureSchemaExt.java index 96280eccb..103e9c9e5 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureSchemaExt.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureSchemaExt.java @@ -74,7 +74,8 @@ default boolean getIgnore() { // behaves exactly like Map, but supports mergeable builder // deserialization // (immutables attributeBuilder does not work with maps yet) - @JsonProperty(value = "properties") + @JsonProperty("properties") + @SuppressWarnings("PMD.LooseCoupling") BuildableMap getPropertyMap(); // custom builder to automatically use keys of properties as name @@ -84,7 +85,7 @@ public abstract ImmutableFeatureSchemaExt.Builder putPropertyMap( String key, ImmutableFeatureSchemaExt.Builder builder); // @JsonMerge - @JsonProperty(value = "properties") + @JsonProperty("properties") public ImmutableFeatureSchemaExt.Builder putProperties2( Map builderMap) { ImmutableFeatureSchemaExt.Builder builder1 = null; @@ -97,7 +98,7 @@ public ImmutableFeatureSchemaExt.Builder putProperties2( // return putPropertyMap(key, builder.name(key)); } - // @JsonProperty(value = "properties") + // @JsonProperty("properties") // @JsonAnySetter public ImmutableFeatureSchemaExt.Builder putProperties2( String key, ImmutableFeatureSchemaExt.Builder builder) { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureSchemaToTypeVisitor.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureSchemaToTypeVisitor.java index e663b4bdd..820ef54a9 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureSchemaToTypeVisitor.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureSchemaToTypeVisitor.java @@ -46,7 +46,7 @@ public FeatureType visit(FeatureSchema schema, List visitedProperti .build(); } - ImmutableMap properties = + Map properties = visitedProperties.stream() .flatMap( types -> { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureSchemaTransformer.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureSchemaTransformer.java index 6e9863001..34a0d0e1e 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureSchemaTransformer.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureSchemaTransformer.java @@ -15,6 +15,7 @@ import java.util.Objects; import java.util.stream.Stream; +@SuppressWarnings("PMD.ImplicitFunctionalInterface") public interface FeatureSchemaTransformer { FeatureSchema visit( diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStorePathParser.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStorePathParser.java index 3b52a4dbc..905a4c0fb 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStorePathParser.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStorePathParser.java @@ -9,6 +9,7 @@ import java.util.List; +@SuppressWarnings("PMD.ImplicitFunctionalInterface") public interface FeatureStorePathParser { interface PathSyntax {} diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStoreQueryGenerator.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStoreQueryGenerator.java index ee986b18d..119c997d0 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStoreQueryGenerator.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStoreQueryGenerator.java @@ -7,6 +7,7 @@ */ package de.ii.xtraplatform.features.domain; +@SuppressWarnings("PMD.ImplicitFunctionalInterface") public interface FeatureStoreQueryGenerator { T getExtentQuery( diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStoreRelatedContainer.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStoreRelatedContainer.java index 5106d9989..e63606a8f 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStoreRelatedContainer.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStoreRelatedContainer.java @@ -24,7 +24,7 @@ default List getPath() { return Stream.concat( Stream.of( getInstanceContainerName() - + (getInstanceConnection().get(0).getSourceFilter().orElse(""))), + + getInstanceConnection().get(0).getSourceFilter().orElse("")), getInstanceConnection().stream() .flatMap( relation -> { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStream.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStream.java index d50a7c1ed..499a9d3a8 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStream.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStream.java @@ -50,6 +50,7 @@ enum PipelineSteps { * * @param error the exception reported by xtraplatform */ + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"}) static void processStreamError(Throwable error) { String errorMessage = error.getMessage(); if (Objects.isNull(errorMessage)) { @@ -131,8 +132,10 @@ interface ResultBase { abstract class Builder> { + @SuppressWarnings("PMD.LinguisticNaming") public abstract U isEmpty(boolean isEmpty); + @SuppressWarnings("PMD.LinguisticNaming") public abstract U hasFeatures(boolean hasFeatures); public abstract U error(Throwable error); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStreamImpl.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStreamImpl.java index e9feca082..1f70600ba 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStreamImpl.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureStreamImpl.java @@ -35,6 +35,7 @@ import java.util.concurrent.CompletionStage; import java.util.function.BiFunction; +@SuppressWarnings("PMD.CouplingBetweenObjects") public class FeatureStreamImpl implements FeatureStream { private final Query query; @@ -76,36 +77,26 @@ public FeatureStreamImpl( this.doTransform = doTransform; this.auditLog = auditLog; - this.stepMappingSchema = - !query.skipPipelineSteps().contains(PipelineSteps.MAPPING_SCHEMA) - && !query.skipPipelineSteps().contains(PipelineSteps.ALL); + this.stepMappingSchema = isStepEnabled(query, PipelineSteps.MAPPING_SCHEMA); this.stepMappingValues = stepMappingSchema || !query.skipPipelineSteps().contains(PipelineSteps.MAPPING_VALUES); - this.stepGeometry = - !query.skipPipelineSteps().contains(PipelineSteps.GEOMETRY) - && !query.skipPipelineSteps().contains(PipelineSteps.ALL); - this.stepCoordinates = - !query.skipPipelineSteps().contains(PipelineSteps.COORDINATES) - && !query.skipPipelineSteps().contains(PipelineSteps.ALL); - this.stepClean = - !query.skipPipelineSteps().contains(PipelineSteps.CLEAN) - && !query.skipPipelineSteps().contains(PipelineSteps.ALL); - this.stepEtag = - !query.skipPipelineSteps().contains(PipelineSteps.ETAG) - && !query.skipPipelineSteps().contains(PipelineSteps.ALL); - this.stepMetadata = - !query.skipPipelineSteps().contains(PipelineSteps.METADATA) - && !query.skipPipelineSteps().contains(PipelineSteps.ALL); - this.stepAudit = - auditLog.isEnabled() - && !query.skipPipelineSteps().contains(PipelineSteps.AUDIT) - && !query.skipPipelineSteps().contains(PipelineSteps.ALL); + this.stepGeometry = isStepEnabled(query, PipelineSteps.GEOMETRY); + this.stepCoordinates = isStepEnabled(query, PipelineSteps.COORDINATES); + this.stepClean = isStepEnabled(query, PipelineSteps.CLEAN); + this.stepEtag = isStepEnabled(query, PipelineSteps.ETAG); + this.stepMetadata = isStepEnabled(query, PipelineSteps.METADATA); + this.stepAudit = auditLog.isEnabled() && isStepEnabled(query, PipelineSteps.AUDIT); this.hasPropertyLinks = hasPropertyLinks(query, data); this.deduplicate = query instanceof MultiFeatureQuery && ((MultiFeatureQuery) query).getDeduplicate(); this.idsArePerType = !data.getGloballyUniqueFeatureIds(); } + private static boolean isStepEnabled(Query query, PipelineSteps step) { + return !query.skipPipelineSteps().contains(step) + && !query.skipPipelineSteps().contains(PipelineSteps.ALL); + } + // For types without properties that are represented as links (an explicit `link` in the // schema or a role that declares a link relation) the PropertyLinks transformer would be a // per-token no-op and is not wired at all. @@ -128,6 +119,7 @@ private static List getTypes(Query query) { } @Override + @SuppressWarnings("PMD.CognitiveComplexity") public CompletionStage runWith( Sink sink, Map propertyTransformations, @@ -232,6 +224,7 @@ public CompletionStage runWith( } @Override + @SuppressWarnings("PMD.CognitiveComplexity") public CompletionStage> runWith( SinkReduced sink, Map propertyTransformations, @@ -488,12 +481,12 @@ private static String renameFullPath(String path, Map renames) { StringBuilder running = new StringBuilder(); for (int i = 0; i < segments.length; i++) { if (i > 0) { - running.append("."); + running.append('.'); } running.append(segments[i]); String renamedSegment = renames.getOrDefault(running.toString(), segments[i]); if (i > 0) { - result.append("."); + result.append('.'); } result.append(renamedSegment); } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenBuffer.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenBuffer.java index 9718ff084..cdc2e02fa 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenBuffer.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenBuffer.java @@ -26,7 +26,7 @@ public class FeatureTokenBuffer< public FeatureTokenBuffer(FeatureEventHandler downstream, W context) { this.downstream = downstream; this.buffer = new ArrayList<>(); - this.bufferIn = (FeatureTokenEmitter2) (buffer::add); + this.bufferIn = (FeatureTokenEmitter2) buffer::add; this.bufferOut = new FeatureTokenReader<>(downstream, context); this.doBuffer = false; this.mark = -1; diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenDecoder.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenDecoder.java index b66047307..e0dd3fae7 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenDecoder.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenDecoder.java @@ -42,15 +42,15 @@ public final boolean canFuse( // TODO: not required here because ModifiableContext is the base context, so enforced by // FeatureTokenContext // move to FeatureTokenTransformer - if (isTransformerFuseable && transformerCustomFuseableIn instanceof FeatureTokenContext) { - if (!ModifiableContext.class.isAssignableFrom( - ((FeatureTokenContext) transformerCustomFuseableIn).getContextInterface())) { - throw new IllegalStateException( - "Cannot fuse FeatureTokenTransformer: " - + ((FeatureTokenContext) transformerCustomFuseableIn).getContextInterface() - + " does not extend " - + this.getContextInterface()); - } + if (isTransformerFuseable + && transformerCustomFuseableIn instanceof FeatureTokenContext + && !ModifiableContext.class.isAssignableFrom( + ((FeatureTokenContext) transformerCustomFuseableIn).getContextInterface())) { + throw new IllegalStateException( + "Cannot fuse FeatureTokenTransformer: " + + ((FeatureTokenContext) transformerCustomFuseableIn).getContextInterface() + + " does not extend " + + this.getContextInterface()); } return isTransformerFuseable; diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenEmitter2.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenEmitter2.java index 653145844..68ecdc77b 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenEmitter2.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenEmitter2.java @@ -13,6 +13,7 @@ import java.util.List; import java.util.OptionalLong; +@FunctionalInterface public interface FeatureTokenEmitter2< T extends SchemaBase, U extends SchemaMappingBase, V extends ModifiableContext> extends FeatureEventHandler { @@ -117,7 +118,6 @@ default void onArrayEnd(List path) { default void onGeometry(V context) { onGeometry(context.path(), context.geometry()); } - ; default void onGeometry(List path, Geometry geometry) { push(FeatureTokenType.GEOMETRY); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenEncoderBase.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenEncoderBase.java index 8973c918c..dc051ee5a 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenEncoderBase.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenEncoderBase.java @@ -15,12 +15,12 @@ public abstract class FeatureTokenEncoderBase< T extends SchemaBase, U extends SchemaMappingBase, V extends ModifiableContext> implements FeatureTokenEncoderGeneric { - private final FeatureTokenReader tokenReader; + private final FeatureTokenReader tokenReader; private Consumer downstream; private Runnable afterInit; protected FeatureTokenEncoderBase() { - this.tokenReader = new FeatureTokenReader(this, null); + this.tokenReader = new FeatureTokenReader<>(this, null); } @Override diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenEncoderDebug.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenEncoderDebug.java index a852c1b7c..2506cfd67 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenEncoderDebug.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenEncoderDebug.java @@ -15,9 +15,7 @@ import java.util.function.Consumer; public class FeatureTokenEncoderDebug - implements FeatureTokenEncoderGeneric< - FeatureSchema, SchemaMapping, ModifiableContext>, - FeatureTokenEncoder>, + implements FeatureTokenEncoder>, FeatureTokenEmitter2< FeatureSchema, SchemaMapping, ModifiableContext> { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenReader.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenReader.java index 84e7b1662..d903ebf7d 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenReader.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenReader.java @@ -39,6 +39,7 @@ public FeatureTokenReader(FeatureEventHandler eventHandler, V context) this.schemaIndexes = new HashMap<>(); } + @SuppressWarnings("PMD.NullAssignment") public void onToken(Object token) { if (token instanceof FeatureTokenType) { if (Objects.nonNull(currentType)) { @@ -46,6 +47,7 @@ public void onToken(Object token) { this.context.setSchemaIndex(-1); } if (token == FeatureTokenType.FLUSH) { + // sentinel: no token is currently in progress this.currentType = null; } initEvent((FeatureTokenType) token); @@ -58,6 +60,7 @@ public void onToken(Object token) { } } + @SuppressWarnings("PMD.CyclomaticComplexity") private void initEvent(FeatureTokenType token) { this.currentType = token; this.contextIndex = 0; @@ -113,9 +116,12 @@ private void initEvent(FeatureTokenType token) { this.context.setInObject(false); } break; + default: + break; } } + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"}) private void readContext(Object context) { switch (currentType) { case INPUT: @@ -163,6 +169,8 @@ private void readContext(Object context) { case FEATURE_END: case INPUT_END: break; + default: + break; } this.contextIndex++; @@ -175,6 +183,7 @@ private void tryReadPath(Object context) { } } + @SuppressWarnings("PMD.CyclomaticComplexity") private void emitEvent() { switch (currentType) { case INPUT: @@ -207,6 +216,8 @@ private void emitEvent() { case INPUT_END: eventHandler.onEnd(context); break; + default: + break; } } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerAudit.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerAudit.java index 9ef1394bc..b984059c1 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerAudit.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerAudit.java @@ -25,6 +25,7 @@ public class FeatureTokenTransformerAudit extends FeatureTokenTransformer { private boolean logAllProperties; public FeatureTokenTransformerAudit(String requestId, AuditLog auditLog) { + super(); this.requestId = requestId; this.auditLog = auditLog; this.includePropertyValues = auditLog.getIncludePropertyValues(requestId); @@ -84,7 +85,7 @@ private void addProperty(String schemaName, String value, boolean isMultiValue) } List values = - (List) featureHolder.computeIfAbsent(schemaName, k -> new ArrayList()); + (List) featureHolder.computeIfAbsent(schemaName, k -> new ArrayList<>()); values.add(value); } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerBase.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerBase.java index c10944b2a..fc7067b83 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerBase.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerBase.java @@ -37,15 +37,15 @@ public final boolean canFuse( boolean isTransformerFuseable = TransformerCustomFuseable.super.canFuse(transformerCustomFuseableIn); - if (isTransformerFuseable && transformerCustomFuseableIn instanceof FeatureTokenContext) { - if (!ModifiableContext.class.isAssignableFrom( - ((FeatureTokenContext) transformerCustomFuseableIn).getContextInterface())) { - throw new IllegalStateException( - "Cannot fuse FeatureTokenTransformer: " - + ((FeatureTokenContext) transformerCustomFuseableIn).getContextInterface() - + " does not extend " - + this.getContextInterface()); - } + if (isTransformerFuseable + && transformerCustomFuseableIn instanceof FeatureTokenContext + && !ModifiableContext.class.isAssignableFrom( + ((FeatureTokenContext) transformerCustomFuseableIn).getContextInterface())) { + throw new IllegalStateException( + "Cannot fuse FeatureTokenTransformer: " + + ((FeatureTokenContext) transformerCustomFuseableIn).getContextInterface() + + " does not extend " + + this.getContextInterface()); } return isTransformerFuseable; diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerCoordinates.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerCoordinates.java index 96917cf21..545abac04 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerCoordinates.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerCoordinates.java @@ -27,6 +27,7 @@ public FeatureTokenTransformerCoordinates( Optional crsTransformerTargetCrs, Optional crsTransformerWgs84, CrsTransformerFactory crsTransformerFactory) { + super(); this.crsTransformerTargetCrs = crsTransformerTargetCrs; this.crsTransformerWgs84 = crsTransformerWgs84; this.crsTransformerFactory = crsTransformerFactory; @@ -35,54 +36,70 @@ public FeatureTokenTransformerCoordinates( @Override public void onGeometry(ModifiableContext context) { Geometry geometry = context.geometry(); - if (geometry != null) { - // A geometry property that is stored in its own CRS (schema option `nativeCrs`) carries a - // position as-is in a non-native CRS — possibly 1D/3D or a CRS the query pipeline cannot - // transform. It is not transformed to the target CRS; when the property declares an - // `originalCrs` (the CRS of the recorded positions, e.g. the authority axis order of a - // geographic CRS whose stored coordinates follow the GIS axis order), the position is - // transformed back to it, so downstream formats reproduce the recorded position verbatim. - Optional propertyCrs = context.schema().flatMap(SchemaBase::getNativeCrs); - if (propertyCrs.isPresent()) { - Optional originalCrs = context.schema().flatMap(FeatureSchema::getOriginalCrs); - if (originalCrs.isPresent() && !originalCrs.get().equals(propertyCrs.get())) { - Optional toOriginal = - crsTransformerFactory.getTransformer(propertyCrs.get(), originalCrs.get()); - if (toOriginal.isPresent()) { - context.setGeometry( - geometry.accept( - new CoordinatesTransformer( - ImmutableCrsTransform.of(Optional.empty(), toOriginal.get())))); - } - } - getDownstream().onGeometry(context); - return; - } + if (geometry == null) { + getDownstream().onGeometry(context); + return; + } - CoordinatesTransformation next = null; + // A geometry property that is stored in its own CRS (schema option `nativeCrs`) carries a + // position as-is in a non-native CRS — possibly 1D/3D or a CRS the query pipeline cannot + // transform. It is not transformed to the target CRS; when the property declares an + // `originalCrs` (the CRS of the recorded positions, e.g. the authority axis order of a + // geographic CRS whose stored coordinates follow the GIS axis order), the position is + // transformed back to it, so downstream formats reproduce the recorded position verbatim. + Optional propertyCrs = context.schema().flatMap(SchemaBase::getNativeCrs); + if (propertyCrs.isPresent()) { + transformToOriginalCrs(context, geometry, propertyCrs.get()); + getDownstream().onGeometry(context); + return; + } - // A SECONDARY_GEOMETRY is always forced to WGS84 longitude/latitude, not the target CRS - boolean isSecondaryGeometry = - context.schema().filter(SchemaBase::isSecondaryGeometry).isPresent(); + transformToTargetCrs(context, geometry); - // since the secondary geometry is in WGS84, the offset may be in the wrong unit, so we skip - // simplification - if (context.query().getMaxAllowableOffset() > 0 && !isSecondaryGeometry) { - next = ImmutableSimplifyLine.of(Optional.empty(), context.query().getMaxAllowableOffset()); - } + getDownstream().onGeometry(context); + } - Optional crsTransformer = - isSecondaryGeometry ? crsTransformerWgs84 : crsTransformerTargetCrs; - if (crsTransformer.isPresent()) { - next = ImmutableCrsTransform.of(Optional.ofNullable(next), crsTransformer.get()); - } + private void transformToOriginalCrs( + ModifiableContext context, + Geometry geometry, + EpsgCrs propertyCrs) { + Optional originalCrs = context.schema().flatMap(FeatureSchema::getOriginalCrs); + if (originalCrs.isEmpty() || originalCrs.get().equals(propertyCrs)) { + return; + } - if (next != null) { - geometry = geometry.accept(new CoordinatesTransformer(next)); - context.setGeometry(geometry); - } + Optional toOriginal = + crsTransformerFactory.getTransformer(propertyCrs, originalCrs.get()); + if (toOriginal.isPresent()) { + context.setGeometry( + geometry.accept( + new CoordinatesTransformer( + ImmutableCrsTransform.of(Optional.empty(), toOriginal.get())))); } + } - getDownstream().onGeometry(context); + private void transformToTargetCrs( + ModifiableContext context, Geometry geometry) { + CoordinatesTransformation next = null; + + // A SECONDARY_GEOMETRY is always forced to WGS84 longitude/latitude, not the target CRS + boolean isSecondaryGeometry = + context.schema().filter(SchemaBase::isSecondaryGeometry).isPresent(); + + // since the secondary geometry is in WGS84, the offset may be in the wrong unit, so we skip + // simplification + if (context.query().getMaxAllowableOffset() > 0 && !isSecondaryGeometry) { + next = ImmutableSimplifyLine.of(Optional.empty(), context.query().getMaxAllowableOffset()); + } + + Optional crsTransformer = + isSecondaryGeometry ? crsTransformerWgs84 : crsTransformerTargetCrs; + if (crsTransformer.isPresent()) { + next = ImmutableCrsTransform.of(Optional.ofNullable(next), crsTransformer.get()); + } + + if (next != null) { + context.setGeometry(geometry.accept(new CoordinatesTransformer(next))); + } } } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerDeduplicate.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerDeduplicate.java index 16bf7e5f7..68d255c8c 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerDeduplicate.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerDeduplicate.java @@ -13,6 +13,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Queue; /** @@ -39,9 +40,10 @@ public class FeatureTokenTransformerDeduplicate extends FeatureTokenTransformer private boolean buffering; private boolean dropping; - private String currentType; + private Optional currentType; public FeatureTokenTransformerDeduplicate(boolean idsArePerType) { + super(); this.seen = new PackedIdSet(MAX_FEATURES); this.idsArePerType = idsArePerType; this.tokenQueue = new LinkedList<>(); @@ -55,12 +57,15 @@ public FeatureTokenTransformerDeduplicate(boolean idsArePerType) { this.inObjectQueue = new LinkedList<>(); this.buffering = false; this.dropping = false; + this.currentType = Optional.empty(); } @Override public void onFeatureStart(ModifiableContext context) { this.currentType = - Objects.nonNull(context.mapping()) ? context.mapping().getTargetSchema().getName() : null; + Objects.nonNull(context.mapping()) + ? Optional.of(context.mapping().getTargetSchema().getName()) + : Optional.empty(); this.buffering = true; this.dropping = false; @@ -148,27 +153,31 @@ public void onValue(ModifiableContext context) { } if (buffering) { buffer(context, FeatureTokenType.VALUE); - - if (context.schema().filter(SchemaBase::isId).isPresent() - && Objects.nonNull(context.value())) { - String key = - idsArePerType && Objects.nonNull(currentType) - ? currentType + ":" + context.value() - : context.value(); - - if (seen.add(key)) { - flush(context); - } else { - clear(); - this.dropping = true; - this.buffering = false; - } - } + handleIdValue(context); return; } super.onValue(context); } + private void handleIdValue(ModifiableContext context) { + if (context.schema().filter(SchemaBase::isId).isEmpty() || Objects.isNull(context.value())) { + return; + } + + String key = + idsArePerType && currentType.isPresent() + ? currentType.get() + ":" + context.value() + : context.value(); + + if (seen.add(key)) { + flush(context); + } else { + clear(); + this.dropping = true; + this.buffering = false; + } + } + private void buffer( ModifiableContext context, FeatureTokenType token) { tokenQueue.add(token); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerExtension.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerExtension.java index 830edbbe7..2f2e12591 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerExtension.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerExtension.java @@ -15,6 +15,7 @@ * before the per-format value-transformation step. This is the right slot for transformers that * need to see raw provider values (pre-format) and rewrite tokens in-place. */ +@FunctionalInterface public interface FeatureTokenTransformerExtension extends FeatureQueryExtension { FeatureTokenTransformer createTransformer(); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerGeometry.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerGeometry.java index 08f30792c..e52ce4c95 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerGeometry.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerGeometry.java @@ -22,9 +22,12 @@ public class FeatureTokenTransformerGeometry extends FeatureTokenTransformer { - public FeatureTokenTransformerGeometry() {} + public FeatureTokenTransformerGeometry() { + super(); + } @Override + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public void onGeometry(ModifiableContext context) { Geometry geometry = context.geometry(); if (geometry != null) { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerHooks.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerHooks.java index 4dd5b5f25..da0712785 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerHooks.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerHooks.java @@ -14,21 +14,23 @@ public class FeatureTokenTransformerHooks extends FeatureTokenTransformer { private final CompletableFuture onCollectionMetadata; - private final Consumer hasFeaturesSetter; + private final Consumer setHasFeatures; private boolean done; public FeatureTokenTransformerHooks( Builder resultBuilder, CompletableFuture onCollectionMetadata) { + super(); this.onCollectionMetadata = onCollectionMetadata; - this.hasFeaturesSetter = resultBuilder::hasFeatures; + this.setHasFeatures = resultBuilder::hasFeatures; this.done = false; } public FeatureTokenTransformerHooks( ImmutableResultReduced.Builder resultBuilder, CompletableFuture onCollectionMetadata) { + super(); this.onCollectionMetadata = onCollectionMetadata; - this.hasFeaturesSetter = resultBuilder::hasFeatures; + this.setHasFeatures = resultBuilder::hasFeatures; this.done = false; } @@ -42,7 +44,7 @@ public void onStart(ModifiableContext context) { @Override public void onFeatureStart(ModifiableContext context) { if (!done) { - hasFeaturesSetter.accept(true); + setHasFeatures.accept(true); this.done = true; } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerLogger.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerLogger.java index 28e39f3fe..040971116 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerLogger.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerLogger.java @@ -16,56 +16,64 @@ public class FeatureTokenTransformerLogger extends FeatureTokenTransformer { @Override public void onFeatureStart(ModifiableContext context) { - LOGGER.debug("START FEATURE {} {}", context.pathAsString(), context.indexes()); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("START FEATURE {} {}", context.pathAsString(), context.indexes()); + } super.onFeatureStart(context); } @Override public void onFeatureEnd(ModifiableContext context) { - LOGGER.debug("END FEATURE {} {}", context.pathAsString(), context.indexes()); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("END FEATURE {} {}", context.pathAsString(), context.indexes()); + } super.onFeatureEnd(context); } @Override public void onObjectStart(ModifiableContext context) { - LOGGER.debug("START OBJECT {} {}", context.pathAsString(), context.indexes()); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("START OBJECT {} {}", context.pathAsString(), context.indexes()); + } super.onObjectStart(context); } @Override public void onObjectEnd(ModifiableContext context) { - LOGGER.debug("END OBJECT {} {}", context.pathAsString(), context.indexes()); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("END OBJECT {} {}", context.pathAsString(), context.indexes()); + } super.onObjectEnd(context); } @Override public void onArrayStart(ModifiableContext context) { - LOGGER.debug("START ARRAY {}", context.pathAsString()); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("START ARRAY {}", context.pathAsString()); + } super.onArrayStart(context); } @Override public void onArrayEnd(ModifiableContext context) { - LOGGER.debug("END ARRAY {}", context.pathAsString()); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("END ARRAY {}", context.pathAsString()); + } super.onArrayEnd(context); } @Override public void onGeometry(ModifiableContext context) { - LOGGER.debug("GEOMETRY {}", context.pathAsString()); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("GEOMETRY {}", context.pathAsString()); + } super.onGeometry(context); } - - @Override - public void onValue(ModifiableContext context) { - - super.onValue(context); - } } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerMappingValuesOnly.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerMappingValuesOnly.java index 19bfa629e..f6b6422de 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerMappingValuesOnly.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerMappingValuesOnly.java @@ -18,14 +18,9 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Objects; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class FeatureTokenTransformerMappingValuesOnly extends FeatureTokenTransformer { - private static final Logger LOGGER = - LoggerFactory.getLogger(FeatureTokenTransformerMappingValuesOnly.class); - private final Map propertyTransformations; private final Map codelists; private final ZoneId nativeTimeZone; @@ -37,16 +32,12 @@ public FeatureTokenTransformerMappingValuesOnly( Map propertyTransformations, Map codelists, ZoneId nativeTimeZone) { + super(); this.propertyTransformations = propertyTransformations; this.codelists = codelists; this.nativeTimeZone = nativeTimeZone; } - @Override - protected void init() { - super.init(); - } - @Override public void onStart(ModifiableContext context) { this.valueTransformerChains = diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerMappings.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerMappings.java index 80477d102..7506dbb50 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerMappings.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerMappings.java @@ -51,16 +51,12 @@ public FeatureTokenTransformerMappings( Map propertyTransformations, Map codelists, ZoneId nativeTimeZone) { + super(); this.propertyTransformations = propertyTransformations; this.codelists = codelists; this.nativeTimeZone = nativeTimeZone; } - @Override - protected void init() { - super.init(); - } - @Override public void onStart(ModifiableContext context) { this.schemaTransformerChains = @@ -73,8 +69,8 @@ public void onStart(ModifiableContext context) { .get(entry.getKey()) .getSchemaTransformations( entry.getValue(), - (!(context.query() instanceof FeatureQuery) - || !((FeatureQuery) context.query()).returnsSingleFeature())))) + !(context.query() instanceof FeatureQuery) + || !((FeatureQuery) context.query()).returnsSingleFeature()))) .collect(ImmutableMap.toImmutableMap(Entry::getKey, Entry::getValue)); this.sliceTransformerChains = diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerMetadata.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerMetadata.java index 4aa5a6fc1..b9b270353 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerMetadata.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerMetadata.java @@ -28,19 +28,21 @@ public class FeatureTokenTransformerMetadata extends FeatureTokenTransformer { private final Consumer spatialExtentSetter; private final Consumer> temporalExtentSetter; private Optional crs; - private double[][] minMax = null; + private double[][] minMax; private String start = ""; private String end = ""; - private boolean isSingleFeature = false; + private boolean isSingleFeature; private String lastModified = ""; public FeatureTokenTransformerMetadata(ImmutableResult.Builder resultBuilder) { + super(); this.lastModifiedSetter = resultBuilder::lastModified; this.spatialExtentSetter = resultBuilder::spatialExtent; this.temporalExtentSetter = resultBuilder::temporalExtent; } public FeatureTokenTransformerMetadata(ImmutableResultReduced.Builder resultBuilder) { + super(); this.lastModifiedSetter = resultBuilder::lastModified; this.spatialExtentSetter = resultBuilder::spatialExtent; this.temporalExtentSetter = resultBuilder::temporalExtent; @@ -55,6 +57,7 @@ public void onStart(ModifiableContext context) { } @Override + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.AvoidCatchingGenericException"}) public void onEnd(ModifiableContext context) { try { if (minMax != null) { @@ -75,25 +78,31 @@ public void onEnd(ModifiableContext context) { minMax[1][2], crs.orElse(OgcCrs.CRS84h))); } - } catch (Throwable ignore) { + } catch (Exception e) { + // ignore, spatial extent is best-effort } try { - if (!start.isEmpty() && !end.isEmpty()) { + boolean hasStart = !start.isEmpty(); + boolean hasEnd = !end.isEmpty(); + + if (hasStart && hasEnd) { temporalExtentSetter.accept(Tuple.of(parseTemporal(start), parseTemporal(end))); - } else if (!start.isEmpty()) { + } else if (hasStart) { temporalExtentSetter.accept(Tuple.of(parseTemporal(start), null)); - } else if (!end.isEmpty()) { + } else if (hasEnd) { temporalExtentSetter.accept(Tuple.of(null, parseTemporal(end))); } - } catch (Throwable ignore) { + } catch (Exception e) { + // ignore, temporal extent is best-effort } try { if (!lastModified.isEmpty()) { lastModifiedSetter.accept(Instant.parse(lastModified)); } - } catch (Throwable ignore) { + } catch (Exception e) { + // ignore, last-modified is best-effort } super.onEnd(context); @@ -114,11 +123,11 @@ private static Instant parseTemporal(String value) { } @Override + @SuppressWarnings("PMD.CognitiveComplexity") public void onGeometry(ModifiableContext context) { if (context.schema().filter(SchemaBase::isPrimaryGeometry).isPresent() && Objects.nonNull(context.geometry())) { - double[][] minMax2 = null; - minMax2 = context.geometry().accept(new MinMaxDeriver()); + double[][] minMax2 = context.geometry().accept(new MinMaxDeriver()); if (minMax == null) { minMax = minMax2; } else { @@ -142,20 +151,12 @@ public void onValue(ModifiableContext context) { String value = context.value(); if (context.schema().filter(SchemaBase::isPrimaryInstant).isPresent()) { - if (start.isEmpty() || value.compareTo(start) < 0) { - this.start = value; - } - if (end.isEmpty() || value.compareTo(end) > 0) { - this.end = value; - } + updateStart(value); + updateEnd(value); } else if (context.schema().filter(SchemaBase::isPrimaryIntervalStart).isPresent()) { - if (start.isEmpty() || value.compareTo(start) < 0) { - this.start = value; - } + updateStart(value); } else if (context.schema().filter(SchemaBase::isPrimaryIntervalEnd).isPresent()) { - if (end.isEmpty() || value.compareTo(end) > 0) { - this.end = value; - } + updateEnd(value); } if (isSingleFeature && context.schema().map(SchemaBase::lastModified).orElse(false)) { @@ -165,4 +166,16 @@ public void onValue(ModifiableContext context) { super.onValue(context); } + + private void updateStart(String value) { + if (start.isEmpty() || value.compareTo(start) < 0) { + this.start = value; + } + } + + private void updateEnd(String value) { + if (end.isEmpty() || value.compareTo(end) > 0) { + this.end = value; + } + } } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerPropertyLinks.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerPropertyLinks.java index c57e14846..a65af6e4c 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerPropertyLinks.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerPropertyLinks.java @@ -13,6 +13,7 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.time.temporal.TemporalAccessor; import java.util.ArrayList; import java.util.List; @@ -106,7 +107,7 @@ static String normalizeToIso(String value) { odt = ((LocalDate) ta).atStartOfDay(ZoneId.of("UTC")).toOffsetDateTime(); } return DateTimeFormatter.ISO_INSTANT.format(odt.toInstant()); - } catch (Throwable ignore) { + } catch (DateTimeParseException ignore) { return value; } } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerRemoveEmptyOptionals.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerRemoveEmptyOptionals.java index b4bd7e7e9..26886766d 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerRemoveEmptyOptionals.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerRemoveEmptyOptionals.java @@ -22,6 +22,7 @@ public class FeatureTokenTransformerRemoveEmptyOptionals extends FeatureTokenTra public FeatureTokenTransformerRemoveEmptyOptionals( Map propertyTransformations) { + super(); this.nestingStack = new ArrayList<>(); this.schemaStack = new ArrayList<>(); this.removeNullValues = @@ -36,7 +37,7 @@ public FeatureTokenTransformerRemoveEmptyOptionals( PropertyTransformations.WILDCARD, pt -> pt.getRemoveNullValues().isPresent() - && pt.getRemoveNullValues().get() == false))) + && !pt.getRemoveNullValues().get()))) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerWeakETag.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerWeakETag.java index 0cffb076c..316b383de 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerWeakETag.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenTransformerWeakETag.java @@ -20,11 +20,13 @@ public class FeatureTokenTransformerWeakETag extends FeatureTokenTransformer { private final ETag.Incremental eTag; public FeatureTokenTransformerWeakETag(Builder resultBuilder) { + super(); this.builder = resultBuilder::eTag; this.eTag = ETag.incremental(); } public FeatureTokenTransformerWeakETag(ImmutableResultReduced.Builder resultBuilder) { + super(); this.builder = resultBuilder::eTag; this.eTag = ETag.incremental(); } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenValidator.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenValidator.java index 5fb5f2384..537f34c39 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenValidator.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTokenValidator.java @@ -18,32 +18,39 @@ public class FeatureTokenValidator extends FeatureTokenTransformer { private final NestingTrackerBase nestingTracker; public FeatureTokenValidator() { + super(); this.nestingTracker = new NestingTrackerBase<>(); } @Override public void onFeatureStart(ModifiableContext context) { - LOGGER.trace("START FEATURE {} {}", context.pathAsString(), context.indexes()); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("START FEATURE {} {}", context.pathAsString(), context.indexes()); + } super.onFeatureStart(context); } @Override public void onFeatureEnd(ModifiableContext context) { - LOGGER.trace("END FEATURE {} {}", context.pathAsString(), context.indexes()); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("END FEATURE {} {}", context.pathAsString(), context.indexes()); + } super.onFeatureEnd(context); } @Override public void onObjectStart(ModifiableContext context) { - LOGGER.trace("START OBJECT {} {}", context.pathAsString(), context.indexes()); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("START OBJECT {} {}", context.pathAsString(), context.indexes()); + } if (nestingTracker.isNested() && nestingTracker.doesNotStartWithPreviousPath(context.path())) { - error(context.path(), Type.object, true); + error(context.path(), Type.OBJECT, true); } if (nestingTracker.inArray() && !nestingTracker.isSamePath(context.path())) { - error(context.path(), Type.object, true); + error(context.path(), Type.OBJECT, true); } nestingTracker.openObject(context.path()); @@ -53,10 +60,12 @@ public void onObjectStart(ModifiableContext contex @Override public void onObjectEnd(ModifiableContext context) { - LOGGER.trace("END OBJECT {} {}", context.pathAsString(), context.indexes()); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("END OBJECT {} {}", context.pathAsString(), context.indexes()); + } if (!nestingTracker.inObject() || !nestingTracker.isSamePath(context.path())) { - error(context.path(), Type.object, false); + error(context.path(), Type.OBJECT, false); } nestingTracker.closeObject(); @@ -66,12 +75,14 @@ public void onObjectEnd(ModifiableContext context) @Override public void onArrayStart(ModifiableContext context) { - LOGGER.trace("START ARRAY {}", context.pathAsString()); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("START ARRAY {}", context.pathAsString()); + } if (nestingTracker.isNested() && nestingTracker.doesNotStartWithPreviousPath(context.path())) { - error(context.path(), Type.array, true); + error(context.path(), Type.ARRAY, true); } if (nestingTracker.inArray()) { - error(context.path(), Type.array, true); + error(context.path(), Type.ARRAY, true); } nestingTracker.openArray(context.path()); @@ -81,9 +92,11 @@ public void onArrayStart(ModifiableContext context @Override public void onArrayEnd(ModifiableContext context) { - LOGGER.trace("END ARRAY {}", context.pathAsString()); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("END ARRAY {}", context.pathAsString()); + } if (!nestingTracker.inArray() || !nestingTracker.isSamePath(context.path())) { - error(context.path(), Type.array, false); + error(context.path(), Type.ARRAY, false); } nestingTracker.closeArray(); @@ -93,12 +106,14 @@ public void onArrayEnd(ModifiableContext context) @Override public void onValue(ModifiableContext context) { - LOGGER.trace("VALUE {} {}", context.pathAsString(), context.value()); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("VALUE {} {}", context.pathAsString(), context.value()); + } if (nestingTracker.isNested() && nestingTracker.doesNotStartWithPreviousPath(context.path())) { - error(context.path(), Type.value, true); + error(context.path(), Type.VALUE, true); } if (nestingTracker.inArray() && !nestingTracker.isSamePath(context.path())) { - error(context.path(), Type.value, true); + error(context.path(), Type.VALUE, true); } super.onValue(context); @@ -106,15 +121,17 @@ public void onValue(ModifiableContext context) { @Override public void onGeometry(ModifiableContext context) { - LOGGER.trace("GEOMETRY {} {}", context.pathAsString(), context.geometry()); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("GEOMETRY {} {}", context.pathAsString(), context.geometry()); + } super.onGeometry(context); } private enum Type { - object, - array, - value + OBJECT, + ARRAY, + VALUE } private void error(List path, Type type, boolean isOpen) { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTransformer.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTransformer.java index 1ef2c72ae..a17ef95ed 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTransformer.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTransformer.java @@ -9,6 +9,7 @@ import de.ii.xtraplatform.features.domain.legacy.TargetMapping; import de.ii.xtraplatform.geometries.domain.GeometryType; +import java.io.IOException; import java.util.List; import java.util.OptionalLong; @@ -18,29 +19,28 @@ public interface FeatureTransformer { String getTargetFormat(); - void onStart(OptionalLong numberReturned, OptionalLong numberMatched) throws Exception; + void onStart(OptionalLong numberReturned, OptionalLong numberMatched) throws IOException; - void onEnd() throws Exception; + void onEnd() throws IOException; - void onFeatureStart(final TargetMapping mapping) throws Exception; + void onFeatureStart(TargetMapping mapping) throws IOException; - void onFeatureEnd() throws Exception; + void onFeatureEnd() throws IOException; - void onPropertyStart(final TargetMapping mapping, List multiplicities) throws Exception; + void onPropertyStart(TargetMapping mapping, List multiplicities) throws IOException; - void onPropertyText(final String text) throws Exception; + void onPropertyText(String text) throws IOException; - void onPropertyEnd() throws Exception; + void onPropertyEnd() throws IOException; - void onGeometryStart( - final TargetMapping mapping, final GeometryType type, final Integer dimension) - throws Exception; + void onGeometryStart(TargetMapping mapping, GeometryType type, Integer dimension) + throws IOException; - void onGeometryNestedStart() throws Exception; + void onGeometryNestedStart() throws IOException; - void onGeometryCoordinates(final String text) throws Exception; + void onGeometryCoordinates(String text) throws IOException; - void onGeometryNestedEnd() throws Exception; + void onGeometryNestedEnd() throws IOException; - void onGeometryEnd() throws Exception; + void onGeometryEnd() throws IOException; } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureType.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureType.java index 9f12a3005..eff2f1ba3 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureType.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureType.java @@ -32,12 +32,12 @@ @JsonDeserialize(builder = ImmutableFeatureType.Builder.class) public interface FeatureType extends Buildable { - abstract static class Builder implements BuildableBuilder { + abstract class Builder implements BuildableBuilder { public abstract ImmutableFeatureType.Builder putProperties( String key, ImmutableFeatureProperty.Builder builder); @JsonAnySetter - @JsonProperty(value = "properties") + @JsonProperty("properties") public ImmutableFeatureType.Builder putProperties2( String key, ImmutableFeatureProperty.Builder builder) { return putProperties(key, builder.name(key)); @@ -56,6 +56,7 @@ default ImmutableFeatureType.Builder getBuilder() { // builder deserialization // (immutables attributeBuilder does not work with maps yet) @JsonMerge + @SuppressWarnings("PMD.LooseCoupling") BuildableMap getProperties(); @JsonIgnore @@ -64,6 +65,7 @@ default ImmutableFeatureType.Builder getBuilder() { // TODO @JsonIgnore @Value.Derived + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.UseStringBufferForStringAppends"}) default Map, List> getPropertiesByPath() { Map, List> builder = new LinkedHashMap<>(); @@ -85,11 +87,13 @@ default Map, List> getPropertiesByPath() { String prefix = entry.getKey(); String uri = entry.getValue(); if (prefix.isBlank()) { - if (resolvedElement.startsWith(":")) + if (resolvedElement.startsWith(":")) { resolvedElement = uri + resolvedElement; - } else + } + } else { resolvedElement = resolvedElement.replaceAll(prefix + ":", uri + ":"); + } } return resolvedElement; diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTypeV2.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTypeV2.java index 520016ff8..10984b536 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTypeV2.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FeatureTypeV2.java @@ -44,16 +44,17 @@ public interface FeatureTypeV2 extends Buildable { // deserialization // (immutables attributeBuilder does not work with maps yet) @JsonMerge + @SuppressWarnings("PMD.LooseCoupling") BuildableMap getProperties(); Map getAdditionalInfo(); // custom builder to automatically use keys of types as name of FeaturePropertyV2 - abstract static class Builder implements BuildableBuilder { + abstract class Builder implements BuildableBuilder { public abstract ImmutableFeatureTypeV2.Builder putProperties( String key, ImmutableFeatureSchema.Builder builder); - @JsonProperty(value = "properties") + @JsonProperty("properties") public ImmutableFeatureTypeV2.Builder putProperties2( String key, ImmutableFeatureSchema.Builder builder) { return putProperties(key, builder.name(key)); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FilterEncoder.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FilterEncoder.java index 9a11938be..883f19649 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FilterEncoder.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/FilterEncoder.java @@ -9,6 +9,7 @@ import de.ii.xtraplatform.cql.domain.Cql2Expression; +@SuppressWarnings("PMD.ImplicitFunctionalInterface") public interface FilterEncoder { T encode(Cql2Expression cqlFilter, String featureType); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/LoggingFeatureProviderMetadataConsumer.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/LoggingFeatureProviderMetadataConsumer.java index 436a498ae..ed20c6421 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/LoggingFeatureProviderMetadataConsumer.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/LoggingFeatureProviderMetadataConsumer.java @@ -13,6 +13,7 @@ /** * @author zahnen */ +@SuppressWarnings("PMD.TooManyMethods") public class LoggingFeatureProviderMetadataConsumer implements FeatureProviderMetadataConsumer { private static final Logger LOGGER = @@ -60,7 +61,9 @@ public void analyzeAbstract(String abstrct) { @Override public void analyzeKeywords(String... keywords) { - LOGGER.debug("analyzeKeywords {}", (Object) keywords); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("analyzeKeywords {}", (Object) keywords); + } } @Override @@ -205,10 +208,13 @@ public void analyzeFeatureTypeAbstract(String featureTypeName, String abstrct) { @Override public void analyzeFeatureTypeKeywords(String featureTypeName, String... keywords) { - LOGGER.debug("analyzeFeatureTypeKeywords {} {}", featureTypeName, (Object) keywords); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("analyzeFeatureTypeKeywords {} {}", featureTypeName, (Object) keywords); + } } @Override + @SuppressWarnings("PMD.UseObjectForClearerAPI") public void analyzeFeatureTypeBoundingBox( String featureTypeName, String xmin, String ymin, String xmax, String ymax) { LOGGER.debug( diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MappedSchemaDeriver.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MappedSchemaDeriver.java index d91d33572..2140e50af 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MappedSchemaDeriver.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MappedSchemaDeriver.java @@ -32,6 +32,7 @@ T create( List merge(FeatureSchema targetSchema, List parentPath, List visitedProperties); @Override + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.AvoidCatchingGenericException"}) default List visit( FeatureSchema schema, List parents, List> visitedProperties) { List> parentPaths1; @@ -40,7 +41,8 @@ default List visit( try { parentPaths1 = getParentPaths(parents); currentPaths = parseSourcePaths(schema, parentPaths1); - } catch (Throwable e) { + } catch (Exception e) { + // parseSourcePaths is implemented by arbitrary subclasses, no common exception type String propertyPath = Stream.concat(parents.stream(), Stream.of(schema)) .map(SchemaBase::getName) @@ -76,12 +78,7 @@ default List visit( parentPath -> currentPaths.stream() .filter( - currentPath -> { - if (isInConcat && !currentPath.parentsIntersect(parentPath)) { - return false; - } - return true; - }) + currentPath -> !isInConcat || currentPath.parentsIntersect(parentPath)) .map( currentPath -> { U finalCurrentPath = diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MappingBuilder.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MappingBuilder.java index b4c30dcba..36fc3b721 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MappingBuilder.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MappingBuilder.java @@ -15,12 +15,9 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class MappingBuilder { - private static final Logger LOGGER = LoggerFactory.getLogger(MappingBuilder.class); private static final Joiner PATH_JOINER = Joiner.on('/').skipNulls(); private final NestingTrackerBase nestingTracker; @@ -47,7 +44,7 @@ public void openType(String name, List path) { new ImmutableFeatureSchema.Builder() .name(name) .type(SchemaBase.Type.OBJECT) - .sourcePath(asSourcePath(path, true)); + .sourcePath(asSourcePath(path, "/")); nestingTracker.openObject(List.of(), current); @@ -130,10 +127,6 @@ private String asSourcePath(List path) { return asSourcePath(path, ""); } - private String asSourcePath(List path, boolean isRoot) { - return asSourcePath(path, "/"); - } - private String asSourcePath(List path, String prefix) { return prefix + PATH_JOINER.join(nestingTracker.relativize(path)); } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MappingOperationResolver.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MappingOperationResolver.java index 890c21b1a..d7c24785a 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MappingOperationResolver.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MappingOperationResolver.java @@ -11,6 +11,7 @@ import de.ii.xtraplatform.features.domain.SchemaBase.Type; import de.ii.xtraplatform.features.domain.transform.ImmutablePropertyTransformation; +import de.ii.xtraplatform.features.domain.transform.PropertyTransformation; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -411,6 +412,7 @@ private FeatureSchema resolveMerge(FeatureSchema schema) { .build(); } + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"}) public static FeatureSchema resolveConcat(FeatureSchema schema) { if (schema.getType() == Type.VALUE_ARRAY) { String basePath = schema.getSourcePath().map(p -> p + "/").orElse(""); @@ -473,41 +475,14 @@ public static FeatureSchema resolveConcat(FeatureSchema schema) { .or(() -> prop.isObject() ? Optional.of(basePath2NoSlash) : Optional.empty()); builder.putPropertyMap( - prefix + prop.getName(), - new ImmutableFeatureSchema.Builder() - .from(prop) - .sourcePath(newSourcePath) - .path(List.of(i + "_" + prop.getName())) - .transformations( - prop.getTransformations().stream() - .map( - transformation -> { - if (transformation.getRename().isPresent()) { - return new ImmutablePropertyTransformation.Builder() - .rename(transformation.getRename().get()) - .renamePathOnly(prefix + transformation.getRename().get()) - .build(); - } - return transformation; - }) - .collect(Collectors.toList())) - .putAdditionalInfo(IS_PROPERTY, "true")); + prefix + prop.getName(), buildConcatProperty(prop, prefix, newSourcePath)); } } if (schema.getConcat().stream().anyMatch(s -> Objects.isNull(s.getDesiredType()))) { builder.concat( schema.getConcat().stream() - .map( - s -> { - if (Objects.isNull(s.getDesiredType())) { - return new ImmutableFeatureSchema.Builder() - .from(s) - .type(schema.getType()) - .build(); - } - return s; - }) + .map(s -> withDesiredType(s, schema.getType())) .collect(Collectors.toList())); } @@ -517,6 +492,42 @@ public static FeatureSchema resolveConcat(FeatureSchema schema) { return schema; } + private static ImmutableFeatureSchema.Builder buildConcatProperty( + FeatureSchema prop, String prefix, Optional newSourcePath) { + return new ImmutableFeatureSchema.Builder() + .from(prop) + .sourcePath(newSourcePath) + .path(List.of(prefix + prop.getName())) + .transformations(renamedTransformations(prop, prefix)) + .putAdditionalInfo(IS_PROPERTY, "true"); + } + + private static List renamedTransformations( + FeatureSchema prop, String prefix) { + return prop.getTransformations().stream() + .map(transformation -> renameWithPrefix(transformation, prefix)) + .collect(Collectors.toList()); + } + + private static PropertyTransformation renameWithPrefix( + PropertyTransformation transformation, String prefix) { + if (transformation.getRename().isEmpty()) { + return transformation; + } + return new ImmutablePropertyTransformation.Builder() + .rename(transformation.getRename().get()) + .renamePathOnly(prefix + transformation.getRename().get()) + .build(); + } + + private static FeatureSchema withDesiredType(FeatureSchema s, Type fallbackType) { + if (Objects.nonNull(s.getDesiredType())) { + return s; + } + return new ImmutableFeatureSchema.Builder().from(s).type(fallbackType).build(); + } + + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"}) public static FeatureSchema resolveCoalesce(FeatureSchema schema) { if (schema.isValue() && !schema.isFeatureRef() && !schema.isArray()) { String basePath = schema.getSourcePath().map(p -> p + "/").orElse(""); @@ -570,26 +581,14 @@ public static FeatureSchema resolveCoalesce(FeatureSchema schema) { for (FeatureSchema prop : schema.getCoalesce().get(i).getProperties()) { builder.putPropertyMap( i + "_" + prop.getName(), - new ImmutableFeatureSchema.Builder() - .from(prop) - .sourcePath(basePath2 + prop.getSourcePath().orElse("")) - .path(List.of(i + "_" + prop.getName()))); + buildCoalesceProperty(prop, i, basePath2 + prop.getSourcePath().orElse(""))); } } if (schema.getCoalesce().stream().anyMatch(s -> Objects.isNull(s.getDesiredType()))) { builder.coalesce( schema.getCoalesce().stream() - .map( - s -> { - if (Objects.isNull(s.getDesiredType())) { - return new ImmutableFeatureSchema.Builder() - .from(s) - .type(schema.getType()) - .build(); - } - return s; - }) + .map(s -> withDesiredType(s, schema.getType())) .collect(Collectors.toList())); } @@ -599,6 +598,14 @@ public static FeatureSchema resolveCoalesce(FeatureSchema schema) { return schema; } + private static ImmutableFeatureSchema.Builder buildCoalesceProperty( + FeatureSchema prop, int index, String sourcePath) { + return new ImmutableFeatureSchema.Builder() + .from(prop) + .sourcePath(sourcePath) + .path(List.of(index + "_" + prop.getName())); + } + private static boolean hasMerge(FeatureSchema schema) { return !schema.getMerge().isEmpty(); } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MappingRulesDeriver.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MappingRulesDeriver.java index b21553611..24b14199e 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MappingRulesDeriver.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MappingRulesDeriver.java @@ -21,6 +21,7 @@ import java.util.Set; import java.util.stream.Stream; +@SuppressWarnings("PMD.GodClass") public class MappingRulesDeriver implements SchemaVisitorWithFinalizer, List> { @@ -59,7 +60,9 @@ public List visit( } @Override - public List finalize(FeatureSchema featureSchema, List mappingRules) { + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"}) + public List finalizeVisit( + FeatureSchema featureSchema, List mappingRules) { Map> rulesByTable = new LinkedHashMap<>(); Map schemaIndexes = new HashMap<>(); @@ -73,51 +76,36 @@ public List finalize(FeatureSchema featureSchema, List continue; } - rulesByTable.put(rule.getIdentifier(), new ArrayList<>(List.of(cleanRule))); + rulesByTable.put(rule.getIdentifier(), newRuleList(cleanRule)); continue; } - if (!schemaIndexes.containsKey(rule.getSource())) { - schemaIndexes.put(rule.getSource(), 0); - } else { + if (schemaIndexes.containsKey(rule.getSource())) { schemaIndexes.put(rule.getSource(), schemaIndexes.get(rule.getSource()) + 1); + } else { + schemaIndexes.put(rule.getSource(), 0); } + MappingRule effectiveRule = rule; if (schemaIndexes.get(rule.getSource()) > 0) { - rule = - new ImmutableMappingRule.Builder() - .from(rule) - .index(schemaIndexes.get(rule.getSource())) - .build(); + effectiveRule = withIndex(rule, schemaIndexes.get(rule.getSource())); } - String tableIdentifier = rule.getIdentifierParent(); + String tableIdentifier = effectiveRule.getIdentifierParent(); // implicit tables - if (rule.hasSourceParent() && !rulesByTable.containsKey(tableIdentifier)) { - MappingRule finalRule = rule; + if (effectiveRule.hasSourceParent() && !rulesByTable.containsKey(tableIdentifier)) { + MappingRule finalRule = effectiveRule; List matchingTables = rulesByTable.keySet().stream() .filter(id -> id.startsWith(finalRule.getSourceParent() + "-")) .toList(); if (matchingTables.isEmpty()) { - MappingRule tableRule = - new ImmutableMappingRule.Builder() - .source(rule.getSourceParent()) - .target( - rule.getTarget().contains(".") - ? rule.getTarget().substring(0, rule.getTarget().lastIndexOf(".")) - : ROOT_TARGET) - .type( - rule.getTarget().endsWith(VALUE_ARRAY_VALUE_SUFFIX) - ? Type.VALUE_ARRAY - : Type.OBJECT_ARRAY) - .index(0) - .build(); - - rulesByTable.put(tableIdentifier, new ArrayList<>(List.of(tableRule, cleanup(rule)))); + MappingRule tableRule = buildImplicitTableRule(effectiveRule); + + rulesByTable.put(tableIdentifier, newRuleList(tableRule, cleanup(effectiveRule))); continue; } @@ -126,12 +114,35 @@ public List finalize(FeatureSchema featureSchema, List tableIdentifier = matchingTables.get(matchingTables.size() - 1); } - rulesByTable.get(tableIdentifier).add(cleanup(rule)); + rulesByTable.get(tableIdentifier).add(cleanup(effectiveRule)); } return sorted(rulesByTable); } + private static List newRuleList(MappingRule... rules) { + return new ArrayList<>(List.of(rules)); + } + + private static MappingRule withIndex(MappingRule rule, int index) { + return new ImmutableMappingRule.Builder().from(rule).index(index).build(); + } + + private static MappingRule buildImplicitTableRule(MappingRule effectiveRule) { + return new ImmutableMappingRule.Builder() + .source(effectiveRule.getSourceParent()) + .target( + effectiveRule.getTarget().contains(".") + ? effectiveRule.getTarget().substring(0, effectiveRule.getTarget().lastIndexOf('.')) + : ROOT_TARGET) + .type( + effectiveRule.getTarget().endsWith(VALUE_ARRAY_VALUE_SUFFIX) + ? Type.VALUE_ARRAY + : Type.OBJECT_ARRAY) + .index(0) + .build(); + } + private static MappingRule cleanup(MappingRule rule) { if (rule.getTarget().endsWith(VALUE_ARRAY_VALUE_SUFFIX)) { return new ImmutableMappingRule.Builder() @@ -143,6 +154,7 @@ private static MappingRule cleanup(MappingRule rule) { return rule; } + @SuppressWarnings("PMD.CognitiveComplexity") private static List sorted(Map> rulesByTable) { List sorted = new ArrayList<>(); List parents = new ArrayList<>(); @@ -151,7 +163,7 @@ private static List sorted(Map> rulesByTa for (String tableIdentifier : rulesByTable.keySet()) { String source = tableIdentifier.substring(0, tableIdentifier.lastIndexOf('-')); - boolean hasParent = MappingRule.maskPathAttributes(source).indexOf("/", 1) > 1; + boolean hasParent = MappingRule.maskPathAttributes(source).indexOf('/', 1) > 1; if (hasParent) { for (int i = parents.size() - 1; i >= 0; i--) { @@ -167,34 +179,8 @@ private static List sorted(Map> rulesByTa break; } if (source.startsWith(parents.get(i) + "/")) { - int span = spans.get(i); - int index = cursors.get(span); - sorted.addAll(index, rulesByTable.get(tableIdentifier)); - - cursors.add(span + 1, index + rulesByTable.get(tableIdentifier).size()); - parents.add(span + 1, source); - spans.add(span + 1, span + 1); - - spans.set(i, span + 1); - for (int j = 0; j < i; j++) { - if (spans.get(j) == span) { - spans.set(j, span + 1); - } - } - for (int j = span + 2; j < spans.size(); j++) { - spans.set(j, spans.get(j) + 1); - } - - cursors.set(i, index + rulesByTable.get(tableIdentifier).size()); - for (int j = 0; j < i; j++) { - if (cursors.get(j) == index) { - cursors.set(j, index + rulesByTable.get(tableIdentifier).size()); - } - } - for (int j = span + 2; j < cursors.size(); j++) { - cursors.set(j, cursors.get(j) + rulesByTable.get(tableIdentifier).size()); - } - + insertAsChild( + i, source, rulesByTable.get(tableIdentifier), parents, spans, cursors, sorted); break; } } @@ -209,6 +195,43 @@ private static List sorted(Map> rulesByTa return sorted; } + private static void insertAsChild( + int i, + String source, + List tableRules, + List parents, + List spans, + List cursors, + List sorted) { + int span = spans.get(i); + int index = cursors.get(span); + sorted.addAll(index, tableRules); + + cursors.add(span + 1, index + tableRules.size()); + parents.add(span + 1, source); + spans.add(span + 1, span + 1); + + spans.set(i, span + 1); + for (int j = 0; j < i; j++) { + if (spans.get(j) == span) { + spans.set(j, span + 1); + } + } + for (int j = span + 2; j < spans.size(); j++) { + spans.set(j, spans.get(j) + 1); + } + + cursors.set(i, index + tableRules.size()); + for (int j = 0; j < i; j++) { + if (cursors.get(j) == index) { + cursors.set(j, index + tableRules.size()); + } + } + for (int j = span + 2; j < cursors.size(); j++) { + cursors.set(j, cursors.get(j) + tableRules.size()); + } + } + private Stream toRules( String parentSourcePath, String sourcePath, FeatureSchema schema) { String target = diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MultiFeatureProviderMetadataConsumer.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MultiFeatureProviderMetadataConsumer.java index 8507f3ad6..123824688 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MultiFeatureProviderMetadataConsumer.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/MultiFeatureProviderMetadataConsumer.java @@ -10,12 +10,13 @@ /** * @author zahnen */ +@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.TooManyMethods"}) public class MultiFeatureProviderMetadataConsumer implements FeatureProviderMetadataConsumer { private final FeatureProviderMetadataConsumer[] analyzers; public MultiFeatureProviderMetadataConsumer(FeatureProviderMetadataConsumer... analyzers) { - this.analyzers = analyzers; + this.analyzers = analyzers.clone(); } @Override @@ -285,6 +286,7 @@ public void analyzeFeatureTypeKeywords(String featureTypeName, String... keyword } @Override + @SuppressWarnings("PMD.UseObjectForClearerAPI") public void analyzeFeatureTypeBoundingBox( String featureTypeName, String xmin, String ymin, String xmax, String ymax) { for (FeatureProviderMetadataConsumer analyzer : analyzers) { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/NestingTracker.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/NestingTracker.java index 449062923..45d8367e2 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/NestingTracker.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/NestingTracker.java @@ -8,7 +8,6 @@ package de.ii.xtraplatform.features.domain; import com.google.common.base.Joiner; -import com.google.common.collect.ImmutableList; import de.ii.xtraplatform.features.domain.FeatureEventHandler.ModifiableContext; import java.util.ArrayList; import java.util.List; @@ -20,6 +19,7 @@ /** * @author zahnen */ +@SuppressWarnings("PMD.GodClass") public class NestingTracker { private static final Logger LOGGER = LoggerFactory.getLogger(NestingTracker.class); @@ -82,6 +82,7 @@ public void openObject() { context.setInObject(true); } + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"}) public void closeObject() { if (nestingStack.isEmpty() || !Objects.equals(nestingStack.get(nestingStack.size() - 1), "O")) { if (LOGGER.isDebugEnabled()) { @@ -107,11 +108,7 @@ public void closeObject() { if (!nestingStack.contains("O")) { context.setInObject(false); } - if (!pathStack.isEmpty()) { - context.pathTracker().track(getCurrentNestingPath()); - } else { - context.pathTracker().track(ImmutableList.of()); - } + context.pathTracker().track(getCurrentNestingPath()); } public void closeArray() { @@ -170,13 +167,13 @@ private void pop() { public List getCurrentNestingPath() { if (pathStack.isEmpty()) { - return null; + return List.of(); } return pathStack.get(pathStack.size() - 1); } public boolean isNested() { - return Objects.nonNull(getCurrentNestingPath()); + return !getCurrentNestingPath().isEmpty(); } public boolean inArray() { @@ -198,7 +195,7 @@ public boolean isNotMain(List nextPath) { } public boolean isFirst(List indexes) { - return indexes.size() > 0 && indexes.get(indexes.size() - 1) == 1; + return !indexes.isEmpty() && indexes.get(indexes.size() - 1) == 1; } public boolean isSamePath(List nextPath) { @@ -210,10 +207,8 @@ public boolean doesNotStartWithPreviousPath(List nextPath) { } public boolean doesStartWithPreviousPath(List nextPath) { - if (Objects.equals(nextPath, getCurrentNestingPath())) { - return false; - } - return startsWith(nextPath, getCurrentNestingPath()); + return !Objects.equals(nextPath, getCurrentNestingPath()) + && startsWith(nextPath, getCurrentNestingPath()); } public boolean hasIndexChanged(List nextIndexes) { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/NestingTrackerBase.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/NestingTrackerBase.java index 19ebee632..dfdac21b1 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/NestingTrackerBase.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/NestingTrackerBase.java @@ -16,6 +16,7 @@ /** * @author zahnen */ +@SuppressWarnings("PMD.GodClass") public class NestingTrackerBase { private static final Logger LOGGER = LoggerFactory.getLogger(NestingTrackerBase.class); @@ -53,7 +54,7 @@ public void openObject(List path, T payload) { } public void closeAuto(List path) { - while (isNested() && (doesNotStartWithPreviousPath(path))) { + while (isNested() && doesNotStartWithPreviousPath(path)) { if (inObject()) { closeObject(); @@ -165,10 +166,8 @@ public boolean doesNotStartWithPreviousPath(List nextPath) { } public boolean doesStartWithPreviousPath(List nextPath) { - if (Objects.equals(nextPath, getCurrentNestingPath())) { - return false; - } - return startsWith(nextPath, getCurrentNestingPath()); + return !Objects.equals(nextPath, getCurrentNestingPath()) + && startsWith(nextPath, getCurrentNestingPath()); } private static boolean startsWith(List longer, List shorter) { @@ -183,7 +182,7 @@ private static boolean startsWith(List longer, List shorter) { public String toString() { StringBuilder s = new StringBuilder(); for (int i = 0; i < pathStack.size(); i++) { - s.append(pathStack.get(i)).append(" ").append(nestingStack.get(i)).append("\n"); + s.append(pathStack.get(i)).append(' ').append(nestingStack.get(i)).append('\n'); } return s.toString(); } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/PackedIdSet.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/PackedIdSet.java index c864fd114..bc5539873 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/PackedIdSet.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/PackedIdSet.java @@ -51,7 +51,7 @@ public boolean add(String id) { long lo; long[] packed = pack(id); - if (packed != null) { + if (packed.length > 0) { hi = packed[0]; lo = packed[1]; } else { @@ -142,7 +142,7 @@ private static int spread(long hi, long lo) { private static long[] pack(String id) { int length = id.length(); if (length == 0 || length > MAX_PACKED_LENGTH) { - return null; + return new long[0]; } long hi = 0; @@ -150,7 +150,7 @@ private static long[] pack(String id) { for (int i = 0; i < length; i++) { int bits = toBits(id.charAt(i)); if (bits < 0) { - return null; + return new long[0]; } hi = (hi << 6) | (lo >>> 58); lo = (lo << 6) | bits; diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/PartialObjectSchema.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/PartialObjectSchema.java index da193f177..ffdd31172 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/PartialObjectSchema.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/PartialObjectSchema.java @@ -34,7 +34,7 @@ public interface PartialObjectSchema Optional getSchema(); - @JsonProperty(value = "properties") + @JsonProperty("properties") @Override BuildableMap getPropertyMap(); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/PropertiesSchema.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/PropertiesSchema.java index 4b5e82847..31f782e62 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/PropertiesSchema.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/PropertiesSchema.java @@ -30,7 +30,8 @@ public interface PropertiesSchema< // behaves exactly like Map, but supports mergeable builder // deserialization // (immutables attributeBuilder does not work with maps yet) - @JsonProperty(value = "properties") + @JsonProperty("properties") + @SuppressWarnings("PMD.LooseCoupling") BuildableMap> getPropertyMap(); interface BuilderWithName, U extends BuilderWithName> @@ -48,7 +49,7 @@ abstract class Builder< public abstract Builder putPropertyMap(String key, U builder); // @JsonMerge - @JsonProperty(value = "properties") + @JsonProperty("properties") public Builder putProperties2(Map builderMap) { Builder builder1 = null; for (Map.Entry entry : builderMap.entrySet()) { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ProviderData.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ProviderData.java index 22c8a287c..036054f10 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ProviderData.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ProviderData.java @@ -10,6 +10,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import de.ii.xtraplatform.docs.DocIgnore; import de.ii.xtraplatform.entities.domain.EntityData; +import java.util.Locale; import java.util.Optional; import org.immutables.value.Value; @@ -28,7 +29,7 @@ public interface ProviderData extends EntityData { @Override default Optional getEntitySubType() { return Optional.of( - String.format("%s/%s", getProviderType(), getProviderSubType()).toLowerCase()); + String.format("%s/%s", getProviderType(), getProviderSubType()).toLowerCase(Locale.ROOT)); } // We need to add the @Value.Auxiliary annotation here again, otherwise createdAt and lastModified diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/Query.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/Query.java index 4332028c6..825958eb6 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/Query.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/Query.java @@ -14,6 +14,7 @@ import java.util.Optional; import org.immutables.value.Value; +@SuppressWarnings("PMD.ImplicitFunctionalInterface") public interface Query { Optional getCrs(); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/QueryRunner.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/QueryRunner.java index 1e655b204..b78e0b586 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/QueryRunner.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/QueryRunner.java @@ -14,6 +14,7 @@ import java.util.concurrent.CompletionStage; import java.util.function.BiFunction; +@FunctionalInterface public interface QueryRunner { CompletionStage runQuery( BiFunction, Stream> stream, diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ReverseSchemaDeriver.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ReverseSchemaDeriver.java index cccddc893..548a618eb 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ReverseSchemaDeriver.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/ReverseSchemaDeriver.java @@ -17,6 +17,8 @@ public interface ReverseSchemaDeriver> extends SchemaVisitor> { + Splitter SPLITTER = Splitter.on('/').omitEmptyStrings(); + @Override default List visit(FeatureSchema schema, List> visitedProperties) { @@ -83,8 +85,6 @@ default List visit(FeatureSchema schema, List> visitedProperties) { T prependToSourcePath(String parentSourcePath, T schema); - Splitter SPLITTER = Splitter.on('/').omitEmptyStrings(); - default List splitPath(String path) { return SPLITTER.splitToList(path); } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaBase.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaBase.java index 60563f0fd..cfd3a06dd 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaBase.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaBase.java @@ -23,6 +23,7 @@ import java.util.stream.Stream; import org.immutables.value.Value; +@SuppressWarnings({"PMD.ExcessivePublicCount", "PMD.TooManyMethods"}) public interface SchemaBase> { enum Role { @@ -183,7 +184,7 @@ enum Scope { SORTABLE; public static List allBut(Scope... scopes) { - return Arrays.stream(Scope.values()) + return Arrays.stream(values()) .filter(s -> Arrays.stream(scopes).noneMatch(scope -> scope == s)) .collect(Collectors.toList()); } @@ -638,10 +639,7 @@ default Optional getEmbeddedSecondaryGeometry() { @Value.Derived @Value.Auxiliary default boolean hasEmbeddedFeature() { - if (!isFeature()) { - return false; - } - return getAllNestedProperties().stream().anyMatch(SchemaBase::isEmbeddedFeature); + return isFeature() && getAllNestedProperties().stream().anyMatch(SchemaBase::isEmbeddedFeature); } @JsonIgnore @@ -907,7 +905,7 @@ default U accept(SchemaVisitorTopDown visitor) { } default V accept(SchemaVisitorWithFinalizer visitor) { - return visitor.finalize((T) this, accept(visitor, ImmutableList.of())); + return visitor.finalizeVisit((T) this, accept(visitor, ImmutableList.of())); } default U accept(SchemaVisitorTopDown visitor, List parents) { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaConstraints.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaConstraints.java index e80eef5a2..f1f3802fa 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaConstraints.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaConstraints.java @@ -210,7 +210,7 @@ public interface SchemaConstraints { * @langDe Liste von erlaubten Werten für die Eigenschaft. Nur bei String- oder * Integer-Eigenschaften sinnvoll. */ - @JsonProperty(value = "enum") + @JsonProperty("enum") List getEnumValues(); /** diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaDeriver.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaDeriver.java index 26ff2906d..710c938a3 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaDeriver.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaDeriver.java @@ -32,6 +32,7 @@ import java.util.stream.IntStream; import java.util.stream.Stream; +@SuppressWarnings({"PMD.GodClass", "PMD.CyclomaticComplexity", "PMD.TooManyMethods"}) public abstract class SchemaDeriver implements SchemaVisitorTopDown { private final Map codelists; @@ -62,13 +63,9 @@ private T deriveRootSchemas(FeatureSchema schema, List visitedProperties) { int k = 0; for (int i = 0; i < schema.getConcat().size(); i++) { - List visitedProperties3 = new ArrayList<>(); - - if (!visitedProperties.isEmpty()) { - for (int j = 0; j < schema.getConcat().get(i).getProperties().size(); j++) { - visitedProperties3.add(visitedProperties.get(k++)); - } - } + int count = schema.getConcat().get(i).getProperties().size(); + List visitedProperties3 = visitedProperties.subList(k, k + count); + k += count; schemas.add(deriveRootSchema(schema.getConcat().get(i), visitedProperties3)); } @@ -135,11 +132,9 @@ private T deriveObjectSchemas(FeatureSchema schema, List visitedProperties) { int k = 0; for (int i = 0; i < schema.getConcat().size(); i++) { - List visitedProperties3 = new ArrayList<>(); - - for (int j = 0; j < schema.getConcat().get(i).getProperties().size(); j++) { - visitedProperties3.add(visitedProperties.get(k++)); - } + int count = schema.getConcat().get(i).getProperties().size(); + List visitedProperties3 = visitedProperties.subList(k, k + count); + k += count; schemas.add(deriveObjectSchema(schema.getConcat().get(i), visitedProperties3, false)); } @@ -157,11 +152,9 @@ private T deriveObjectSchemas(FeatureSchema schema, List visitedProperties) { int k = 0; for (int i = 0; i < schema.getCoalesce().size(); i++) { - List visitedProperties3 = new ArrayList<>(); - - for (int j = 0; j < schema.getCoalesce().get(i).getProperties().size(); j++) { - visitedProperties3.add(visitedProperties.get(k++)); - } + int count = schema.getCoalesce().get(i).getProperties().size(); + List visitedProperties3 = visitedProperties.subList(k, k + count); + k += count; schemas.add(deriveObjectSchema(schema.getCoalesce().get(i), visitedProperties3, false)); } @@ -232,6 +225,7 @@ && isPropertyRequired(property)) return objectSchema; } + @SuppressWarnings({"PMD.NcssCount", "PMD.CognitiveComplexity", "PMD.NPathComplexity"}) protected T deriveValueSchema(FeatureSchema schema) { if (schema.getTransformations().stream() .anyMatch(t -> t.getRemove().map(v -> ALWAYS.name().equals(v)).isPresent())) { @@ -240,7 +234,7 @@ protected T deriveValueSchema(FeatureSchema schema) { T valueSchema = null; Type propertyType = schema.getType(); - if (Type.VALUE.equals(propertyType) && schema.getValueType().isPresent()) { + if (Type.VALUE == propertyType && schema.getValueType().isPresent()) { propertyType = schema.getValueType().get(); } String propertyName = schema.getName(); @@ -250,7 +244,7 @@ protected T deriveValueSchema(FeatureSchema schema) { Optional role = schema .getRole() - .filter(r -> !Role.FILTER_GEOMETRY.equals(r)) + .filter(r -> r != Role.FILTER_GEOMETRY) .map(Enum::name) .map(r -> CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, r)) .or(() -> schema.getRefType().map(ignore -> "reference")) diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaMapping.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaMapping.java index e199fab3f..98c02b76a 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaMapping.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaMapping.java @@ -45,19 +45,24 @@ default List getSchemasForTargetPath(List path) { List transformedSchemas = SchemaMappingBase.super.getSchemasForTargetPath(transformedPath); - for (DynamicTargetSchemaTransformer transformer : getDynamicTransformers()) { - if (transformer.isApplicableDynamic(path)) { - transformedSchemas = transformer.transformSchemaDynamic(transformedSchemas, path); - } - } - - return transformedSchemas; + return applyDynamicTransformers(path, transformedSchemas); } } return SchemaMappingBase.super.getSchemasForTargetPath(path); } + private List applyDynamicTransformers( + List path, List transformedSchemas) { + List result = transformedSchemas; + for (DynamicTargetSchemaTransformer transformer : getDynamicTransformers()) { + if (transformer.isApplicableDynamic(path)) { + result = transformer.transformSchemaDynamic(result, path); + } + } + return result; + } + static SchemaMapping of(FeatureSchema schema) { return new ImmutableSchemaMapping.Builder().targetSchema(schema).build(); } @@ -70,41 +75,47 @@ default List getSchemas( .anyMatch( schema -> !schema.getCoalesce().isEmpty() && schema.getPropertyMap().isEmpty())) { return schemas.stream() - .map( - schema -> { - if (!schema.getCoalesce().isEmpty()) { - for (FeatureSchema coalesce : schema.getCoalesce()) { - if (coalesce.getSourcePath().isPresent()) { - List sourcePath = - coalesce.getConstantValue().isPresent() - ? List.of(coalesce.getSourcePath().get()) - : Splitter.on('/') - .omitEmptyStrings() - .splitToList(coalesce.getSourcePath().get()); - if (Objects.equals( - sourcePath, path.subList(path.size() - sourcePath.size(), path.size()))) { - ImmutableFeatureSchema build = - new ImmutableFeatureSchema.Builder() - .from(schema) - .sourcePath(coalesce.getSourcePath()) - .valueType(coalesce.getValueType().orElse(coalesce.getType())) - .sourcePaths(List.of()) - .coalesce(List.of()) - .build(); - return build; - } - } - } - } - - return schema; - }) + .map(schema -> resolveCoalesceSourcePath(schema, path)) .collect(Collectors.toList()); } return schemas; } + private static FeatureSchema resolveCoalesceSourcePath(FeatureSchema schema, List path) { + if (schema.getCoalesce().isEmpty()) { + return schema; + } + + for (FeatureSchema coalesce : schema.getCoalesce()) { + if (coalesce.getSourcePath().isEmpty()) { + continue; + } + + List sourcePath = + coalesce.getConstantValue().isPresent() + ? List.of(coalesce.getSourcePath().get()) + : Splitter.on('/').omitEmptyStrings().splitToList(coalesce.getSourcePath().get()); + + if (Objects.equals(sourcePath, path.subList(path.size() - sourcePath.size(), path.size()))) { + return resolveCoalesceSourcePath(schema, coalesce); + } + } + + return schema; + } + + private static FeatureSchema resolveCoalesceSourcePath( + FeatureSchema schema, FeatureSchema coalesce) { + return new ImmutableFeatureSchema.Builder() + .from(schema) + .sourcePath(coalesce.getSourcePath()) + .valueType(coalesce.getValueType().orElse(coalesce.getType())) + .sourcePaths(List.of()) + .coalesce(List.of()) + .build(); + } + @Override default List cleanPath(List path) { if (path.stream().anyMatch(elem -> elem.contains("{"))) { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaMappingBase.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaMappingBase.java index b9c42ece6..7bfe9ed80 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaMappingBase.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaMappingBase.java @@ -131,7 +131,7 @@ default Map, List> getSchemasByPath( Entry::getKey, Entry::getValue, (first, second) -> { - ArrayList schemas = new ArrayList<>(first); + List schemas = new ArrayList<>(first); schemas.addAll(second); return schemas; })); @@ -155,7 +155,7 @@ default Map, List> getPositionsByPath( path.isEmpty() ? "" : path.get(path.size() - 1) - .substring(path.get(path.size() - 1).lastIndexOf("=") + 1); + .substring(path.get(path.size() - 1).lastIndexOf('=') + 1); if (!Objects.equals(prio, prevPrio[0])) { i[0]++; } @@ -170,7 +170,7 @@ default Map, List> getPositionsByPath( Entry::getKey, Entry::getValue, (first, second) -> { - ArrayList positions = new ArrayList<>(first); + List positions = new ArrayList<>(first); positions.addAll(second); return positions; })); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaReferenceResolver.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaReferenceResolver.java index 01906c53e..164f03339 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaReferenceResolver.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaReferenceResolver.java @@ -16,13 +16,9 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Stream; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class SchemaReferenceResolver implements TypesResolver { - private static final Logger LOGGER = LoggerFactory.getLogger(SchemaReferenceResolver.class); - private final FeatureProviderDataV2 data; private final Lazy> schemaResolvers; private final SchemaFragmentResolver localFragmentResolver; @@ -109,19 +105,7 @@ public FeatureSchema resolve(FeatureSchema property, List parents } if (hasMergeWithSchema(property)) { - List partials = new ArrayList<>(); - - for (PartialObjectSchema partial : property.getMerge()) { - if (hasSchema(partial)) { - PartialObjectSchema resolvedPartial = resolve(partial.getSchema().get(), partial); - - if (Objects.nonNull(resolvedPartial)) { - partials.add(resolvedPartial); - } - } else { - partials.add(partial); - } - } + List partials = resolveMergePartials(property.getMerge()); return new ImmutableFeatureSchema.Builder().from(property).merge(partials).build(); } @@ -149,6 +133,23 @@ public FeatureSchema resolve(FeatureSchema property, List parents return property; } + private List resolveMergePartials(List partials) { + List resolved = new ArrayList<>(); + + for (PartialObjectSchema partial : partials) { + if (hasSchema(partial)) { + PartialObjectSchema resolvedPartial = resolve(partial.getSchema().get(), partial); + + if (Objects.nonNull(resolvedPartial)) { + resolved.add(resolvedPartial); + } + } else { + resolved.add(partial); + } + } + return resolved; + } + private List resolvePartials(List partials) { List resolved = new ArrayList<>(); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaToPathsVisitor.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaToPathsVisitor.java index b7f7a3548..fa2bf5929 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaToPathsVisitor.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaToPathsVisitor.java @@ -31,7 +31,6 @@ public class SchemaToPathsVisitor> private final BiFunction sourcePathTransformer; private final boolean useTargetPath; private int counter; - private int emptyCounter; SchemaToPathsVisitor(boolean useTargetPath) { this(useTargetPath, IDENTITY); @@ -42,7 +41,6 @@ public class SchemaToPathsVisitor> this.sourcePathTransformer = sourcePathTransformer; this.useTargetPath = useTargetPath; this.counter = 0; - this.emptyCounter = 0; } private static List appendToLast(List list, String suffix) { @@ -56,13 +54,14 @@ private static List appendToLast(List list, String suffix) { } @Override + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"}) public Multimap, T> visit( T schema, List, T>> visitedProperties) { counter++; List> paths = useTargetPath - ? ImmutableList.of(appendToLast(schema.getPath(), "{priority=" + (counter) + "}")) // ) + ? ImmutableList.of(appendToLast(schema.getPath(), "{priority=" + counter + "}")) // ) // TODO: static cleanup method in PathParser : schema.getEffectiveSourcePaths().stream() .map( @@ -84,7 +83,7 @@ public Multimap, T> visit( .replaceAll("\\{sortKey=.*?\\}", "") .replaceAll("\\{primaryKey=.*?\\}", "") + "{priority=" - + (counter) + + counter + "}"); return p.stream() .flatMap( @@ -97,7 +96,7 @@ public Multimap, T> visit( .collect(Collectors.toList()); } - return SPLITTER.splitToList(sourcePath + "{priority=" + (counter) + "}"); + return SPLITTER.splitToList(sourcePath + "{priority=" + counter + "}"); }) .collect(Collectors.toList()); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaVisitor.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaVisitor.java index e504eb2de..fca979d7b 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaVisitor.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaVisitor.java @@ -9,6 +9,7 @@ import java.util.List; +@SuppressWarnings("PMD.ImplicitFunctionalInterface") public interface SchemaVisitor, U> { U visit(T schema, List visitedProperties); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaVisitorTopDown.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaVisitorTopDown.java index 04d882681..964f1e66b 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaVisitorTopDown.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaVisitorTopDown.java @@ -15,6 +15,7 @@ import java.util.Objects; import java.util.function.Function; +@SuppressWarnings("PMD.ImplicitFunctionalInterface") public interface SchemaVisitorTopDown, U> { U visit(T schema, List parents, List visitedProperties); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaVisitorWithFinalizer.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaVisitorWithFinalizer.java index 35b887623..303c43e33 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaVisitorWithFinalizer.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SchemaVisitorWithFinalizer.java @@ -10,5 +10,5 @@ public interface SchemaVisitorWithFinalizer, U, V> extends SchemaVisitorTopDown { - V finalize(T t, U u); + V finalizeVisit(T t, U u); } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SortKey.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SortKey.java index 8fa93a9fa..7999be78b 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SortKey.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SortKey.java @@ -11,6 +11,7 @@ import org.immutables.value.Value.Default; @Value.Immutable +@SuppressWarnings("PMD.ImplicitFunctionalInterface") public interface SortKey { enum Direction { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SourceSchemaValidator.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SourceSchemaValidator.java index ff5e7a19d..a3ed1a9f2 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SourceSchemaValidator.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/SourceSchemaValidator.java @@ -11,6 +11,7 @@ import de.ii.xtraplatform.entities.domain.ValidationResult.MODE; import java.util.List; +@SuppressWarnings("PMD.ImplicitFunctionalInterface") public interface SourceSchemaValidator> { ValidationResult validate(String typeName, List sourceSchemas, MODE mode); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/Tuple.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/Tuple.java index 98db8731a..36a5e96db 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/Tuple.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/Tuple.java @@ -10,7 +10,6 @@ import javax.annotation.Nullable; import org.immutables.value.Value; -// TODO: move to xtraplatform-base @Value.Immutable public interface Tuple { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/TypesResolver.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/TypesResolver.java index bbcb68bcf..ccf250031 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/TypesResolver.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/TypesResolver.java @@ -40,7 +40,7 @@ default boolean needsResolving(Map types) { .anyMatch(property -> needsResolving(property, false, false, false)) || types.values().stream() .flatMap(type -> type.getAllNestedPartials().stream()) - .anyMatch(property -> needsResolving(property)) + .anyMatch(this::needsResolving) || types.values().stream() .flatMap(type -> type.getAllNestedConcatProperties().stream()) .anyMatch(property -> needsResolving(property, false, true, false)) diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/WithConnectionInfo.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/WithConnectionInfo.java index a535fad73..9e3e20d2e 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/WithConnectionInfo.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/WithConnectionInfo.java @@ -7,6 +7,7 @@ */ package de.ii.xtraplatform.features.domain; +@SuppressWarnings("PMD.ImplicitFunctionalInterface") public interface WithConnectionInfo { T getConnectionInfo(); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/legacy/TargetMapping.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/legacy/TargetMapping.java index 2a7486ec0..e717f8973 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/legacy/TargetMapping.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/legacy/TargetMapping.java @@ -25,23 +25,18 @@ public interface TargetMapping> { String BASE_TYPE = "general"; - // TODO @Nullable String getName(); - // TODO @Nullable T getType(); - // TODO @Nullable Boolean getEnabled(); - // TODO @Nullable Integer getSortPriority(); - // TODO @Nullable String getFormat(); @@ -50,30 +45,25 @@ default TargetMapping mergeCopyWithBase(TargetMapping targetMapping) { return this; } - // TODO @JsonIgnore boolean isSpatial(); - // TODO @JsonIgnore @Value.Derived default boolean isEnabled() { return getEnabled() == null || getEnabled(); } - // TODO @JsonIgnore default boolean isReference() { return false; } - // TODO @JsonIgnore default boolean isReferenceEmbed() { return false; } - // TODO @JsonIgnore default TargetMapping getBaseMapping() { return null; diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureEventHandlerSimple.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureEventHandlerSimple.java index e95909709..e5d5aab0d 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureEventHandlerSimple.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureEventHandlerSimple.java @@ -100,6 +100,7 @@ interface ModifiableContext extends Context { // TODO: default values are not cached by Modifiable @Value.Default + @Override default ModifiableCollectionMetadata metadata() { ModifiableCollectionMetadata collectionMetadata = ModifiableCollectionMetadata.create(); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenBufferSimple.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenBufferSimple.java index 64c912337..9ebb93377 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenBufferSimple.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenBufferSimple.java @@ -26,7 +26,7 @@ public class FeatureTokenBufferSimple> public FeatureTokenBufferSimple(FeatureEventHandlerSimple downstream, W context) { this.downstream = downstream; this.buffer = new ArrayList<>(); - this.bufferIn = (FeatureTokenEmitterSimple) (buffer::add); + this.bufferIn = (FeatureTokenEmitterSimple) buffer::add; this.bufferOut = new FeatureTokenReaderSimple<>(downstream, context); this.doBuffer = false; this.mark = -1; diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenDecoderSimple.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenDecoderSimple.java index 06b6bbce5..1fae487e5 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenDecoderSimple.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenDecoderSimple.java @@ -42,15 +42,14 @@ public final boolean canFuse( boolean isTransformerFuseable = TranformerCustomFuseableOut.super.canFuse(transformerCustomFuseableIn); - if (isTransformerFuseable && transformerCustomFuseableIn instanceof FeatureTokenContext) { - if (!ModifiableContext.class.isAssignableFrom( - ((FeatureTokenContext) transformerCustomFuseableIn).getContextInterface())) { - throw new IllegalStateException( - "Cannot fuse FeatureTokenTransformer: " - + ((FeatureTokenContext) transformerCustomFuseableIn).getContextInterface() - + " does not extend " - + this.getContextInterface()); - } + if (isTransformerFuseable + && transformerCustomFuseableIn instanceof FeatureTokenContext featureTokenContext + && !ModifiableContext.class.isAssignableFrom(featureTokenContext.getContextInterface())) { + throw new IllegalStateException( + "Cannot fuse FeatureTokenTransformer: " + + featureTokenContext.getContextInterface() + + " does not extend " + + this.getContextInterface()); } return isTransformerFuseable; diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenEmitterSimple.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenEmitterSimple.java index e76f1390c..dcf8c6606 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenEmitterSimple.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenEmitterSimple.java @@ -14,6 +14,7 @@ import java.util.List; import java.util.OptionalLong; +@FunctionalInterface public interface FeatureTokenEmitterSimple> extends FeatureEventHandlerSimple { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenReaderSimple.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenReaderSimple.java index cd10112b0..07405991c 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenReaderSimple.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenReaderSimple.java @@ -24,9 +24,9 @@ public class FeatureTokenReaderSimple> { private FeatureTokenType currentType; private int contextIndex; - private V context; - private List nestingStack; - private Map, Integer> schemaIndexes; + private final V context; + private final List nestingStack; + private final Map, Integer> schemaIndexes; public FeatureTokenReaderSimple(FeatureEventHandlerSimple eventHandler, V context) { this.eventHandler = eventHandler; @@ -41,9 +41,6 @@ public void onToken(Object token) { emitEvent(); this.context.setSchemaIndex(-1); } - if (token == FeatureTokenType.FLUSH) { - this.currentType = null; - } initEvent((FeatureTokenType) token); } else { readContext(token); @@ -54,6 +51,7 @@ public void onToken(Object token) { } } + @SuppressWarnings("PMD.CyclomaticComplexity") private void initEvent(FeatureTokenType token) { this.currentType = token; this.contextIndex = 0; @@ -108,9 +106,14 @@ private void initEvent(FeatureTokenType token) { break; case GEOMETRY: break; + case INPUT: + case FEATURE_END: + case INPUT_END: + break; } } + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"}) private void readContext(Object context) { switch (currentType) { case INPUT: @@ -149,6 +152,7 @@ private void readContext(Object context) { break; case FEATURE_END: case INPUT_END: + case FLUSH: break; } @@ -161,6 +165,7 @@ private void tryReadPath(Object context) { } } + @SuppressWarnings("PMD.CyclomaticComplexity") private void emitEvent() { switch (currentType) { case INPUT: @@ -193,6 +198,8 @@ private void emitEvent() { case INPUT_END: eventHandler.onEnd(context); break; + case FLUSH: + break; } } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenTransformerBaseSimple.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenTransformerBaseSimple.java index de7c59cf0..36c2f7951 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenTransformerBaseSimple.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/pipeline/FeatureTokenTransformerBaseSimple.java @@ -38,15 +38,15 @@ public final boolean canFuse( boolean isTransformerFuseable = TransformerCustomFuseable.super.canFuse(transformerCustomFuseableIn); - if (isTransformerFuseable && transformerCustomFuseableIn instanceof FeatureTokenContext) { - if (!ModifiableContext.class.isAssignableFrom( - ((FeatureTokenContext) transformerCustomFuseableIn).getContextInterface())) { - throw new IllegalStateException( - "Cannot fuse FeatureTokenTransformer: " - + ((FeatureTokenContext) transformerCustomFuseableIn).getContextInterface() - + " does not extend " - + this.getContextInterface()); - } + if (isTransformerFuseable + && transformerCustomFuseableIn instanceof FeatureTokenContext + && !ModifiableContext.class.isAssignableFrom( + ((FeatureTokenContext) transformerCustomFuseableIn).getContextInterface())) { + throw new IllegalStateException( + "Cannot fuse FeatureTokenTransformer: " + + ((FeatureTokenContext) transformerCustomFuseableIn).getContextInterface() + + " does not extend " + + this.getContextInterface()); } return isTransformerFuseable; diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/profile/ProfileTransformations.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/profile/ProfileTransformations.java index f00723f9d..40863078e 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/profile/ProfileTransformations.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/profile/ProfileTransformations.java @@ -24,6 +24,7 @@ @Value.Immutable @Value.Style(builder = "new") @JsonDeserialize(builder = ImmutableProfileTransformations.Builder.class) +@FunctionalInterface public interface ProfileTransformations extends PropertyTransformations { String REL_AS_KEY = "rel-as-key"; @@ -77,6 +78,8 @@ static void addPredefined( mapToLink(property, builder); } break; + default: + break; } }); } else if (VAL_AS_TITLE.equals(profileId)) { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/DefaultRolesResolver.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/DefaultRolesResolver.java index c8193c2cc..361e5c54b 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/DefaultRolesResolver.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/DefaultRolesResolver.java @@ -50,6 +50,7 @@ public boolean needsResolving( } @Override + @SuppressWarnings("PMD.CognitiveComplexity") public FeatureSchema resolve(FeatureSchema property, List parents) { boolean isEmbedded = property.isEmbeddedFeature(); Optional primaryGeometry = diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureEncoderSfFlat.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureEncoderSfFlat.java index 96d5fb07e..a2633f345 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureEncoderSfFlat.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureEncoderSfFlat.java @@ -19,9 +19,10 @@ public abstract class FeatureEncoderSfFlat protected final long transformerStart; protected long processingStart; protected Long featureDuration = 0L; - protected long written = 0; + protected long written; protected FeatureEncoderSfFlat(EncodingContextSfFlat encodingContext) { + super(); this.properties = encodingContext.getFields().values().stream().findFirst().orElse(ImmutableList.of("*")); this.allProperties = properties.contains("*"); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureEventBuffer.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureEventBuffer.java index 3bbd877d7..f2177f108 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureEventBuffer.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureEventBuffer.java @@ -26,7 +26,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Objects; -import java.util.Vector; import java.util.stream.Collectors; /** @@ -51,6 +50,7 @@ * are contiguous and a transformer's slice cannot swallow an unrelated property emitted between * them - and at the latest at flush when no transformer ran. */ +@SuppressWarnings({"PMD.GodClass", "PMD.CyclomaticComplexity", "PMD.TooManyMethods"}) public class FeatureEventBuffer< U extends SchemaBase, V extends SchemaMappingBase, W extends ModifiableContext> implements FeatureTokenEmitter2 { @@ -61,7 +61,7 @@ public class FeatureEventBuffer< private final FeatureTokenReader bufferOut; private final int[] events; - private final Vector> enclosings; + private final List> enclosings; private final Map mappings; private boolean doBuffer; private boolean indexStale; @@ -72,9 +72,8 @@ public FeatureEventBuffer( FeatureEventHandler downstream, W context, Map mappings) { this.downstream = downstream; this.buffer = new ArrayList<>(); - this.bufferIn = (FeatureTokenEmitter2) (this::append); + this.bufferIn = this::append; this.bufferOut = new FeatureTokenReader<>(downstream, context); - this.enclosings = new Vector<>(); this.mappings = mappings; this.doBuffer = false; @@ -89,7 +88,7 @@ public FeatureEventBuffer( * 2 + 2; this.events = new int[maxEvents]; - enclosings.setSize(maxEvents); + this.enclosings = new ArrayList<>(Collections.nCopies(maxEvents, List.of())); } public FeatureTokenEmitter2 getBuffer() { @@ -194,6 +193,7 @@ private void ensureOrdered() { * which is exactly the slice {@link #getSlice(int)} hands to a transformer. Runs only when a * slice is actually accessed, so features without slice transformers never pay for it. */ + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"}) private void computeIndex() { Arrays.fill(events, 0); indexStale = false; @@ -341,6 +341,11 @@ private List orderedBySchema(List tokens) { return ordered; } + @SuppressWarnings({ + "PMD.AvoidInstantiatingObjectsInLoops", + "PMD.CognitiveComplexity", + "PMD.CyclomaticComplexity" + }) private static void buildTree(List tokens, Node root) { Deque stack = new ArrayDeque<>(); stack.push(root); @@ -628,6 +633,7 @@ public void onValue(W context) { } } + @Override public String toString() { return sliceToString(buffer); } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTokenSliceTransformer.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTokenSliceTransformer.java index 4f6add080..89a776d24 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTokenSliceTransformer.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTokenSliceTransformer.java @@ -23,9 +23,14 @@ import java.util.function.Function; import javax.annotation.Nullable; +@SuppressWarnings("PMD.TooManyMethods") public interface FeaturePropertyTokenSliceTransformer extends FeaturePropertyTransformer> { + Joiner PATH_JOINER = Joiner.on('.'); + + Splitter PATH_SPLITTER = Splitter.on('.'); + FeatureSchema transformSchema(FeatureSchema schema); void transformObject( @@ -85,6 +90,7 @@ default List transformObjects(String currentPropertyPath, List s return transformed; } + @SuppressWarnings("PMD.CyclomaticComplexity") default List transformValueArray(List path, List slice) { if (slice.isEmpty()) { return slice; @@ -104,9 +110,7 @@ default List transformValueArray(List path, List slice) transformed.addAll(before); - if (!inArray) { - transformValue(slice, min, max + 1, transformed); - } else { + if (inArray) { int start = findPos(slice, FeatureTokenType.ARRAY, path, min); int end = findPos(slice, FeatureTokenType.ARRAY_END, path, start); @@ -128,6 +132,8 @@ default List transformValueArray(List path, List slice) end = findPos(slice, FeatureTokenType.ARRAY_END, path, start); } + } else { + transformValue(slice, min, max + 1, transformed); } transformed.addAll(after); @@ -135,6 +141,7 @@ default List transformValueArray(List path, List slice) return transformed; } + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"}) default List transformValues(List path, boolean isArray, List slice) { if (slice.isEmpty()) { return slice; @@ -154,9 +161,7 @@ default List transformValues(List path, boolean isArray, List transformValues(List path, boolean isArray, List transformValues(List path, boolean isArray, List path) { return PATH_JOINER.join(path); } @@ -297,6 +300,7 @@ default int findFirst(List slice, List path, int offset) { return -1; } + @SuppressWarnings("PMD.CyclomaticComplexity") default int findLast(List slice, List path, int offset) { if (offset == -1) { return -1; @@ -415,10 +419,10 @@ default Map getValueIndexes(List slice, int from, int t Map valueIndexes = new LinkedHashMap<>(); for (int i = from; i < to; i++) { - if (slice.get(i) == FeatureTokenType.VALUE) { - if (i + 2 < to && slice.get(i + 1) instanceof List) { - valueIndexes.put(joinPath((List) slice.get(i + 1)), i + 2); - } + if (slice.get(i) == FeatureTokenType.VALUE + && i + 2 < to + && slice.get(i + 1) instanceof List) { + valueIndexes.put(joinPath((List) slice.get(i + 1)), i + 2); } } @@ -430,12 +434,11 @@ default Map getValueIndexesByProp( Map valueIndexes = new LinkedHashMap<>(); for (int i = from; i < to; i++) { - if (slice.get(i) == FeatureTokenType.VALUE) { - if (i + 2 < to - && slice.get(i + 1) instanceof List - && ((List) slice.get(i + 1)).size() > depth) { - valueIndexes.put(((List) slice.get(i + 1)).get(depth), i + 2); - } + if (slice.get(i) == FeatureTokenType.VALUE + && i + 2 < to + && slice.get(i + 1) instanceof List + && ((List) slice.get(i + 1)).size() > depth) { + valueIndexes.put(((List) slice.get(i + 1)).get(depth), i + 2); } } @@ -447,10 +450,11 @@ default Map getValueIndexesList(List slice, int from, i int j = 0; for (int i = from; i < to; i++) { - if (slice.get(i) == FeatureTokenType.VALUE) { - if (i + 2 < to && slice.get(i + 1) instanceof List) { - valueIndexes.put(Integer.toString(j++), i + 2); - } + if (slice.get(i) == FeatureTokenType.VALUE + && i + 2 < to + && slice.get(i + 1) instanceof List) { + valueIndexes.put(Integer.toString(j), i + 2); + j++; } } @@ -544,12 +548,11 @@ static String getValue(List slice, int valueIndex) { static int getValueIndex(List slice, String path, int from, int to) { for (int i = from; i < to; i++) { - if (slice.get(i) == FeatureTokenType.VALUE) { - if (i + 2 < to && slice.get(i + 1) instanceof List) { - if (Objects.equals(path, joinPath((List) slice.get(i + 1)))) { - return i + 2; - } - } + if (slice.get(i) == FeatureTokenType.VALUE + && i + 2 < to + && slice.get(i + 1) instanceof List + && Objects.equals(path, joinPath((List) slice.get(i + 1)))) { + return i + 2; } } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerCoalesce.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerCoalesce.java index 4a3f7dcf3..932e7e175 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerCoalesce.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerCoalesce.java @@ -70,12 +70,12 @@ public List transform(String currentPropertyPath, List slice) { return transformed; } + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"}) private List coalesceValues(List slice) { List transformed = new ArrayList<>(); boolean skip = false; boolean found = false; int valueIndex = -1; - String value = null; for (int i = 0; i < slice.size(); i++) { if (isValueWithPath(slice, i, schema.getFullPath())) { @@ -85,7 +85,7 @@ private List coalesceValues(List slice) { skip = true; valueIndex++; - value = (String) slice.get(i + 2); + String value = (String) slice.get(i + 2); for (FeaturePropertyValueTransformer transformer : valueTransformers().get(valueIndex)) { value = transformer.transform(getPropertyPath(), value); } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerCodelist.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerCodelist.java index 375827569..8eccf7cc4 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerCodelist.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerCodelist.java @@ -40,11 +40,13 @@ default String getType() { @Override default String transform(String currentPropertyPath, String input) { if (!getCodelists().containsKey(getParameter())) { - LOGGER.warn( - "Skipping {} transformation for property '{}', codelist '{}' not found.", - getType(), - getPropertyPath(), - getParameter()); + if (LOGGER.isWarnEnabled()) { + LOGGER.warn( + "Skipping {} transformation for property '{}', codelist '{}' not found.", + getType(), + getPropertyPath(), + getParameter()); + } return input; } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerConcat.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerConcat.java index 34e1f9844..d4c62f0d5 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerConcat.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerConcat.java @@ -60,7 +60,7 @@ public List transform(String currentPropertyPath, List slice) { return slice; } - boolean isArray = slice.get(min) == FeatureTokenType.ARRAY; + boolean isArray = slice.get(min) == ARRAY; List transformed = new ArrayList<>(); if (!isArray) { @@ -85,11 +85,8 @@ private List concatObjects(List slice) { for (int i = 0; i < slice.size(); i++) { if (isTypeWithPath(slice, i, ARRAY, schema.getFullPath())) { - if (!isArrayOpen) { - isArrayOpen = true; - } else { - skip = true; - } + skip = isArrayOpen; + isArrayOpen = true; } else if (isTypeWithPath(slice, i, ARRAY_END, schema.getFullPath())) { if (i < slice.size() - 2) { skip = true; diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerDateFormat.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerDateFormat.java index cbd773a4b..5c83870ef 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerDateFormat.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerDateFormat.java @@ -9,6 +9,7 @@ import com.google.common.collect.ImmutableList; import de.ii.xtraplatform.features.domain.SchemaBase; +import java.time.DateTimeException; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.OffsetDateTime; @@ -60,13 +61,15 @@ default String transform(String currentPropertyPath, String input) { ZonedDateTime zdt = parse(input, getDefaultTimeZone()); return formatter().format(zdt); - } catch (Throwable e) { - LOGGER.warn( - "{} transformation for property '{}' with value '{}' failed: {}", - getType(), - getPropertyPath(), - input, - e.getMessage()); + } catch (DateTimeException e) { + if (LOGGER.isWarnEnabled()) { + LOGGER.warn( + "{} transformation for property '{}' with value '{}' failed: {}", + getType(), + getPropertyPath(), + input, + e.getMessage()); + } } return input; diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerFlatten.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerFlatten.java index 99ed65bfe..e4cf71acc 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerFlatten.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerFlatten.java @@ -48,6 +48,7 @@ public FeatureSchemaFlattener getFlattener() { } @Override + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public List transform(String currentPropertyPath, List slice) { List transformed = new ArrayList<>(); boolean isValue = false; @@ -58,7 +59,7 @@ public List transform(String currentPropertyPath, List slice) { boolean inArray = false; boolean isObject = false; Map, Integer> arrays = new HashMap<>(); - List arrayPath = null; + List arrayPath = List.of(); List currentPath = null; for (Object token : slice) { @@ -79,7 +80,6 @@ public List transform(String currentPropertyPath, List slice) { arrays.put(arrayPath, 0); inArray = true; } else if (isArrayEnd) { - arrayPath = null; inArray = false; } @@ -88,14 +88,7 @@ public List transform(String currentPropertyPath, List slice) { } if (isValue && inArray) { - List newPath = new ArrayList<>(arrayPath); - newPath.set( - newPath.size() - 1, - newPath.get(newPath.size() - 1) + "[" + arrays.get(arrayPath) + "]"); - if (currentPath.size() > arrayPath.size()) { - newPath.add(currentPath.get(currentPath.size() - 1)); - } - currentPath = newPath; + currentPath = toIndexedPath(currentPath, arrayPath, arrays.get(arrayPath)); } } @@ -113,6 +106,16 @@ public List transform(String currentPropertyPath, List slice) { return transformed; } + private static List toIndexedPath( + List currentPath, List arrayPath, Integer index) { + List newPath = new ArrayList<>(arrayPath); + newPath.set(newPath.size() - 1, newPath.get(newPath.size() - 1) + "[" + index + "]"); + if (currentPath.size() > arrayPath.size()) { + newPath.add(currentPath.get(currentPath.size() - 1)); + } + return newPath; + } + @Override public FeatureSchema transformSchema(FeatureSchema schema) { if (!schema.isFeature()) { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerNullValue.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerNullValue.java index 4d909dcc0..cb642f4f5 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerNullValue.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerNullValue.java @@ -29,7 +29,9 @@ default List getSupportedPropertyTypes() { @Override default String transform(String currentPropertyPath, String input) { - if (input.matches(getParameter())) return null; + if (input.matches(getParameter())) { + return null; + } return input; } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerObjectAddConstants.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerObjectAddConstants.java index 53615d435..acfbe8e68 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerObjectAddConstants.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerObjectAddConstants.java @@ -44,6 +44,7 @@ default FeatureSchema transformSchema(FeatureSchema schema) { return builder.build(); } + @Override default void transformObject( String currentPropertyPath, List slice, diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerObjectMapDuplicate.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerObjectMapDuplicate.java index 7f38e638a..15eaab33e 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerObjectMapDuplicate.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerObjectMapDuplicate.java @@ -66,6 +66,7 @@ default FeatureSchema transformSchema(FeatureSchema schema) { return builder.build(); } + @Override default void transformObject( String currentPropertyPath, List slice, diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerObjectMapFormat.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerObjectMapFormat.java index 10ff3afd3..7739215b8 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerObjectMapFormat.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerObjectMapFormat.java @@ -50,6 +50,7 @@ default FeatureSchema transformSchema(FeatureSchema schema) { return builder.build(); } + @Override default void transformObject( String currentPropertyPath, List slice, diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerObjectReduceSelect.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerObjectReduceSelect.java index d52e00325..709dad0e3 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerObjectReduceSelect.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerObjectReduceSelect.java @@ -8,7 +8,6 @@ package de.ii.xtraplatform.features.domain.transform; import de.ii.xtraplatform.features.domain.FeatureSchema; -import de.ii.xtraplatform.features.domain.ImmutableFeatureSchema; import de.ii.xtraplatform.features.domain.ImmutableFeatureSchema.Builder; import de.ii.xtraplatform.features.domain.SchemaBase.Type; import de.ii.xtraplatform.features.domain.Tuple; @@ -41,17 +40,15 @@ default FeatureSchema transformSchema(FeatureSchema schema) { schema.getSourcePath().map(s -> s + "/").orElse("") + selected.get().getSourcePath().orElse(""); - ImmutableFeatureSchema build = - new Builder() - .from(selected.get()) - .type(schema.isArray() ? Type.VALUE_ARRAY : Type.VALUE) - .valueType(selected.get().getValueType().orElse(selected.get().getType())) - .name(schema.getName()) - .sourcePath(mergedSourcePath) - .path(schema.getPath()) - .parentPath(schema.getParentPath()) - .build(); - return build; + return new Builder() + .from(selected.get()) + .type(schema.isArray() ? Type.VALUE_ARRAY : Type.VALUE) + .valueType(selected.get().getValueType().orElse(selected.get().getType())) + .name(schema.getName()) + .sourcePath(mergedSourcePath) + .path(schema.getPath()) + .parentPath(schema.getParentPath()) + .build(); } @Override diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerRemove.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerRemove.java index 38599b271..710bc245d 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerRemove.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerRemove.java @@ -9,6 +9,7 @@ import de.ii.xtraplatform.features.domain.FeatureSchema; import java.util.Arrays; +import java.util.Locale; import java.util.Set; import java.util.stream.Collectors; import org.immutables.value.Value; @@ -40,23 +41,26 @@ default String getType() { @Override default FeatureSchema transform(String currentPropertyPath, FeatureSchema schema) { - Condition condition = Condition.NEVER; - String parameter = getParameter().toUpperCase(); + String parameter = getParameter().toUpperCase(Locale.ROOT); + Condition condition; try { condition = Condition.valueOf(parameter); - } catch (Throwable e) { - LOGGER.warn( - "Skipping {} transformation for property '{}', condition '{}' is not supported. Supported types: {}", - getType(), - getPropertyPath(), - getParameter(), - Condition.values()); + } catch (IllegalArgumentException e) { + if (LOGGER.isWarnEnabled()) { + LOGGER.warn( + "Skipping {} transformation for property '{}', condition '{}' is not supported. Supported types: {}", + getType(), + getPropertyPath(), + getParameter(), + Condition.values()); + } return schema; } if (condition == Condition.ALWAYS - || (condition == Condition.IN_COLLECTION && inCollection()) + || condition == Condition.IN_COLLECTION + && inCollection() && currentPropertyPath.startsWith(getPropertyPath())) { return null; } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerRename.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerRename.java index d7a2f174b..33c4ba980 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerRename.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerRename.java @@ -72,7 +72,7 @@ default Map adjustProperties( } static List merge(List path, String name) { - ArrayList merged = new ArrayList<>(path); + List merged = new ArrayList<>(path); merged.add(name); return merged; } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerWrap.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerWrap.java index 3260a758b..14e45e141 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerWrap.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyTransformerWrap.java @@ -99,6 +99,7 @@ private List wrapWithValueArray(List slice) { return transformed; } + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"}) private List wrapWithObjectArray(List slice) { List transformed = new ArrayList<>(); boolean foundFirstObject = false; @@ -166,22 +167,24 @@ private List wrapWithObject(List slice) { return transformed; } + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"}) private List wrapSingleValuesWithObject(List slice, boolean wrapEachValue) { List transformed = new ArrayList<>(); boolean lastWasChildOfPath = false; for (int i = 0; i < slice.size(); i++) { if (isChildOfPath(slice, i, schema.getFullPath())) { - if (!lastWasChildOfPath) { - transformed.add(FeatureTokenType.OBJECT); - transformed.add(schema.getFullPath()); - lastWasChildOfPath = true; - } else if (wrapEachValue) { + if (lastWasChildOfPath && wrapEachValue) { transformed.add(FeatureTokenType.OBJECT_END); transformed.add(schema.getFullPath()); transformed.add(FeatureTokenType.OBJECT); transformed.add(schema.getFullPath()); } + if (!lastWasChildOfPath) { + transformed.add(FeatureTokenType.OBJECT); + transformed.add(schema.getFullPath()); + lastWasChildOfPath = true; + } } else if (slice.get(i) instanceof FeatureTokenType && lastWasChildOfPath) { transformed.add(FeatureTokenType.OBJECT_END); transformed.add(schema.getFullPath()); @@ -198,6 +201,7 @@ private List wrapSingleValuesWithObject(List slice, boolean wrap return transformed; } + @Override public void transformObject( String currentPropertyPath, List slice, diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyValueTransformer.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyValueTransformer.java index c24ca4d61..e7d6ea0d8 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyValueTransformer.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeaturePropertyValueTransformer.java @@ -25,7 +25,7 @@ default boolean matches(FeatureSchema schema) { boolean isTypeMatching = getSupportedPropertyTypes().isEmpty() || getSupportedPropertyTypes().contains(valueType); - if (!isTypeMatching) { + if (!isTypeMatching && LOGGER.isWarnEnabled()) { LOGGER.warn( "Skipping {} transformation for property '{}', type {} is not supported. Supported types: {}", getType(), diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureRefEmbedder.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureRefEmbedder.java index 6bb68ec92..ef5052425 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureRefEmbedder.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureRefEmbedder.java @@ -91,8 +91,8 @@ public class FeatureRefEmbedder implements TypesResolver { public FeatureRefEmbedder(String providerId) { this.providerId = providerId; this.withoutRoles = new WithoutRoles(); - this.allTypes = null; - this.typesByRound = null; + this.allTypes = Map.of(); + this.typesByRound = List.of(); this.currentRound = -1; } @@ -103,16 +103,12 @@ public int maxRounds() { @Override public boolean needsResolving(Map types) { - if (Objects.isNull(allTypes)) { + if (allTypes.isEmpty()) { this.allTypes = new LinkedHashMap<>(types); this.typesByRound = getTypesByRound(types, providerId); } - if (typesByRound.isEmpty()) { - return false; - } - - return TypesResolver.super.needsResolving(types); + return !typesByRound.isEmpty() && TypesResolver.super.needsResolving(types); } @Override @@ -180,6 +176,7 @@ public FeatureSchema resolve(FeatureSchema property, List parents return getBuilder(property, allTypes).map(b -> b.build().accept(withoutRoles)).orElse(null); } + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) private static Optional getBuilder( FeatureSchema schema, Map types) { String ref = @@ -242,7 +239,7 @@ private static Optional getBuilder( return Optional.of(builder); } - @SuppressWarnings("UnstableApiUsage") + @SuppressWarnings({"UnstableApiUsage", "PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"}) private static List> getTypesByRound( Map types, String providerId) { // determine graph of feature refs @@ -265,13 +262,12 @@ private static List> getTypesByRound( Map map2 = Map.copyOf(map); types.forEach( (key, value) -> { - if (!map.containsKey(key)) { - if (!graph2.nodes().contains(key) - || graph2.successors(key).stream() - .filter(n -> !n.equals(key)) - .allMatch(map2::containsKey)) { - map.put(key, currentPrio); - } + if (!map.containsKey(key) + && (!graph2.nodes().contains(key) + || graph2.successors(key).stream() + .filter(n -> !n.equals(key)) + .allMatch(map2::containsKey))) { + map.put(key, currentPrio); } }); prio++; @@ -319,40 +315,48 @@ private static Graph getEmbeds(Map types) { (FeatureSchema featureSchema) -> featureSchema.getAllNestedProperties().stream())) .filter(SchemaBase::isEmbed) - .forEach( - p -> { - if (!p.getConcat().isEmpty()) { - p.getConcat().stream() - .map(FeatureSchema::getRefType) - .filter(Optional::isPresent) - .map(Optional::get) - .filter(ref -> !ref.equals(key)) - .forEach(ref -> builder.putEdge(key, ref)); - } else if (!p.getCoalesce().isEmpty()) { - p.getCoalesce().stream() - .map(FeatureSchema::getRefType) - .filter(Optional::isPresent) - .map(Optional::get) - .filter(ref -> !ref.equals(key)) - .forEach(ref -> builder.putEdge(key, ref)); - } else { - p.getRefType() - .filter( - ref -> { - if (ref.equals(key)) { - if (LOGGER.isWarnEnabled()) { - LOGGER.warn( - "Feature type with id '{}' has a feature reference that embeds itself at '{}'. The feature reference will not be embedded.", - key, - p.getFullPathAsString()); - } - return false; - } - return true; - }) - .ifPresent(ref -> builder.putEdge(key, ref)); - } - })); + .forEach(p -> addEmbeddingEdges(builder, key, p))); return builder.build(); } + + private static void addEmbeddingEdges( + ImmutableGraph.Builder builder, String key, FeatureSchema property) { + if (property.getConcat().isEmpty()) { + if (property.getCoalesce().isEmpty()) { + property + .getRefType() + .filter(ref -> shouldEmbedRef(key, property, ref)) + .ifPresent(ref -> builder.putEdge(key, ref)); + return; + } + + property.getCoalesce().stream() + .map(FeatureSchema::getRefType) + .filter(Optional::isPresent) + .map(Optional::get) + .filter(ref -> !ref.equals(key)) + .forEach(ref -> builder.putEdge(key, ref)); + return; + } + + property.getConcat().stream() + .map(FeatureSchema::getRefType) + .filter(Optional::isPresent) + .map(Optional::get) + .filter(ref -> !ref.equals(key)) + .forEach(ref -> builder.putEdge(key, ref)); + } + + private static boolean shouldEmbedRef(String key, FeatureSchema property, String ref) { + if (!ref.equals(key)) { + return true; + } + if (LOGGER.isWarnEnabled()) { + LOGGER.warn( + "Feature type with id '{}' has a feature reference that embeds itself at '{}'. The feature reference will not be embedded.", + key, + property.getFullPathAsString()); + } + return false; + } } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureRefResolver.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureRefResolver.java index 7beadc70e..c853bb25c 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureRefResolver.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureRefResolver.java @@ -327,7 +327,7 @@ private boolean isConnected(Optional sourcePath) { Optional idProperty = property.getProperties().stream() .filter(Objects::nonNull) - .filter(p -> Objects.equals(p.getName(), FeatureRefResolver.ID)) + .filter(p -> Objects.equals(p.getName(), ID)) .findFirst(); if (idProperty.isPresent()) { return Stream.of( @@ -368,6 +368,7 @@ public List resolveAll( .collect(Collectors.toList()); } + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public FeatureSchema resolve( FeatureSchema schema, List properties, @@ -424,18 +425,8 @@ public FeatureSchema resolve( .sourcePath(sourcePath) .excludedScopes(excludedScopes)); - if (schema.getRefUriTemplate().isPresent()) { - builder.addTransformations( - new ImmutablePropertyTransformation.Builder() - .objectAddConstants(Map.of(URI_TEMPLATE, schema.getRefUriTemplate().get())) - .build()); - } - if (schema.getRefKeyTemplate().isPresent()) { - builder.addTransformations( - new ImmutablePropertyTransformation.Builder() - .objectAddConstants(Map.of(KEY_TEMPLATE, schema.getRefKeyTemplate().get())) - .build()); - } + addConstantTransformation(builder, URI_TEMPLATE, schema.getRefUriTemplate()); + addConstantTransformation(builder, KEY_TEMPLATE, schema.getRefKeyTemplate()); } else { builder .putProperties2( @@ -523,42 +514,20 @@ public FeatureSchema resolve( .build()); } } - if (schema.getRefUriTemplate().isPresent()) { - if (isConnected(schema.getSourcePath())) { - newTransformations.add( - new ImmutablePropertyTransformation.Builder() - .objectAddConstants(Map.of(URI_TEMPLATE, schema.getRefUriTemplate().get())) - .build()); - } else { - newVisitedProperties.add( - new Builder() - .name(URI_TEMPLATE) - .type(Type.STRING) - .path(List.of(URI_TEMPLATE)) - .parentPath(schema.getPath()) - .constantValue(schema.getRefUriTemplate()) - .excludedScopes(excludedScopes) - .build()); - } - } - if (schema.getRefKeyTemplate().isPresent()) { - if (isConnected(schema.getSourcePath())) { - newTransformations.add( - new ImmutablePropertyTransformation.Builder() - .objectAddConstants(Map.of(KEY_TEMPLATE, schema.getRefKeyTemplate().get())) - .build()); - } else { - newVisitedProperties.add( - new Builder() - .name(KEY_TEMPLATE) - .type(Type.STRING) - .path(List.of(KEY_TEMPLATE)) - .parentPath(schema.getPath()) - .constantValue(schema.getRefKeyTemplate()) - .excludedScopes(excludedScopes) - .build()); - } - } + addTemplatePropertyOrTransformation( + schema, + excludedScopes, + URI_TEMPLATE, + schema.getRefUriTemplate(), + newTransformations, + newVisitedProperties); + addTemplatePropertyOrTransformation( + schema, + excludedScopes, + KEY_TEMPLATE, + schema.getRefKeyTemplate(), + newTransformations, + newVisitedProperties); return new ImmutableFeatureSchema.Builder() .from(schema) @@ -573,4 +542,44 @@ public FeatureSchema resolve( private static boolean isStatic(Optional refType) { return refType.filter(refType2 -> !Objects.equals(refType2, REF_TYPE_DYNAMIC)).isPresent(); } + + private static void addConstantTransformation( + Builder builder, String key, Optional value) { + value.ifPresent( + template -> + builder.addTransformations( + new ImmutablePropertyTransformation.Builder() + .objectAddConstants(Map.of(key, template)) + .build())); + } + + private void addTemplatePropertyOrTransformation( + FeatureSchema schema, + List excludedScopes, + String key, + Optional value, + List transformations, + List visitedProperties) { + if (value.isEmpty()) { + return; + } + + if (isConnected(schema.getSourcePath())) { + transformations.add( + new ImmutablePropertyTransformation.Builder() + .objectAddConstants(Map.of(key, value.get())) + .build()); + return; + } + + visitedProperties.add( + new Builder() + .name(key) + .type(Type.STRING) + .path(List.of(key)) + .parentPath(schema.getPath()) + .constantValue(value) + .excludedScopes(excludedScopes) + .build()); + } } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureSchemaFlattener.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureSchemaFlattener.java index 949c02349..0b435da51 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureSchemaFlattener.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureSchemaFlattener.java @@ -81,7 +81,7 @@ private FeatureSchema flattenProperty( .valueType(Optional.empty()) .name(flatName(property, namePrefix)) .label(flatLabel(property, labelPrefix)) - .path(flatPath(property, namePrefix)) + .path(flatPath(property)) .concat(List.of()) .coalesce(List.of()) .build(); @@ -91,7 +91,7 @@ private String flatName(FeatureSchema property, String prefix) { return prefix + property.getName() + (property.isArray() ? arraySuffix : ""); } - private List flatPath(FeatureSchema property, String prefix) { + private List flatPath(FeatureSchema property) { return property.getFullPath(); } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureSfFlat.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureSfFlat.java index 002451018..ee198ae70 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureSfFlat.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/FeatureSfFlat.java @@ -50,55 +50,56 @@ default SortedMap getPropertiesAsMap() { // Since properties must be "flat" (no arrays or objects), we map any arrays or objects to // a string using a JSON representation of arrays and objects. + @SuppressWarnings("PMD.CyclomaticComplexity") private Object getValue(PropertySfFlat property, boolean withQuotes) { switch (property.getType()) { case VALUE: - switch (property.getSchema().map(FeatureSchema::getType).orElse(Type.UNKNOWN)) { - case BOOLEAN: - return "t".equalsIgnoreCase(property.getValue()) - || "true".equalsIgnoreCase(property.getValue()) - || "1".equals(property.getValue()); + return switch (property.getSchema().map(FeatureSchema::getType).orElse(Type.UNKNOWN)) { + case BOOLEAN -> + "t".equalsIgnoreCase(property.getValue()) + || "true".equalsIgnoreCase(property.getValue()) + || "1".equals(property.getValue()); - case INTEGER: + case INTEGER -> { try { - return Long.parseLong(Objects.requireNonNull(property.getValue())); - } catch (Throwable e) { + yield Long.parseLong(property.getValue()); + } catch (NumberFormatException e) { // ignore - return null; + yield null; } + } - case FLOAT: + case FLOAT -> { try { - return Double.parseDouble(Objects.requireNonNull(property.getValue())); - } catch (Throwable e) { + yield Double.parseDouble(property.getValue()); + } catch (NumberFormatException e) { // ignore - return null; + yield null; } + } - case DATE: - case DATETIME: - case STRING: - case FEATURE_REF: - case UNKNOWN: - return withQuotes ? "'" + property.getValue() + "'" : property.getValue(); + case DATE, DATETIME, STRING, FEATURE_REF, UNKNOWN -> + withQuotes ? "'" + property.getValue() + "'" : property.getValue(); - case GEOMETRY: - // geometries are handled separately, ignore them in this map - default: - return null; - } + case GEOMETRY -> + // geometries are handled separately, ignore them in this map + null; + + default -> null; + }; case OBJECT: - return Type.GEOMETRY.equals( - property.getSchema().map(FeatureSchema::getType).orElse(Type.UNKNOWN)) + return property.getSchema().map(FeatureSchema::getType).orElse(Type.UNKNOWN) + == Type.GEOMETRY ? null : getObjectAsString(property); case ARRAY: return getArrayAsString(property); - } - return null; + default: + return null; + } } private String getObjectAsString(PropertySfFlat property) { @@ -107,12 +108,16 @@ private String getObjectAsString(PropertySfFlat property) { .map( p -> { Object val = getValue(p, true); - if (Objects.isNull(val)) return null; + if (Objects.isNull(val)) { + return null; + } return String.format("'%s': %s", p.getName(), val); }) .filter(Objects::nonNull) .collect(Collectors.joining(", ")); - if (value.isBlank()) return null; + if (value.isBlank()) { + return null; + } return String.format("{ %s }", value); } @@ -122,12 +127,16 @@ private String getArrayAsString(PropertySfFlat property) { .map( p -> { Object val = getValue(p, true); - if (Objects.isNull(val)) return null; + if (Objects.isNull(val)) { + return null; + } return val.toString(); }) .filter(Objects::nonNull) .collect(Collectors.joining(", ")); - if (value.isBlank()) return null; + if (value.isBlank()) { + return null; + } return String.format("[ %s ]", value); } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/ImplicitMappingResolver.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/ImplicitMappingResolver.java index 0f8309aca..04cfb9636 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/ImplicitMappingResolver.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/ImplicitMappingResolver.java @@ -24,7 +24,7 @@ public boolean needsResolving( boolean isFeatureRefInConcat = property.isFeatureRef() && isInConcat; - return ((property.isObject() || property.isArray()) && (property.getSourcePath().isEmpty())) + return ((property.isObject() || property.isArray()) && property.getSourcePath().isEmpty()) || (property.isObject() && property.getSourcePath().isPresent() && property.getValueNames().isEmpty()) diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/OnlyQueryables.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/OnlyQueryables.java index 512625e4c..a17f5ab71 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/OnlyQueryables.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/OnlyQueryables.java @@ -67,6 +67,7 @@ public FeatureSchema visit( class OnlyQueryablesIncluder implements SchemaVisitorTopDown { @Override + @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CyclomaticComplexity"}) public FeatureSchema visit( FeatureSchema schema, List parents, List visitedProperties) { @@ -86,15 +87,8 @@ public FeatureSchema visit( // TODO: In the next major release move to FeatureSchema.queryable() and exclude // incompatible properties. - if (!isCompatible(schema)) { - if (wildcard) { - return null; - } - if (LOGGER.isWarnEnabled()) { - LOGGER.warn( - "Property '{}' has a value transformation or is a constant value. The property should not be used as a queryable as filtering on the values may not work as expected.", - schema.getFullPathAsString(pathSeparator)); - } + if (!isCompatible(schema) && shouldSkipIncompatibleQueryable(schema)) { + return null; } } else if (!schema.isObject() || (!parents.isEmpty() && visitedProperties.stream().noneMatch(Objects::nonNull))) { @@ -158,13 +152,6 @@ private FeatureSchema cleanupPathsIfDesired(FeatureSchema property) { return property; } - private String getKey(FeatureSchema property) { - return cleanupKeys - // TODO: separator - ? property.getFullPathAsString(pathSeparator).replaceAll("(^|\\.)([0-9]+)_", "$1") - : property.getFullPathAsString(pathSeparator); - } - private FeatureSchema adjustType(List parents, FeatureSchema property) { if (!property.queryable()) { // not a queryable, we have an object that has embedded queryables @@ -194,11 +181,27 @@ private boolean isParentExcluded(FeatureSchema parent) { return (parent.isMultiSource() && !parent.isFeature()) || excludePathMatcher.test(parent.getSourcePath().orElse("")); } + + private void logIncompatibleQueryable(FeatureSchema schema) { + if (LOGGER.isWarnEnabled()) { + LOGGER.warn( + "Property '{}' has a value transformation or is a constant value. The property should not be used as a queryable as filtering on the values may not work as expected.", + schema.getFullPathAsString(pathSeparator)); + } + } + + private boolean shouldSkipIncompatibleQueryable(FeatureSchema schema) { + if (!wildcard) { + logIncompatibleQueryable(schema); + return false; + } + return true; + } } static FeatureSchema cleanupPaths(FeatureSchema property) { - if ((property.getPath().stream().anyMatch(elem -> elem.matches("^([0-9]+)_.*")) - || property.getParentPath().stream().anyMatch(elem -> elem.matches("^([0-9]+)_.*")))) { + if (property.getPath().stream().anyMatch(elem -> elem.matches("^([0-9]+)_.*")) + || property.getParentPath().stream().anyMatch(elem -> elem.matches("^([0-9]+)_.*"))) { return new ImmutableFeatureSchema.Builder() .from(property) .path( diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/OnlySortables.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/OnlySortables.java index a2d195f1b..67d12f10e 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/OnlySortables.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/OnlySortables.java @@ -60,6 +60,7 @@ public FeatureSchema visit( class OnlySortablesIncluder implements SchemaVisitorTopDown { @Override + @SuppressWarnings("PMD.CyclomaticComplexity") public FeatureSchema visit( FeatureSchema schema, List parents, List visitedProperties) { @@ -85,15 +86,8 @@ public FeatureSchema visit( // TODO: In the next major release move to FeatureSchema.sortable() and exclude // incompatible properties. - if (!isCompatible(schema)) { - if (wildcard) { - return null; - } - if (LOGGER.isWarnEnabled()) { - LOGGER.warn( - "Property '{}' has a value transformation or is a constant value. The property should not be used as a sortable as sorting by the values may not work as expected.", - schema.getFullPathAsString(pathSeparator)); - } + if (!isCompatible(schema) && shouldSkipIncompatibleSortable(schema)) { + return null; } } else if (!schema.isFeature()) { return null; @@ -121,6 +115,22 @@ public FeatureSchema visit( .concat(visitedConcat) .build(); } + + private void logIncompatibleSortable(FeatureSchema schema) { + if (LOGGER.isWarnEnabled()) { + LOGGER.warn( + "Property '{}' has a value transformation or is a constant value. The property should not be used as a sortable as sorting by the values may not work as expected.", + schema.getFullPathAsString(pathSeparator)); + } + } + + private boolean shouldSkipIncompatibleSortable(FeatureSchema schema) { + if (!wildcard) { + logIncompatibleSortable(schema); + return false; + } + return true; + } } private boolean isCompatible(FeatureSchema schema) { diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/PropertyTransformation.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/PropertyTransformation.java index 9c211be33..ebd4b16d7 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/PropertyTransformation.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/PropertyTransformation.java @@ -20,7 +20,7 @@ import de.ii.xtraplatform.entities.domain.maptobuilder.BuildableBuilder; import de.ii.xtraplatform.features.domain.SchemaBase.Type; import java.text.MessageFormat; -import java.time.LocalDate; +import java.time.DateTimeException; import java.time.format.DateTimeFormatter; import java.util.Collection; import java.util.List; @@ -323,22 +323,21 @@ default ImmutableValidationResult.Builder validate( String property, Collection codelists) { final Optional remove = getRemove(); - if (remove.isPresent()) { - if (!FeaturePropertyTransformerRemove.CONDITION_VALUES.contains(remove.get())) { - builder.addStrictErrors( - MessageFormat.format( - "The remove transformation in collection ''{0}'' for property ''{1}'' is invalid. The value ''{2}'' is not one of the known values: {3}.", - collectionId, - property, - remove.get(), - FeaturePropertyTransformerRemove.CONDITION_VALUES)); - } + if (remove.isPresent() + && !FeaturePropertyTransformerRemove.CONDITION_VALUES.contains(remove.get())) { + builder.addStrictErrors( + MessageFormat.format( + "The remove transformation in collection ''{0}'' for property ''{1}'' is invalid. The value ''{2}'' is not one of the known values: {3}.", + collectionId, + property, + remove.get(), + FeaturePropertyTransformerRemove.CONDITION_VALUES)); } final Optional dateFormat = getDateFormat(); if (dateFormat.isPresent()) { try { - LocalDate.now().format(DateTimeFormatter.ofPattern(dateFormat.get())); - } catch (Exception e) { + DateTimeFormatter.ofPattern(dateFormat.get()); + } catch (IllegalArgumentException | DateTimeException e) { builder.addWarnings( MessageFormat.format( "The dateFormat transformation in collection ''{0}'' for property ''{1}'' with value ''{2}'' is invalid, if used with a timestamp: {3}.", @@ -346,13 +345,11 @@ default ImmutableValidationResult.Builder validate( } } final Optional codelist = getCodelist(); - if (codelist.isPresent()) { - if (!codelists.contains(codelist.get())) { - builder.addStrictErrors( - MessageFormat.format( - "The codelist transformation in collection ''{0}'' for property ''{1}'' is invalid. The codelist ''{2}'' is not one of the known values: {3}.", - collectionId, property, codelist.get(), codelists)); - } + if (codelist.isPresent() && !codelists.contains(codelist.get())) { + builder.addStrictErrors( + MessageFormat.format( + "The codelist transformation in collection ''{0}'' for property ''{1}'' is invalid. The codelist ''{2}'' is not one of the known values: {3}.", + collectionId, property, codelist.get(), codelists)); } return builder; diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/PropertyTransformations.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/PropertyTransformations.java index 9154eacbf..4519f3b0b 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/PropertyTransformations.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/PropertyTransformations.java @@ -23,6 +23,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +@FunctionalInterface public interface PropertyTransformations { Logger LOGGER = LoggerFactory.getLogger(PropertyTransformations.class); diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/PropertyTransformationsCollector.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/PropertyTransformationsCollector.java index cfd13e3d7..6c32e7830 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/PropertyTransformationsCollector.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/PropertyTransformationsCollector.java @@ -84,15 +84,11 @@ public Map> visit( } @Override - public PropertyTransformations finalize( + public PropertyTransformations finalizeVisit( FeatureSchema schema, Map> transformations) { PropertyTransformations schemaTransformations = () -> transformations; - - PropertyTransformations mergedTransformations = - preferSchemaTransformations - ? schemaTransformations.mergeInto(additionalTransformations) - : additionalTransformations.mergeInto(schemaTransformations); - - return mergedTransformations; + return preferSchemaTransformations + ? schemaTransformations.mergeInto(additionalTransformations) + : additionalTransformations.mergeInto(schemaTransformations); } } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/SchemaTransformerChain.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/SchemaTransformerChain.java index 5fb56f036..744a4d67f 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/SchemaTransformerChain.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/SchemaTransformerChain.java @@ -79,16 +79,17 @@ public FeatureSchema visit( @Nullable @Override public FeatureSchema transform(String path, FeatureSchema schema) { - FeatureSchema transformed = schema; - for (int i = currentParentProperties.size() - 1; i >= 0; i--) { String parentPath = currentParentProperties.get(i); if (!path.startsWith(parentPath)) { currentParentProperties.remove(i); - } else if (transformers.containsKey(parentPath)) { - transformed = run(transformers, parentPath, path, schema); - if (Objects.isNull(transformed)) { + continue; + } + + if (transformers.containsKey(parentPath)) { + FeatureSchema transformedParent = run(transformers, parentPath, path, schema); + if (Objects.isNull(transformedParent)) { return null; } } @@ -101,9 +102,7 @@ public FeatureSchema transform(String path, FeatureSchema schema) { currentParentProperties.add(path); } - transformed = run(transformers, path, path, schema); - - return transformed; + return run(transformers, path, path, schema); } @Override diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/TokenSliceTransformerChain.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/TokenSliceTransformerChain.java index fc573d9a4..d5fccf504 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/TokenSliceTransformerChain.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/TokenSliceTransformerChain.java @@ -109,6 +109,7 @@ public FeatureSchema visit( .build()); } + @SuppressWarnings("PMD.CognitiveComplexity") public Map transform(FeatureEventBuffer buffer) { Map applied = new HashMap<>(); @@ -211,11 +212,7 @@ public Map transform(FeatureEventBuffer buffer) { @Nullable @Override public List transform(String path, List slice) { - List transformed = slice; - - transformed = run(transformers, path, path, slice); - - return transformed; + return run(transformers, path, path, slice); } @Override diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/ValueTransformerChain.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/ValueTransformerChain.java index dca169f6c..8a7be6e61 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/ValueTransformerChain.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/ValueTransformerChain.java @@ -76,11 +76,7 @@ public ValueTransformerChain( @Nullable @Override public String transform(String path, String value) { - String transformed = value; - - transformed = run(transformers, path, path, value); - - return transformed; + return run(transformers, path, path, value); } @Override diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/WithScope.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/WithScope.java index 7940b65b2..7d134b5f1 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/WithScope.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/WithScope.java @@ -38,12 +38,7 @@ public FeatureSchema visit( FeatureSchema schema, List parents, List visitedProperties) { // always include ID property - if (!schema.hasOneOf(scopes) - && !schema.isId() - && !schema.isEmbeddedId() - && (!schema.isObject() - || scopes.contains(Scope.RETURNABLE) - || scopes.contains(Scope.RECEIVABLE))) { + if (isExcludedByScope(schema)) { return null; } @@ -67,11 +62,7 @@ public FeatureSchema visit( .filter(Objects::nonNull) .collect(Collectors.toList()); - if (schema.isObject() - && !parents.isEmpty() - && visitedProperties.isEmpty() - && visitedConcat.isEmpty() - && visitedCoalesce.isEmpty()) { + if (isEmptyNestedObject(schema, parents, visitedProperties, visitedConcat, visitedCoalesce)) { return null; } @@ -82,4 +73,26 @@ public FeatureSchema visit( .coalesce(visitedCoalesce) .build(); } + + private boolean isExcludedByScope(FeatureSchema schema) { + return !schema.hasOneOf(scopes) + && !schema.isId() + && !schema.isEmbeddedId() + && (!schema.isObject() + || scopes.contains(Scope.RETURNABLE) + || scopes.contains(Scope.RECEIVABLE)); + } + + private boolean isEmptyNestedObject( + FeatureSchema schema, + List parents, + List visitedProperties, + List visitedConcat, + List visitedCoalesce) { + return schema.isObject() + && !parents.isEmpty() + && visitedProperties.isEmpty() + && visitedConcat.isEmpty() + && visitedCoalesce.isEmpty(); + } } diff --git a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/WithTransformationsApplied.java b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/WithTransformationsApplied.java index d6945168f..126bf1bbe 100644 --- a/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/WithTransformationsApplied.java +++ b/xtraplatform-features/src/main/java/de/ii/xtraplatform/features/domain/transform/WithTransformationsApplied.java @@ -89,7 +89,7 @@ private Optional getFeatureTransformations(FeatureSchema : additionalTransformations.mergeInto(schemaTransformations); List featureTransformations = - mergedTransformations.getTransformations().get(PropertyTransformations.WILDCARD); + mergedTransformations.getTransformations().get(WILDCARD); return Optional.ofNullable(featureTransformations) .filter(list -> !list.isEmpty()) @@ -114,11 +114,8 @@ private PropertyTransformations getPropertyTransformations(FeatureSchema schema) .collect( ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue))); - PropertyTransformations mergedTransformations = - preferSchemaTransformations - ? schemaTransformations.mergeInto(additionalTransformations) - : additionalTransformations.mergeInto(schemaTransformations); - - return mergedTransformations; + return preferSchemaTransformations + ? schemaTransformations.mergeInto(additionalTransformations) + : additionalTransformations.mergeInto(schemaTransformations); } }