Skip to content

Commit

Permalink
MID-7834, MID-8995: Fixed Expression to Axiom Query logic
Browse files Browse the repository at this point in the history
Added more detailed logic and tests for special cases such as:
  simple paths, simple constants, one line groovy scripts.

GUI: Do not execute scripts in Query Converter GUI

Signed-off-by: Tony Tkáčik <tonydamage@gmail.com>
  • Loading branch information
tonydamage committed Oct 2, 2023
1 parent b5df130 commit f86db14
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,13 @@ private ObjectQuery getQueryTypeFromXmlQuery(Task task, OperationResult result)
QueryType queryType = getPrismContext().parserFor(xmlQuery).language(dataLanguage).parseRealValue(QueryType.class);
ObjectQuery objectQuery = getPrismContext().getQueryConverter().createObjectQuery(getClassFromObjectType(), queryType);

return ExpressionUtil.evaluateQueryExpressions(
objectQuery, new VariablesMap(),
MiscSchemaUtil.getExpressionProfile(),
getPageBase().getExpressionFactory(),
"evaluate query expressions", task, result);
// Do not evaluate queries to convert? Jus
return objectQuery;
// return ExpressionUtil.evaluateQueryExpressions(
// objectQuery, new VariablesMap(),
// MiscSchemaUtil.getExpressionProfile(),
// getPageBase().getExpressionFactory(),
// "evaluate query expressions", task, result);
}

private String getXmlQuery() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@

import java.util.Map;

import com.evolveum.midpoint.prism.*;

import jakarta.xml.bind.JAXBElement;
import javax.xml.namespace.QName;

import com.evolveum.midpoint.prism.ExpressionWrapper;
import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismValue;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.query.PrismQueryExpressionFactory;
import com.evolveum.midpoint.util.exception.SchemaException;
Expand All @@ -27,6 +25,8 @@ public class PrismQueryExpressionSupport implements PrismQueryExpressionFactory
private static final String YAML = "yaml";
private static final String CONST = "const";

private static final String YAML_PREAMBLE = "---\n";



@Override
Expand Down Expand Up @@ -74,4 +74,132 @@ public ExpressionWrapper parsePath(ItemPath path) {
expressionT.expressionEvaluator(new JAXBElement<>(PATH, ItemPathType.class, new ItemPathType(path)));
return new ExpressionWrapper(EXPRESSION, expressionT);
}

@Override
public void serializeExpression(ExpressionWriter writer, ExpressionWrapper wrapper) throws SchemaException {
PrismPropertyDefinition<ExpressionType> expressionDef = PrismContext.get().getSchemaRegistry().findPropertyDefinitionByElementName(EXPRESSION);
var expression = wrapper.getExpression();
if (expression instanceof ExpressionType expressionType) {
if (isSimple(expressionType)) {
var evaluator = extractEvaluator(expressionType);

//var serialized = PrismContext.get().serializerFor(YAML).serialize(wrapper.getExpression());

// Detect simple const
if (evaluator instanceof ConstExpressionEvaluatorType constEvaluator) {
writer.writeConst(constEvaluator.getValue());
return;
}
// Detect simple variable
if (evaluator instanceof ItemPathType path) {
writer.writeVariable(path.getItemPath());
return;
}
if (evaluator instanceof ScriptExpressionEvaluatorType script) {
// Detect simple groovy
if (isSimple(script)) {
writer.writeScript(script.getLanguage(), script.getCode());
return;
}

}
}
// Fallback (YAML serialization)
var prop = PrismContext.get().itemFactory().createProperty(EXPRESSION, expressionDef);
prop.setRealValue(expressionType);
var serialized = withoutYamlPreamble(PrismContext.get().serializerFor(YAML).serialize(prop));
writer.writeScript(YAML, serialized);
}

}

private String withoutYamlPreamble(String serialize) {
if (serialize.startsWith(YAML_PREAMBLE)) {
return serialize.substring(YAML_PREAMBLE.length());
}
return serialize;
}

private void writeCode(ExpressionWriter writer, String language, String code) {


}

private Object extractEvaluator(ExpressionType type) {
var jaxbElemList = type.getExpressionEvaluator();
if (jaxbElemList == null) {
// Or should be fail?
return null;
}
if (jaxbElemList.isEmpty()) {
// Or should be fail?
return null;
}
return jaxbElemList.get(0).getValue();
}

private boolean isSimple(ExpressionType type) {
if (type.getReturnType() != null) {
return false;
}
if (type.isTrace() != null) {
return false;
}
if (type.getName() != null) {
return false;
}
if (type.getReturnMultiplicity() != null) {
return false;
}
if (type.getQueryInterpretationOfNoValue() != null) {
return false;
}
if (type.getRunAsRef() != null) {
return false;
}
if (type.getDescription() != null) {
return false;
}
if (!type.getParameter().isEmpty()) {
return false;
}
if (type.getPrivileges() != null) {
return false;
}
if (!type.getStringFilter().isEmpty()) {
return false;
}
if (type.getExtension() != null) {
return false;
}
if (type.getDocumentation() != null) {
return false;
}
return true;
}

private boolean isSimple(ScriptExpressionEvaluatorType type) {
if (type.getDescription() != null) {
return false;
}
if (type.getDocumentation() != null) {
return false;
}
if (type.getReturnType() != null) {
return false;
}
if (type.getCondition() != null) {
return false;
}
if (type.getRelativityMode() != null) {
return false;
}
if (type.getObjectVariableMode() != null) {
return false;
}
if (type.getValueVariableMode() != null) {
return false;
}
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public void test145EvaluateConstantFilter() throws Exception {
OperationResult result = task.getResult();

ObjectFilter filter = evaluateExpressionAssertFilter("expression-aql-constant-filter.xml",
null, EqualFilter.class, task, result);
null, EqualFilter.class, task, result,"extension/tales = @blabla" );

var equalFilter = (EqualFilter<?>) filter;
AssertJUnit.assertNotNull("Expected 1 value in filter", equalFilter.getValues());
Expand All @@ -154,7 +154,7 @@ public void test150EvaluateExpressionEmployeeTypeDefaultsNull() throws Exception
OperationResult result = task.getResult();

ObjectFilter filter = evaluateExpressionAssertFilter("expression-employeeType-filter-defaults.xml",
null, EqualFilter.class, task, result);
null, EqualFilter.class, task, result, "subtype = $input");

var equalFilter = (EqualFilter<?>) filter;
AssertJUnit.assertNull("Expected NO values in filter, but found " + equalFilter.getValues(), equalFilter.getValues());
Expand All @@ -169,7 +169,7 @@ public void test152EvaluateExpressionEmployeeTypeDefaultsCaptain() throws Except
OperationResult result = task.getResult();

ObjectFilter filter = evaluateExpressionAssertFilter("expression-employeeType-filter-defaults.xml",
"CAPTAIN", EqualFilter.class, task, result);
"CAPTAIN", EqualFilter.class, task, result,"subtype = $input");

//noinspection unchecked
var equalFilter = (EqualFilter<String>) filter;
Expand Down Expand Up @@ -279,7 +279,7 @@ public void test320AqlEvaluateExpressionNameFilter() throws Exception {
OperationResult result = task.getResult();

ObjectFilter filter = evaluateExpressionAssertFilter("expression-aql-name-value-filter.xml",
null, EqualFilter.class, task, result);
null, EqualFilter.class, task, result, "name = `return \"barbossa\";`");

//noinspection unchecked
var equalFilter = (EqualFilter<PolyString>) filter;
Expand All @@ -305,7 +305,13 @@ public void test330EvaluateExpressionLinkRefObjectReferenceTypeDefaultsNull() th

private ObjectFilter evaluateExpressionAssertFilter(String filename,
String input, Class<? extends ObjectFilter> expectedType,
Task task, OperationResult result) throws SchemaException, IOException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException {
Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, CommunicationException, SecurityViolationException, ConfigurationException, ObjectNotFoundException, IOException, PrismQuerySerialization.NotSupportedException {
return evaluateExpressionAssertFilter(filename, input, expectedType, task, result, null);
}

private ObjectFilter evaluateExpressionAssertFilter(String filename,
String input, Class<? extends ObjectFilter> expectedType,
Task task, OperationResult result, String axiomExpected) throws SchemaException, IOException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException, PrismQuerySerialization.NotSupportedException {
PrismContext prismContext = PrismTestUtil.getPrismContext();

SearchFilterType filterType = PrismTestUtil.parseAtomicValue(new File(TEST_DIR, filename), SearchFilterType.COMPLEX_TYPE);
Expand All @@ -317,6 +323,12 @@ private ObjectFilter evaluateExpressionAssertFilter(String filename,
pval = prismContext.itemFactory().createPropertyValue(input);
}

displayValue("Filter", filter);
var axiom = PrismContext.get().querySerializer().serialize(filter);
displayValue("Axiom Variant", axiom.filterText());
if (axiomExpected != null) {
assertEquals("Axiom serialization does not match", axiomExpected, axiom.filterText());
}
VariablesMap variables = createVariables(
ExpressionConstants.VAR_INPUT, pval, PrimitiveType.STRING);

Expand All @@ -333,11 +345,14 @@ private ObjectFilter evaluateExpressionAssertFilter(String filename,
return evaluatedFilter;
}

private void executeFilter(ObjectFilter filter, int expectedNumberOfResults, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException {
private void executeFilter(ObjectFilter filter, int expectedNumberOfResults, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException, PrismQuerySerialization.NotSupportedException {
ObjectQuery query = prismContext.queryFactory().createQuery(filter);

SearchResultList<PrismObject<UserType>> objects = modelService.searchObjects(UserType.class, query, null, task, result);
display("Found objects", objects);
assertEquals("Wrong number of results (found: " + objects + ")", expectedNumberOfResults, objects.size());


}

}

0 comments on commit f86db14

Please sign in to comment.