Skip to content

Commit

Permalink
Support for prism property dynamic values
Browse files Browse the repository at this point in the history
  • Loading branch information
semancik committed May 9, 2017
1 parent 93ad3ac commit 381af77
Show file tree
Hide file tree
Showing 22 changed files with 512 additions and 26 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2014 Evolveum
* Copyright (c) 2010-2017 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -14,7 +14,9 @@
* limitations under the License.
*/

package com.evolveum.midpoint.prism.query;
package com.evolveum.midpoint.prism;

import com.evolveum.midpoint.util.PrettyPrinter;

/**
* @author mederly
Expand All @@ -30,4 +32,11 @@ public Object getExpression() {
public void setExpression(Object expression) {
this.expression = expression;
}

@Override
public String toString() {
return expression==null?"ExpressionWrapper(null)":PrettyPrinter.prettyPrint(expression);
}


}
Expand Up @@ -122,4 +122,6 @@ public class PrismConstants {

public static final boolean EQUALS_DEFAULT_IGNORE_METADATA = true;
public static final boolean EQUALS_DEFAULT_IS_LITERAL = false;

public static final String EXPRESSION_LOCAL_PART = "expression";
}
Expand Up @@ -519,6 +519,8 @@ public String debugDump(int indent) {
if (value.isRaw()) {
sb.append(formatRawValueForDump(value.getRawElement()));
sb.append(" (raw)");
} else if (value.getExpression() != null) {
sb.append(" (expression)");
} else {
T realValue = value.getValue();
if (realValue instanceof DebugDumpable) {
Expand Down Expand Up @@ -546,6 +548,8 @@ public String debugDump(int indent) {
if (value.isRaw()) {
sb.append(formatRawValueForDump(value.getRawElement()));
sb.append(" (raw)");
} else if (value.getExpression() != null) {
sb.append(" (expression)");
} else {
if (DebugUtil.isDetailedDebugDump()) {
sb.append(PrettyPrinter.prettyPrint(value));
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2013 Evolveum
* Copyright (c) 2010-2017 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -60,26 +60,29 @@ public class PrismPropertyValue<T> extends PrismValue implements DebugDumpable,
// We can't do anything smarter, as we don't have definition nor prism context. So we store the raw
// elements here and process them later (e.g. during applyDefinition or getting a value with explicit type).
private XNode rawElement;

@Nullable private ExpressionWrapper expression;

public PrismPropertyValue(T value) {
this(value, null, null);
}

public PrismPropertyValue(T value, PrismContext prismContext) {
this(value, prismContext, null, null);
this(value, prismContext, null, null, null);
}

public PrismPropertyValue(T value, OriginType type, Objectable source) {
this(value, null, type, source);
this(value, null, type, source, null);
}

public PrismPropertyValue(T value, PrismContext prismContext, OriginType type, Objectable source) {
public PrismPropertyValue(T value, PrismContext prismContext, OriginType type, Objectable source, ExpressionWrapper expression) {
super(type, source);
if (value instanceof PrismPropertyValue) {
throw new IllegalArgumentException("Probably problem somewhere, encapsulating property " +
"value object to another property value.");
}
this.value = value;
this.expression = expression;
checkValue();
}

Expand Down Expand Up @@ -170,11 +173,25 @@ public boolean isRaw() {
return rawElement != null;
}

@Nullable
public ExpressionWrapper getExpression() {
return expression;
}

public void setExpression(@Nullable ExpressionWrapper expression) {
this.expression = expression;
}

@Override
public void applyDefinition(ItemDefinition definition) throws SchemaException {
PrismPropertyDefinition propertyDefinition = (PrismPropertyDefinition) definition;
if (propertyDefinition != null && !propertyDefinition.isAnyType() && rawElement != null) {
value = (T) parseRawElementToNewRealValue(this, propertyDefinition);
if (value == null) {
// Be careful here. Expression element can be legal sub-element of complex properties.
// Therefore parse expression only if there is no legal value.
expression = PrismUtil.parseExpression(rawElement, prismContext);
}
rawElement = null;
}
}
Expand Down Expand Up @@ -235,6 +252,9 @@ void checkValue() {
// Cannot really check raw values
return;
}
if (expression != null) {
return;
}
if (value == null) {
// can be used not because of prism forms in gui (will be fixed later [lazyman]
// throw new IllegalArgumentException("Null value in "+this);
Expand Down Expand Up @@ -274,8 +294,8 @@ public void checkConsistenceInternal(Itemable rootItem, boolean requireDefinitio
if (prohibitRaw && rawElement != null) {
throw new IllegalStateException("Raw element in property value "+this+" ("+myPath+" in "+rootItem+")");
}
if (value == null && rawElement == null) {
throw new IllegalStateException("Neither value nor raw element specified in property value "+this+" ("+myPath+" in "+rootItem+")");
if (value == null && rawElement == null && expression == null) {
throw new IllegalStateException("Neither value, expression nor raw element specified in property value "+this+" ("+myPath+" in "+rootItem+")");
}
if (value != null && rawElement != null) {
throw new IllegalStateException("Both value and raw element specified in property value "+this+" ("+myPath+" in "+rootItem+")");
Expand Down Expand Up @@ -592,6 +612,13 @@ public String debugDump(int indent) {
}
debugDumpValue(sb, indent, value, prismContext);
}
} else if (expression != null) {
if (!wasIndent) {
DebugUtil.indentDebugDump(sb, indent);
}
sb.append("expression: ");
// TODO: nicer output
sb.append(expression);
} else {
if (!wasIndent) {
DebugUtil.indentDebugDump(sb, indent);
Expand Down Expand Up @@ -640,10 +667,17 @@ private void dumpSuffix(StringBuilder builder) {
builder.append(", raw element: ");
builder.append(PrettyPrinter.prettyPrint(getRawElement()));
}
if (getExpression() != null) {
builder.append(", expression: ");
builder.append(getExpression());
}
}

@Override
public String toHumanReadableString() {
if (value == null && expression != null) {
return ("expression("+expression+")");
}
return PrettyPrinter.prettyPrint(value);
}

Expand Down
Expand Up @@ -163,6 +163,16 @@ private <T> T unmarshalInternal(@NotNull XNode xnode, @NotNull Class<T> beanClas
throw new SchemaException("Cannot convert primitive value to bean of type " + beanClass);
}
} else {

if (beanClass.getPackage().getName().equals("java.lang")) {
// We obviously have primitive data type, but we have are asked to unmarshall from map xnode
// TODO: more robust implementation
// TODO: look for "value" subnode with primitive value and try that.
// This is most likely attempt to parse primitive value with dynamic expression.
// Therefore just ignore entire map content.
return null;
}

@SuppressWarnings("unchecked")
MapUnmarshaller<T> unmarshaller = specialMapUnmarshallers.get(beanClass);
if (xnode instanceof MapXNode && unmarshaller != null) { // TODO: what about special unmarshaller + hetero list?
Expand Down
Expand Up @@ -18,6 +18,7 @@
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.polystring.PolyString;
import com.evolveum.midpoint.prism.schema.SchemaRegistry;
import com.evolveum.midpoint.prism.util.PrismUtil;
import com.evolveum.midpoint.prism.xml.XmlTypeConverter;
import com.evolveum.midpoint.prism.xnode.*;
import com.evolveum.midpoint.util.DOMUtil;
Expand Down Expand Up @@ -388,6 +389,12 @@ private QName createReferenceQName(QName qname, String namespace) {
//region Serializing properties - specific functionality
private <T> XNode serializePropertyValue(@NotNull PrismPropertyValue<T> value, PrismPropertyDefinition<T> definition, QName typeNameIfNoDefinition) throws SchemaException {
@Nullable QName typeName = definition != null ? definition.getTypeName() : typeNameIfNoDefinition;
ExpressionWrapper expression = value.getExpression();
if (expression != null) {
// Store expression, not the value. In this case the value (if any) is
// a transient product of the expression evaluation.
return createExpressionXNode(expression);
}
T realValue = value.getValue();
if (realValue instanceof PolyString) {
return serializePolyString((PolyString) realValue);
Expand All @@ -408,7 +415,7 @@ private <T> XNode serializePropertyValue(@NotNull PrismPropertyValue<T> value, P
}
}

private XNode serializePolyString(PolyString realValue) {
private XNode serializePolyString(PolyString realValue) {
PrimitiveXNode<PolyString> xprim = new PrimitiveXNode<>();
xprim.setValue(realValue, PolyStringType.COMPLEX_TYPE);
return xprim;
Expand Down Expand Up @@ -444,6 +451,11 @@ private <T> PrimitiveXNode<T> createPrimitiveXNode(T val, QName type) {
xprim.setValue(val, type);
return xprim;
}

@NotNull
private XNode createExpressionXNode(@NotNull ExpressionWrapper expression) {
return PrismUtil.serializeExpression(expression);
}

@NotNull
private SchemaRegistry getSchemaRegistry() {
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2016 Evolveum
* Copyright (c) 2010-2017 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -30,13 +30,15 @@
import com.evolveum.prism.xml.ns._public.types_3.PolyStringType;
import com.evolveum.prism.xml.ns._public.types_3.SchemaDefinitionType;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import java.util.Map.Entry;
import java.util.Set;

public class PrismUnmarshaller {

Expand Down Expand Up @@ -370,7 +372,14 @@ private <T> PrismPropertyValue<T> parsePropertyValue(@NotNull XNode node,
return null;
}
if (realValue == null) {
return null;
// Be careful here. Expression element can be legal sub-element of complex properties.
// Therefore parse expression only if there is no legal value.
ExpressionWrapper expression = PrismUtil.parseExpression(node, prismContext);
if (expression != null) {
PrismPropertyValue<T> ppv = new PrismPropertyValue<>(null, prismContext, null, null, expression);
return ppv;

}
}
PrismPropertyValue<T> ppv = new PrismPropertyValue<>(realValue);
ppv.setPrismContext(prismContext);
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2016 Evolveum
* Copyright (c) 2010-2017 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -35,6 +35,7 @@

import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.query.OrgFilter.Scope;
import com.evolveum.midpoint.prism.util.PrismUtil;
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.QNameUtil;
import com.evolveum.midpoint.util.exception.SchemaException;
Expand Down Expand Up @@ -496,18 +497,8 @@ private static <C extends Containerable> RefFilter parseRefFilter(MapXNode claus

private static ExpressionWrapper parseExpression(MapXNode xmap, PrismContext prismContext) throws SchemaException {
Entry<QName, XNode> expressionEntry = xmap.getSingleEntryThatDoesNotMatch(

ELEMENT_VALUE, ELEMENT_MATCHING, ELEMENT_PATH);
if (expressionEntry != null) {
RootXNode expressionRoot = new RootXNode(expressionEntry);
PrismPropertyValue expressionPropertyValue = prismContext.parserFor(expressionRoot).parseItemValue();
ExpressionWrapper expressionWrapper = new ExpressionWrapper();
expressionWrapper.setExpression(expressionPropertyValue.getValue());
return expressionWrapper;
}

return null;

return PrismUtil.parseExpression(expressionEntry, prismContext);
}

private static <C extends Containerable> SubstringFilter parseSubstringFilter(MapXNode clauseXMap, PrismContainerDefinition<C> pcd, boolean preliminaryParsingOnly, PrismContext prismContext)
Expand Down Expand Up @@ -841,8 +832,7 @@ private static <V extends PrismValue, D extends ItemDefinition> MapXNode seriali

ExpressionWrapper xexpression = filter.getExpression();
if (xexpression != null) {
//map.merge(xexpression);
//TODO serialize expression
map.merge(PrismUtil.serializeExpression(xexpression));
}

return map;
Expand Down
Expand Up @@ -16,6 +16,7 @@

package com.evolveum.midpoint.prism.query;

import com.evolveum.midpoint.prism.ExpressionWrapper;
import com.evolveum.midpoint.prism.PrismContainerValue;
import com.evolveum.midpoint.prism.match.MatchingRuleRegistry;
import com.evolveum.midpoint.util.DebugUtil;
Expand Down
Expand Up @@ -15,6 +15,7 @@
*/
package com.evolveum.midpoint.prism.query;

import com.evolveum.midpoint.prism.ExpressionWrapper;
import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.PrismContainerValue;

Expand Down
Expand Up @@ -20,6 +20,7 @@
import java.util.Collection;
import java.util.Iterator;

import com.evolveum.midpoint.prism.ExpressionWrapper;
import com.evolveum.midpoint.prism.PrismContainer;
import com.evolveum.midpoint.prism.PrismObject;
import org.apache.commons.lang.StringUtils;
Expand Down
Expand Up @@ -16,6 +16,7 @@

package com.evolveum.midpoint.prism.query;

import com.evolveum.midpoint.prism.ExpressionWrapper;
import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismPropertyDefinition;
Expand Down
Expand Up @@ -23,6 +23,9 @@
import com.evolveum.midpoint.prism.polystring.PolyString;
import com.evolveum.midpoint.prism.polystring.PolyStringNormalizer;
import com.evolveum.midpoint.prism.xml.XsdTypeMapper;
import com.evolveum.midpoint.prism.xnode.MapXNode;
import com.evolveum.midpoint.prism.xnode.RootXNode;
import com.evolveum.midpoint.prism.xnode.XNode;
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.prism.xml.ns._public.types_3.PolyStringType;
Expand Down Expand Up @@ -234,4 +237,35 @@ public String toString() {
}
};
}

public static ExpressionWrapper parseExpression(XNode node, PrismContext prismContext) throws SchemaException {
if (!(node instanceof MapXNode)) {
return null;
}
if (((MapXNode)node).isEmpty()) {
return null;
}
for (Entry<QName, XNode> entry: ((MapXNode)node).entrySet()) {
if (PrismConstants.EXPRESSION_LOCAL_PART.equals(entry.getKey().getLocalPart())) {
return parseExpression(entry, prismContext);
}
}
return null;
}

public static ExpressionWrapper parseExpression(Entry<QName, XNode> expressionEntry, PrismContext prismContext) throws SchemaException {
if (expressionEntry == null) {
return null;
}
RootXNode expressionRoot = new RootXNode(expressionEntry);
PrismPropertyValue expressionPropertyValue = prismContext.parserFor(expressionRoot).parseItemValue();
ExpressionWrapper expressionWrapper = new ExpressionWrapper();
expressionWrapper.setExpression(expressionPropertyValue.getValue());
return expressionWrapper;
}

public static MapXNode serializeExpression(ExpressionWrapper expression) {
// TODO
return new MapXNode();
}
}

0 comments on commit 381af77

Please sign in to comment.