Skip to content

Commit

Permalink
Merge pull request #41 Add FindObjects function
Browse files Browse the repository at this point in the history
  • Loading branch information
domi-b authored Jan 11, 2024
2 parents f8b9a20 + dade8bc commit 57ef59e
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public abstract class BaseInterlisFunction implements InterlisFunction {
protected TransferDescription td;
protected Settings settings;
protected Validator validator;
protected ObjectPool objectPool;

@Override
public final void init(TransferDescription td, Settings settings, IoxValidationConfig validationConfig, ObjectPool objectPool, LogEventFactory logEventFactory) {
Expand All @@ -24,6 +25,7 @@ public final void init(TransferDescription td, Settings settings, IoxValidationC
this.td = td;
this.settings = settings;
this.validator = (Validator) settings.getTransientObject(IOX_VALIDATOR);
this.objectPool = objectPool;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package ch.geowerkstatt.ilivalidator.extensions.functions;

import ch.ehi.iox.objpool.impl.ObjPoolImpl2;
import ch.interlis.ili2c.metamodel.Element;
import ch.interlis.ili2c.metamodel.PathEl;
import ch.interlis.ili2c.metamodel.TextType;
import ch.interlis.ili2c.metamodel.Viewable;
import ch.interlis.iom.IomObject;
import ch.interlis.iox_j.validator.ObjectPoolKey;
import ch.interlis.iox_j.validator.Value;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

public final class FindObjectsIoxPlugin extends BaseInterlisFunction {
private static final Map<FindObjectsKey, List<IomObject>> OBJECTS_CACHE = new HashMap<>();

@Override
public String getQualifiedIliName() {
return "GeoW_FunctionsExt.FindObjects";
}

@Override
protected Value evaluateInternal(String validationKind, String usageScope, IomObject contextObject, Value[] arguments) {
Value argClassName = arguments[0];
Value argPath = arguments[1];
Value argValue = arguments[2];

if (argClassName.isUndefined() || argPath.isUndefined()) {
return Value.createSkipEvaluation();
}

String className = argClassName.getValue();
String attributePath = argPath.getValue();
if (className == null || attributePath == null) {
return Value.createUndefined();
}

FindObjectsKey key = new FindObjectsKey(className, attributePath, argValue);
return new Value(OBJECTS_CACHE.computeIfAbsent(key, this::findObjects));
}

private List<IomObject> findObjects(FindObjectsKey key) {
Element classElement = td.getElement(key.className);
if (!(classElement instanceof Viewable)) {
throw new IllegalStateException("Could not find class \"" + key.className + "\"");
}
PathEl[] attributePath = EvaluationHelper.getAttributePathEl(validator, (Viewable) classElement, new Value(new TextType(), key.attributePath));

List<IomObject> objects = findObjectsOfClass(key.className);
return objects.stream()
.filter(object -> {
Value value = validator.getValueFromObjectPath(null, object, attributePath, null);
return value.compareTo(key.value) == 0;
})
.collect(Collectors.toList());
}

private List<IomObject> findObjectsOfClass(String className) {
List<IomObject> objects = new ArrayList<>();
for (String basketId : objectPool.getBasketIds()) {
ObjPoolImpl2<ObjectPoolKey, IomObject> basketObjectPool = objectPool.getObjectsOfBasketId(basketId);
Iterator<IomObject> valueIterator = basketObjectPool.valueIterator();
while (valueIterator.hasNext()) {
IomObject object = valueIterator.next();
if (object.getobjecttag().equals(className)) {
objects.add(object);
}
}
}
return objects;
}

private static final class FindObjectsKey {
private final String className;
private final String attributePath;
private final Value value;

FindObjectsKey(String className, String attributePath, Value value) {
this.className = className;
this.attributePath = attributePath;
this.value = value;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof FindObjectsKey)) {
return false;
}
FindObjectsKey that = (FindObjectsKey) o;
return className.equals(that.className)
&& attributePath.equals(that.attributePath)
&& value.compareTo(that.value) == 0;
}

@Override
public int hashCode() {
return Objects.hash(className, attributePath, value.getValue());
}
}
}
6 changes: 6 additions & 0 deletions src/model/GeoW_FunctionsExt.ili
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,10 @@ MODEL GeoW_FunctionsExt
!!@ fn.return = "TRUE, wenn sich zwei Linien überlappen oder zwischen zwei Linien eine gemeinsame Teilstrecke vorhanden ist";
!!@ fn.since = "2023-12-18";
FUNCTION PolylinesOverlap (Objects: OBJECTS OF ANYCLASS; LineAttr: TEXT): BOOLEAN;

!!@ fn.description = "Sucht im aktuellen Transfer nach Objekten der angegebenen Klasse, welche das Filterkriterium erfüllen. Für 'FilterAttr' soll der Pfad zum Attribut in INTERLIS 2 Syntax angegeben werden. Für 'FilterValue' kann ein beliebiger Wert angegeben werden.";
!!@ fn.param = "ClassName: Qualifizierter Klassenname (inklusive Modell und Topic) der Objekte, die gesucht werden. FilterAttr: Pfad zum Attribut, welches für den Filter verwendet werden soll. FilterValue: Wert für das Filterkriterium";
!!@ fn.return = "Alle Objekte der angegebenen Klasse aus dem aktuellen Transfer, welche das Filterkriterium erfüllen";
!!@ fn.since = "2024-01-10";
FUNCTION FindObjects(ClassName: TEXT; FilterAttr: TEXT; FilterValue: ANYSTRUCTURE): BAG OF ANYSTRUCTURE;
END GeoW_FunctionsExt.
26 changes: 26 additions & 0 deletions src/test/data/FindObjects/MandatoryConstraints.ili
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
INTERLIS 2.4;

MODEL TestSuite
AT "mailto:[email protected]" VERSION "2022-12-02" =
IMPORTS GeoW_FunctionsExt;

TOPIC FunctionTestTopic =

CLASS ReferencedClass =
textAttr: TEXT*16;
enumAttr: (val1,val2,val3);
numberAttr: 0..10;
END ReferencedClass;

CLASS BaseClass =
MANDATORY CONSTRAINT trueConstraintTextAttr: INTERLIS.elementCount(GeoW_FunctionsExt.FindObjects("TestSuite.FunctionTestTopic.ReferencedClass", "textAttr", "Some Value")) == 2;
MANDATORY CONSTRAINT trueConstraintEnumAttr: INTERLIS.elementCount(GeoW_FunctionsExt.FindObjects("TestSuite.FunctionTestTopic.ReferencedClass", "enumAttr", #val2)) == 3;
MANDATORY CONSTRAINT trueConstraintNumberAttr: INTERLIS.elementCount(GeoW_FunctionsExt.FindObjects("TestSuite.FunctionTestTopic.ReferencedClass", "numberAttr", 3)) == 1;
MANDATORY CONSTRAINT falseConstraintTextAttr: INTERLIS.elementCount(GeoW_FunctionsExt.FindObjects("TestSuite.FunctionTestTopic.ReferencedClass", "textAttr", "Some Value")) == 0;
MANDATORY CONSTRAINT falseConstraintEnumAttr: INTERLIS.elementCount(GeoW_FunctionsExt.FindObjects("TestSuite.FunctionTestTopic.ReferencedClass", "enumAttr", #val2)) == 0;
MANDATORY CONSTRAINT falseConstraintNumberAttr: INTERLIS.elementCount(GeoW_FunctionsExt.FindObjects("TestSuite.FunctionTestTopic.ReferencedClass", "numberAttr", 3)) == 0;
END BaseClass;

END FunctionTestTopic;

END TestSuite.
42 changes: 42 additions & 0 deletions src/test/data/FindObjects/TestData.xtf
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<ili:transfer xmlns:ili="http://www.interlis.ch/xtf/2.4/INTERLIS" xmlns:geom="http://www.interlis.ch/geometry/1.0"
xmlns:TestSuite="http://www.interlis.ch/xtf/2.4/TestSuite">
<ili:headersection>
<ili:models>
<ili:model>GeoW_FunctionsExt</ili:model>
<ili:model>TestSuite</ili:model>
</ili:models>
<ili:sender>ili2gpkg-4.6.1-63db90def1260a503f0f2d4cb846686cd4851184</ili:sender>
</ili:headersection>
<ili:datasection>
<TestSuite:FunctionTestTopic ili:bid="TestSuite.FunctionTestTopic">
<TestSuite:BaseClass ili:tid="base">
</TestSuite:BaseClass>
<TestSuite:ReferencedClass ili:tid="1">
<TestSuite:textAttr>Some Value</TestSuite:textAttr>
<TestSuite:enumAttr>val2</TestSuite:enumAttr>
<TestSuite:numberAttr>2</TestSuite:numberAttr>
</TestSuite:ReferencedClass>
<TestSuite:ReferencedClass ili:tid="2">
<TestSuite:textAttr>aaa</TestSuite:textAttr>
<TestSuite:enumAttr>val2</TestSuite:enumAttr>
<TestSuite:numberAttr>2</TestSuite:numberAttr>
</TestSuite:ReferencedClass>
<TestSuite:ReferencedClass ili:tid="3">
<TestSuite:textAttr>aaa</TestSuite:textAttr>
<TestSuite:enumAttr>val2</TestSuite:enumAttr>
<TestSuite:numberAttr>2</TestSuite:numberAttr>
</TestSuite:ReferencedClass>
<TestSuite:ReferencedClass ili:tid="4">
<TestSuite:textAttr>Some Value</TestSuite:textAttr>
<TestSuite:enumAttr>val3</TestSuite:enumAttr>
<TestSuite:numberAttr>1</TestSuite:numberAttr>
</TestSuite:ReferencedClass>
<TestSuite:ReferencedClass ili:tid="5">
<TestSuite:textAttr>bbb</TestSuite:textAttr>
<TestSuite:enumAttr>val1</TestSuite:enumAttr>
<TestSuite:numberAttr>3</TestSuite:numberAttr>
</TestSuite:ReferencedClass>
</TestSuite:FunctionTestTopic>
</ili:datasection>
</ili:transfer>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ch.geowerkstatt.ilivalidator.extensions.functions;

import ch.interlis.ili2c.Ili2cFailure;
import ch.interlis.iox.IoxException;
import com.vividsolutions.jts.util.Assert;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class FindObjectsIoxPluginTest {
protected static final String TEST_DATA = "FindObjects/TestData.xtf";
private ValidationTestHelper vh = null;

@BeforeEach
void setUp() {
vh = new ValidationTestHelper();
vh.addFunction(new FindObjectsIoxPlugin());
}

@Test
void mandatoryConstraint() throws Ili2cFailure, IoxException {
vh.runValidation(new String[]{TEST_DATA}, new String[]{"FindObjects/MandatoryConstraints.ili"});
Assert.equals(3, vh.getErrs().size());
AssertionHelper.assertNoConstraintError(vh, "trueConstraintTextAttr");
AssertionHelper.assertNoConstraintError(vh, "trueConstraintEnumAttr");
AssertionHelper.assertNoConstraintError(vh, "trueConstraintNumberAttr");
AssertionHelper.assertConstraintErrors(vh, 1, "base", "falseConstraintTextAttr");
AssertionHelper.assertConstraintErrors(vh, 1, "base", "falseConstraintEnumAttr");
AssertionHelper.assertConstraintErrors(vh, 1, "base", "falseConstraintNumberAttr");
}
}

0 comments on commit 57ef59e

Please sign in to comment.