Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add operators validation #3809

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.eclipse.edc.connector.core.event.EventRouterImpl;
import org.eclipse.edc.connector.core.health.HealthCheckServiceConfiguration;
import org.eclipse.edc.connector.core.health.HealthCheckServiceImpl;
import org.eclipse.edc.connector.core.store.CriterionOperatorRegistryImpl;
import org.eclipse.edc.connector.core.validator.DataAddressValidatorRegistryImpl;
import org.eclipse.edc.connector.core.validator.JsonObjectValidatorRegistryImpl;
import org.eclipse.edc.core.transform.TypeTransformerRegistryImpl;
Expand All @@ -39,6 +40,7 @@
import org.eclipse.edc.spi.command.CommandHandlerRegistry;
import org.eclipse.edc.spi.event.EventRouter;
import org.eclipse.edc.spi.message.RemoteMessageDispatcherRegistry;
import org.eclipse.edc.spi.query.CriterionOperatorRegistry;
import org.eclipse.edc.spi.security.Vault;
import org.eclipse.edc.spi.system.ExecutorInstrumentation;
import org.eclipse.edc.spi.system.Hostname;
Expand Down Expand Up @@ -186,6 +188,10 @@ public DataAddressValidatorRegistry dataAddressValidatorRegistry(ServiceExtensio
return new DataAddressValidatorRegistryImpl(context.getMonitor());
}

@Provider
public CriterionOperatorRegistry criterionOperatorRegistry() {
return CriterionOperatorRegistryImpl.ofDefaults();
}

private HealthCheckServiceConfiguration getHealthCheckConfig(ServiceExtensionContext context) {
return HealthCheckServiceConfiguration.Builder.newInstance()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
Expand All @@ -12,11 +12,9 @@
*
*/

package org.eclipse.edc.connector.asset;
package org.eclipse.edc.connector.core.store;

import org.eclipse.edc.connector.core.store.CriterionToPredicateConverterImpl;
import org.eclipse.edc.spi.query.CriterionToAssetPredicateConverter;
import org.eclipse.edc.spi.query.CriterionToPredicateConverter;
import org.eclipse.edc.spi.query.PropertyLookup;
import org.eclipse.edc.spi.types.domain.asset.Asset;

import java.util.Map;
Expand All @@ -26,12 +24,12 @@

import static java.util.Map.entry;

/**
* Extension class that supports converting criterion to predicate looking at the Asset properties.
*/
public class CriterionToAssetPredicateConverterImpl extends CriterionToPredicateConverterImpl implements CriterionToAssetPredicateConverter, CriterionToPredicateConverter {
public class AssetPropertyLookup implements PropertyLookup {

private final PropertyLookup fallbackPropertyLookup = new ReflectionPropertyLookup();

public Object property(String key, Object object) {
@Override
public Object getProperty(String key, Object object) {
if (object instanceof Asset asset) {
Stream<Map.Entry<String, Function<Asset, Map<String, Object>>>> mappings = Stream.of(
entry("%s", Asset::getProperties),
Expand All @@ -40,11 +38,12 @@ public Object property(String key, Object object) {
entry("'%s'", Asset::getPrivateProperties));

return mappings
.map(entry -> super.property(entry.getKey().formatted(key), entry.getValue().apply(asset)))
.map(entry -> fallbackPropertyLookup.getProperty(entry.getKey().formatted(key), entry.getValue().apply(asset)))
.filter(Objects::nonNull)
.findFirst()
.orElseGet(() -> super.property(key, asset));
.orElseGet(() -> fallbackPropertyLookup.getProperty(key, asset));
}
throw new IllegalArgumentException("Can only handle objects of type " + Asset.class.getSimpleName() + " but received an " + object.getClass().getSimpleName());

return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
*
*/

package org.eclipse.edc.connector.core.store;

import org.eclipse.edc.spi.query.OperatorPredicate;

import java.util.Collection;

public class ContainsOperatorPredicate implements OperatorPredicate {

@Override
public boolean test(Object property, Object operandRight) {
if (property instanceof Collection<?> collection) {
return collection.contains(operandRight);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

theoretically operandRight could be a List itself, IDK what would happen then...

Copy link
Member Author

@ndr-brt ndr-brt Feb 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the (postgre)SQL context it can be only a single object, because eventually I guess another operator/syntax would need to be used.
I think if we want to being able to pass a list as operandRight we'll need another operator (containsAll?)

}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
*
*/

package org.eclipse.edc.connector.core.store;

import org.eclipse.edc.spi.query.Criterion;
import org.eclipse.edc.spi.query.CriterionOperatorRegistry;
import org.eclipse.edc.spi.query.OperatorPredicate;
import org.eclipse.edc.spi.query.PropertyLookup;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;

import static java.lang.String.format;

/**
* Implementation for {@link CriterionOperatorRegistry}
*/
public class CriterionOperatorRegistryImpl implements CriterionOperatorRegistry {

private final Map<String, OperatorPredicate> operatorPredicates = new HashMap<>();
private final List<PropertyLookup> propertyLookups = new ArrayList<>();

public static CriterionOperatorRegistry ofDefaults() {
var registry = new CriterionOperatorRegistryImpl();
registry.registerPropertyLookup(new ReflectionPropertyLookup());
registry.registerPropertyLookup(new AssetPropertyLookup());
registry.registerOperatorPredicate(EQUAL, new EqualOperatorPredicate());
registry.registerOperatorPredicate(IN, new InOperatorPredicate());
registry.registerOperatorPredicate(LIKE, new LikeOperatorPredicate());
registry.registerOperatorPredicate(CONTAINS, new ContainsOperatorPredicate());
return registry;
}

@Override
public void registerOperatorPredicate(String operator, OperatorPredicate converter) {
operatorPredicates.put(operator.toLowerCase(), converter);
}

@Override
public void registerPropertyLookup(PropertyLookup propertyLookup) {
propertyLookups.add(0, propertyLookup);
}

@Override
public void unregister(String operator) {
operatorPredicates.remove(operator.toLowerCase());
}

@Override
public boolean isSupported(String operator) {
return operatorPredicates.containsKey(operator.toLowerCase());
}

@Override
public <T> Predicate<T> toPredicate(Criterion criterion) {
var predicate = operatorPredicates.get(criterion.getOperator().toLowerCase());
if (predicate == null) {
throw new IllegalArgumentException(format("Operator [%s] is not supported.", criterion.getOperator()));
}

return t -> {

var operandLeft = (String) criterion.getOperandLeft();

var property = propertyLookups.stream()
.map(it -> it.getProperty(operandLeft, t))
.filter(Objects::nonNull)
.findFirst()
.orElse(null);

if (property == null) {
return false;
}

return predicate.test(property, criterion.getOperandRight());
};

}

}

This file was deleted.

Loading
Loading