From ab133598634102f8f8d130b5e73f44dc999187ac Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Tue, 18 May 2021 10:58:41 +0200 Subject: [PATCH 01/23] PerfTest Role Authorization Signed-off-by: Tony Tkacik --- .../story/security/PerfTestRoleMembers.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 testing/story/src/test/java/com/evolveum/midpoint/testing/story/security/PerfTestRoleMembers.java diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/security/PerfTestRoleMembers.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/security/PerfTestRoleMembers.java new file mode 100644 index 00000000000..21bc54f6971 --- /dev/null +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/security/PerfTestRoleMembers.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.testing.story.security; + +import java.util.ArrayList; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Tests for privacy-enhancing setup. E.g. broad get authorizations, but limited search. + * + * @author semancik + */ +@ContextConfiguration(locations = { "classpath:ctx-story-test-main.xml" }) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) +public class PerfTestRoleMembers extends TestRoleMembers { + + private static final int REPETITIONS = 5000; + + + @DataProvider(name = "repetitions") + public Object[][] repetitions() { + ArrayList configs = new ArrayList<>(); + for (int rep = 0; rep < REPETITIONS; rep++) { + configs.add(new Object[] { rep }); + } + return configs.toArray(new Object[configs.size()][]); + } + + /** + * MID-4893, MID-4947 + */ + @Test(dataProvider = "repetitions") + public void test100AutzGuybrushNoMembers(int repetition) throws Exception { + test100AutzGuybrushNoMembers(); + } + + /** + * MID-4893 + */ + @Test(dataProvider = "repetitions") + public void test105AutzElaineMembers(int repetition) throws Exception { + test105AutzElaineMembers(); + } +} From 407e21948705623600f5b1ead4d8f8ac6ff27106 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Tue, 18 May 2021 11:02:01 +0200 Subject: [PATCH 02/23] Moved canRead, canModify, canAdd to separate interface Signed-off-by: Tony Tkacik --- .../midpoint/prism/ItemDefinition.java | 41 +--------------- .../prism/PrismItemAccessDefinition.java | 49 +++++++++++++++++++ 2 files changed, 50 insertions(+), 40 deletions(-) create mode 100644 infra/prism-api/src/main/java/com/evolveum/midpoint/prism/PrismItemAccessDefinition.java diff --git a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/ItemDefinition.java b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/ItemDefinition.java index 91119eef0eb..c397e753038 100644 --- a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/ItemDefinition.java +++ b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/ItemDefinition.java @@ -23,7 +23,7 @@ /** * @author mederly */ -public interface ItemDefinition extends Definition { +public interface ItemDefinition extends Definition, PrismItemAccessDefinition { @NotNull ItemName getItemName(); @@ -71,45 +71,6 @@ default boolean isMultiValue() { */ boolean isDynamic(); - /** - * Returns true if this item can be read (displayed). - * In case of containers this flag is, strictly speaking, not applicable. Container is an - * empty shell. What matters is access to individual sub-item. However, for containers this - * value has a "hint" meaning. It means that the container itself contains something that is - * readable. Which can be used as a hint by the presentation to display container label or block. - * This usually happens if the container contains at least one readable item. - * This does NOT mean that also all the container items can be displayed. The sub-item permissions - * are controlled by similar properties on the items. This property only applies to the container - * itself: the "shell" of the container. - *

- * Note: It was considered to use a different meaning for this flag - a meaning that would allow - * canRead()=false containers to have readable items. However, this was found not to be very useful. - * Therefore the "something readable inside" meaning was confirmed instead. - */ - boolean canRead(); - - /** - * Returns true if this item can be modified (updated). - * In case of containers this means that the container itself should be displayed in modification forms - * E.g. that the container label or block should be displayed. This usually happens if the container - * contains at least one modifiable item. - * This does NOT mean that also all the container items can be modified. The sub-item permissions - * are controlled by similar properties on the items. This property only applies to the container - * itself: the "shell" of the container. - */ - boolean canModify(); - - /** - * Returns true if this item can be added: it can be part of an object that is created. - * In case of containers this means that the container itself should be displayed in creation forms - * E.g. that the container label or block should be displayed. This usually happens if the container - * contains at least one createable item. - * This does NOT mean that also all the container items can be created. The sub-item permissions - * are controlled by similar properties on the items. This property only applies to the container - * itself: the "shell" of the container. - */ - boolean canAdd(); - /** * Returns the name of an element this one can be substituted for (e.g. c:user -> c:object, * s:pipeline -> s:expression, etc). EXPERIMENTAL diff --git a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/PrismItemAccessDefinition.java b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/PrismItemAccessDefinition.java new file mode 100644 index 00000000000..fc6f608dba7 --- /dev/null +++ b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/PrismItemAccessDefinition.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.prism; + +public interface PrismItemAccessDefinition { + + /** + * Returns true if this item can be read (displayed). + * In case of containers this flag is, strictly speaking, not applicable. Container is an + * empty shell. What matters is access to individual sub-item. However, for containers this + * value has a "hint" meaning. It means that the container itself contains something that is + * readable. Which can be used as a hint by the presentation to display container label or block. + * This usually happens if the container contains at least one readable item. + * This does NOT mean that also all the container items can be displayed. The sub-item permissions + * are controlled by similar properties on the items. This property only applies to the container + * itself: the "shell" of the container. + *

+ * Note: It was considered to use a different meaning for this flag - a meaning that would allow + * canRead()=false containers to have readable items. However, this was found not to be very useful. + * Therefore the "something readable inside" meaning was confirmed instead. + */ + boolean canRead(); + + /** + * Returns true if this item can be modified (updated). + * In case of containers this means that the container itself should be displayed in modification forms + * E.g. that the container label or block should be displayed. This usually happens if the container + * contains at least one modifiable item. + * This does NOT mean that also all the container items can be modified. The sub-item permissions + * are controlled by similar properties on the items. This property only applies to the container + * itself: the "shell" of the container. + */ + boolean canModify(); + + /** + * Returns true if this item can be added: it can be part of an object that is created. + * In case of containers this means that the container itself should be displayed in creation forms + * E.g. that the container label or block should be displayed. This usually happens if the container + * contains at least one createable item. + * This does NOT mean that also all the container items can be created. The sub-item permissions + * are controlled by similar properties on the items. This property only applies to the container + * itself: the "shell" of the container. + */ + boolean canAdd(); +} From fddd755054c1416003960bd16938ca94f14888eb Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Mon, 24 May 2021 20:07:38 +0200 Subject: [PATCH 03/23] *FilterImpl: toString fixes/enhancements, cleanup, some generics --- .../prism/impl/query/ExistsFilterImpl.java | 57 ++++++------ .../prism/impl/query/FullTextFilterImpl.java | 43 ++++----- .../prism/impl/query/InOidFilterImpl.java | 90 ++++++++++--------- .../prism/impl/query/LogicalFilterImpl.java | 35 ++++---- .../prism/impl/query/ObjectQueryImpl.java | 31 +++---- .../prism/impl/query/OrgFilterImpl.java | 30 ++++--- .../prism/impl/query/ValueFilterImpl.java | 10 +-- 7 files changed, 155 insertions(+), 141 deletions(-) diff --git a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/ExistsFilterImpl.java b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/ExistsFilterImpl.java index 2f9b0bee819..6b4bf8c0f13 100644 --- a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/ExistsFilterImpl.java +++ b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/ExistsFilterImpl.java @@ -1,12 +1,15 @@ /* - * Copyright (c) 2010-2018 Evolveum and contributors + * Copyright (C) 2010-2021 Evolveum and contributors * * This work is dual-licensed under the Apache License 2.0 * and European Union Public License. See LICENSE file for details. */ - package com.evolveum.midpoint.prism.impl.query; +import java.util.Objects; + +import org.jetbrains.annotations.NotNull; + import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.match.MatchingRuleRegistry; import com.evolveum.midpoint.prism.path.ItemPath; @@ -16,7 +19,6 @@ import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.PrettyPrinter; import com.evolveum.midpoint.util.exception.SchemaException; -import org.jetbrains.annotations.NotNull; /** * TODO think about creating abstract ItemFilter (ItemRelatedFilter) for this filter and ValueFilter. @@ -27,10 +29,10 @@ public final class ExistsFilterImpl extends ObjectFilterImpl implements ExistsFilter { @NotNull private final ItemPath fullPath; - private final ItemDefinition definition; + private final ItemDefinition definition; private ObjectFilter filter; - private ExistsFilterImpl(@NotNull ItemPath fullPath, ItemDefinition definition, ObjectFilter filter) { + private ExistsFilterImpl(@NotNull ItemPath fullPath, ItemDefinition definition, ObjectFilter filter) { this.fullPath = fullPath; this.definition = definition; this.filter = filter; @@ -65,18 +67,17 @@ protected void performFreeze() { } public static ExistsFilter createExists(ItemPath itemPath, PrismContainerDefinition containerDef, - ObjectFilter filter) throws SchemaException { - ItemDefinition itemDefinition = FilterImplUtil.findItemDefinition(itemPath, containerDef); + ObjectFilter filter) throws SchemaException { + ItemDefinition itemDefinition = FilterImplUtil.findItemDefinition(itemPath, containerDef); return new ExistsFilterImpl(itemPath, itemDefinition, filter); } public static ExistsFilter createExists(ItemPath itemPath, Class clazz, PrismContext prismContext, - ObjectFilter filter) { - ItemDefinition itemDefinition = FilterImplUtil.findItemDefinition(itemPath, clazz, prismContext); + ObjectFilter filter) { + ItemDefinition itemDefinition = FilterImplUtil.findItemDefinition(itemPath, clazz, prismContext); return new ExistsFilterImpl(itemPath, itemDefinition, filter); } - @SuppressWarnings("CloneDoesntCallSuperClone") @Override public ExistsFilterImpl clone() { ObjectFilter f = filter != null ? filter.clone() : null; @@ -111,10 +112,10 @@ public boolean match(PrismContainerValue value, MatchingRuleRegistry matchingRul @Override public void checkConsistence(boolean requireDefinitions) { if (fullPath.isEmpty()) { - throw new IllegalArgumentException("Null or empty path in "+this); + throw new IllegalArgumentException("Null or empty path in " + this); } if (requireDefinitions && definition == null) { - throw new IllegalArgumentException("Null definition in "+this); + throw new IllegalArgumentException("Null definition in " + this); } // null subfilter is legal. It means "ALL". if (filter != null) { @@ -132,7 +133,7 @@ public String debugDump(int indent) { DebugUtil.indentDebugDump(sb, indent + 1); sb.append("DEF: "); if (getDefinition() != null) { - sb.append(getDefinition().toString()); + sb.append(getDefinition()); } else { sb.append("null"); } @@ -145,13 +146,11 @@ public String debugDump(int indent) { @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("EXISTS("); - sb.append(PrettyPrinter.prettyPrint(fullPath)); - sb.append(","); - sb.append(filter); - sb.append(")"); - return sb.toString(); + return "EXISTS(" + + PrettyPrinter.prettyPrint(fullPath) + + ", " + + filter + + ")"; } @Override @@ -164,16 +163,20 @@ public void accept(Visitor visitor) { @Override public boolean equals(Object o, boolean exact) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } ExistsFilterImpl that = (ExistsFilterImpl) o; - if (!fullPath.equals(that.fullPath, exact)) return false; - if (exact) { - if (definition != null ? !definition.equals(that.definition) : that.definition != null) { - return false; - } + if (!fullPath.equals(that.fullPath, exact)) { + return false; + } + if (exact && !Objects.equals(definition, that.definition)) { + return false; } return filter != null ? filter.equals(that.filter, exact) : that.filter == null; } diff --git a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/FullTextFilterImpl.java b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/FullTextFilterImpl.java index 727505e3492..aef7c649749 100644 --- a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/FullTextFilterImpl.java +++ b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/FullTextFilterImpl.java @@ -1,26 +1,25 @@ /* - * Copyright (c) 2010-2018 Evolveum and contributors + * Copyright (C) 2010-2021 Evolveum and contributors * * This work is dual-licensed under the Apache License 2.0 * and European Union Public License. See LICENSE file for details. */ - package com.evolveum.midpoint.prism.impl.query; +import java.util.Arrays; +import java.util.Collection; +import java.util.Objects; + +import com.google.common.collect.ImmutableList; +import org.apache.commons.lang.StringUtils; +import org.jetbrains.annotations.NotNull; + import com.evolveum.midpoint.prism.ExpressionWrapper; import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.match.MatchingRuleRegistry; import com.evolveum.midpoint.prism.query.FullTextFilter; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.exception.SchemaException; -import com.google.common.collect.ImmutableList; -import org.apache.commons.lang.StringUtils; -import org.jetbrains.annotations.NotNull; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Objects; -import java.util.stream.Collectors; public final class FullTextFilterImpl extends ObjectFilterImpl implements FullTextFilter { @@ -35,11 +34,11 @@ private FullTextFilterImpl(ExpressionWrapper expression) { this.expression = expression; } - public static FullTextFilter createFullText(Collection values){ + public static FullTextFilter createFullText(Collection values) { return new FullTextFilterImpl(values); } - public static FullTextFilter createFullText(String... values){ + public static FullTextFilter createFullText(String... values) { return new FullTextFilterImpl(Arrays.asList(values)); } @@ -78,14 +77,14 @@ protected void performFreeze() { @Override public void checkConsistence(boolean requireDefinitions) { if (values == null) { - throw new IllegalArgumentException("Null 'values' in "+this); + throw new IllegalArgumentException("Null 'values' in " + this); } if (values.isEmpty()) { - throw new IllegalArgumentException("No values in "+this); + throw new IllegalArgumentException("No values in " + this); } - for (String value: values) { + for (String value : values) { if (StringUtils.isBlank(value)) { - throw new IllegalArgumentException("Empty value in "+this); + throw new IllegalArgumentException("Empty value in " + this); } } } @@ -98,7 +97,7 @@ public String debugDump(int indent) { if (values != null) { sb.append("\n"); for (String value : values) { - DebugUtil.indentDebugDump(sb, indent+1); + DebugUtil.indentDebugDump(sb, indent + 1); sb.append(value); sb.append("\n"); } @@ -113,7 +112,7 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append("FULLTEXT: "); if (values != null) { - sb.append(values.stream().collect(Collectors.joining("; "))); + sb.append(String.join("; ", values)); } return sb.toString(); } @@ -132,8 +131,12 @@ public boolean match(PrismContainerValue value, MatchingRuleRegistry matchingRul @Override public boolean equals(Object o, boolean exact) { - if (this == o) return true; - if (!(o instanceof FullTextFilterImpl)) return false; + if (this == o) { + return true; + } + if (!(o instanceof FullTextFilterImpl)) { + return false; + } FullTextFilterImpl that = (FullTextFilterImpl) o; return Objects.equals(values, that.values) && Objects.equals(expression, that.expression); diff --git a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/InOidFilterImpl.java b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/InOidFilterImpl.java index 03cffa844cb..52f9a47757b 100644 --- a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/InOidFilterImpl.java +++ b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/InOidFilterImpl.java @@ -1,22 +1,21 @@ /* - * Copyright (c) 2010-2018 Evolveum and contributors + * Copyright (C) 2010-2021 Evolveum and contributors * * This work is dual-licensed under the Apache License 2.0 * and European Union Public License. See LICENSE file for details. */ - package com.evolveum.midpoint.prism.impl.query; import java.util.*; -import com.evolveum.midpoint.prism.ExpressionWrapper; -import com.evolveum.midpoint.prism.PrismContainer; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.query.InOidFilter; import org.apache.commons.lang.StringUtils; +import com.evolveum.midpoint.prism.ExpressionWrapper; +import com.evolveum.midpoint.prism.PrismContainer; import com.evolveum.midpoint.prism.PrismContainerValue; +import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.match.MatchingRuleRegistry; +import com.evolveum.midpoint.prism.query.InOidFilter; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.exception.SchemaException; @@ -24,39 +23,39 @@ public final class InOidFilterImpl extends ObjectFilterImpl implements InOidFilt private List oids; private ExpressionWrapper expression; - private boolean considerOwner; // temporary hack (checks owner OID) + private final boolean considerOwner; private InOidFilterImpl(boolean considerOwner, Collection oids) { this.considerOwner = considerOwner; setOids(oids); } - private InOidFilterImpl(boolean considerOwner, ExpressionWrapper expression){ + private InOidFilterImpl(boolean considerOwner, ExpressionWrapper expression) { this.considerOwner = considerOwner; this.expression = expression; } - public static InOidFilter createInOid(boolean considerOwner, Collection oids){ + public static InOidFilter createInOid(boolean considerOwner, Collection oids) { return new InOidFilterImpl(considerOwner, oids); } - public static InOidFilter createInOid(Collection oids){ + public static InOidFilter createInOid(Collection oids) { return new InOidFilterImpl(false, oids); } - public static InOidFilter createInOid(String... oids){ + public static InOidFilter createInOid(String... oids) { return new InOidFilterImpl(false, Arrays.asList(oids)); } - public static InOidFilter createOwnerHasOidIn(Collection oids){ + public static InOidFilter createOwnerHasOidIn(Collection oids) { return new InOidFilterImpl(true, oids); } - public static InOidFilter createOwnerHasOidIn(String... oids){ + public static InOidFilter createOwnerHasOidIn(String... oids) { return new InOidFilterImpl(true, Arrays.asList(oids)); } - public static InOidFilter createInOid(boolean considerOwner, ExpressionWrapper expression){ + public static InOidFilter createInOid(boolean considerOwner, ExpressionWrapper expression) { return new InOidFilterImpl(considerOwner, expression); } @@ -96,11 +95,11 @@ protected void performFreeze() { @Override public void checkConsistence(boolean requireDefinitions) { if (oids == null) { - throw new IllegalArgumentException("Null oids in "+this); + throw new IllegalArgumentException("Null oids in " + this); } - for (String oid: oids) { + for (String oid : oids) { if (StringUtils.isBlank(oid)) { - throw new IllegalArgumentException("Empty oid in "+this); + throw new IllegalArgumentException("Empty oid in " + this); } } } @@ -109,15 +108,15 @@ public void checkConsistence(boolean requireDefinitions) { public String debugDump(int indent) { StringBuilder sb = new StringBuilder(); DebugUtil.indentDebugDump(sb, indent); - sb.append("IN OID: "); + sb.append("IN OID"); if (considerOwner) { - sb.append("(for owner)"); + sb.append(" (for owner)"); } - sb.append("VALUE:"); + sb.append(": "); if (getOids() != null) { for (String oid : getOids()) { sb.append("\n"); - DebugUtil.indentDebugDump(sb, indent+1); + DebugUtil.indentDebugDump(sb, indent + 1); sb.append(oid); } } else { @@ -125,21 +124,29 @@ public String debugDump(int indent) { } return sb.toString(); - } @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("IN OID: "); - if (getOids() != null){ + sb.append("IN OID"); + if (considerOwner) { + sb.append(" (for owner)"); + } + sb.append(": "); + if (getOids() != null) { + boolean first = true; for (String value : getOids()) { if (value == null) { sb.append("null"); } else { sb.append(value); } - sb.append("; "); + if (first) { + first = false; + } else { + sb.append("; "); + } } } return sb.toString(); @@ -155,7 +162,7 @@ public InOidFilterImpl clone() { @Override public boolean match(PrismContainerValue value, MatchingRuleRegistry matchingRuleRegistry) throws SchemaException { if (value == null) { - return false; // just for sure + return false; // just for sure } // are we a prism object? @@ -163,38 +170,37 @@ public boolean match(PrismContainerValue value, MatchingRuleRegistry matchingRul if (considerOwner) { return false; } - String oid = ((PrismObject) (value.getParent())).getOid(); + String oid = ((PrismObject) (value.getParent())).getOid(); return StringUtils.isNotBlank(oid) && oids != null && oids.contains(oid); } - final PrismContainerValue pcvToConsider; + PrismContainerValue pcvToConsider; if (considerOwner) { if (!(value.getParent() instanceof PrismContainer)) { return false; } - PrismContainer container = (PrismContainer) value.getParent(); - if (!(container.getParent() instanceof PrismContainerValue)) { - return false; - } - pcvToConsider = container.getParent(); + pcvToConsider = ((PrismContainer) value.getParent()).getParent(); } else { pcvToConsider = value; } - return pcvToConsider.getId() != null && oids.contains(pcvToConsider.getId()); + return pcvToConsider != null + && pcvToConsider.getId() != null + && oids.contains(pcvToConsider.getId().toString()); } @Override public boolean equals(Object o, boolean exact) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - InOidFilterImpl that = (InOidFilterImpl) o; - - if (considerOwner != that.considerOwner) return false; - if (oids != null ? !oids.equals(that.oids) : that.oids != null) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { return false; } - return expression != null ? expression.equals(that.expression) : that.expression == null; + + InOidFilterImpl that = (InOidFilterImpl) o; + return considerOwner == that.considerOwner + && Objects.equals(oids, that.oids) + && Objects.equals(expression, that.expression); } diff --git a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/LogicalFilterImpl.java b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/LogicalFilterImpl.java index ed9eb37e5ca..18cf82cab06 100644 --- a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/LogicalFilterImpl.java +++ b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/LogicalFilterImpl.java @@ -1,20 +1,20 @@ /* - * Copyright (c) 2010-2018 Evolveum and contributors + * Copyright (C) 2010-2021 Evolveum and contributors * * This work is dual-licensed under the Apache License 2.0 * and European Union Public License. See LICENSE file for details. */ - package com.evolveum.midpoint.prism.impl.query; import java.util.ArrayList; import java.util.List; +import com.google.common.collect.ImmutableList; + import com.evolveum.midpoint.prism.query.LogicalFilter; import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.prism.query.Visitor; import com.evolveum.midpoint.util.DebugUtil; -import com.google.common.collect.ImmutableList; public abstract class LogicalFilterImpl extends ObjectFilterImpl implements LogicalFilter { @@ -22,7 +22,7 @@ public abstract class LogicalFilterImpl extends ObjectFilterImpl implements Logi @Override public List getConditions() { - if (conditions == null){ + if (conditions == null) { conditions = new ArrayList<>(); } return conditions; @@ -64,7 +64,7 @@ protected List getClonedConditions() { return null; } List clonedConditions = new ArrayList<>(conditions.size()); - for (ObjectFilter condition: conditions) { + for (ObjectFilter condition : conditions) { clonedConditions.add(condition.clone()); } return clonedConditions; @@ -78,14 +78,14 @@ public boolean isEmpty() { @Override public void checkConsistence(boolean requireDefinitions) { if (conditions == null) { - throw new IllegalArgumentException("Null conditions in "+this); + throw new IllegalArgumentException("Null conditions in " + this); } if (conditions.isEmpty()) { - throw new IllegalArgumentException("Empty conditions in "+this); + throw new IllegalArgumentException("Empty conditions in " + this); } - for (ObjectFilter condition: conditions) { + for (ObjectFilter condition : conditions) { if (condition == null) { - throw new IllegalArgumentException("Null subfilter in "+this); + throw new IllegalArgumentException("Null subfilter in " + this); } condition.checkConsistence(requireDefinitions); } @@ -94,7 +94,7 @@ public void checkConsistence(boolean requireDefinitions) { @Override public void accept(Visitor visitor) { super.accept(visitor); - for (ObjectFilter condition: getConditions()) { + for (ObjectFilter condition : getConditions()) { condition.accept(visitor); } } @@ -115,9 +115,12 @@ public int hashCode() { @Override public boolean equals(Object obj, boolean exact) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } LogicalFilterImpl other = (LogicalFilterImpl) obj; if (conditions != null) { if (conditions.size() != other.conditions.size()) { @@ -139,7 +142,7 @@ public String debugDump(int indent) { StringBuilder sb = new StringBuilder(); DebugUtil.indentDebugDump(sb, indent); sb.append(getDebugDumpOperationName()).append(":"); - for (ObjectFilter filter : getConditions()){ + for (ObjectFilter filter : getConditions()) { sb.append("\n"); sb.append(filter.debugDump(indent + 1)); } @@ -151,10 +154,10 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getDebugDumpOperationName()); sb.append("("); - for (int i = 0; i < getConditions().size(); i++){ + for (int i = 0; i < getConditions().size(); i++) { sb.append(getConditions().get(i)); if (i != getConditions().size() - 1) { - sb.append(","); + sb.append("; "); // clearer separation than with ',' used in value filters } } sb.append(")"); diff --git a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/ObjectQueryImpl.java b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/ObjectQueryImpl.java index a3c0765f6a2..5a834ca46b3 100644 --- a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/ObjectQueryImpl.java +++ b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/ObjectQueryImpl.java @@ -1,17 +1,16 @@ /* - * Copyright (c) 2010-2018 Evolveum and contributors + * Copyright (C) 2010-2021 Evolveum and contributors * * This work is dual-licensed under the Apache License 2.0 * and European Union Public License. See LICENSE file for details. */ - package com.evolveum.midpoint.prism.impl.query; +import com.evolveum.midpoint.prism.impl.xnode.XNodeImpl; import com.evolveum.midpoint.prism.query.AllFilter; import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.prism.query.ObjectPaging; import com.evolveum.midpoint.prism.query.ObjectQuery; -import com.evolveum.midpoint.prism.impl.xnode.XNodeImpl; import com.evolveum.midpoint.util.DebugUtil; public class ObjectQueryImpl implements ObjectQuery { @@ -74,6 +73,7 @@ public static ObjectQuery createObjectQuery(ObjectFilter filter, ObjectPaging pa return query; } + @SuppressWarnings("MethodDoesntCallSuperMethod") public ObjectQueryImpl clone() { ObjectQueryImpl clone = cloneEmpty(); if (this.filter != null) { @@ -128,20 +128,20 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Q{"); if (filter != null) { - sb.append(filter.toString()); - sb.append(","); + sb.append(filter); } else { sb.append("null filter"); } + sb.append(", "); if (paging != null) { - sb.append(paging.toString()); - sb.append(","); + sb.append(paging); } else { sb.append("null paging"); } if (allowPartialResults) { - sb.append(",partial"); + sb.append(", partial"); } + sb.append('}'); return sb.toString(); } @@ -160,9 +160,6 @@ public Integer getOffset() { if (paging == null) { return null; } -// if (paging.getCookie() != null) { -// throw new UnsupportedOperationException("Paging cookie is not supported here."); -// } return paging.getOffset(); } @@ -171,9 +168,6 @@ public Integer getMaxSize() { if (paging == null) { return null; } -// if (paging.getCookie() != null) { -// throw new UnsupportedOperationException("Paging cookie is not supported here."); -// } return paging.getMaxSize(); } @@ -187,8 +181,12 @@ public boolean equivalent(Object o) { } public boolean equals(Object o, boolean exact) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } ObjectQueryImpl that = (ObjectQueryImpl) o; @@ -199,7 +197,6 @@ public boolean equals(Object o, boolean exact) { return false; } return paging != null ? paging.equals(that.paging, exact) : that.paging == null; - } @Override diff --git a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/OrgFilterImpl.java b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/OrgFilterImpl.java index e8a6d9d0da8..1f3c864dc90 100644 --- a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/OrgFilterImpl.java +++ b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/OrgFilterImpl.java @@ -1,12 +1,13 @@ /* - * Copyright (c) 2010-2018 Evolveum and contributors + * Copyright (C) 2010-2021 Evolveum and contributors * * This work is dual-licensed under the Apache License 2.0 * and European Union Public License. See LICENSE file for details. */ - package com.evolveum.midpoint.prism.impl.query; +import java.util.Objects; + import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismReferenceValue; import com.evolveum.midpoint.prism.impl.PrismReferenceValueImpl; @@ -80,7 +81,7 @@ protected void performFreeze() { @Override public void checkConsistence(boolean requireDefinitions) { if (!root && baseOrgRef == null) { - throw new IllegalArgumentException("Null baseOrgRef in "+this); + throw new IllegalArgumentException("Null baseOrgRef in " + this); } } @@ -96,18 +97,16 @@ public int hashCode() { @Override public boolean equals(Object obj, boolean exact) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - OrgFilterImpl other = (OrgFilterImpl) obj; - if (baseOrgRef == null) { - if (other.baseOrgRef != null) return false; - } else if (!baseOrgRef.equals(other.baseOrgRef)) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { return false; } - if (scope != other.scope) return false; - if (root != other.root) return false; - return true; + OrgFilterImpl other = (OrgFilterImpl) obj; + return Objects.equals(baseOrgRef, other.baseOrgRef) + && scope == other.scope + && root == other.root; } // Just to make checkstyle happy @@ -143,8 +142,11 @@ public String debugDump(int indent) { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("ORG: "); + if (isRoot()) { + sb.append("ROOT"); + } if (getOrgRef() != null) { - sb.append(getOrgRef().toString()); + sb.append(getOrgRef()); sb.append(", "); } if (getScope() != null) { diff --git a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/ValueFilterImpl.java b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/ValueFilterImpl.java index f9e97b175c4..7d18dce3391 100644 --- a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/ValueFilterImpl.java +++ b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/query/ValueFilterImpl.java @@ -323,7 +323,7 @@ protected void debugDump(int indent, StringBuilder sb) { sb.append("\n"); DebugUtil.indentDebugDump(sb, indent + 1); sb.append("PATH: "); - sb.append(getFullPath().toString()); + sb.append(getFullPath()); sb.append("\n"); DebugUtil.indentDebugDump(sb, indent + 1); @@ -358,7 +358,7 @@ protected void debugDump(int indent, StringBuilder sb) { sb.append("\n"); DebugUtil.indentDebugDump(sb, indent + 1); sb.append("RIGHT SIDE PATH: "); - sb.append(getFullPath().toString()); + sb.append(getFullPath()); sb.append("\n"); DebugUtil.indentDebugDump(sb, indent + 1); sb.append("RIGHT SIDE DEF: "); @@ -379,15 +379,15 @@ protected void debugDump(int indent, StringBuilder sb) { } protected String toString(StringBuilder sb) { - sb.append(getFullPath().toString()); - sb.append(","); + sb.append(getFullPath()); + sb.append(", "); if (getValues() != null) { for (int i = 0; i < getValues().size(); i++) { PrismValue value = getValues().get(i); if (value == null) { sb.append("null"); } else { - sb.append(value.toString()); + sb.append(value); } if (i != getValues().size() - 1) { sb.append(","); From 95ca85784167ed7fa41f14dfd65de17f0a4b8c13 Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Tue, 25 May 2021 11:35:48 +0200 Subject: [PATCH 04/23] repo-sqale: added m_assignment_holder to SQL schema + objectType CHECKs CHECK constraints for objectType were added to prune query plan if "WHERE objecttype='...'" is used, although this is probably obscure condition, I don't plan to use it for TYPE filter either. It's always better to use subtable matching the type. Also "objecttype='FOCUS'" does not select anything, by definition it can't match any row in SQL table as no real row is 'FOCUS'. --- repo/repo-sqale/sql/pgnew-repo.sql | 184 +++++++++++++++++++---------- 1 file changed, 121 insertions(+), 63 deletions(-) diff --git a/repo/repo-sqale/sql/pgnew-repo.sql b/repo/repo-sqale/sql/pgnew-repo.sql index 039f9ddebbd..b218c6c8faf 100644 --- a/repo/repo-sqale/sql/pgnew-repo.sql +++ b/repo/repo-sqale/sql/pgnew-repo.sql @@ -215,17 +215,21 @@ INSERT INTO m_uri (id, uri) -- See https://docs.evolveum.com/midpoint/architecture/archive/data-model/midpoint-common-schema/objecttype/ -- Following is recommended for each concrete table (see m_resource for example): -- 1) override OID like this (PK+FK): oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), --- 2) define object type class (change value): objectType ObjectType GENERATED ALWAYS AS ('XY') STORED, +-- 2) define object type class (change value as needed): +-- objectType ObjectType GENERATED ALWAYS AS ('XY') STORED CHECK (objectType = 'XY'), +-- The CHECK part helps with query optimization when the column is uses in WHERE. -- 3) add three triggers _oid_{insert|update|delete}_tr -- 4) add indexes for nameOrig and nameNorm columns (nameNorm as unique) -- 5) the rest varies on the concrete table, other indexes or constraints, etc. -- 6) any required FK must be created on the concrete table, even for inherited columns - CREATE TABLE m_object ( -- Default OID value is covered by INSERT triggers. No PK defined on abstract tables. oid UUID NOT NULL, -- objectType will be overridden with GENERATED value in concrete table - objectType ObjectType NOT NULL, + -- CHECK helps optimizer to avoid this table when different type is asked, mind that + -- WHERE objectType = 'OBJECT' never returns anything (unlike select * from m_object). + -- We don't want this check to be inherited as it would prevent any inserts of other types. + objectType ObjectType NOT NULL CHECK (objectType = 'OBJECT') NO INHERIT, nameOrig TEXT NOT NULL, nameNorm TEXT NOT NULL, fullObject BYTEA, @@ -262,6 +266,16 @@ CREATE TABLE m_object ( ); -- No indexes here, always add indexes and referential constraints on concrete sub-tables. +-- Represents AssignmentHolderType (all objects except shadows) +-- extending m_object, but still abstract, hence the CHECK (false) +CREATE TABLE m_assignment_holder ( + -- objectType will be overridden with GENERATED value in concrete table + objectType ObjectType NOT NULL CHECK (objectType = 'ASSIGNMENT_HOLDER') NO INHERIT, + + CHECK (FALSE) NO INHERIT +) + INHERITS (m_object); + -- Purely abstract table (no entries are allowed). Represents Containerable/PrismContainerValue. -- Allows querying all separately persisted containers, but not necessary for the application. CREATE TABLE m_container ( @@ -302,7 +316,8 @@ CREATE TABLE m_reference ( -- stores AssignmentHolderType/archetypeRef CREATE TABLE m_ref_archetype ( ownerOid UUID NOT NULL REFERENCES m_object_oid(oid) ON DELETE CASCADE, - referenceType ReferenceType GENERATED ALWAYS AS ('ARCHETYPE') STORED, + referenceType ReferenceType GENERATED ALWAYS AS ('ARCHETYPE') STORED + CHECK (referenceType = 'ARCHETYPE'), PRIMARY KEY (ownerOid, relationId, targetOid) ) @@ -314,7 +329,8 @@ CREATE INDEX m_ref_archetypeTargetOidRelationId_idx -- stores AssignmentHolderType/delegatedRef CREATE TABLE m_ref_delegated ( ownerOid UUID NOT NULL REFERENCES m_object_oid(oid) ON DELETE CASCADE, - referenceType ReferenceType GENERATED ALWAYS AS ('DELEGATED') STORED, + referenceType ReferenceType GENERATED ALWAYS AS ('DELEGATED') STORED + CHECK (referenceType = 'DELEGATED'), PRIMARY KEY (ownerOid, relationId, targetOid) ) @@ -326,7 +342,8 @@ CREATE INDEX m_ref_delegatedTargetOidRelationId_idx -- stores ObjectType/metadata/createApproverRef CREATE TABLE m_ref_object_create_approver ( ownerOid UUID NOT NULL REFERENCES m_object_oid(oid) ON DELETE CASCADE, - referenceType ReferenceType GENERATED ALWAYS AS ('OBJECT_CREATE_APPROVER') STORED, + referenceType ReferenceType GENERATED ALWAYS AS ('OBJECT_CREATE_APPROVER') STORED + CHECK (referenceType = 'OBJECT_CREATE_APPROVER'), PRIMARY KEY (ownerOid, relationId, targetOid) ) @@ -338,7 +355,8 @@ CREATE INDEX m_ref_object_create_approverTargetOidRelationId_idx -- stores ObjectType/metadata/modifyApproverRef CREATE TABLE m_ref_object_modify_approver ( ownerOid UUID NOT NULL REFERENCES m_object_oid(oid) ON DELETE CASCADE, - referenceType ReferenceType GENERATED ALWAYS AS ('OBJECT_MODIFY_APPROVER') STORED, + referenceType ReferenceType GENERATED ALWAYS AS ('OBJECT_MODIFY_APPROVER') STORED + CHECK (referenceType = 'OBJECT_MODIFY_APPROVER'), PRIMARY KEY (ownerOid, relationId, targetOid) ) @@ -350,7 +368,8 @@ CREATE INDEX m_ref_object_modify_approverTargetOidRelationId_idx -- stores AssignmentHolderType/roleMembershipRef CREATE TABLE m_ref_role_membership ( ownerOid UUID NOT NULL REFERENCES m_object_oid(oid) ON DELETE CASCADE, - referenceType ReferenceType GENERATED ALWAYS AS ('ROLE_MEMBERSHIP') STORED, + referenceType ReferenceType GENERATED ALWAYS AS ('ROLE_MEMBERSHIP') STORED + CHECK (referenceType = 'ROLE_MEMBERSHIP'), PRIMARY KEY (ownerOid, relationId, targetOid) ) @@ -362,10 +381,10 @@ CREATE INDEX m_ref_role_memberTargetOidRelationId_idx -- region FOCUS related tables -- Represents FocusType (Users, Roles, ...), see https://docs.evolveum.com/midpoint/reference/schema/focus-and-projections/ --- extending m_object, but still abstract, hence DEFAULT for objectType and CHECK (false) +-- extending m_object, but still abstract, hence the CHECK (false) CREATE TABLE m_focus ( - -- will be overridden with GENERATED value in concrete table - objectType ObjectType NOT NULL, + -- objectType will be overridden with GENERATED value in concrete table + objectType ObjectType NOT NULL CHECK (objectType = 'FOCUS') NO INHERIT, costCenter TEXT, emailAddress TEXT, photo BYTEA, -- will be TOAST-ed if necessary @@ -393,12 +412,13 @@ CREATE TABLE m_focus ( CHECK (FALSE) NO INHERIT ) - INHERITS (m_object); + INHERITS (m_assignment_holder); -- stores FocusType/personaRef CREATE TABLE m_ref_persona ( ownerOid UUID NOT NULL REFERENCES m_object_oid(oid) ON DELETE CASCADE, - referenceType ReferenceType GENERATED ALWAYS AS ('PERSONA') STORED, + referenceType ReferenceType GENERATED ALWAYS AS ('PERSONA') STORED + CHECK (referenceType = 'PERSONA'), PRIMARY KEY (ownerOid, relationId, targetOid) ) @@ -410,7 +430,8 @@ CREATE INDEX m_ref_personaTargetOidRelationId_idx -- stores FocusType/linkRef ("projection" is newer and better term) CREATE TABLE m_ref_projection ( ownerOid UUID NOT NULL REFERENCES m_object_oid(oid) ON DELETE CASCADE, - referenceType ReferenceType GENERATED ALWAYS AS ('PROJECTION') STORED, + referenceType ReferenceType GENERATED ALWAYS AS ('PROJECTION') STORED + CHECK (referenceType = 'PROJECTION'), PRIMARY KEY (ownerOid, relationId, targetOid) ) @@ -422,7 +443,8 @@ CREATE INDEX m_ref_projectionTargetOidRelationId_idx -- Represents GenericObjectType, see https://docs.evolveum.com/midpoint/reference/schema/generic-objects/ CREATE TABLE m_generic_object ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), - objectType ObjectType GENERATED ALWAYS AS ('GENERIC_OBJECT') STORED, + objectType ObjectType GENERATED ALWAYS AS ('GENERIC_OBJECT') STORED + CHECK (objectType = 'GENERIC_OBJECT'), genericObjectTypeId INTEGER NOT NULL REFERENCES m_uri(id) -- GenericObjectType#objectType ) INHERITS (m_focus); @@ -444,7 +466,8 @@ ALTER TABLE m_generic_object ADD CONSTRAINT m_generic_object_nameNorm_key UNIQUE -- Represents UserType, see https://docs.evolveum.com/midpoint/architecture/archive/data-model/midpoint-common-schema/usertype/ CREATE TABLE m_user ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), - objectType ObjectType GENERATED ALWAYS AS ('USER') STORED, + objectType ObjectType GENERATED ALWAYS AS ('USER') STORED + CHECK (objectType = 'USER'), additionalNameOrig TEXT, additionalNameNorm TEXT, employeeNumber TEXT, @@ -498,8 +521,8 @@ CREATE TABLE m_user_organizational_unit ( -- region ROLE related tables -- Represents AbstractRoleType, see https://docs.evolveum.com/midpoint/architecture/concepts/abstract-role/ CREATE TABLE m_abstract_role ( - -- will be overridden with GENERATED value in concrete table - objectType ObjectType NOT NULL, + -- objectType will be overridden with GENERATED value in concrete table + objectType ObjectType NOT NULL CHECK (objectType = 'ABSTRACT_ROLE') NO INHERIT, autoAssignEnabled BOOLEAN, displayNameOrig TEXT, displayNameNorm TEXT, @@ -520,7 +543,8 @@ CREATE INDEX iAutoassignEnabled ON m_abstract_role(autoassign_enabled); -- Represents RoleType, see https://docs.evolveum.com/midpoint/architecture/archive/data-model/midpoint-common-schema/roletype/ CREATE TABLE m_role ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), - objectType ObjectType GENERATED ALWAYS AS ('ROLE') STORED, + objectType ObjectType GENERATED ALWAYS AS ('ROLE') STORED + CHECK (objectType = 'ROLE'), roleType TEXT ) INHERITS (m_abstract_role); @@ -538,7 +562,8 @@ ALTER TABLE m_role ADD CONSTRAINT m_role_nameNorm_key UNIQUE (nameNorm); -- Represents ServiceType, see https://wiki.evolveum.com/display/midPoint/Service+Account+Management CREATE TABLE m_service ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), - objectType ObjectType GENERATED ALWAYS AS ('SERVICE') STORED, + objectType ObjectType GENERATED ALWAYS AS ('SERVICE') STORED + CHECK (objectType = 'SERVICE'), displayOrder INTEGER ) INHERITS (m_abstract_role); @@ -557,6 +582,7 @@ ALTER TABLE m_service ADD CONSTRAINT m_service_nameNorm_key UNIQUE (nameNorm); CREATE TABLE m_archetype ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), objectType ObjectType GENERATED ALWAYS AS ('ARCHETYPE') STORED + CHECK (objectType = 'ARCHETYPE') ) INHERITS (m_abstract_role); @@ -575,7 +601,8 @@ ALTER TABLE m_archetype ADD CONSTRAINT m_archetype_nameNorm_key UNIQUE (nameNorm -- Represents OrgType, see https://docs.evolveum.com/midpoint/architecture/archive/data-model/midpoint-common-schema/orgtype/ CREATE TABLE m_org ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), - objectType ObjectType GENERATED ALWAYS AS ('ORG') STORED, + objectType ObjectType GENERATED ALWAYS AS ('ORG') STORED + CHECK (objectType = 'ORG'), displayOrder INTEGER, tenant BOOLEAN ) @@ -595,7 +622,8 @@ CREATE INDEX m_org_displayOrder_idx ON m_org (displayOrder); -- stores ObjectType/parentOrgRef CREATE TABLE m_ref_object_parent_org ( ownerOid UUID NOT NULL REFERENCES m_object_oid(oid) ON DELETE CASCADE, - referenceType ReferenceType GENERATED ALWAYS AS ('OBJECT_PARENT_ORG') STORED, + referenceType ReferenceType GENERATED ALWAYS AS ('OBJECT_PARENT_ORG') STORED + CHECK (referenceType = 'OBJECT_PARENT_ORG'), -- TODO wouldn't (ownerOid, targetOid, relationId) perform better for typical queries? PRIMARY KEY (ownerOid, relationId, targetOid) @@ -702,14 +730,15 @@ END; $$; -- Represents ResourceType, see https://wiki.evolveum.com/display/midPoint/Resource+Configuration CREATE TABLE m_resource ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), - objectType ObjectType GENERATED ALWAYS AS ('RESOURCE') STORED, + objectType ObjectType GENERATED ALWAYS AS ('RESOURCE') STORED + CHECK (objectType = 'RESOURCE'), business_administrativeState ResourceAdministrativeStateType, operationalState_lastAvailabilityStatus AvailabilityStatusType, connectorRefTargetOid UUID, connectorRefTargetType ObjectType, connectorRefRelationId INTEGER REFERENCES m_uri(id) ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_resource_oid_insert_tr BEFORE INSERT ON m_resource FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -738,7 +767,8 @@ CREATE INDEX m_ref_resource_biz_config_approverTargetOidRelationId_idx -- and also https://docs.evolveum.com/midpoint/reference/schema/focus-and-projections/ CREATE TABLE m_shadow ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), - objectType ObjectType GENERATED ALWAYS AS ('SHADOW') STORED, + objectType ObjectType GENERATED ALWAYS AS ('SHADOW') STORED + CHECK (objectType = 'SHADOW'), objectClassId INTEGER REFERENCES m_uri(id), resourceRefTargetOid UUID, resourceRefTargetType ObjectType, @@ -788,10 +818,11 @@ ALTER TABLE m_shadow ADD CONSTRAINT iPrimaryIdentifierValueWithOC -- Represents NodeType, see https://wiki.evolveum.com/display/midPoint/Managing+cluster+nodes CREATE TABLE m_node ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), - objectType ObjectType GENERATED ALWAYS AS ('NODE') STORED, + objectType ObjectType GENERATED ALWAYS AS ('NODE') STORED + CHECK (objectType = 'NODE'), nodeIdentifier TEXT ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_node_oid_insert_tr BEFORE INSERT ON m_node FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -808,8 +839,9 @@ ALTER TABLE m_node ADD CONSTRAINT m_node_nameNorm_key UNIQUE (nameNorm); CREATE TABLE m_system_configuration ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), objectType ObjectType GENERATED ALWAYS AS ('SYSTEM_CONFIGURATION') STORED + CHECK (objectType = 'SYSTEM_CONFIGURATION') ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_system_configuration_oid_insert_tr BEFORE INSERT ON m_system_configuration FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -824,8 +856,9 @@ CREATE TRIGGER m_system_configuration_oid_delete_tr AFTER DELETE ON m_system_con CREATE TABLE m_security_policy ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), objectType ObjectType GENERATED ALWAYS AS ('SECURITY_POLICY') STORED + CHECK (objectType = 'SECURITY_POLICY') ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_security_policy_oid_insert_tr BEFORE INSERT ON m_security_policy FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -840,8 +873,9 @@ CREATE TRIGGER m_security_policy_oid_delete_tr AFTER DELETE ON m_security_policy CREATE TABLE m_object_collection ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), objectType ObjectType GENERATED ALWAYS AS ('OBJECT_COLLECTION') STORED + CHECK (objectType = 'OBJECT_COLLECTION') ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_object_collection_oid_insert_tr BEFORE INSERT ON m_object_collection FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -857,8 +891,9 @@ ALTER TABLE m_object_collection ADD CONSTRAINT m_object_collection_nameNorm_key CREATE TABLE m_dashboard ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), objectType ObjectType GENERATED ALWAYS AS ('DASHBOARD') STORED + CHECK (objectType = 'DASHBOARD') ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_dashboard_oid_insert_tr BEFORE INSERT ON m_dashboard FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -874,8 +909,9 @@ ALTER TABLE m_dashboard ADD CONSTRAINT m_dashboard_nameNorm_key UNIQUE (nameNorm CREATE TABLE m_value_policy ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), objectType ObjectType GENERATED ALWAYS AS ('VALUE_POLICY') STORED + CHECK (objectType = 'VALUE_POLICY') ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_value_policy_oid_insert_tr BEFORE INSERT ON m_value_policy FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -890,11 +926,12 @@ ALTER TABLE m_value_policy ADD CONSTRAINT m_value_policy_nameNorm_key UNIQUE (na -- Represents ReportType, see https://wiki.evolveum.com/display/midPoint/Report+Configuration CREATE TABLE m_report ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), - objectType ObjectType GENERATED ALWAYS AS ('REPORT') STORED, + objectType ObjectType GENERATED ALWAYS AS ('REPORT') STORED + CHECK (objectType = 'REPORT'), orientation OrientationType, parent BOOLEAN ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_report_oid_insert_tr BEFORE INSERT ON m_report FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -910,12 +947,13 @@ ALTER TABLE m_report ADD CONSTRAINT m_report_nameNorm_key UNIQUE (nameNorm); -- Represents ReportDataType, see also m_report above CREATE TABLE m_report_data ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), - objectType ObjectType GENERATED ALWAYS AS ('REPORT_DATA') STORED, + objectType ObjectType GENERATED ALWAYS AS ('REPORT_DATA') STORED + CHECK (objectType = 'REPORT_DATA'), reportRefTargetOid UUID, reportRefTargetType ObjectType, reportRefRelationId INTEGER REFERENCES m_uri(id) ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_report_data_oid_insert_tr BEFORE INSERT ON m_report_data FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -931,8 +969,9 @@ ALTER TABLE m_report_data ADD CONSTRAINT m_report_data_nameNorm_key UNIQUE (name CREATE TABLE m_lookup_table ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), objectType ObjectType GENERATED ALWAYS AS ('LOOKUP_TABLE') STORED + CHECK (objectType = 'LOOKUP_TABLE') ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_lookup_table_oid_insert_tr BEFORE INSERT ON m_lookup_table FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -947,7 +986,8 @@ ALTER TABLE m_lookup_table ADD CONSTRAINT m_lookup_table_nameNorm_key UNIQUE (na -- Represents LookupTableRowType, see also m_lookup_table above CREATE TABLE m_lookup_table_row ( ownerOid UUID NOT NULL REFERENCES m_lookup_table(oid) ON DELETE CASCADE, - containerType ContainerType GENERATED ALWAYS AS ('LOOKUP_TABLE_ROW') STORED, + containerType ContainerType GENERATED ALWAYS AS ('LOOKUP_TABLE_ROW') STORED + CHECK (containerType = 'LOOKUP_TABLE_ROW'), key TEXT, value TEXT, labelOrig TEXT, @@ -964,7 +1004,8 @@ ALTER TABLE m_lookup_table_row -- Represents ConnectorType, see https://wiki.evolveum.com/display/midPoint/Identity+Connectors CREATE TABLE m_connector ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), - objectType ObjectType GENERATED ALWAYS AS ('CONNECTOR') STORED, + objectType ObjectType GENERATED ALWAYS AS ('CONNECTOR') STORED + CHECK (objectType = 'CONNECTOR'), connectorBundle TEXT, -- typically a package name connectorType TEXT, -- typically a class name connectorVersion TEXT, @@ -974,7 +1015,7 @@ CREATE TABLE m_connector ( connectorHostRefRelationId INTEGER REFERENCES m_uri(id), targetSystemTypes TEXT[] -- TODO any strings? cached URIs? ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_connector_oid_insert_tr BEFORE INSERT ON m_connector FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -997,11 +1038,12 @@ ALTER TABLE m_connector ADD CONSTRAINT m_connector_nameNorm_key UNIQUE (nameNorm -- Represents ConnectorHostType, see https://wiki.evolveum.com/display/midPoint/Connector+Server CREATE TABLE m_connector_host ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), - objectType ObjectType GENERATED ALWAYS AS ('CONNECTOR_HOST') STORED, + objectType ObjectType GENERATED ALWAYS AS ('CONNECTOR_HOST') STORED + CHECK (objectType = 'CONNECTOR_HOST'), hostname TEXT, port TEXT ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_connector_host_oid_insert_tr BEFORE INSERT ON m_connector_host FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -1016,7 +1058,8 @@ ALTER TABLE m_connector_host ADD CONSTRAINT m_connector_host_nameNorm_key UNIQUE -- Represents persistent TaskType, see https://wiki.evolveum.com/display/midPoint/Task+Manager CREATE TABLE m_task ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), - objectType ObjectType GENERATED ALWAYS AS ('TASK') STORED, + objectType ObjectType GENERATED ALWAYS AS ('TASK') STORED + CHECK (objectType = 'TASK'), taskIdentifier TEXT, binding TaskBindingType, category TEXT, @@ -1040,7 +1083,7 @@ CREATE TABLE m_task ( waitingReason TaskWaitingReasonType, dependentTaskIdentifiers TEXT[] -- contains values of taskIdentifier ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_task_oid_insert_tr BEFORE INSERT ON m_task FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -1061,7 +1104,8 @@ CREATE INDEX m_task_dependentTaskIdentifiers_idx ON m_task USING GIN(dependentTa -- Represents CaseType, see https://wiki.evolveum.com/display/midPoint/Case+Management CREATE TABLE m_case ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), - objectType ObjectType GENERATED ALWAYS AS ('CASE') STORED, + objectType ObjectType GENERATED ALWAYS AS ('CASE') STORED + CHECK (objectType = 'CASE'), state TEXT, closeTimestamp TIMESTAMPTZ, objectRefTargetOid UUID, @@ -1077,7 +1121,7 @@ CREATE TABLE m_case ( targetRefTargetType ObjectType, targetRefRelationId INTEGER REFERENCES m_uri(id) ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_case_oid_insert_tr BEFORE INSERT ON m_case FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -1097,7 +1141,8 @@ CREATE INDEX m_case_closeTimestamp_idx ON m_case(closeTimestamp); CREATE TABLE m_case_wi ( ownerOid UUID NOT NULL REFERENCES m_object_oid(oid) ON DELETE CASCADE, - containerType ContainerType GENERATED ALWAYS AS ('CASE_WORK_ITEM') STORED, + containerType ContainerType GENERATED ALWAYS AS ('CASE_WORK_ITEM') STORED + CHECK (containerType = 'CASE_WORK_ITEM'), closeTimestamp TIMESTAMPTZ, createTimestamp TIMESTAMPTZ, deadline TIMESTAMPTZ, @@ -1119,7 +1164,8 @@ CREATE TABLE m_case_wi ( -- Represents AccessCertificationDefinitionType, see https://wiki.evolveum.com/display/midPoint/Access+Certification CREATE TABLE m_access_cert_definition ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), - objectType ObjectType GENERATED ALWAYS AS ('ACCESS_CERTIFICATION_DEFINITION') STORED, + objectType ObjectType GENERATED ALWAYS AS ('ACCESS_CERTIFICATION_DEFINITION') STORED + CHECK (objectType = 'ACCESS_CERTIFICATION_DEFINITION'), handlerUriId INTEGER REFERENCES m_uri(id), lastCampaignStartedTimestamp TIMESTAMPTZ, lastCampaignClosedTimestamp TIMESTAMPTZ, @@ -1127,7 +1173,7 @@ CREATE TABLE m_access_cert_definition ( ownerRefTargetType ObjectType, ownerRefRelationId INTEGER REFERENCES m_uri(id) ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_access_cert_definition_oid_insert_tr BEFORE INSERT ON m_access_cert_definition FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -1144,7 +1190,8 @@ CREATE INDEX m_access_cert_definition_ext_idx ON m_access_cert_definition USING -- TODO not mapped yet CREATE TABLE m_access_cert_campaign ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), - objectType ObjectType GENERATED ALWAYS AS ('ACCESS_CERTIFICATION_CAMPAIGN') STORED, + objectType ObjectType GENERATED ALWAYS AS ('ACCESS_CERTIFICATION_CAMPAIGN') STORED + CHECK (objectType = 'ACCESS_CERTIFICATION_CAMPAIGN'), definitionRefTargetOid UUID, definitionRefTargetType ObjectType, definitionRefRelationId INTEGER REFERENCES m_uri(id), @@ -1158,7 +1205,7 @@ CREATE TABLE m_access_cert_campaign ( startTimestamp TIMESTAMPTZ, state INTEGER ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_access_cert_campaign_oid_insert_tr BEFORE INSERT ON m_access_cert_campaign FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -1174,7 +1221,8 @@ CREATE INDEX m_access_cert_campaign_ext_idx ON m_access_cert_campaign USING gin CREATE TABLE m_access_cert_case ( ownerOid UUID NOT NULL REFERENCES m_object_oid(oid) ON DELETE CASCADE, - containerType ContainerType GENERATED ALWAYS AS ('ACCESS_CERTIFICATION_CASE') STORED, + containerType ContainerType GENERATED ALWAYS AS ('ACCESS_CERTIFICATION_CASE') STORED + CHECK (containerType = 'ACCESS_CERTIFICATION_CASE'), administrativeStatus INTEGER, archiveTimestamp TIMESTAMPTZ, disableReason TEXT, @@ -1213,7 +1261,8 @@ CREATE TABLE m_access_cert_case ( CREATE TABLE m_access_cert_wi ( ownerOid UUID NOT NULL, -- PK+FK accCertCaseCid INTEGER NOT NULL, -- PK+FK - containerType ContainerType GENERATED ALWAYS AS ('ACCESS_CERTIFICATION_WORK_ITEM') STORED, + containerType ContainerType GENERATED ALWAYS AS ('ACCESS_CERTIFICATION_WORK_ITEM') STORED + CHECK (containerType = 'ACCESS_CERTIFICATION_WORK_ITEM'), closeTimestamp TIMESTAMPTZ, iteration INTEGER NOT NULL, outcome TEXT, @@ -1267,8 +1316,9 @@ CREATE INDEX iCertWorkItemRefTargetOid ON m_access_cert_wi_reference (targetOid) CREATE TABLE m_object_template ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), objectType ObjectType GENERATED ALWAYS AS ('OBJECT_TEMPLATE') STORED + CHECK (objectType = 'OBJECT_TEMPLATE') ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_object_template_oid_insert_tr BEFORE INSERT ON m_object_template FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -1283,7 +1333,8 @@ ALTER TABLE m_object_template ADD CONSTRAINT m_object_template_nameNorm_key UNIQ -- stores ObjectTemplateType/includeRef CREATE TABLE m_ref_include ( ownerOid UUID NOT NULL REFERENCES m_object_oid(oid) ON DELETE CASCADE, - referenceType ReferenceType GENERATED ALWAYS AS ('INCLUDE') STORED, + referenceType ReferenceType GENERATED ALWAYS AS ('INCLUDE') STORED + CHECK (referenceType = 'INCLUDE'), PRIMARY KEY (ownerOid, relationId, targetOid) ) @@ -1298,8 +1349,9 @@ CREATE INDEX m_ref_includeTargetOidRelationId_idx CREATE TABLE m_function_library ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), objectType ObjectType GENERATED ALWAYS AS ('FUNCTION_LIBRARY') STORED + CHECK (objectType = 'FUNCTION_LIBRARY') ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_function_library_oid_insert_tr BEFORE INSERT ON m_function_library FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -1315,8 +1367,9 @@ ALTER TABLE m_function_library ADD CONSTRAINT m_function_library_nameNorm_key UN CREATE TABLE m_sequence ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), objectType ObjectType GENERATED ALWAYS AS ('SEQUENCE') STORED + CHECK (objectType = 'SEQUENCE') ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_sequence_oid_insert_tr BEFORE INSERT ON m_sequence FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -1331,9 +1384,10 @@ ALTER TABLE m_sequence ADD CONSTRAINT m_sequence_nameNorm_key UNIQUE (nameNorm); -- Represents FormType, see https://wiki.evolveum.com/display/midPoint/Custom+forms CREATE TABLE m_form ( oid UUID NOT NULL PRIMARY KEY REFERENCES m_object_oid(oid), - objectType ObjectType GENERATED ALWAYS AS ('SEQUENCE') STORED + objectType ObjectType GENERATED ALWAYS AS ('FORM') STORED + CHECK (objectType = 'FORM') ) - INHERITS (m_object); + INHERITS (m_assignment_holder); CREATE TRIGGER m_form_oid_insert_tr BEFORE INSERT ON m_form FOR EACH ROW EXECUTE PROCEDURE insert_object_oid(); @@ -1422,7 +1476,8 @@ CREATE INDEX m_assignment_resourceRefTargetOid_idx ON m_assignment (resourceRefT CREATE TABLE m_assignment_ref_create_approver ( ownerOid UUID NOT NULL REFERENCES m_object_oid(oid) ON DELETE CASCADE, assignmentCid INTEGER NOT NULL, - referenceType ReferenceType GENERATED ALWAYS AS ('ASSIGNMENT_CREATE_APPROVER') STORED, + referenceType ReferenceType GENERATED ALWAYS AS ('ASSIGNMENT_CREATE_APPROVER') STORED + CHECK (referenceType = 'ASSIGNMENT_CREATE_APPROVER'), PRIMARY KEY (ownerOid, assignmentCid, referenceType, relationId, targetOid) ) @@ -1437,7 +1492,8 @@ ALTER TABLE m_assignment_ref_create_approver ADD CONSTRAINT m_assignment_ref_cre CREATE TABLE m_assignment_ref_modify_approver ( ownerOid UUID NOT NULL REFERENCES m_object_oid(oid) ON DELETE CASCADE, assignmentCid INTEGER NOT NULL, - referenceType ReferenceType GENERATED ALWAYS AS ('ASSIGNMENT_MODIFY_APPROVER') STORED, + referenceType ReferenceType GENERATED ALWAYS AS ('ASSIGNMENT_MODIFY_APPROVER') STORED + CHECK (referenceType = 'ASSIGNMENT_MODIFY_APPROVER'), PRIMARY KEY (ownerOid, assignmentCid, referenceType, relationId, targetOid) ) @@ -1453,7 +1509,8 @@ ALTER TABLE m_assignment_ref_modify_approver ADD CONSTRAINT m_assignment_ref_mod -- stores ObjectType/trigger (TriggerType) CREATE TABLE m_trigger ( ownerOid UUID NOT NULL REFERENCES m_object_oid(oid) ON DELETE CASCADE, - containerType ContainerType GENERATED ALWAYS AS ('TRIGGER') STORED, + containerType ContainerType GENERATED ALWAYS AS ('TRIGGER') STORED + CHECK (containerType = 'TRIGGER'), handlerUriId INTEGER REFERENCES m_uri(id), timestampValue TIMESTAMPTZ, @@ -1466,7 +1523,8 @@ CREATE INDEX m_trigger_timestampValue_idx ON m_trigger (timestampValue); -- stores ObjectType/operationExecution (OperationExecutionType) CREATE TABLE m_operation_execution ( ownerOid UUID NOT NULL REFERENCES m_object_oid(oid) ON DELETE CASCADE, - containerType ContainerType GENERATED ALWAYS AS ('OPERATION_EXECUTION') STORED, + containerType ContainerType GENERATED ALWAYS AS ('OPERATION_EXECUTION') STORED + CHECK (containerType = 'OPERATION_EXECUTION'), status OperationResultStatusType, recordType OperationExecutionRecordTypeType, initiatorRefTargetOid UUID, From 2a46d0ce83ad4b3c23929cd34eaf74be755abe62 Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Tue, 25 May 2021 16:01:01 +0200 Subject: [PATCH 05/23] repo-sqale: QAssignmentHolder fully incorporated into Q-hierarchy This eliminates the need for additional TYPE filter if AssignHolderType is queried (refineAssignmentHolderQuery from old repo). Also, mapping stuff is more clean now, QObject(Mapping) does not contain anything beyond ObjectType mapping. QCaseMapping#storeRelatedEntities fixed, now it calls super.method(). --- .../repo/sqale/qmodel/QObjectTemplate.java | 4 +- .../sqale/qmodel/QObjectTemplateMapping.java | 4 +- .../QAccessCertificationDefinition.java | 4 +- ...QAccessCertificationDefinitionMapping.java | 4 +- .../repo/sqale/qmodel/cases/QCase.java | 4 +- .../repo/sqale/qmodel/cases/QCaseMapping.java | 23 ++- .../sqale/qmodel/connector/QConnector.java | 4 +- .../qmodel/connector/QConnectorHost.java | 4 +- .../connector/QConnectorHostMapping.java | 4 +- .../qmodel/connector/QConnectorMapping.java | 4 +- .../repo/sqale/qmodel/focus/QFocus.java | 4 +- .../sqale/qmodel/focus/QFocusMapping.java | 4 +- .../qmodel/lookuptable/MLookupTable.java | 2 +- .../qmodel/lookuptable/QLookupTable.java | 4 +- .../lookuptable/QLookupTableMapping.java | 4 +- .../repo/sqale/qmodel/node/QNode.java | 4 +- .../repo/sqale/qmodel/node/QNodeMapping.java | 4 +- .../repo/sqale/qmodel/object/MObjectType.java | 3 +- .../qmodel/object/QAssignmentHolder.java | 33 ++++ .../object/QAssignmentHolderMapping.java | 83 +++++++-- .../sqale/qmodel/object/QObjectMapping.java | 35 +--- .../repo/sqale/qmodel/other/QDashboard.java | 4 +- .../sqale/qmodel/other/QDashboardMapping.java | 4 +- .../repo/sqale/qmodel/other/QForm.java | 4 +- .../repo/sqale/qmodel/other/QFormMapping.java | 4 +- .../sqale/qmodel/other/QFunctionLibrary.java | 4 +- .../qmodel/other/QFunctionLibraryMapping.java | 4 +- .../sqale/qmodel/other/QObjectCollection.java | 4 +- .../other/QObjectCollectionMapping.java | 4 +- .../repo/sqale/qmodel/other/QSequence.java | 4 +- .../sqale/qmodel/other/QSequenceMapping.java | 4 +- .../repo/sqale/qmodel/report/QReport.java | 4 +- .../repo/sqale/qmodel/report/QReportData.java | 4 +- .../qmodel/report/QReportDataMapping.java | 4 +- .../sqale/qmodel/report/QReportMapping.java | 4 +- .../repo/sqale/qmodel/resource/QResource.java | 4 +- .../qmodel/resource/QResourceMapping.java | 5 +- .../repo/sqale/qmodel/shadow/QShadow.java | 1 - .../sqale/qmodel/system/QSecurityPolicy.java | 4 +- .../qmodel/system/QSecurityPolicyMapping.java | 4 +- .../qmodel/system/QSystemConfiguration.java | 4 +- .../system/QSystemConfigurationMapping.java | 4 +- .../sqale/qmodel/system/QValuePolicy.java | 4 +- .../qmodel/system/QValuePolicyMapping.java | 4 +- .../repo/sqale/qmodel/task/QTask.java | 4 +- .../repo/sqale/qmodel/task/QTaskMapping.java | 4 +- .../sqale/func/SqaleRepoSearchObjectTest.java | 161 +++++++++++++++++- 47 files changed, 349 insertions(+), 149 deletions(-) create mode 100644 repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/QAssignmentHolder.java diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/QObjectTemplate.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/QObjectTemplate.java index b84083fa0f5..29b55f4e038 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/QObjectTemplate.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/QObjectTemplate.java @@ -7,13 +7,13 @@ package com.evolveum.midpoint.repo.sqale.qmodel; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; /** * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QObjectTemplate extends QObject { +public class QObjectTemplate extends QAssignmentHolder { private static final long serialVersionUID = 5428353336949587877L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/QObjectTemplateMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/QObjectTemplateMapping.java index 7bf93c339ee..316d8fe87c6 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/QObjectTemplateMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/QObjectTemplateMapping.java @@ -12,7 +12,7 @@ import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.repo.sqale.qmodel.ref.QObjectReferenceMapping; import com.evolveum.midpoint.repo.sqlbase.JdbcSession; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTemplateType; @@ -21,7 +21,7 @@ * Mapping between {@link QObjectTemplate} and {@link ObjectTemplateType}. */ public class QObjectTemplateMapping - extends QObjectMapping { + extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "ot"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/accesscert/QAccessCertificationDefinition.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/accesscert/QAccessCertificationDefinition.java index f5205f73b67..7b843daabb1 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/accesscert/QAccessCertificationDefinition.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/accesscert/QAccessCertificationDefinition.java @@ -15,14 +15,14 @@ import com.querydsl.sql.ColumnMetadata; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObjectType; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; import com.evolveum.midpoint.repo.sqlbase.querydsl.UuidPath; /** * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QAccessCertificationDefinition extends QObject { +public class QAccessCertificationDefinition extends QAssignmentHolder { private static final long serialVersionUID = 6073628996722018176L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/accesscert/QAccessCertificationDefinitionMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/accesscert/QAccessCertificationDefinitionMapping.java index 0c782c0d664..0a306d0e972 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/accesscert/QAccessCertificationDefinitionMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/accesscert/QAccessCertificationDefinitionMapping.java @@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull; import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.repo.sqlbase.JdbcSession; import com.evolveum.midpoint.util.MiscUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationDefinitionType; @@ -21,7 +21,7 @@ * and {@link AccessCertificationDefinitionType}. */ public class QAccessCertificationDefinitionMapping - extends QObjectMapping { public static final String DEFAULT_ALIAS_NAME = "acd"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/cases/QCase.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/cases/QCase.java index eeacb2eec81..79d0d3fe102 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/cases/QCase.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/cases/QCase.java @@ -16,14 +16,14 @@ import com.querydsl.sql.ColumnMetadata; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObjectType; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; import com.evolveum.midpoint.repo.sqlbase.querydsl.UuidPath; /** * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QCase extends QObject { +public class QCase extends QAssignmentHolder { private static final long serialVersionUID = -5546874425855732858L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/cases/QCaseMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/cases/QCaseMapping.java index 3d82493033a..6cd9744e811 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/cases/QCaseMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/cases/QCaseMapping.java @@ -9,13 +9,12 @@ import static com.evolveum.midpoint.xml.ns._public.common.common_3.CaseType.*; import java.util.List; -import java.util.Objects; import org.jetbrains.annotations.NotNull; import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; import com.evolveum.midpoint.repo.sqale.qmodel.cases.workitem.QCaseWorkItemMapping; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.repo.sqlbase.JdbcSession; import com.evolveum.midpoint.util.MiscUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.CaseType; @@ -25,7 +24,7 @@ * Mapping between {@link QCase} and {@link CaseType}. */ public class QCaseMapping - extends QObjectMapping { + extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "cs"; @@ -73,24 +72,24 @@ public MCase newRowObject() { @Override public @NotNull MCase toRowObjectWithoutFullObject( - CaseType acase, JdbcSession jdbcSession) { - MCase row = super.toRowObjectWithoutFullObject(acase, jdbcSession); + CaseType schemaObject, JdbcSession jdbcSession) { + MCase row = super.toRowObjectWithoutFullObject(schemaObject, jdbcSession); - row.state = acase.getState(); - row.closeTimestamp = MiscUtil.asInstant(acase.getCloseTimestamp()); - setReference(acase.getObjectRef(), + row.state = schemaObject.getState(); + row.closeTimestamp = MiscUtil.asInstant(schemaObject.getCloseTimestamp()); + setReference(schemaObject.getObjectRef(), o -> row.objectRefTargetOid = o, t -> row.objectRefTargetType = t, r -> row.objectRefRelationId = r); - setReference(acase.getParentRef(), + setReference(schemaObject.getParentRef(), o -> row.parentRefTargetOid = o, t -> row.parentRefTargetType = t, r -> row.parentRefRelationId = r); - setReference(acase.getRequestorRef(), + setReference(schemaObject.getRequestorRef(), o -> row.requestorRefTargetOid = o, t -> row.requestorRefTargetType = t, r -> row.requestorRefRelationId = r); - setReference(acase.getTargetRef(), + setReference(schemaObject.getTargetRef(), o -> row.targetRefTargetOid = o, t -> row.targetRefTargetType = t, r -> row.targetRefRelationId = r); @@ -101,7 +100,7 @@ public MCase newRowObject() { @Override public void storeRelatedEntities( @NotNull MCase row, @NotNull CaseType schemaObject, @NotNull JdbcSession jdbcSession) { - Objects.requireNonNull(row.oid); + super.storeRelatedEntities(row, schemaObject, jdbcSession); List workItems = schemaObject.getWorkItem(); if (!workItems.isEmpty()) { diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnector.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnector.java index ebeaa3fcca0..d1d8f4d31d0 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnector.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnector.java @@ -15,14 +15,14 @@ import com.querydsl.sql.ColumnMetadata; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObjectType; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; import com.evolveum.midpoint.repo.sqlbase.querydsl.UuidPath; /** * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QConnector extends QObject { +public class QConnector extends QAssignmentHolder { private static final long serialVersionUID = 6073628996722018176L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnectorHost.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnectorHost.java index 46db9898f46..a2a756bf6b6 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnectorHost.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnectorHost.java @@ -11,13 +11,13 @@ import com.querydsl.core.types.dsl.StringPath; import com.querydsl.sql.ColumnMetadata; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; /** * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QConnectorHost extends QObject { +public class QConnectorHost extends QAssignmentHolder { private static final long serialVersionUID = 8908570767190499506L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnectorHostMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnectorHostMapping.java index ccf8474a3a6..609d168aaf2 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnectorHostMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnectorHostMapping.java @@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull; import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.repo.sqlbase.JdbcSession; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorHostType; @@ -20,7 +20,7 @@ * Mapping between {@link QConnectorHost} and {@link ConnectorHostType}. */ public class QConnectorHostMapping - extends QObjectMapping { + extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "conh"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnectorMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnectorMapping.java index aebdedbbd45..99c76974d9a 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnectorMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnectorMapping.java @@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull; import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.repo.sqlbase.JdbcSession; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorType; @@ -19,7 +19,7 @@ * Mapping between {@link QConnector} and {@link ConnectorType}. */ public class QConnectorMapping - extends QObjectMapping { + extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "con"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/focus/QFocus.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/focus/QFocus.java index 94e6fceaa20..f13b2e90641 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/focus/QFocus.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/focus/QFocus.java @@ -15,7 +15,7 @@ import com.querydsl.core.types.dsl.StringPath; import com.querydsl.sql.ColumnMetadata; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationStatusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.LockoutStatusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.TimeIntervalStatusType; @@ -24,7 +24,7 @@ * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QFocus extends QObject { +public class QFocus extends QAssignmentHolder { private static final long serialVersionUID = -535915621882761789L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/focus/QFocusMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/focus/QFocusMapping.java index 92fb26d92ae..c922fde4528 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/focus/QFocusMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/focus/QFocusMapping.java @@ -14,7 +14,7 @@ import org.jetbrains.annotations.NotNull; import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.repo.sqale.qmodel.ref.QObjectReferenceMapping; import com.evolveum.midpoint.repo.sqlbase.JdbcSession; import com.evolveum.midpoint.schema.GetOperationOptions; @@ -30,7 +30,7 @@ * @param row type related to the {@link Q} */ public class QFocusMapping, R extends MFocus> - extends QObjectMapping { + extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "f"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/lookuptable/MLookupTable.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/lookuptable/MLookupTable.java index 6e6aab32bed..dc29a59acf4 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/lookuptable/MLookupTable.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/lookuptable/MLookupTable.java @@ -13,5 +13,5 @@ */ public class MLookupTable extends MObject { - // TODO if no additional fields are needed (e.g. for rows) replace with MObject + // TODO if no additional fields are needed (e.g. for rows) replace with MAssignmentHolder } diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/lookuptable/QLookupTable.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/lookuptable/QLookupTable.java index f2420f6e0f3..e22ae1f8e4d 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/lookuptable/QLookupTable.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/lookuptable/QLookupTable.java @@ -6,13 +6,13 @@ */ package com.evolveum.midpoint.repo.sqale.qmodel.lookuptable; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; /** * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QLookupTable extends QObject { +public class QLookupTable extends QAssignmentHolder { private static final long serialVersionUID = -2040531200445583676L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/lookuptable/QLookupTableMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/lookuptable/QLookupTableMapping.java index a7723179d0f..4caea3c6eec 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/lookuptable/QLookupTableMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/lookuptable/QLookupTableMapping.java @@ -13,7 +13,7 @@ import org.jetbrains.annotations.NotNull; import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.repo.sqlbase.JdbcSession; import com.evolveum.midpoint.xml.ns._public.common.common_3.LookupTableRowType; import com.evolveum.midpoint.xml.ns._public.common.common_3.LookupTableType; @@ -22,7 +22,7 @@ * Mapping between {@link QLookupTable} and {@link LookupTableType}. */ public class QLookupTableMapping - extends QObjectMapping { + extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "lt"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/node/QNode.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/node/QNode.java index 7ec429f8bda..85b03c7c263 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/node/QNode.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/node/QNode.java @@ -11,13 +11,13 @@ import com.querydsl.core.types.dsl.StringPath; import com.querydsl.sql.ColumnMetadata; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; /** * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QNode extends QObject { +public class QNode extends QAssignmentHolder { private static final long serialVersionUID = 2042159341967925185L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/node/QNodeMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/node/QNodeMapping.java index 397cd366306..49328c31835 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/node/QNodeMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/node/QNodeMapping.java @@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull; import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.repo.sqlbase.JdbcSession; import com.evolveum.midpoint.xml.ns._public.common.common_3.NodeType; @@ -19,7 +19,7 @@ * Mapping between {@link QNode} and {@link NodeType}. */ public class QNodeMapping - extends QObjectMapping { + extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "nod"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/MObjectType.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/MObjectType.java index bd3fae411a5..90b49e444e3 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/MObjectType.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/MObjectType.java @@ -23,7 +23,6 @@ import com.evolveum.midpoint.repo.sqale.qmodel.focus.QUser; import com.evolveum.midpoint.repo.sqale.qmodel.lookuptable.QLookupTable; import com.evolveum.midpoint.repo.sqale.qmodel.node.QNode; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping.QAssignmentHolder; import com.evolveum.midpoint.repo.sqale.qmodel.other.*; import com.evolveum.midpoint.repo.sqale.qmodel.report.QReport; import com.evolveum.midpoint.repo.sqale.qmodel.report.QReportData; @@ -48,7 +47,7 @@ public enum MObjectType { ACCESS_CERTIFICATION_DEFINITION( QAccessCertificationDefinition.class, AccessCertificationDefinitionType.class), ARCHETYPE(QArchetype.class, ArchetypeType.class), - ASSIGNMENT_HOLDER(QAssignmentHolder.class, AssignmentHolderType.class), + ASSIGNMENT_HOLDER(QAssignmentHolder.CLASS, AssignmentHolderType.class), CASE(QCase.class, CaseType.class), CONNECTOR(QConnector.class, ConnectorType.class), CONNECTOR_HOST(QConnectorHost.class, ConnectorHostType.class), diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/QAssignmentHolder.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/QAssignmentHolder.java new file mode 100644 index 00000000000..d48a467c21b --- /dev/null +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/QAssignmentHolder.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2010-2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.repo.sqale.qmodel.object; + +/** + * Querydsl query type for {@value #TABLE_NAME} table. + */ +public class QAssignmentHolder extends QObject { + + private static final long serialVersionUID = -8772807624205702543L; + + /** + * If {@code QAssignmentHolder.class} is not enough because of generics, + * try {@code QAssignmentHolder.CLASS}. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static final Class> CLASS = + (Class) QAssignmentHolder.class; + + public static final String TABLE_NAME = "m_assignment_holder"; + + public QAssignmentHolder(Class type, String variable) { + this(type, variable, DEFAULT_SCHEMA_NAME, TABLE_NAME); + } + + public QAssignmentHolder(Class type, String variable, String schema, String table) { + super(type, variable, schema, table); + } +} diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/QAssignmentHolderMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/QAssignmentHolderMapping.java index 170ce467d08..12f5a3eb6e7 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/QAssignmentHolderMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/QAssignmentHolderMapping.java @@ -6,40 +6,87 @@ */ package com.evolveum.midpoint.repo.sqale.qmodel.object; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentHolderType.*; + +import java.util.List; + import org.jetbrains.annotations.NotNull; import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; +import com.evolveum.midpoint.repo.sqale.qmodel.assignment.QAssignmentMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.ref.QObjectReferenceMapping; +import com.evolveum.midpoint.repo.sqlbase.JdbcSession; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentHolderType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; /** - * Mapping for {@link AssignmentHolderType} - this is served by M_OBJECT mapping. - * Technically, many mappings should be derived from this, but they are derived from - * {@link QObjectMapping} instead and this class is ignored, except for mapping - just to support - * queries typed to {@link AssignmentHolderType}. + * Mapping between {@link QAssignmentHolder} and {@link AssignmentHolderType}. + * + * @param schema type for the assignment holder object + * @param type of entity path + * @param row type related to the {@link Q} */ -public class QAssignmentHolderMapping extends QObjectMapping< - AssignmentHolderType, - QAssignmentHolderMapping.QAssignmentHolder, - QAssignmentHolderMapping.MAssignmentHolder> { +public class QAssignmentHolderMapping< + S extends AssignmentHolderType, Q extends QAssignmentHolder, R extends MObject> + extends QObjectMapping { public static final String DEFAULT_ALIAS_NAME = "ah"; - public static QAssignmentHolderMapping init(@NotNull SqaleRepoContext repositoryContext) { - return new QAssignmentHolderMapping(repositoryContext); + public static QAssignmentHolderMapping init(@NotNull SqaleRepoContext repositoryContext) { + return new QAssignmentHolderMapping<>(QAssignmentHolder.TABLE_NAME, DEFAULT_ALIAS_NAME, + AssignmentHolderType.class, QAssignmentHolder.CLASS, + repositoryContext); } - protected QAssignmentHolderMapping(@NotNull SqaleRepoContext repositoryContext) { - super(QObject.TABLE_NAME, DEFAULT_ALIAS_NAME, - AssignmentHolderType.class, QAssignmentHolder.class, - repositoryContext); + protected QAssignmentHolderMapping( + @NotNull String tableName, + @NotNull String defaultAliasName, + @NotNull Class schemaType, + @NotNull Class queryType, + @NotNull SqaleRepoContext repositoryContext) { + super(tableName, defaultAliasName, schemaType, queryType, repositoryContext); + + addContainerTableMapping(AssignmentHolderType.F_ASSIGNMENT, + QAssignmentMapping.initAssignment(repositoryContext), + joinOn((o, a) -> o.oid.eq(a.ownerOid))); + + addRefMapping(F_ARCHETYPE_REF, QObjectReferenceMapping.initForArchetype(repositoryContext)); + addRefMapping(F_DELEGATED_REF, QObjectReferenceMapping.initForDelegated(repositoryContext)); + addRefMapping(F_ROLE_MEMBERSHIP_REF, + QObjectReferenceMapping.initForRoleMembership(repositoryContext)); + } + + @Override + protected Q newAliasInstance(String alias) { + //noinspection unchecked + return (Q) new QAssignmentHolder<>(MObject.class, alias); } - public static class MAssignmentHolder extends MObject { + @SuppressWarnings("DuplicatedCode") // activation code duplicated with assignment + @Override + public @NotNull R toRowObjectWithoutFullObject(S schemaObject, JdbcSession jdbcSession) { + R row = super.toRowObjectWithoutFullObject(schemaObject, jdbcSession); + + // TODO + return row; } - public static class QAssignmentHolder extends QObject { - private QAssignmentHolder() { - super(MAssignmentHolder.class, DEFAULT_ALIAS_NAME); + @Override + public void storeRelatedEntities( + @NotNull R row, @NotNull S schemaObject, @NotNull JdbcSession jdbcSession) { + super.storeRelatedEntities(row, schemaObject, jdbcSession); + + List assignments = schemaObject.getAssignment(); + if (!assignments.isEmpty()) { + assignments.forEach(assignment -> + QAssignmentMapping.getAssignment().insert(assignment, row, jdbcSession)); } + + storeRefs(row, schemaObject.getArchetypeRef(), + QObjectReferenceMapping.getForArchetype(), jdbcSession); + storeRefs(row, schemaObject.getDelegatedRef(), + QObjectReferenceMapping.getForDelegated(), jdbcSession); + storeRefs(row, schemaObject.getRoleMembershipRef(), + QObjectReferenceMapping.getForRoleMembership(), jdbcSession); } } diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/QObjectMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/QObjectMapping.java index 8fab14efb76..970a7ee9234 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/QObjectMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/QObjectMapping.java @@ -25,7 +25,6 @@ import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; import com.evolveum.midpoint.repo.sqale.SqaleUtils; import com.evolveum.midpoint.repo.sqale.qmodel.SqaleTableMapping; -import com.evolveum.midpoint.repo.sqale.qmodel.assignment.QAssignmentMapping; import com.evolveum.midpoint.repo.sqale.qmodel.common.QUri; import com.evolveum.midpoint.repo.sqale.qmodel.ref.QObjectReferenceMapping; import com.evolveum.midpoint.repo.sqlbase.JdbcSession; @@ -35,7 +34,10 @@ import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.util.MiscUtil; import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import com.evolveum.midpoint.xml.ns._public.common.common_3.MetadataType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationExecutionType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.TriggerType; /** * Mapping between {@link QObject} and {@link ObjectType}. @@ -102,21 +104,12 @@ protected QObjectMapping( addRefMapping(F_PARENT_ORG_REF, QObjectReferenceMapping.initForParentOrg(repositoryContext)); - addContainerTableMapping(AssignmentHolderType.F_ASSIGNMENT, - QAssignmentMapping.initAssignment(repositoryContext), - joinOn((o, a) -> o.oid.eq(a.ownerOid))); addContainerTableMapping(F_OPERATION_EXECUTION, QOperationExecutionMapping.init(repositoryContext), joinOn((o, trg) -> o.oid.eq(trg.ownerOid))); addContainerTableMapping(F_TRIGGER, QTriggerMapping.init(repositoryContext), joinOn((o, trg) -> o.oid.eq(trg.ownerOid))); - - // AssignmentHolderType - addRefMapping(F_ARCHETYPE_REF, QObjectReferenceMapping.initForArchetype(repositoryContext)); - addRefMapping(F_DELEGATED_REF, QObjectReferenceMapping.initForDelegated(repositoryContext)); - addRefMapping(F_ROLE_MEMBERSHIP_REF, - QObjectReferenceMapping.initForRoleMembership(repositoryContext)); } @Override @@ -264,10 +257,6 @@ public void storeRelatedEntities( storeRefs(row, schemaObject.getParentOrgRef(), QObjectReferenceMapping.getForParentOrg(), jdbcSession); - if (schemaObject instanceof AssignmentHolderType) { - storeAssignmentHolderEntities(row, (AssignmentHolderType) schemaObject, jdbcSession); - } - /* TODO EAV extensions - the relevant code from old repo RObject#copyObjectInformationFromJAXB if (jaxb.getExtension() != null) { copyExtensionOrAttributesFromJAXB(jaxb.getExtension().asPrismContainerValue(), repo, repositoryContext, RObjectExtensionType.EXTENSION, generatorResult); @@ -275,22 +264,6 @@ public void storeRelatedEntities( */ } - private void storeAssignmentHolderEntities( - R row, AssignmentHolderType schemaObject, JdbcSession jdbcSession) { - List assignments = schemaObject.getAssignment(); - if (!assignments.isEmpty()) { - assignments.forEach(assignment -> - QAssignmentMapping.getAssignment().insert(assignment, row, jdbcSession)); - } - - storeRefs(row, schemaObject.getArchetypeRef(), - QObjectReferenceMapping.getForArchetype(), jdbcSession); - storeRefs(row, schemaObject.getDelegatedRef(), - QObjectReferenceMapping.getForDelegated(), jdbcSession); - storeRefs(row, schemaObject.getRoleMembershipRef(), - QObjectReferenceMapping.getForRoleMembership(), jdbcSession); - } - /** * Serializes schema object and sets {@link R#fullObject}. */ diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QDashboard.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QDashboard.java index ab9955be5e2..492c4b02213 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QDashboard.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QDashboard.java @@ -7,13 +7,13 @@ package com.evolveum.midpoint.repo.sqale.qmodel.other; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; /** * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QDashboard extends QObject { +public class QDashboard extends QAssignmentHolder { private static final long serialVersionUID = -3546780348548754579L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QDashboardMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QDashboardMapping.java index 6b53c75d151..b4983755fe7 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QDashboardMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QDashboardMapping.java @@ -10,14 +10,14 @@ import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.xml.ns._public.common.common_3.DashboardType; /** * Mapping between {@link QDashboard} and {@link DashboardType}. */ public class QDashboardMapping - extends QObjectMapping { + extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "d"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QForm.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QForm.java index b71628c07f2..7be16233b97 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QForm.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QForm.java @@ -7,13 +7,13 @@ package com.evolveum.midpoint.repo.sqale.qmodel.other; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; /** * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QForm extends QObject { +public class QForm extends QAssignmentHolder { private static final long serialVersionUID = -8782193461498358493L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QFormMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QFormMapping.java index d4d3c5fab43..a45cdd8becc 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QFormMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QFormMapping.java @@ -10,13 +10,13 @@ import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.xml.ns._public.common.common_3.FormType; /** * Mapping between {@link QForm} and {@link FormType}. */ -public class QFormMapping extends QObjectMapping { +public class QFormMapping extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "form"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QFunctionLibrary.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QFunctionLibrary.java index 420c674b833..bbe0a1a747c 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QFunctionLibrary.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QFunctionLibrary.java @@ -7,13 +7,13 @@ package com.evolveum.midpoint.repo.sqale.qmodel.other; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; /** * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QFunctionLibrary extends QObject { +public class QFunctionLibrary extends QAssignmentHolder { private static final long serialVersionUID = -8437964574227439797L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QFunctionLibraryMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QFunctionLibraryMapping.java index c9840342900..1966958c09f 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QFunctionLibraryMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QFunctionLibraryMapping.java @@ -10,14 +10,14 @@ import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.xml.ns._public.common.common_3.FunctionLibraryType; /** * Mapping between {@link QFunctionLibrary} and {@link FunctionLibraryType}. */ public class QFunctionLibraryMapping - extends QObjectMapping { + extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "flib"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QObjectCollection.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QObjectCollection.java index 957906296c1..e403462ca05 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QObjectCollection.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QObjectCollection.java @@ -7,13 +7,13 @@ package com.evolveum.midpoint.repo.sqale.qmodel.other; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; /** * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QObjectCollection extends QObject { +public class QObjectCollection extends QAssignmentHolder { private static final long serialVersionUID = -62230817260259478L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QObjectCollectionMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QObjectCollectionMapping.java index 2a47f1b81d6..c112992510d 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QObjectCollectionMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QObjectCollectionMapping.java @@ -10,14 +10,14 @@ import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectCollectionType; /** * Mapping between {@link QObjectCollection} and {@link ObjectCollectionType}. */ public class QObjectCollectionMapping - extends QObjectMapping { + extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "oc"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QSequence.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QSequence.java index a62b5d74436..fefb27dff09 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QSequence.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QSequence.java @@ -7,13 +7,13 @@ package com.evolveum.midpoint.repo.sqale.qmodel.other; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; /** * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QSequence extends QObject { +public class QSequence extends QAssignmentHolder { private static final long serialVersionUID = 1340389166467004733L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QSequenceMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QSequenceMapping.java index 7a650d183c2..dce9862047b 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QSequenceMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/other/QSequenceMapping.java @@ -10,13 +10,13 @@ import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.xml.ns._public.common.common_3.SequenceType; /** * Mapping between {@link QSequence} and {@link SequenceType}. */ -public class QSequenceMapping extends QObjectMapping { +public class QSequenceMapping extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "seq"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/report/QReport.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/report/QReport.java index cc892dd3295..9ade319cc8a 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/report/QReport.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/report/QReport.java @@ -12,14 +12,14 @@ import com.querydsl.core.types.dsl.EnumPath; import com.querydsl.sql.ColumnMetadata; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; import com.evolveum.midpoint.xml.ns._public.common.common_3.OrientationType; /** * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QReport extends QObject { +public class QReport extends QAssignmentHolder { private static final long serialVersionUID = -5738006878845987541L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/report/QReportData.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/report/QReportData.java index a423be8f691..acb0dfca40c 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/report/QReportData.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/report/QReportData.java @@ -13,14 +13,14 @@ import com.querydsl.sql.ColumnMetadata; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObjectType; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; import com.evolveum.midpoint.repo.sqlbase.querydsl.UuidPath; /** * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QReportData extends QObject { +public class QReportData extends QAssignmentHolder { private static final long serialVersionUID = -544485328996889511L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/report/QReportDataMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/report/QReportDataMapping.java index e409993c199..9be4859d293 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/report/QReportDataMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/report/QReportDataMapping.java @@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull; import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.repo.sqlbase.JdbcSession; import com.evolveum.midpoint.xml.ns._public.common.common_3.ReportDataType; @@ -19,7 +19,7 @@ * Mapping between {@link QReportData} and {@link ReportDataType}. */ public class QReportDataMapping - extends QObjectMapping { + extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "repout"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/report/QReportMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/report/QReportMapping.java index 151312f9b71..01a5a3169ff 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/report/QReportMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/report/QReportMapping.java @@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull; import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.repo.sqlbase.JdbcSession; import com.evolveum.midpoint.xml.ns._public.common.common_3.JasperReportEngineConfigurationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ReportType; @@ -18,7 +18,7 @@ * Mapping between {@link QReport} and {@link ReportType}. */ public class QReportMapping - extends QObjectMapping { + extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "rep"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/resource/QResource.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/resource/QResource.java index c423c93aae5..96c9db6b769 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/resource/QResource.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/resource/QResource.java @@ -13,7 +13,7 @@ import com.querydsl.sql.ColumnMetadata; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObjectType; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; import com.evolveum.midpoint.repo.sqlbase.querydsl.UuidPath; import com.evolveum.midpoint.xml.ns._public.common.common_3.AvailabilityStatusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceAdministrativeStateType; @@ -22,7 +22,7 @@ * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QResource extends QObject { +public class QResource extends QAssignmentHolder { private static final long serialVersionUID = 4311838248823321876L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/resource/QResourceMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/resource/QResourceMapping.java index 289871fadc1..dfb5e6eda7e 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/resource/QResourceMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/resource/QResourceMapping.java @@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull; import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.repo.sqale.qmodel.ref.QObjectReferenceMapping; import com.evolveum.midpoint.repo.sqlbase.JdbcSession; import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationalStateType; @@ -21,7 +21,8 @@ /** * Mapping between {@link QResource} and {@link ResourceType}. */ -public class QResourceMapping extends QObjectMapping { +public class QResourceMapping + extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "res"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/shadow/QShadow.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/shadow/QShadow.java index 4531c09ed7b..072f2c4dcf1 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/shadow/QShadow.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/shadow/QShadow.java @@ -28,7 +28,6 @@ public class QShadow extends QObject { public static final String TABLE_NAME = "m_shadow"; - // TODO public static final ColumnMetadata OBJECT_CLASS_ID = ColumnMetadata.named("objectClassId").ofType(Types.INTEGER); public static final ColumnMetadata RESOURCE_REF_TARGET_OID = diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QSecurityPolicy.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QSecurityPolicy.java index d1c04cb8b8b..1629898a721 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QSecurityPolicy.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QSecurityPolicy.java @@ -7,13 +7,13 @@ package com.evolveum.midpoint.repo.sqale.qmodel.system; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; /** * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QSecurityPolicy extends QObject { +public class QSecurityPolicy extends QAssignmentHolder { private static final long serialVersionUID = 289603300613404007L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QSecurityPolicyMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QSecurityPolicyMapping.java index af1e42c0853..0f2806ae855 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QSecurityPolicyMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QSecurityPolicyMapping.java @@ -10,14 +10,14 @@ import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.xml.ns._public.common.common_3.SecurityPolicyType; /** * Mapping between {@link QSecurityPolicy} and {@link SecurityPolicyType}. */ public class QSecurityPolicyMapping - extends QObjectMapping { + extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "sp"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QSystemConfiguration.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QSystemConfiguration.java index 8d59518f318..763b227e19d 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QSystemConfiguration.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QSystemConfiguration.java @@ -7,13 +7,13 @@ package com.evolveum.midpoint.repo.sqale.qmodel.system; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; /** * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QSystemConfiguration extends QObject { +public class QSystemConfiguration extends QAssignmentHolder { private static final long serialVersionUID = -2157392986065893792L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QSystemConfigurationMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QSystemConfigurationMapping.java index e54d99c287e..17aab166e07 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QSystemConfigurationMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QSystemConfigurationMapping.java @@ -10,14 +10,14 @@ import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemConfigurationType; /** * Mapping between {@link QSystemConfiguration} and {@link SystemConfigurationType}. */ public class QSystemConfigurationMapping - extends QObjectMapping { + extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "sc"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QValuePolicy.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QValuePolicy.java index bdb931b40e0..02320efbe52 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QValuePolicy.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QValuePolicy.java @@ -7,13 +7,13 @@ package com.evolveum.midpoint.repo.sqale.qmodel.system; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; /** * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QValuePolicy extends QObject { +public class QValuePolicy extends QAssignmentHolder { private static final long serialVersionUID = 5623917383769868004L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QValuePolicyMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QValuePolicyMapping.java index 94d75b731ae..e0f26481b81 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QValuePolicyMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/system/QValuePolicyMapping.java @@ -10,14 +10,14 @@ import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.xml.ns._public.common.common_3.ValuePolicyType; /** * Mapping between {@link QValuePolicy} and {@link ValuePolicyType}. */ public class QValuePolicyMapping - extends QObjectMapping { + extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "vp"; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/task/QTask.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/task/QTask.java index ad9ae14b128..96cb740a21b 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/task/QTask.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/task/QTask.java @@ -13,7 +13,7 @@ import com.querydsl.sql.ColumnMetadata; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObjectType; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; import com.evolveum.midpoint.repo.sqlbase.querydsl.UuidPath; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; @@ -21,7 +21,7 @@ * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QTask extends QObject { +public class QTask extends QAssignmentHolder { private static final long serialVersionUID = 6249403929032616177L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/task/QTaskMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/task/QTaskMapping.java index acd439e3ff8..5250d26665a 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/task/QTaskMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/task/QTaskMapping.java @@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull; import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; -import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolderMapping; import com.evolveum.midpoint.repo.sqlbase.JdbcSession; import com.evolveum.midpoint.util.MiscUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType; @@ -18,7 +18,7 @@ * Mapping between {@link QTask} and {@link TaskType}. */ public class QTaskMapping - extends QObjectMapping { + extends QAssignmentHolderMapping { public static final String DEFAULT_ALIAS_NAME = "t"; diff --git a/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoSearchObjectTest.java b/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoSearchObjectTest.java index e3fd231a902..6e343367d35 100644 --- a/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoSearchObjectTest.java +++ b/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoSearchObjectTest.java @@ -13,16 +13,20 @@ import java.util.UUID; import javax.xml.namespace.QName; -import com.evolveum.midpoint.prism.path.ItemPath; - import org.jetbrains.annotations.NotNull; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.polystring.PolyString; +import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.repo.sqale.SqaleRepoBaseTest; +import com.evolveum.midpoint.repo.sqale.qmodel.focus.QFocus; +import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; +import com.evolveum.midpoint.repo.sqale.qmodel.object.MObjectType; +import com.evolveum.midpoint.repo.sqale.qmodel.object.QAssignmentHolder; import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; import com.evolveum.midpoint.repo.sqlbase.perfmon.SqlPerformanceMonitorImpl; import com.evolveum.midpoint.schema.GetOperationOptions; @@ -490,6 +494,7 @@ public void test301QueryForFocusWithInOid() throws SchemaException { } /* + // TODO TYPE tests - unclear how to implement TYPE filter at the moment @Test public void test310QueryWithTypeFilter() throws SchemaException { when("query includes type filter"); @@ -499,8 +504,8 @@ public void test310QueryWithTypeFilter() throws SchemaException { .type(FocusType.class) .block() .id(user1Oid, task1Oid, org2Oid) // task will not match, it's not a focus -// .and() TODO I want this -// .item(FocusType.F_COST_CENTER).eq("5") + .and() + .item(FocusType.F_COST_CENTER).eq("5") .endBlock() .build(), operationResult); @@ -513,8 +518,73 @@ public void test310QueryWithTypeFilter() throws SchemaException { } */ - // TODO TYPE tests - // TODO EXISTS tests +/* TODO EXISTS tests +1. @Count property => pendingOperationCount > 0; see: ClassDefinitionParser#parseMethod() + getJaxbName() +EXISTS(pendingOperation, null) + +2. multi-value container stored in table: +EXISTS(operationExecution, AND(REF: taskRef, PRV(oid=task-oid-2, targetType=null); EQUAL: status, PPV(OperationResultStatusType:SUCCESS))) + +3. cointainer query (AccessCertificationWorkItemType) with EXISTS to the parent container (AccessCertificationCaseType) + matching on parent's ownerID (OID of AccessCertificationCampaignType) + its own CID (AccessCertificationCaseType) +EXISTS({http://prism.evolveum.com/xml/ns/public/types-3}parent, AND(IN OID (for owner): e8c07a7a-1b11-11e8-9b32-1715a2e8273b, IN OID: 1)) + +parent vs ..? + +4. part of AND in container query, used on sub-container (workItem) with nested AND condition +CertificationTest.test730CurrentUnansweredCases >>> Q{ +AND( + EQUAL: stageNumber, {http://prism.evolveum.com/xml/ns/public/types-3}parent/stageNumber; + EQUAL: ../state, PPV(AccessCertificationCampaignStateType:IN_REVIEW_STAGE); + EXISTS(workItem, + AND( + EQUAL: closeTimestamp, ; + EQUAL: output/outcome, ))) +, null paging} + +5. EXISTS with .. (another way how to say parent) +EXISTS(.., + OR( + IN OID: c0c010c0-d34d-b33f-f00d-111111111111; , + REF: ownerRef,PRV(oid=c0c010c0-d34d-b33f-f00d-111111111111, targetType={.../common/common-3}UserType))) + +6. nothing new, nested in OR, EXISTS(workItem) with AND + +OR( + IN OID: af69e388-88bd-43f9-9259-73676124c196; , + EXISTS(workItem, + AND( + EQUAL: closeTimestamp,, + REF: assigneeRef, PRV(oid=af69e388-88bd-43f9-9259-73676124c196, targetType=null), PRV(oid=c0c010c0-d34d-b33f-f00d-111111111111, targetType=null)))) + +OR( + NONE, + LESS-OR-EQUAL: activation/validFrom,PPV(XMLGregorianCalendarImpl:2021-05-21T15:44:41.955+02:00), + LESS-OR-EQUAL: activation/validTo,PPV(XMLGregorianCalendarImpl:2021-05-21T15:44:41.955+02:00), + EXISTS(assignment, + OR( + LESS-OR-EQUAL: activation/validFrom,PPV(XMLGregorianCalendarImpl:2021-05-21T15:44:41.955+02:00), + LESS-OR-EQUAL: activation/validTo,PPV(XMLGregorianCalendarImpl:2021-05-21T15:44:41.955+02:00)))) + +7. typical case EXISTS(assignment, ...) + +8. AND(2x EXISTS with multiple ref values) +main >>> Q{ +AND( + EXISTS(assignment, + REF: targetRef, + PRV(oid=4076afcc-4075-4f18-b596-edb71dbf72a9, targetType={.../common/common-3}OrgType, targetName=A-newOrg, relation={.../common/org-3}default), + PRV(oid=4076afcc-4075-4f18-b596-edb71dbf72a9, targetType={.../common/common-3}OrgType, targetName=A-newOrg, relation={.../common/org-3}manager), + PRV(oid=4076afcc-4075-4f18-b596-edb71dbf72a9, targetType={.../common/common-3}OrgType, targetName=A-newOrg, relation={.../common/org-3}approver), + PRV(oid=4076afcc-4075-4f18-b596-edb71dbf72a9, targetType={.../common/common-3}OrgType, targetName=A-newOrg, relation={.../common/org-3}owner)); + EXISTS(assignment, + REF: targetRef, + PRV(oid=4076afcc-4075-4f18-b596-edb71dbf72a9, targetType={.../common/common-3}OrgType, targetName=A-newOrg, relation={.../common/org-3}default), + PRV(oid=4076afcc-4075-4f18-b596-edb71dbf72a9, targetType={.../common/common-3}OrgType, targetName=A-newOrg, relation={.../common/org-3}manager), + PRV(oid=4076afcc-4075-4f18-b596-edb71dbf72a9, targetType={.../common/common-3}OrgType, targetName=A-newOrg, relation={.../common/org-3}approver), + PRV(oid=4076afcc-4075-4f18-b596-edb71dbf72a9, targetType={.../common/common-3}OrgType, targetName=A-newOrg, relation={.../common/org-3}owner))) +, null paging} +*/ // endregion // region special cases @@ -531,6 +601,59 @@ public void test900SearchByWholeContainerIsNotPossible() { // even if query was possible this would fail in the actual repo search, which is expected } + @Test + public void test920SearchObjectTypeFindsAllObjects() throws SchemaException { + OperationResult operationResult = createOperationResult(); + + given("query without any filter"); + ObjectQuery query = prismContext.queryFor(ObjectType.class).build(); + + when("search is called with ObjectType"); + SearchResultList result = + searchObjects(ObjectType.class, query, operationResult); + + then("all repository objects are returned"); + assertThat(result).hasSize((int) count(QObject.CLASS)); + } + + @Test + public void test921SearchAssignmentHolderTypeFindsAllObjectsExceptShadows() + throws SchemaException { + OperationResult operationResult = createOperationResult(); + + given("query without any filter"); + ObjectQuery query = prismContext.queryFor(ObjectType.class).build(); + + when("search is called with AssignmentHolderType"); + SearchResultList result = + searchObjects(AssignmentHolderType.class, query, operationResult); + + then("all repository objects except shadows are returned"); + QObject o = aliasFor(QObject.CLASS); + assertThat(result).hasSize((int) count(o, o.objectType.ne(MObjectType.SHADOW))); + assertThat(result).hasSize((int) count(QAssignmentHolder.CLASS)); + // without additional objects the test would be meaningless + assertThat(result).hasSizeLessThan((int) count(o)); + } + + @Test + public void test921SearchFocusTypeFindsOnlyFocusObjects() + throws SchemaException { + OperationResult operationResult = createOperationResult(); + + given("query without any filter"); + ObjectQuery query = prismContext.queryFor(ObjectType.class).build(); + + when("search is called with FocusType"); + SearchResultList result = + searchObjects(FocusType.class, query, operationResult); + + then("only focus objects from repository are returned"); + assertThat(result).hasSize((int) count(QFocus.CLASS)); + // without additional objects the test would be meaningless + assertThat(result).hasSizeLessThan((int) count(QObject.CLASS)); + } + @Test public void test950SearchOperationUpdatesPerformanceMonitor() throws SchemaException { OperationResult operationResult = createOperationResult(); @@ -549,9 +672,35 @@ public void test950SearchOperationUpdatesPerformanceMonitor() throws SchemaExcep assertThatOperationResult(operationResult).isSuccess(); assertSingleOperationRecorded(pm, RepositoryService.OP_SEARCH_OBJECTS); } + + @Test(enabled = false) + public void test960SearchByAxiomQueryLanguage() throws SchemaException { + OperationResult operationResult = createOperationResult(); + SearchResultList focusTypes = searchObjects(FocusType.class, + ". type UserType and employeeNumber startsWith \"5\"", + operationResult); + System.out.println("focusTypes = " + focusTypes); + // even if query was possible this would fail in the actual repo search, which is expected + } // endregion // support methods + + /** Search objects using Axiom query language. */ + @SafeVarargs + @NotNull + private SearchResultList searchObjects( + @NotNull Class type, + String query, + OperationResult operationResult, + SelectorOptions... selectorOptions) + throws SchemaException { + ObjectFilter objectFilter = prismContext.createQueryParser().parseQuery(type, query); + ObjectQuery objectQuery = prismContext.queryFactory().createQuery(objectFilter); + return searchObjects(type, objectQuery, operationResult, selectorOptions); + } + + /** Search objects using {@link ObjectQuery}. */ @SafeVarargs @NotNull private SearchResultList searchObjects( From 4a3912a57dce8979c8b9791047990758136d3ef5 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Tue, 25 May 2021 19:22:07 +0200 Subject: [PATCH 06/23] Prism: Added Delegator interfaces Delegator interfaces delegates most of the calls to delegate(), useful for implementation of wrappers which modifies only few items. --- .../deleg/ComplexTypeDefinitionDelegator.java | 171 +++++++++++++++ .../deleg/ContainerDefinitionDelegator.java | 161 ++++++++++++++ .../prism/deleg/DefinitionDelegator.java | 183 ++++++++++++++++ .../prism/deleg/ItemDefinitionDelegator.java | 199 ++++++++++++++++++ .../deleg/ObjectDefinitionDelegator.java | 48 +++++ .../deleg/PropertyDefinitionDelegator.java | 76 +++++++ .../deleg/ReferenceDefinitionDelegator.java | 48 +++++ .../prism/deleg/TypeDefinitionDelegator.java | 48 +++++ 8 files changed, 934 insertions(+) create mode 100644 infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ComplexTypeDefinitionDelegator.java create mode 100644 infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ContainerDefinitionDelegator.java create mode 100644 infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/DefinitionDelegator.java create mode 100644 infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ItemDefinitionDelegator.java create mode 100644 infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ObjectDefinitionDelegator.java create mode 100644 infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/PropertyDefinitionDelegator.java create mode 100644 infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ReferenceDefinitionDelegator.java create mode 100644 infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/TypeDefinitionDelegator.java diff --git a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ComplexTypeDefinitionDelegator.java b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ComplexTypeDefinitionDelegator.java new file mode 100644 index 00000000000..3758302b3c4 --- /dev/null +++ b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ComplexTypeDefinitionDelegator.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +package com.evolveum.midpoint.prism.deleg; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import javax.xml.namespace.QName; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.evolveum.midpoint.prism.ComplexTypeDefinition; +import com.evolveum.midpoint.prism.Containerable; +import com.evolveum.midpoint.prism.ItemDefinition; +import com.evolveum.midpoint.prism.PrismContainerDefinition; +import com.evolveum.midpoint.prism.PrismPropertyDefinition; +import com.evolveum.midpoint.prism.PrismReferenceDefinition; +import com.evolveum.midpoint.prism.path.ItemName; +import com.evolveum.midpoint.prism.path.ItemPath; + +public interface ComplexTypeDefinitionDelegator extends TypeDefinitionDelegator, ComplexTypeDefinition { + + @Override + ComplexTypeDefinition delegate(); + + @Override + default ID findLocalItemDefinition(@NotNull QName name, @NotNull Class clazz, + boolean caseInsensitive) { + return delegate().findLocalItemDefinition(name, clazz, caseInsensitive); + } + + + @Override + default ID findLocalItemDefinition(@NotNull QName name) { + return delegate().findLocalItemDefinition(name); + } + + + @Override + default boolean isShared() { + return delegate().isShared(); + } + + @Override + default ID findItemDefinition(@NotNull ItemPath path) { + return delegate().findItemDefinition(path); + } + + @Override + default @Nullable QName getExtensionForType() { + return delegate().getExtensionForType(); + } + + @Override + default PrismReferenceDefinition findReferenceDefinition(@NotNull ItemName name) { + return delegate().findReferenceDefinition(name); + } + + @Override + default PrismContainerDefinition findContainerDefinition(@NotNull String name) { + return delegate().findContainerDefinition(name); + } + + @Override + default boolean isReferenceMarker() { + return delegate().isReferenceMarker(); + } + + @Override + default boolean isContainerMarker() { + return delegate().isContainerMarker(); + } + + @Override + default ID findItemDefinition(@NotNull ItemPath path, @NotNull Class clazz) { + return delegate().findItemDefinition(path, clazz); + } + + @Override + default ID findNamedItemDefinition(@NotNull QName firstName, @NotNull ItemPath rest, + @NotNull Class clazz) { + return delegate().findNamedItemDefinition(firstName, rest, clazz); + } + + @Override + default PrismPropertyDefinition findPropertyDefinition(@NotNull ItemPath path) { + return delegate().findPropertyDefinition(path); + } + + @Override + default boolean isObjectMarker() { + return delegate().isObjectMarker(); + } + + @Override + default PrismReferenceDefinition findReferenceDefinition(@NotNull ItemPath path) { + return delegate().findReferenceDefinition(path); + } + + @Override + default boolean isXsdAnyMarker() { + return delegate().isXsdAnyMarker(); + } + + @Override + default PrismContainerDefinition findContainerDefinition(@NotNull ItemPath path) { + return delegate().findContainerDefinition(path); + } + + @Override + default boolean isListMarker() { + return delegate().isListMarker(); + } + + @Override + default @Nullable String getDefaultNamespace() { + return delegate().getDefaultNamespace(); + } + + @Override + default @NotNull List getIgnoredNamespaces() { + return delegate().getIgnoredNamespaces(); + } + + @Override + default void merge(ComplexTypeDefinition otherComplexTypeDef) { + delegate().merge(otherComplexTypeDef); + } + + @Override + default boolean isEmpty() { + return delegate().isEmpty(); + } + + @Override + default void trimTo(@NotNull Collection paths) { + delegate().trimTo(paths); + } + + @Override + default boolean containsItemDefinition(QName itemName) { + return delegate().containsItemDefinition(itemName); + } + + @Override + default boolean hasSubstitutions() { + return delegate().hasSubstitutions(); + } + + @Override + default Optional> substitution(QName name) { + return delegate().substitution(name); + } + + @Override + default Optional> itemOrSubstitution(QName name) { + return delegate().itemOrSubstitution(name); + } + + @Override + default @NotNull List getDefinitions() { + return delegate().getDefinitions(); + } + +} diff --git a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ContainerDefinitionDelegator.java b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ContainerDefinitionDelegator.java new file mode 100644 index 00000000000..a190260339f --- /dev/null +++ b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ContainerDefinitionDelegator.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +package com.evolveum.midpoint.prism.deleg; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import javax.xml.namespace.QName; + +import org.jetbrains.annotations.NotNull; + +import com.evolveum.midpoint.prism.ComplexTypeDefinition; +import com.evolveum.midpoint.prism.Containerable; +import com.evolveum.midpoint.prism.ItemDefinition; +import com.evolveum.midpoint.prism.PrismContainer; +import com.evolveum.midpoint.prism.PrismContainerDefinition; +import com.evolveum.midpoint.prism.PrismContainerValue; +import com.evolveum.midpoint.prism.PrismPropertyDefinition; +import com.evolveum.midpoint.prism.PrismReferenceDefinition; +import com.evolveum.midpoint.prism.delta.ContainerDelta; +import com.evolveum.midpoint.prism.path.ItemName; +import com.evolveum.midpoint.prism.path.ItemPath; + +public interface ContainerDefinitionDelegator extends ItemDefinitionDelegator>, PrismContainerDefinition { + + @Override + PrismContainerDefinition delegate(); + + @Override + default Class getCompileTimeClass() { + return delegate().getCompileTimeClass(); + } + + @Override + default ComplexTypeDefinition getComplexTypeDefinition() { + return delegate().getComplexTypeDefinition(); + } + + @Override + default String getDefaultNamespace() { + return delegate().getDefaultNamespace(); + } + + @Override + default List getIgnoredNamespaces() { + return delegate().getIgnoredNamespaces(); + } + + @Override + default List getDefinitions() { + return delegate().getDefinitions(); + } + + @Override + default Collection getItemNames() { + return delegate().getItemNames(); + } + + @Override + default ID findLocalItemDefinition(@NotNull QName name, @NotNull Class clazz, + boolean caseInsensitive) { + return delegate().findLocalItemDefinition(name, clazz, caseInsensitive); + } + + @Override + default ID findLocalItemDefinition(@NotNull QName name) { + return delegate().findLocalItemDefinition(name); + } + + @Override + default boolean isCompletelyDefined() { + return delegate().isCompletelyDefined(); + } + + @Override + default List getPropertyDefinitions() { + return delegate().getPropertyDefinitions(); + } + + @Override + default ID findItemDefinition(@NotNull ItemPath path) { + return delegate().findItemDefinition(path); + } + + @Override + default PrismReferenceDefinition findReferenceDefinition(@NotNull ItemName name) { + return delegate().findReferenceDefinition(name); + } + + @Override + default PrismContainerDefinition cloneWithReplacedDefinition(QName itemName, ItemDefinition newDefinition) { + return delegate().cloneWithReplacedDefinition(itemName, newDefinition); + } + + @Override + default void replaceDefinition(QName itemName, ItemDefinition newDefinition) { + delegate().replaceDefinition(itemName, newDefinition); + } + + @Override + default PrismContainerValue createValue() { + return delegate().createValue(); + } + + @Override + default PrismContainerDefinition findContainerDefinition(@NotNull String name) { + return delegate().findContainerDefinition(name); + } + + @Override + default boolean isEmpty() { + return delegate().isEmpty(); + } + + @Override + default boolean canRepresent(@NotNull QName type) { + return delegate().canRepresent(type); + } + + @Override + default ID findNamedItemDefinition(@NotNull QName firstName, @NotNull ItemPath rest, + @NotNull Class clazz) { + return delegate().findNamedItemDefinition(firstName, rest, clazz); + } + + @Override + default PrismPropertyDefinition findPropertyDefinition(@NotNull ItemPath path) { + return delegate().findPropertyDefinition(path); + } + + @Override + default PrismReferenceDefinition findReferenceDefinition(@NotNull ItemPath path) { + return delegate().findReferenceDefinition(path); + } + + @Override + default PrismContainerDefinition findContainerDefinition(@NotNull ItemPath path) { + return delegate().findContainerDefinition(path); + } + + @Override + default ContainerDelta createEmptyDelta(ItemPath path) { + return delegate().createEmptyDelta(path); + } + + @Override + default Class getTypeClass() { + return delegate().getTypeClass(); + } + + @Override + default Optional structuredType() { + return delegate().structuredType(); + } + +} diff --git a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/DefinitionDelegator.java b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/DefinitionDelegator.java new file mode 100644 index 00000000000..a42c1a81d08 --- /dev/null +++ b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/DefinitionDelegator.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +package com.evolveum.midpoint.prism.deleg; + +import java.util.IdentityHashMap; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.jetbrains.annotations.NotNull; + +import com.evolveum.midpoint.prism.Definition; +import com.evolveum.midpoint.prism.ItemProcessing; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.SchemaMigration; +import com.evolveum.midpoint.prism.SmartVisitation; +import com.evolveum.midpoint.prism.Visitor; +import com.evolveum.midpoint.prism.schema.SchemaRegistry; + +public interface DefinitionDelegator extends Definition { + + Definition delegate(); + + @Override + default PrismContext getPrismContext() { + return delegate().getPrismContext(); + } + + @Override + default void accept(Visitor visitor) { + delegate().accept(visitor); + } + + @Override + default String debugDump() { + return delegate().debugDump(); + } + + @Override + default boolean accept(Visitor visitor, SmartVisitation visitation) { + return delegate().accept(visitor, visitation); + } + + @Override + default @NotNull QName getTypeName() { + return delegate().getTypeName(); + } + + @Override + default String debugDump(int indent) { + return delegate().debugDump(indent); + } + + @Override + default Object debugDumpLazily() { + return delegate().debugDumpLazily(); + } + + @Override + default Object debugDumpLazily(int indent) { + return delegate().debugDumpLazily(indent); + } + + @Override + default boolean isRuntimeSchema() { + return delegate().isRuntimeSchema(); + } + + @Override + default boolean isIgnored() { + return delegate().isIgnored(); + } + + @Override + default ItemProcessing getProcessing() { + return delegate().getProcessing(); + } + + @Override + default boolean isAbstract() { + return delegate().isAbstract(); + } + + @Override + default boolean isDeprecated() { + return delegate().isDeprecated(); + } + + @Override + default boolean isExperimental() { + return delegate().isExperimental(); + } + + @Override + default String getPlannedRemoval() { + return delegate().getPlannedRemoval(); + } + + @Override + default boolean isElaborate() { + return delegate().isElaborate(); + } + + @Override + default String getDeprecatedSince() { + return delegate().getDeprecatedSince(); + } + + @Override + default boolean isEmphasized() { + return delegate().isEmphasized(); + } + + @Override + default String getDisplayName() { + return delegate().getDisplayName(); + } + + @Override + default Integer getDisplayOrder() { + return delegate().getDisplayOrder(); + } + + @Override + default String getHelp() { + return delegate().getHelp(); + } + + @Override + default String getDocumentation() { + return delegate().getDocumentation(); + } + + @Override + default String getDocumentationPreview() { + return delegate().getDocumentationPreview(); + } + + @Override + default SchemaRegistry getSchemaRegistry() { + return delegate().getSchemaRegistry(); + } + + @Override + default Class getTypeClassIfKnown() { + return delegate().getTypeClassIfKnown(); + } + + @Override + default Class getTypeClass() { + return delegate().getTypeClass(); + } + + @Override + default A getAnnotation(QName qname) { + return delegate().getAnnotation(qname); + } + + @Override + default void setAnnotation(QName qname, A value) { + delegate().setAnnotation(qname, value); + } + + @Override + default List getSchemaMigrations() { + return delegate().getSchemaMigrations(); + } + + @Override + default String debugDump(int indent, IdentityHashMap seen) { + return delegate().debugDump(indent, seen); + } + + @Override + default String getMutabilityFlag() { + return delegate().getMutabilityFlag(); + } +} diff --git a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ItemDefinitionDelegator.java b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ItemDefinitionDelegator.java new file mode 100644 index 00000000000..087de38feda --- /dev/null +++ b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ItemDefinitionDelegator.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +package com.evolveum.midpoint.prism.deleg; + +import java.util.Map; +import java.util.Optional; +import java.util.function.Consumer; + +import javax.xml.namespace.QName; + +import org.jetbrains.annotations.NotNull; + +import com.evolveum.midpoint.prism.ComplexTypeDefinition; +import com.evolveum.midpoint.prism.Item; +import com.evolveum.midpoint.prism.ItemDefinition; +import com.evolveum.midpoint.prism.PrismReferenceValue; +import com.evolveum.midpoint.prism.PrismValue; +import com.evolveum.midpoint.prism.delta.ItemDelta; +import com.evolveum.midpoint.prism.path.ItemName; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.util.exception.SchemaException; + +public interface ItemDefinitionDelegator> extends DefinitionDelegator, ItemDefinition { + + @Override + ItemDefinition delegate(); + + @Override + default boolean canRead() { + return delegate().canRead(); + } + + @Override + default @NotNull ItemName getItemName() { + return delegate().getItemName(); + } + + @Override + default String getNamespace() { + return delegate().getNamespace(); + } + + @Override + default int getMinOccurs() { + return delegate().getMinOccurs(); + } + + @Override + default int getMaxOccurs() { + return delegate().getMaxOccurs(); + } + + @Override + default boolean isSingleValue() { + return delegate().isSingleValue(); + } + + @Override + default boolean isMultiValue() { + return delegate().isMultiValue(); + } + + @Override + default boolean isMandatory() { + return delegate().isMandatory(); + } + + @Override + default boolean isOptional() { + return delegate().isOptional(); + } + + @Override + default boolean isOperational() { + return delegate().isOperational(); + } + + @Override + default boolean isIndexOnly() { + return delegate().isIndexOnly(); + } + + @Override + default boolean canModify() { + return delegate().canModify(); + } + + @Override + default boolean isInherited() { + return delegate().isInherited(); + } + + @Override + default boolean isDynamic() { + return delegate().isDynamic(); + } + + @Override + default boolean canAdd() { + return delegate().canAdd(); + } + + @Override + default QName getSubstitutionHead() { + return delegate().getSubstitutionHead(); + } + + @Override + default boolean isHeterogeneousListItem() { + return delegate().isHeterogeneousListItem(); + } + + @Override + default PrismReferenceValue getValueEnumerationRef() { + return delegate().getValueEnumerationRef(); + } + + @Override + default boolean isValidFor(QName elementQName, Class clazz) { + return delegate().isValidFor(elementQName, clazz); + } + + @Override + default boolean isValidFor(@NotNull QName elementQName, @NotNull Class clazz, + boolean caseInsensitive) { + return delegate().isValidFor(elementQName, clazz, caseInsensitive); + } + + @Override + default void adoptElementDefinitionFrom(ItemDefinition otherDef) { + delegate().adoptElementDefinitionFrom(otherDef); + } + + @Override + default @NotNull I instantiate() throws SchemaException { + return delegate().instantiate(); + } + + @Override + default @NotNull I instantiate(QName name) throws SchemaException { + return delegate().instantiate(name); + } + + @Override + default T findItemDefinition(@NotNull ItemPath path, @NotNull Class clazz) { + if (path.isEmpty()) { + if (clazz.isAssignableFrom(this.getClass())) { + return (T) this; + } else { + throw new IllegalArgumentException("Looking for definition of class " + clazz + " but found " + this); + } + } else { + return null; + } + } + + @Override + default ItemDelta createEmptyDelta(ItemPath path) { + return delegate().createEmptyDelta(path); + } + + @Override + default ItemDefinition deepClone(boolean ultraDeep, Consumer postCloneAction) { + return delegate().deepClone(ultraDeep, postCloneAction); + } + + @Override + default ItemDefinition deepClone(Map ctdMap, + Map onThisPath, Consumer postCloneAction) { + return delegate().deepClone(ctdMap, onThisPath, postCloneAction); + } + + @Override + default void debugDumpShortToString(StringBuilder sb) { + delegate().debugDumpShortToString(sb); + } + + @Override + default boolean canBeDefinitionOf(I item) { + return delegate().canBeDefinitionOf(item); + } + + @Override + default boolean canBeDefinitionOf(PrismValue pvalue) { + return delegate().canBeDefinitionOf(pvalue); + } + + @Override + default Optional structuredType() { + return delegate().structuredType(); + } + + +} diff --git a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ObjectDefinitionDelegator.java b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ObjectDefinitionDelegator.java new file mode 100644 index 00000000000..b99334aee79 --- /dev/null +++ b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ObjectDefinitionDelegator.java @@ -0,0 +1,48 @@ +package com.evolveum.midpoint.prism.deleg; + +import java.util.function.Consumer; + +import javax.xml.namespace.QName; + +import org.jetbrains.annotations.NotNull; + +import com.evolveum.midpoint.prism.ItemDefinition; +import com.evolveum.midpoint.prism.Objectable; +import com.evolveum.midpoint.prism.PrismContainerDefinition; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.PrismObjectDefinition; +import com.evolveum.midpoint.prism.PrismObjectValue; +import com.evolveum.midpoint.util.exception.SchemaException; + +public interface ObjectDefinitionDelegator extends ContainerDefinitionDelegator, PrismObjectDefinition { + + @Override + public PrismObjectDefinition delegate(); + + @Override + default PrismContainerDefinition getExtensionDefinition() { + return delegate().getExtensionDefinition(); + } + + @Override + default @NotNull PrismObject instantiate() throws SchemaException { + return delegate().instantiate(); + } + + @Override + default @NotNull PrismObject instantiate(QName name) throws SchemaException { + return delegate().instantiate(name); + } + + @Override + default PrismObjectValue createValue() { + return delegate().createValue(); + } + + @Override + PrismObjectDefinition cloneWithReplacedDefinition(QName itemName, ItemDefinition newDefinition); + + @Override + PrismObjectDefinition deepClone(boolean ultraDeep, Consumer postCloneAction); + +} diff --git a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/PropertyDefinitionDelegator.java b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/PropertyDefinitionDelegator.java new file mode 100644 index 00000000000..98d259b9320 --- /dev/null +++ b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/PropertyDefinitionDelegator.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +package com.evolveum.midpoint.prism.deleg; + +import java.util.Collection; +import javax.xml.namespace.QName; + +import org.jetbrains.annotations.NotNull; + +import com.evolveum.midpoint.prism.PrismProperty; +import com.evolveum.midpoint.prism.PrismPropertyDefinition; +import com.evolveum.midpoint.prism.delta.PropertyDelta; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.util.DisplayableValue; + +public interface PropertyDefinitionDelegator extends ItemDefinitionDelegator>, PrismPropertyDefinition { + + @Override + PrismPropertyDefinition delegate(); + + @Override + default Collection> getAllowedValues() { + return delegate().getAllowedValues(); + } + + @Override + default T defaultValue() { + return delegate().defaultValue(); + } + + @Deprecated + @Override + default QName getValueType() { + return delegate().getValueType(); + } + + @Override + default Boolean isIndexed() { + return delegate().isIndexed(); + } + + @Override + default boolean isAnyType() { + return delegate().isAnyType(); + } + + @Override + default QName getMatchingRuleQName() { + return delegate().getMatchingRuleQName(); + } + + @Override + default PropertyDelta createEmptyDelta(ItemPath path) { + return delegate().createEmptyDelta(path); + } + + @Override + default @NotNull PrismProperty instantiate() { + return delegate().instantiate(); + } + + @Override + default @NotNull PrismProperty instantiate(QName name) { + return delegate().instantiate(name); + } + + @Override + default Class getTypeClass() { + return delegate().getTypeClass(); + } +} diff --git a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ReferenceDefinitionDelegator.java b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ReferenceDefinitionDelegator.java new file mode 100644 index 00000000000..d28e8241982 --- /dev/null +++ b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ReferenceDefinitionDelegator.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +package com.evolveum.midpoint.prism.deleg; + +import javax.xml.namespace.QName; + +import org.jetbrains.annotations.NotNull; + +import com.evolveum.midpoint.prism.PrismReference; +import com.evolveum.midpoint.prism.PrismReferenceDefinition; + +public interface ReferenceDefinitionDelegator extends ItemDefinitionDelegator, PrismReferenceDefinition { + + @Override + PrismReferenceDefinition delegate(); + + @Override + default QName getTargetTypeName() { + return delegate().getTargetTypeName(); + } + + @Deprecated + @Override + default QName getCompositeObjectElementName() { + return delegate().getCompositeObjectElementName(); + } + + @Override + default boolean isComposite() { + return delegate().isComposite(); + } + + @Override + default @NotNull PrismReference instantiate() { + return delegate().instantiate(); + } + + @Override + default @NotNull PrismReference instantiate(QName name) { + return delegate().instantiate(name); + } + +} diff --git a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/TypeDefinitionDelegator.java b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/TypeDefinitionDelegator.java new file mode 100644 index 00000000000..d7c4ee06160 --- /dev/null +++ b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/TypeDefinitionDelegator.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +package com.evolveum.midpoint.prism.deleg; + +import java.util.Collection; + +import javax.xml.namespace.QName; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.evolveum.midpoint.prism.TypeDefinition; + +public interface TypeDefinitionDelegator extends DefinitionDelegator, TypeDefinition { + + @Override + TypeDefinition delegate(); + + @Override + default @Nullable Class getCompileTimeClass() { + return delegate().getCompileTimeClass(); + } + + @Override + default @Nullable QName getSuperType() { + return delegate().getSuperType(); + } + + @Override + default @NotNull Collection getStaticSubTypes() { + return delegate().getStaticSubTypes(); + } + + @Override + default Integer getInstantiationOrder() { + return delegate().getInstantiationOrder(); + } + + @Override + default boolean canRepresent(QName typeName) { + return delegate().canRepresent(typeName); + } +} From 2a71216f79061e457b9e9c26a8aeb29cda7a910d Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Tue, 25 May 2021 19:22:45 +0200 Subject: [PATCH 07/23] Added mutable interface to PrismAccessDefinition --- .../midpoint/prism/PrismItemAccessDefinition.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/PrismItemAccessDefinition.java b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/PrismItemAccessDefinition.java index fc6f608dba7..e0c8ccae369 100644 --- a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/PrismItemAccessDefinition.java +++ b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/PrismItemAccessDefinition.java @@ -46,4 +46,14 @@ public interface PrismItemAccessDefinition { * itself: the "shell" of the container. */ boolean canAdd(); + + interface Mutable extends PrismItemAccessDefinition { + + void setCanRead(boolean val); + + void setCanModify(boolean val); + + void setCanAdd(boolean val); + + } } From 903d157f495924a7a4b3f14751329ebc8f4020a0 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Wed, 26 May 2021 18:37:13 +0200 Subject: [PATCH 08/23] Added delegators for refined definitions --- .../RefinedAttributeDefinitionDelegator.java | 174 ++++++++++++++++++ .../deleg/ContainerDefinitionDelegator.java | 6 + ...AttributeContainerDefinitionDelegator.java | 120 ++++++++++++ .../deleg/AttributeDefinitionDelegator.java | 63 +++++++ .../ObjectClassTypeDefinitionDelegator.java | 134 ++++++++++++++ 5 files changed, 497 insertions(+) create mode 100644 infra/common/src/main/java/com/evolveum/midpoint/common/refinery/deleg/RefinedAttributeDefinitionDelegator.java create mode 100644 infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/deleg/AttributeContainerDefinitionDelegator.java create mode 100644 infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/deleg/AttributeDefinitionDelegator.java create mode 100644 infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/deleg/ObjectClassTypeDefinitionDelegator.java diff --git a/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/deleg/RefinedAttributeDefinitionDelegator.java b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/deleg/RefinedAttributeDefinitionDelegator.java new file mode 100644 index 00000000000..d8bcc6ddbbc --- /dev/null +++ b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/deleg/RefinedAttributeDefinitionDelegator.java @@ -0,0 +1,174 @@ +package com.evolveum.midpoint.common.refinery.deleg; + +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import javax.xml.namespace.QName; + +import com.evolveum.midpoint.common.refinery.PropertyLimitations; +import com.evolveum.midpoint.common.refinery.RefinedAttributeDefinition; +import com.evolveum.midpoint.prism.ComplexTypeDefinition; +import com.evolveum.midpoint.prism.ItemDefinition; +import com.evolveum.midpoint.prism.ItemProcessing; +import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; +import com.evolveum.midpoint.schema.processor.deleg.AttributeDefinitionDelegator; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AttributeFetchStrategyType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AttributeStorageStrategyType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.LayerType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingType; + +public interface RefinedAttributeDefinitionDelegator extends AttributeDefinitionDelegator, RefinedAttributeDefinition { + + @Override + RefinedAttributeDefinition delegate(); + + @Override + default boolean isTolerant() { + return delegate().isTolerant(); + } + + @Override + default Boolean isSecondaryIdentifierOverride() { + return delegate().isSecondaryIdentifierOverride(); + } + + @Override + default boolean canAdd(LayerType layer) { + return delegate().canAdd(layer); + } + + @Override + default boolean canRead(LayerType layer) { + return delegate().canRead(layer); + } + + @Override + default boolean canModify(LayerType layer) { + return delegate().canModify(layer); + } + + @Override + default boolean isIgnored(LayerType layer) { + return delegate().isIgnored(layer); + } + + @Override + default ItemProcessing getProcessing(LayerType layer) { + return delegate().getProcessing(layer); + } + + @Override + default String getDescription() { + return delegate().getDescription(); + } + + @Override + default ResourceAttributeDefinition getAttributeDefinition() { + return delegate().getAttributeDefinition(); + } + + @Override + default MappingType getOutboundMappingType() { + return delegate().getOutboundMappingType(); + } + + @Override + default boolean hasOutboundMapping() { + return delegate().hasOutboundMapping(); + } + + @Override + default List getInboundMappingTypes() { + return delegate().getInboundMappingTypes(); + } + + @Override + default int getMaxOccurs(LayerType layer) { + return delegate().getMaxOccurs(layer); + } + + @Override + default int getMinOccurs(LayerType layer) { + return delegate().getMinOccurs(layer); + } + + @Override + default boolean isOptional(LayerType layer) { + return delegate().isOptional(layer); + } + + @Override + default boolean isMandatory(LayerType layer) { + return delegate().isMandatory(layer); + } + + @Override + default boolean isMultiValue(LayerType layer) { + return delegate().isMultiValue(layer); + } + + @Override + default boolean isSingleValue(LayerType layer) { + return delegate().isSingleValue(layer); + } + + @Override + default boolean isExclusiveStrong() { + return delegate().isExclusiveStrong(); + } + + @Override + default PropertyLimitations getLimitations(LayerType layer) { + return delegate().getLimitations(layer); + } + + @Override + default AttributeFetchStrategyType getFetchStrategy() { + return delegate().getFetchStrategy(); + } + + @Override + default AttributeStorageStrategyType getStorageStrategy() { + return delegate().getStorageStrategy(); + } + + @Override + default List getTolerantValuePattern() { + return delegate().getTolerantValuePattern(); + } + + @Override + default List getIntolerantValuePattern() { + return delegate().getIntolerantValuePattern(); + } + + @Override + default boolean isVolatilityTrigger() { + return delegate().isVolatilityTrigger(); + } + + @Override + default String debugDump(int indent, LayerType layer) { + return delegate().debugDump(indent, layer); + } + + @Override + default Integer getModificationPriority() { + return delegate().getModificationPriority(); + } + + @Override + default Boolean getReadReplaceMode() { + return delegate().getReadReplaceMode(); + } + + @Override + default boolean isDisplayNameAttribute() { + return delegate().isDisplayNameAttribute(); + } + + @Override + RefinedAttributeDefinition deepClone(Map ctdMap, + Map onThisPath, Consumer postCloneAction); +} diff --git a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ContainerDefinitionDelegator.java b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ContainerDefinitionDelegator.java index a190260339f..5b998e07619 100644 --- a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ContainerDefinitionDelegator.java +++ b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ContainerDefinitionDelegator.java @@ -92,6 +92,12 @@ default PrismReferenceDefinition findReferenceDefinition(@NotNull ItemName name) return delegate().findReferenceDefinition(name); } + @Override + default T findItemDefinition(@NotNull ItemPath path, @NotNull Class clazz) { + return delegate().findItemDefinition(path, clazz); + } + + @Override default PrismContainerDefinition cloneWithReplacedDefinition(QName itemName, ItemDefinition newDefinition) { return delegate().cloneWithReplacedDefinition(itemName, newDefinition); diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/deleg/AttributeContainerDefinitionDelegator.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/deleg/AttributeContainerDefinitionDelegator.java new file mode 100644 index 00000000000..b806721253c --- /dev/null +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/deleg/AttributeContainerDefinitionDelegator.java @@ -0,0 +1,120 @@ +package com.evolveum.midpoint.schema.processor.deleg; + +import java.util.Collection; +import java.util.List; +import javax.xml.namespace.QName; + +import org.jetbrains.annotations.NotNull; + +import com.evolveum.midpoint.prism.PrismObjectDefinition; +import com.evolveum.midpoint.prism.deleg.ContainerDefinitionDelegator; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition; +import com.evolveum.midpoint.schema.processor.ResourceAttributeContainer; +import com.evolveum.midpoint.schema.processor.ResourceAttributeContainerDefinition; +import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowAttributesType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; + +public interface AttributeContainerDefinitionDelegator extends ContainerDefinitionDelegator, ResourceAttributeContainerDefinition { + + @Override + ResourceAttributeContainerDefinition delegate(); + + @Override + default Collection getPrimaryIdentifiers() { + return delegate().getPrimaryIdentifiers(); + } + + @Override + default Collection getSecondaryIdentifiers() { + return delegate().getSecondaryIdentifiers(); + } + + @Override + default Collection getAllIdentifiers() { + return delegate().getAllIdentifiers(); + } + + @Override + default ResourceAttributeDefinition getDescriptionAttribute() { + return delegate().getDescriptionAttribute(); + } + + @Override + default ResourceAttributeDefinition getNamingAttribute() { + return delegate().getNamingAttribute(); + } + + @Override + default String getNativeObjectClass() { + return delegate().getNativeObjectClass(); + } + + @Override + default boolean isDefaultInAKind() { + return delegate().isDefaultInAKind(); + } + + @Override + default String getIntent() { + return delegate().getIntent(); + } + + @Override + default ShadowKindType getKind() { + return delegate().getKind(); + } + + @Override + default ResourceAttributeDefinition getDisplayNameAttribute() { + return delegate().getDisplayNameAttribute(); + } + + @Override + default ResourceAttributeDefinition findAttributeDefinition(QName elementQName, boolean caseInsensitive) { + return delegate().findAttributeDefinition(elementQName, caseInsensitive); + } + + @Override + default ResourceAttributeDefinition findAttributeDefinition(ItemPath elementPath) { + return delegate().findAttributeDefinition(elementPath); + } + + @Override + default ResourceAttributeDefinition findAttributeDefinition(String elementLocalname) { + return delegate().findAttributeDefinition(elementLocalname); + } + + @Override + default List getAttributeDefinitions() { + return delegate().getAttributeDefinitions(); + } + + @Override + default @NotNull PrismObjectDefinition toShadowDefinition() { + return delegate().toShadowDefinition(); + } + + @Override + default @NotNull ResourceAttributeContainer instantiate() { + return delegate().instantiate(); + } + + @Override + default @NotNull ResourceAttributeContainer instantiate(QName name) { + return delegate().instantiate(name); + } + + @Override + default List getDefinitions() { + return delegate().getDefinitions(); + } + + @Override + default ObjectClassComplexTypeDefinition getComplexTypeDefinition() { + return delegate().getComplexTypeDefinition(); + } + +} diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/deleg/AttributeDefinitionDelegator.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/deleg/AttributeDefinitionDelegator.java new file mode 100644 index 00000000000..18cbcd6f486 --- /dev/null +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/deleg/AttributeDefinitionDelegator.java @@ -0,0 +1,63 @@ +package com.evolveum.midpoint.schema.processor.deleg; + +import javax.xml.namespace.QName; + +import org.jetbrains.annotations.NotNull; + +import com.evolveum.midpoint.prism.deleg.PropertyDefinitionDelegator; +import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition; +import com.evolveum.midpoint.schema.processor.ResourceAttribute; +import com.evolveum.midpoint.schema.processor.ResourceAttributeContainerDefinition; +import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; + +public interface AttributeDefinitionDelegator extends PropertyDefinitionDelegator, ResourceAttributeDefinition { + + @Override + ResourceAttributeDefinition delegate(); + + @Override + default Boolean getReturnedByDefault() { + return delegate().getReturnedByDefault(); + } + + @Override + default boolean isReturnedByDefault() { + return delegate().isReturnedByDefault(); + } + + @Override + default boolean isPrimaryIdentifier(ResourceAttributeContainerDefinition objectDefinition) { + return delegate().isPrimaryIdentifier(objectDefinition); + } + + @Override + default boolean isPrimaryIdentifier(ObjectClassComplexTypeDefinition objectDefinition) { + return delegate().isPrimaryIdentifier(objectDefinition); + } + + @Override + default boolean isSecondaryIdentifier(ObjectClassComplexTypeDefinition objectDefinition) { + return delegate().isSecondaryIdentifier(objectDefinition); + } + + @Override + default String getNativeAttributeName() { + return delegate().getNativeAttributeName(); + } + + @Override + default String getFrameworkAttributeName() { + return delegate().getFrameworkAttributeName(); + } + + @Override + default @NotNull ResourceAttribute instantiate() { + return delegate().instantiate(); + } + + @Override + default @NotNull ResourceAttribute instantiate(QName name) { + return delegate().instantiate(name); + } + +} diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/deleg/ObjectClassTypeDefinitionDelegator.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/deleg/ObjectClassTypeDefinitionDelegator.java new file mode 100644 index 00000000000..13eccb06627 --- /dev/null +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/deleg/ObjectClassTypeDefinitionDelegator.java @@ -0,0 +1,134 @@ +package com.evolveum.midpoint.schema.processor.deleg; + +import java.util.Collection; +import javax.xml.namespace.QName; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.evolveum.midpoint.prism.deleg.ComplexTypeDefinitionDelegator; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition; +import com.evolveum.midpoint.schema.processor.ResourceAttributeContainer; +import com.evolveum.midpoint.schema.processor.ResourceAttributeContainerDefinition; +import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; + +public interface ObjectClassTypeDefinitionDelegator extends ComplexTypeDefinitionDelegator, ObjectClassComplexTypeDefinition { + + @Override + ObjectClassComplexTypeDefinition delegate(); + + @Override + default @NotNull Collection> getAttributeDefinitions() { + return delegate().getAttributeDefinitions(); + } + + @Override + default @Nullable ResourceAttributeDefinition findAttributeDefinition(QName name) { + return delegate().findAttributeDefinition(name); + } + + @Override + default @Nullable ResourceAttributeDefinition findAttributeDefinition(QName name, boolean caseInsensitive) { + return delegate().findAttributeDefinition(name, caseInsensitive); + } + + @Override + default ResourceAttributeDefinition findAttributeDefinition(String name) { + return delegate().findAttributeDefinition(name); + } + + @Override + default @NotNull Collection> getPrimaryIdentifiers() { + return delegate().getPrimaryIdentifiers(); + } + + @Override + default boolean isPrimaryIdentifier(QName attrName) { + return delegate().isPrimaryIdentifier(attrName); + } + + @Override + default @NotNull Collection> getSecondaryIdentifiers() { + return delegate().getSecondaryIdentifiers(); + } + + @Override + default boolean isSecondaryIdentifier(QName attrName) { + return delegate().isSecondaryIdentifier(attrName); + } + + @Override + default ResourceAttributeDefinition getDescriptionAttribute() { + return delegate().getDescriptionAttribute(); + } + + @Override + default ResourceAttributeDefinition getNamingAttribute() { + return delegate().getNamingAttribute(); + } + + @Override + default ResourceAttributeDefinition getDisplayNameAttribute() { + return delegate().getDisplayNameAttribute(); + } + + @Override + default Collection> getAllIdentifiers() { + return delegate().getAllIdentifiers(); + } + + @Override + default String getNativeObjectClass() { + return delegate().getNativeObjectClass(); + } + + @Override + default boolean isAuxiliary() { + return delegate().isAuxiliary(); + } + + @Override + default ShadowKindType getKind() { + return delegate().getKind(); + } + + @Override + default boolean isDefaultInAKind() { + return delegate().isDefaultInAKind(); + } + + @Override + default String getIntent() { + return delegate().getIntent(); + } + + @Override + default ResourceAttributeContainerDefinition toResourceAttributeContainerDefinition() { + return delegate().toResourceAttributeContainerDefinition(); + } + + @Override + default ResourceAttributeContainerDefinition toResourceAttributeContainerDefinition(QName elementName) { + return delegate().toResourceAttributeContainerDefinition(elementName); + } + + @Override + default ObjectQuery createShadowSearchQuery(String resourceOid) throws SchemaException { + return delegate().createShadowSearchQuery(resourceOid); + } + + @Override + default ResourceAttributeContainer instantiate(QName elementName) { + return delegate().instantiate(elementName); + } + + @Deprecated + @Override + default boolean matches(ShadowType shadow) { + return delegate().matches(shadow); + } +} From 0f1292ecb250da0721bc80cf638b5f47e1469f05 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Wed, 26 May 2021 18:38:29 +0200 Subject: [PATCH 09/23] Added Transformable Definitions implementations. Instead of full copies, these carry only changes to common access / customization attributes of schema --- .../TransformableComplexTypeDefinition.java | 220 +++++++++++++ .../TransformableContainerDefinition.java | 309 ++++++++++++++++++ .../TransformableItemDefinition.java | 254 ++++++++++++++ .../TransformableObjectDefinition.java | 85 +++++ .../TransformablePropertyDefinition.java | 103 ++++++ .../TransformableReferenceDefinition.java | 49 +++ 6 files changed, 1020 insertions(+) create mode 100644 model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableComplexTypeDefinition.java create mode 100644 model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableContainerDefinition.java create mode 100644 model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableItemDefinition.java create mode 100644 model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableObjectDefinition.java create mode 100644 model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformablePropertyDefinition.java create mode 100644 model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableReferenceDefinition.java diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableComplexTypeDefinition.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableComplexTypeDefinition.java new file mode 100644 index 00000000000..8d02d469ce1 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableComplexTypeDefinition.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +package com.evolveum.midpoint.model.impl.schema.transform; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Consumer; + +import javax.xml.namespace.QName; + +import org.jetbrains.annotations.NotNull; + +import com.evolveum.midpoint.prism.ComplexTypeDefinition; +import com.evolveum.midpoint.prism.ItemDefinition; +import com.evolveum.midpoint.prism.MutableComplexTypeDefinition; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.deleg.ComplexTypeDefinitionDelegator; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.schema.processor.MutableObjectClassComplexTypeDefinition; +import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition; +import com.evolveum.midpoint.schema.processor.deleg.ObjectClassTypeDefinitionDelegator; + +public class TransformableComplexTypeDefinition implements ComplexTypeDefinitionDelegator { + + + private static final long serialVersionUID = 1L; + private final Map> overrides = new HashMap<>(); + private transient ComplexTypeDefinition delegate; + + public TransformableComplexTypeDefinition(ComplexTypeDefinition delegate) { + this.delegate = delegate; + } + + @Override + public ComplexTypeDefinition delegate() { + return delegate; + } + + public static TransformableComplexTypeDefinition from(ComplexTypeDefinition complexTypeDefinition) { + if (complexTypeDefinition instanceof ObjectClassComplexTypeDefinition) { + return new ObjectClass(complexTypeDefinition); + } + if (complexTypeDefinition != null) { + return new TransformableComplexTypeDefinition(complexTypeDefinition); + } + return null; + } + + @SuppressWarnings("rawtypes") + @Override + public ID findLocalItemDefinition(@NotNull QName name) { + return overriden(ComplexTypeDefinitionDelegator.super.findLocalItemDefinition(name)); + } + + @SuppressWarnings("unchecked") + private > ID overriden(ID originalItem) { + if (originalItem == null) { + return null; + } + ItemDefinition overriden = overrides.computeIfAbsent(originalItem.getItemName(), k -> TransformableItemDefinition.from(originalItem)); + TransformableItemDefinition.apply(overriden, originalItem); + return (ID) overriden; + } + + @SuppressWarnings("rawtypes") + @Override + public ID findLocalItemDefinition(@NotNull QName name, @NotNull Class clazz, + boolean caseInsensitive) { + return overriden(ComplexTypeDefinitionDelegator.super.findLocalItemDefinition(name, clazz, caseInsensitive)); + } + + @SuppressWarnings("rawtypes") + @Override + public ID findItemDefinition(@NotNull ItemPath path, @NotNull Class clazz) { + // FIXME: Implement proper + return overriden(ComplexTypeDefinitionDelegator.super.findItemDefinition(path, clazz)); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public ID findItemDefinition(@NotNull ItemPath path) { + return (ID) findItemDefinition(path, ItemDefinition.class); + } + + @SuppressWarnings("rawtypes") + @Override + public ID findNamedItemDefinition(@NotNull QName firstName, @NotNull ItemPath rest, + @NotNull Class clazz) { + + ItemDefinition itemDef = findLocalItemDefinition(firstName); + if (itemDef != null) { + // FIXME: Is this correct? + return itemDef.findItemDefinition(rest, clazz); + } + return null; + } + + @Override + public @NotNull List> getDefinitions() { + List> ret = new ArrayList<>(); + for (ItemDefinition originalItem : ComplexTypeDefinitionDelegator.super.getDefinitions()) { + ret.add(overriden(originalItem)); + } + return ret; + } + + @Override + public Optional> substitution(QName name) { + Optional> original = ComplexTypeDefinitionDelegator.super.substitution(name); + if (original.isPresent()) { + return Optional.of(overriden(original.get())); + } + return Optional.empty(); + } + + @Override + public Optional> itemOrSubstitution(QName name) { + Optional> original = ComplexTypeDefinitionDelegator.super.itemOrSubstitution(name); + if (original.isPresent()) { + return Optional.of(overriden(original.get())); + } + return Optional.empty(); + } + + @Override + public void revive(PrismContext prismContext) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public ComplexTypeDefinition clone() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isImmutable() { + return false; + } + + @Override + public void freeze() { + // NOOP for now + } + + @SuppressWarnings("rawtypes") + @Override + public @NotNull ComplexTypeDefinition deepClone(Map ctdMap, + Map onThisPath, Consumer postCloneAction) { + throw new UnsupportedOperationException(); + } + + @Override + public MutableComplexTypeDefinition toMutable() { + throw new UnsupportedOperationException(); + } + + /** + * + * Currently used only to replace Refined* with LayerRefined* + * + * @param name + * @param definition + */ + public void replaceDefinition(QName name, ItemDefinition definition) { + overrides.put(name, definition); + } + + public TransformableComplexTypeDefinition copy() { + TransformableComplexTypeDefinition copy = new TransformableComplexTypeDefinition(delegate()); + copy.overrides.putAll(overrides); + return copy; + } + + + public static class ObjectClass extends TransformableComplexTypeDefinition implements ObjectClassTypeDefinitionDelegator { + + private static final long serialVersionUID = 1L; + + public ObjectClass(ComplexTypeDefinition delegate) { + super(delegate); + } + + @Override + public ObjectClassComplexTypeDefinition delegate() { + return (ObjectClassComplexTypeDefinition) super.delegate(); + } + + @Override + public ObjectClassComplexTypeDefinition clone() { + throw new UnsupportedOperationException(); + } + + @Override + public ObjectClass copy() { + return new ObjectClass(this); + } + + @Override + public MutableObjectClassComplexTypeDefinition toMutable() { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("rawtypes") + @Override + public @NotNull ObjectClassComplexTypeDefinition deepClone(Map ctdMap, + Map onThisPath, Consumer postCloneAction) { + throw new UnsupportedOperationException(); + } + + } + +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableContainerDefinition.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableContainerDefinition.java new file mode 100644 index 00000000000..38a2d452ec2 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableContainerDefinition.java @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +package com.evolveum.midpoint.model.impl.schema.transform; + +import java.util.ArrayList; +import java.util.List; +import javax.xml.namespace.QName; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.evolveum.midpoint.prism.ComplexTypeDefinition; +import com.evolveum.midpoint.prism.Containerable; +import com.evolveum.midpoint.prism.ItemDefinition; +import com.evolveum.midpoint.prism.MutablePrismContainerDefinition; +import com.evolveum.midpoint.prism.PrismContainer; +import com.evolveum.midpoint.prism.PrismContainerDefinition; +import com.evolveum.midpoint.prism.PrismContainerValue; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.PrismPropertyDefinition; +import com.evolveum.midpoint.prism.PrismReferenceDefinition; +import com.evolveum.midpoint.prism.deleg.ContainerDefinitionDelegator; +import com.evolveum.midpoint.prism.delta.ContainerDelta; +import com.evolveum.midpoint.prism.path.ItemName; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.schema.processor.ResourceAttributeContainerDefinition; +import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; +import com.evolveum.midpoint.schema.processor.deleg.AttributeContainerDefinitionDelegator; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowAttributesType; +import com.google.common.base.Preconditions; + +public class TransformableContainerDefinition extends TransformableItemDefinition, PrismContainerDefinition> implements ContainerDefinitionDelegator { + + + + + private static final long serialVersionUID = 1L; + + protected final TransformableComplexTypeDefinition complexTypeDefinition; + + protected TransformableContainerDefinition(PrismContainerDefinition delegate) { + this(delegate, delegate.getComplexTypeDefinition()); + + } + + public TransformableContainerDefinition(PrismContainerDefinition delegate, ComplexTypeDefinition typeDef) { + super(delegate); + complexTypeDefinition = TransformableComplexTypeDefinition.from(typeDef); + } + + + + public static TransformableContainerDefinition of(PrismContainerDefinition originalItem) { + if (originalItem instanceof TransformableContainerDefinition) { + return (TransformableContainerDefinition) originalItem; + } + if (originalItem instanceof ResourceAttributeContainerDefinition) { + return (TransformableContainerDefinition) new AttributeContainer((ResourceAttributeContainerDefinition) originalItem); + } + + return new TransformableContainerDefinition<>(originalItem); + } + + @Override + public @NotNull QName getTypeName() { + return complexTypeDefinition.getTypeName(); + } + + @Override + public Class getTypeClass() { + return complexTypeDefinition.getTypeClass(); + } + + @SuppressWarnings("unchecked") + @Override + public ID findItemDefinition(@NotNull ItemPath path) { + return (ID) findItemDefinition(path, ItemDefinition.class); + } + + @Override + public T findItemDefinition(@NotNull ItemPath path, @NotNull Class clazz) { + for (;;) { + if (path.isEmpty() && clazz.isInstance(this)) { + return clazz.cast(this); + } + @Nullable + Object first = path.first(); + if (ItemPath.isName(first)) { + return findNamedItemDefinition(ItemPath.toName(first), path.rest(), clazz); + } + if (ItemPath.isId(first)) { + path = path.rest(); + } else if (ItemPath.isParent(first)) { + // FIXME: Probably lookup parent? + throw new IllegalArgumentException("Parent path in limited context"); + } else if (ItemPath.isObjectReference(first)) { + throw new IllegalStateException("Couldn't use '@' path segment in this context. PCD=" + getTypeName() + ", path=" + path); + } else { + throw new IllegalStateException("Unexpected path segment: " + first + " in " + path); + } + } + } + + + @Override + public ID findLocalItemDefinition(@NotNull QName name, @NotNull Class clazz, + boolean caseInsensitive) { + if (complexTypeDefinition != null) { + return complexTypeDefinition.findLocalItemDefinition(name, clazz, caseInsensitive); + } else { + return null; // xsd:any and similar dynamic definitions + } + } + + @Override + public ID findNamedItemDefinition(@NotNull QName firstName, @NotNull ItemPath rest, + @NotNull Class clazz) { + if (complexTypeDefinition != null) { + ID maybe = complexTypeDefinition.findNamedItemDefinition(firstName, rest, clazz); + if (maybe != null) { + return maybe; + } + } + if (complexTypeDefinition != null && complexTypeDefinition.isXsdAnyMarker()) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + return null; + } + + @Override + public PrismContainerDefinition findContainerDefinition(@NotNull ItemPath path) { + return findItemDefinition(path, PrismContainerDefinition.class); + } + + @Override + public ID findLocalItemDefinition(@NotNull QName name) { + return (ID) findLocalItemDefinition(name, ItemDefinition.class, false); + } + + @SuppressWarnings("unchecked") + @Override + public PrismPropertyDefinition findPropertyDefinition(@NotNull ItemPath path) { + return findItemDefinition(path, PrismPropertyDefinition.class); + } + + @Override + public PrismReferenceDefinition findReferenceDefinition(@NotNull ItemName name) { + return findLocalItemDefinition(name, PrismReferenceDefinition.class, false); + } + + @Override + public PrismReferenceDefinition findReferenceDefinition(@NotNull ItemPath path) { + return findItemDefinition(path, PrismReferenceDefinition.class); + } + + @SuppressWarnings("unchecked") + @Override + public PrismContainerDefinition findContainerDefinition(@NotNull String name) { + return findItemDefinition(new ItemName(name), PrismContainerDefinition.class); + } + + @Override + public Class getCompileTimeClass() { + return delegate().getCompileTimeClass(); + } + + @Override + public TransformableComplexTypeDefinition getComplexTypeDefinition() { + return complexTypeDefinition; + } + + @Override + public String getDefaultNamespace() { + return delegate().getDefaultNamespace(); + } + + @Override + public List getIgnoredNamespaces() { + return delegate().getIgnoredNamespaces(); + } + + @Override + public List getDefinitions() { + if (complexTypeDefinition != null) { + return complexTypeDefinition.getDefinitions(); + } + return new ArrayList<>(); + } + + @Override + public boolean isCompletelyDefined() { + return delegate().isCompletelyDefined(); + } + + @Override + public List getPropertyDefinitions() { + List props = new ArrayList<>(); + for (ItemDefinition def : complexTypeDefinition.getDefinitions()) { + if (def instanceof PrismPropertyDefinition) { + props.add((PrismPropertyDefinition) def); + } + } + return props; + } + + @Override + public ContainerDelta createEmptyDelta(ItemPath path) { + return delegate().createEmptyDelta(path); + } + + @Override + public @NotNull PrismContainerDefinition clone() { + throw new UnsupportedOperationException("Clone not supported"); + } + + @Override + public PrismContainerDefinition cloneWithReplacedDefinition(QName itemName, ItemDefinition newDefinition) { + TransformableComplexTypeDefinition typeDefCopy = complexTypeDefinition.copy(); + typeDefCopy.replaceDefinition(itemName, newDefinition); + return new TransformableContainerDefinition<>(this, typeDefCopy); + } + + @Override + public void replaceDefinition(QName itemName, ItemDefinition newDefinition) { + complexTypeDefinition.replaceDefinition(itemName, newDefinition); + } + + + @Override + public MutablePrismContainerDefinition toMutable() { + return null; + } + + @Override + public boolean isImmutable() { + // TODO Auto-generated method stub + return false; + } + + @Override + public void freeze() { + // FIXME: Intentional NOOP + } + + + @Override + protected PrismContainerDefinition publicView() { + return this; + } + + public static void ensureMutableType(PrismContainerValue pcv) { + PrismContainerDefinition origDef = pcv.getDefinition(); + ComplexTypeDefinition complexTypeDef = pcv.getComplexTypeDefinition(); + if (complexTypeDef instanceof TransformableComplexTypeDefinition) { + return; + } + try { + pcv.applyDefinition(new TransformableContainerDefinition<>(origDef, complexTypeDef), true); + } catch (SchemaException e) { + throw new IllegalStateException("Can not apply wrapped definition", e); + } + } + + public static TransformableContainerDefinition require(PrismContainerDefinition assocContainer) { + Preconditions.checkArgument(assocContainer instanceof TransformableContainerDefinition); + return (TransformableContainerDefinition) assocContainer; + } + + public static class AttributeContainer extends TransformableContainerDefinition implements AttributeContainerDefinitionDelegator { + + /** + * + */ + private static final long serialVersionUID = 1L; + + protected AttributeContainer(ResourceAttributeContainerDefinition delegate) { + super(delegate); + } + + @Override + public ResourceAttributeContainerDefinition delegate() { + return (ResourceAttributeContainerDefinition) super.delegate(); + } + + @Override + public List getDefinitions() { + // FIXME: Later + return (List) super.getDefinitions(); + } + + @Override + public TransformableComplexTypeDefinition.ObjectClass getComplexTypeDefinition() { + return (TransformableComplexTypeDefinition.ObjectClass) super.getComplexTypeDefinition(); + } + + @Override + public @NotNull ResourceAttributeContainerDefinition clone() { + throw new UnsupportedOperationException(); + } + + } +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableItemDefinition.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableItemDefinition.java new file mode 100644 index 00000000000..5f3400f99da --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableItemDefinition.java @@ -0,0 +1,254 @@ +package com.evolveum.midpoint.model.impl.schema.transform; + +import com.evolveum.midpoint.prism.Item; +import com.evolveum.midpoint.prism.ItemDefinition; +import com.evolveum.midpoint.prism.ItemProcessing; +import com.evolveum.midpoint.prism.PrismContainerDefinition; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.PrismItemAccessDefinition; +import com.evolveum.midpoint.prism.PrismObjectDefinition; +import com.evolveum.midpoint.prism.PrismPropertyDefinition; +import com.evolveum.midpoint.prism.PrismReferenceDefinition; +import com.evolveum.midpoint.prism.PrismReferenceValue; +import com.evolveum.midpoint.prism.deleg.ItemDefinitionDelegator; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTemplateItemDefinitionType; +import com.google.common.base.Preconditions; + +/* + * Copyright (c) 2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +public abstract class TransformableItemDefinition,D extends ItemDefinition> implements ItemDefinitionDelegator, PrismItemAccessDefinition.Mutable { + + private static final long serialVersionUID = 1L; + + private D delegate; + + protected TransformableItemDefinition(D delegate) { + if (delegate instanceof TransformableItemDefinition) { + // CopyOf constructor + + @SuppressWarnings("unchecked") + TransformableItemDefinition copyOf = (TransformableItemDefinition) delegate; + this.allowAdd = copyOf.allowAdd; + this.allowRead = copyOf.allowRead; + this.allowModify = copyOf.allowModify; + this.template = copyOf.template; + this.minOccurs = copyOf.minOccurs; + this.maxOccurs = copyOf.maxOccurs; + this.processing = copyOf.processing; + this.valueEnumerationRef = copyOf.valueEnumerationRef; + this.delegate = copyOf.delegate(); + } else { + this.delegate = delegate; + } + + } + + private boolean allowAdd = true; + private boolean allowRead = true; + private boolean allowModify = true; + + private ObjectTemplateItemDefinitionType template; + private Integer minOccurs; + private Integer maxOccurs; + private ItemProcessing processing; + private PrismReferenceValue valueEnumerationRef; + + @Override + public D delegate() { + return delegate; + } + + @Override + public boolean canAdd() { + return allowAdd; + } + + @Override + public boolean canModify() { + return allowModify; + } + + @Override + public boolean canRead() { + return allowRead; + } + + @Override + public void setCanAdd(boolean val) { + allowAdd = val; + } + + @Override + public void setCanModify(boolean val) { + allowModify = val; + } + + @Override + public void setCanRead(boolean val) { + allowRead = val; + } + + + @Override + public int getMinOccurs() { + return preferLocal(minOccurs, delegate().getMinOccurs()); + } + + @Override + public int getMaxOccurs() { + return preferLocal(maxOccurs, delegate.getMaxOccurs()); + } + + @Override + public ItemProcessing getProcessing() { + return preferLocal(processing, delegate.getProcessing()); + } + + @SuppressWarnings("unchecked") + protected > ID apply(ID originalItem) { + if (delegate == null) { + delegate = (D) originalItem; + } + return (ID) publicView(); + } + + @SuppressWarnings("unchecked") + public static > TransformableItemDefinition from(ID originalItem) { + if (originalItem == null) { + return null; + } + if (originalItem instanceof TransformableItemDefinition) { + return ((TransformableItemDefinition) originalItem); + } + if (originalItem instanceof PrismPropertyDefinition) { + return (TransformableItemDefinition) TransformablePropertyDefinition.of((PrismPropertyDefinition) originalItem); + } + if (originalItem instanceof PrismReferenceDefinition) { + return (TransformableItemDefinition) TransformableReferenceDefinition.of((PrismReferenceDefinition) originalItem); + } + if (originalItem instanceof PrismObjectDefinition) { + return (TransformableItemDefinition) TransformableObjectDefinition.of((PrismObjectDefinition) originalItem); + } + if (originalItem instanceof PrismContainerDefinition) { + return (TransformableItemDefinition) TransformableContainerDefinition.of((PrismContainerDefinition) originalItem); + } + throw new IllegalArgumentException("Unsupported item definition type " + originalItem.getClass()); + } + + public static > ID publicFrom(ID definition) { + TransformableItemDefinition accessDef = from(definition); + if (accessDef != null) { + return accessDef.publicView(); + } + return null; + } + + protected abstract D publicView(); + + @Override + public ItemDefinition clone() { + throw new UnsupportedOperationException(); + } + + @Override + public void freeze() { + // Intentional Noop for now + + } + + @Override + public boolean isImmutable() { + // Intentional Noop for now + return false; + } + + @Override + public void revive(PrismContext prismContext) { + delegate.revive(prismContext); + } + + public static boolean isMutableAccess(ItemDefinition definition) { + return definition instanceof TransformableItemDefinition; + } + + public static TransformableItemDefinition access(ItemDefinition itemDef) { + Preconditions.checkArgument(itemDef instanceof TransformableItemDefinition, "Definition must be %s", TransformableItemDefinition.class.getName()); + return (TransformableItemDefinition) itemDef; + } + + public void applyTemplate(ObjectTemplateItemDefinitionType templateItemDefType) { + this.template = templateItemDefType; + } + + @Override + public String getDisplayName() { + return preferLocal(template.getDisplayName(), delegate().getDisplayName()); + } + + @Override + public String getHelp() { + return preferLocal(template.getHelp(), delegate().getHelp()); + } + + @Override + public Integer getDisplayOrder() { + return preferLocal(template.getDisplayOrder(), delegate().getDisplayOrder()); + } + + @Override + public boolean isEmphasized() { + return preferLocal(template.isEmphasized(), delegate().isEmphasized()); + } + + @Override + public boolean isDeprecated() { + return preferLocal(template.isDeprecated(), delegate().isDeprecated()); + } + + @Override + public boolean isExperimental() { + return preferLocal(template.isExperimental(), delegate().isExperimental()); + } + + private T preferLocal(T fromTemplate, T fromDelegate) { + return fromTemplate != null ? fromTemplate : fromDelegate; + } + + public void setMinOccurs(Integer value) { + this.minOccurs = value; + } + + public void setMaxOccurs(Integer value) { + this.maxOccurs = value; + } + + public void setValueEnumerationRef(PrismReferenceValue valueEnumerationRVal) { + this.valueEnumerationRef = valueEnumerationRVal; + } + + @Override + public PrismReferenceValue getValueEnumerationRef() { + return preferLocal(valueEnumerationRef, delegate().getValueEnumerationRef()); + } + + public void setProcessing(ItemProcessing itemProcessing) { + this.processing = itemProcessing; + } + + static void apply(ItemDefinition overriden, ItemDefinition originalItem) { + if (overriden instanceof TransformableItemDefinition) { + ((TransformableItemDefinition) overriden).apply(originalItem); + } + } + + @Override + public String toString() { + return "Transformable:" + delegate.toString(); + } + +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableObjectDefinition.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableObjectDefinition.java new file mode 100644 index 00000000000..746d2d90a14 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableObjectDefinition.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +package com.evolveum.midpoint.model.impl.schema.transform; + +import java.util.function.Consumer; + +import javax.xml.namespace.QName; + +import org.jetbrains.annotations.NotNull; + +import com.evolveum.midpoint.prism.ComplexTypeDefinition; +import com.evolveum.midpoint.prism.ItemDefinition; +import com.evolveum.midpoint.prism.MutablePrismObjectDefinition; +import com.evolveum.midpoint.prism.Objectable; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.PrismObjectDefinition; +import com.evolveum.midpoint.prism.deleg.ObjectDefinitionDelegator; +import com.evolveum.midpoint.util.exception.SchemaException; + +public class TransformableObjectDefinition extends TransformableContainerDefinition implements ObjectDefinitionDelegator { + + public TransformableObjectDefinition(PrismObjectDefinition delegate) { + super(delegate); + } + + public TransformableObjectDefinition(PrismObjectDefinition delegate, ComplexTypeDefinition typedef) { + super(delegate, typedef); + } + + public static TransformableObjectDefinition of(PrismObjectDefinition originalItem) { + return new TransformableObjectDefinition<>(originalItem); + } + + @Override + protected PrismObjectDefinition publicView() { + return this; + } + + @Override + public @NotNull PrismObjectDefinition clone() { + throw new UnsupportedOperationException(); + } + + @Override + public MutablePrismObjectDefinition toMutable() { + throw new UnsupportedOperationException(); + } + + @Override + public PrismObjectDefinition delegate() { + return (PrismObjectDefinition) super.delegate(); + } + + @Override + public PrismObjectDefinition cloneWithReplacedDefinition(QName itemName, ItemDefinition newDefinition) { + TransformableComplexTypeDefinition typedef = complexTypeDefinition.copy(); + typedef.replaceDefinition(itemName, newDefinition); + return new TransformableObjectDefinition<>(this, typedef); + } + + @Override + public PrismObjectDefinition deepClone(boolean ultraDeep, Consumer postCloneAction) { + throw new UnsupportedOperationException(); + } + + public static PrismObjectDefinition of(PrismObject object) { + PrismObjectDefinition origDef = object.getDefinition(); + if (origDef instanceof TransformableObjectDefinition) { + return origDef; + } + TransformableObjectDefinition newDef = TransformableObjectDefinition.of(origDef); + try { + object.applyDefinition(newDef, true); + } catch (SchemaException e) { + throw new IllegalStateException("Can not replace definition for transformable one", e); + } + return newDef; + } + +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformablePropertyDefinition.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformablePropertyDefinition.java new file mode 100644 index 00000000000..927ffe862b8 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformablePropertyDefinition.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +package com.evolveum.midpoint.model.impl.schema.transform; + +import org.jetbrains.annotations.NotNull; + +import com.evolveum.midpoint.prism.ItemDefinition; +import com.evolveum.midpoint.prism.MutablePrismPropertyDefinition; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.PrismProperty; +import com.evolveum.midpoint.prism.PrismPropertyDefinition; +import com.evolveum.midpoint.prism.deleg.PropertyDefinitionDelegator; +import com.evolveum.midpoint.schema.processor.MutableResourceAttributeDefinition; +import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; +import com.evolveum.midpoint.schema.processor.deleg.AttributeDefinitionDelegator; + +public class TransformablePropertyDefinition extends TransformableItemDefinition, PrismPropertyDefinition> implements PropertyDefinitionDelegator { + + + private static final long serialVersionUID = 1L; + + public TransformablePropertyDefinition(PrismPropertyDefinition delegate) { + super(delegate); + } + + public static PrismPropertyDefinition of(PrismPropertyDefinition originalItem) { + if (originalItem instanceof TransformablePropertyDefinition) { + return originalItem; + } + if (originalItem instanceof ResourceAttributeDefinition) { + return new ResourceAttribute<>(originalItem); + } + + + return new TransformablePropertyDefinition<>(originalItem); + } + + @Override + public void revive(PrismContext prismContext) { + + } + + @Override + public boolean isImmutable() { + return false; + } + + @Override + public void freeze() { + // NOOP + } + + @Override + public @NotNull PrismPropertyDefinition clone() { + throw new UnsupportedOperationException(); + } + + @Override + public MutablePrismPropertyDefinition toMutable() { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + @Override + protected > ID apply(ID originalItem) { + return (ID) publicView(); + } + + @Override + protected PrismPropertyDefinition publicView() { + return this; + } + + public static class ResourceAttribute extends TransformablePropertyDefinition implements AttributeDefinitionDelegator { + private static final long serialVersionUID = 1L; + + public ResourceAttribute(PrismPropertyDefinition delegate) { + super(delegate); + } + + @Override + public ResourceAttributeDefinition delegate() { + return (ResourceAttributeDefinition) super.delegate(); + } + + @Override + public @NotNull ResourceAttributeDefinition clone() { + throw new UnsupportedOperationException(); + } + + @Override + public MutableResourceAttributeDefinition toMutable() { + throw new UnsupportedOperationException(); + } + } + + +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableReferenceDefinition.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableReferenceDefinition.java new file mode 100644 index 00000000000..5925f16d243 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableReferenceDefinition.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +package com.evolveum.midpoint.model.impl.schema.transform; + +import org.jetbrains.annotations.NotNull; + +import com.evolveum.midpoint.prism.MutableItemDefinition; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.PrismReference; +import com.evolveum.midpoint.prism.PrismReferenceDefinition; +import com.evolveum.midpoint.prism.deleg.ReferenceDefinitionDelegator; + +public class TransformableReferenceDefinition extends TransformableItemDefinition implements ReferenceDefinitionDelegator { + + private static final long serialVersionUID = 1L; + + protected TransformableReferenceDefinition(PrismReferenceDefinition delegate) { + super(delegate); + } + + public static TransformableReferenceDefinition of(PrismReferenceDefinition original) { + return new TransformableReferenceDefinition(original); + } + + @Override + protected PrismReferenceDefinition publicView() { + return this; + } + + @Override + public void revive(PrismContext prismContext) { + + } + + @Override + public MutableItemDefinition toMutable() { + throw new UnsupportedOperationException(); + } + + @Override + public @NotNull PrismReferenceDefinition clone() { + throw new UnsupportedOperationException(); + } +} From c941eb107babe59dc8113c7deba2e7e19e14cf9f Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Wed, 26 May 2021 18:39:09 +0200 Subject: [PATCH 10/23] Use Transformables in SchemaTransformer --- .../ModelInteractionServiceImpl.java | 19 ++-- .../impl/controller/SchemaTransformer.java | 89 ++++++++++--------- 2 files changed, 57 insertions(+), 51 deletions(-) diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java index 3cd6d5a087c..a8cf849fc71 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java @@ -57,6 +57,8 @@ import com.evolveum.midpoint.model.impl.lens.projector.AssignmentOrigin; import com.evolveum.midpoint.model.impl.lens.projector.ContextLoader; import com.evolveum.midpoint.model.impl.lens.projector.mappings.MappingEvaluator; +import com.evolveum.midpoint.model.impl.schema.transform.TransformableContainerDefinition; +import com.evolveum.midpoint.model.impl.schema.transform.TransformableObjectDefinition; import com.evolveum.midpoint.model.impl.security.GuiProfileCompiler; import com.evolveum.midpoint.model.impl.security.SecurityHelper; import com.evolveum.midpoint.model.impl.visualizer.Visualizer; @@ -217,9 +219,7 @@ public ModelContext unwrapModelContext(LensContextType @Override public PrismObjectDefinition getEditObjectDefinition(PrismObject object, AuthorizationPhaseType phase, Task task, OperationResult parentResult) throws SchemaException, ConfigurationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, SecurityViolationException { OperationResult result = parentResult.createMinorSubresult(GET_EDIT_OBJECT_DEFINITION); - MutablePrismObjectDefinition objectDefinition = object.getDefinition() - .deepClone(true, schemaTransformer::setFullAccessFlags) - .toMutable(); + TransformableObjectDefinition objectDefinition = schemaTransformer.transformableDefinition(object.getDefinition()); try { // Re-read the object from the repository to make sure we have all the properties. // the object from method parameters may be already processed by the security code @@ -250,7 +250,7 @@ public PrismObjectDefinition getEditObjectDefinition(P } } - private void applyObjectClassDefinition(MutablePrismObjectDefinition objectDefinition, + private void applyObjectClassDefinition(TransformableObjectDefinition objectDefinition, PrismObject object, AuthorizationPhaseType phase, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, ConfigurationException, ExpressionEvaluationException, CommunicationException, SecurityViolationException { @@ -267,16 +267,16 @@ private void applyObjectClassDefinition(MutablePrismObjec } RefinedObjectClassDefinition refinedObjectClassDefinition = getEditObjectClassDefinition(shadow, resource, phase, task, result); if (refinedObjectClassDefinition != null) { - objectDefinition.getComplexTypeDefinition().toMutable().replaceDefinition(ShadowType.F_ATTRIBUTES, + objectDefinition.replaceDefinition(ShadowType.F_ATTRIBUTES, refinedObjectClassDefinition.toResourceAttributeContainerDefinition()); - objectDefinition.findContainerDefinition(ItemPath.create(ShadowType.F_ASSOCIATION)).toMutable() - .replaceDefinition(ShadowAssociationType.F_IDENTIFIERS, refinedObjectClassDefinition.toResourceAttributeContainerDefinition(ShadowAssociationType.F_IDENTIFIERS)); + PrismContainerDefinition assocContainer = objectDefinition.findContainerDefinition(ItemPath.create(ShadowType.F_ASSOCIATION)); + TransformableContainerDefinition.require(assocContainer).replaceDefinition(ShadowAssociationType.F_IDENTIFIERS, refinedObjectClassDefinition.toResourceAttributeContainerDefinition(ShadowAssociationType.F_IDENTIFIERS)); } } } - private void applyArchetypePolicy(MutablePrismObjectDefinition objectDefinition, + private void applyArchetypePolicy(PrismObjectDefinition objectDefinition, PrismObject object, OperationResult result) throws SchemaException { try { ArchetypePolicyType archetypePolicy = archetypeManager.determineArchetypePolicy(object, result); @@ -408,6 +408,7 @@ public MetadataItemProcessingSpec getMetadataItemProcessi } } + @Override public ItemSecurityConstraints getAllowedRequestAssignmentItems(PrismObject object, PrismObject target, Task task, OperationResult result) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException { return securityEnforcer.getAllowedRequestAssignmentItems(securityContextManager.getPrincipal(), ModelAuthorizationAction.ASSIGN.getUrl(), object, target, null, task, result); } @@ -665,6 +666,7 @@ public SecurityPolicyType getSecurityPolicy(RefinedObjectClassDefinition rOCDef, } } + @Override @NotNull public CompiledGuiProfile getCompiledGuiProfile(Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { MidPointPrincipal principal = null; @@ -1062,6 +1064,7 @@ private ValuePolicyType resolveValuePolicy(PolicyItemDefinitionType policyItemDe return defaultPolicy; } + @Override public void validateValue(PrismObject object, PolicyItemsDefinitionType policyItemsDefinition, Task task, OperationResult parentResult) throws ExpressionEvaluationException, SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, PolicyViolationException { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java index 4b83df0db6f..d01041dc035 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java @@ -15,7 +15,11 @@ import com.evolveum.midpoint.model.impl.lens.LensElementContext; import com.evolveum.midpoint.model.impl.lens.LensFocusContext; import com.evolveum.midpoint.model.impl.lens.LensProjectionContext; +import com.evolveum.midpoint.model.impl.schema.transform.TransformableContainerDefinition; +import com.evolveum.midpoint.model.impl.schema.transform.TransformableItemDefinition; +import com.evolveum.midpoint.model.impl.schema.transform.TransformableObjectDefinition; import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.PrismItemAccessDefinition.Mutable; import com.evolveum.midpoint.prism.delta.ContainerDelta; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; @@ -194,7 +198,8 @@ void applySchemasAndSecurity(PrismObject object, GetOp validateObject(object, rootOptions, result); ObjectSecurityConstraints securityConstraints = compileSecurityConstraints(object, task, result); - PrismObjectDefinition objectDefinition = object.deepCloneDefinition(true, this::setFullAccessFlags); + + PrismObjectDefinition objectDefinition = TransformableObjectDefinition.of(object); if (phase == null) { if (!GetOperationOptions.isExecutionPhase(rootOptions)) { @@ -388,10 +393,13 @@ private void applySecurityConstraints(PrismContainerValue pcv, ObjectSecurity if (pcv.hasNoItems()) { return; } + // FIX PCV type for subtypes + TransformableContainerDefinition.ensureMutableType(pcv); List itemsToRemove = new ArrayList<>(); for (Item item : pcv.getItems()) { ItemPath itemPath = item.getPath(); - ItemDefinition itemDef = item.getDefinition(); + @SuppressWarnings({ "unchecked", "rawtypes" }) + ItemDefinition itemDef = ensureMutableDefinition((Item) item); if (itemDef != null && itemDef.isElaborate()) { LOGGER.trace("applySecurityConstraints(item): {}: skip (elaborate)", itemPath); continue; @@ -404,13 +412,13 @@ private void applySecurityConstraints(PrismContainerValue pcv, ObjectSecurity itemPath, itemReadDecision, itemAddDecision, itemModifyDecision); if (applyToDefinitions && itemDef != null) { if (itemReadDecision != AuthorizationDecisionType.ALLOW) { - itemDef.toMutable().setCanRead(false); + mutable(itemDef).setCanRead(false); } if (itemAddDecision != AuthorizationDecisionType.ALLOW) { - itemDef.toMutable().setCanAdd(false); + mutable(itemDef).setCanAdd(false); } if (itemModifyDecision != AuthorizationDecisionType.ALLOW) { - itemDef.toMutable().setCanModify(false); + mutable(itemDef).setCanModify(false); } } if (item instanceof PrismContainer) { @@ -444,6 +452,24 @@ private void applySecurityConstraints(PrismContainerValue pcv, ObjectSecurity } } + private > D ensureMutableDefinition(Item item) { + D original = item.getDefinition(); + if (TransformableItemDefinition.isMutableAccess(original)) { + return original; + } + D replace = TransformableItemDefinition.publicFrom(original); + try { + item.applyDefinition(replace, true); + } catch (SchemaException e) { + throw new IllegalStateException("Can not replace definition with wrapper"); + } + return replace; + } + + private Mutable mutable(ItemDefinition itemDef) { + return TransformableItemDefinition.access(itemDef); + } + private void applySecurityConstraints(ObjectDelta objectDelta, ObjectSecurityConstraints securityConstraints, AuthorizationPhaseType phase, AuthorizationDecisionType defaultReadDecision, AuthorizationDecisionType defaultAddDecision, AuthorizationDecisionType defaultModifyDecision) { LOGGER.trace("applySecurityConstraints(objectDelta): items={}, phase={}, defaults R={}, A={}, M={}", @@ -452,7 +478,8 @@ private void applySecurityConstraints(ObjectDelta obje return; } if (objectDelta.isAdd()) { - applySecurityConstraints(objectDelta.getObjectToAdd().getValue(), securityConstraints, phase, defaultReadDecision, defaultAddDecision, defaultModifyDecision, false); + applySecurityConstraints(objectDelta.getObjectToAdd().getValue(), securityConstraints, phase, defaultReadDecision, + defaultAddDecision, defaultModifyDecision, false); return; } if (objectDelta.isDelete()) { @@ -604,23 +631,23 @@ private void applySecurityConstraintsItemDef(D itemDe nameOnlyItemPath, readDecision, addDecision, modifyDecision, anySubElementRead, anySubElementAdd, anySubElementModify); if (readDecision != AuthorizationDecisionType.ALLOW) { - itemDefinition.toMutable().setCanRead(false); + mutable(itemDefinition).setCanRead(false); } if (addDecision != AuthorizationDecisionType.ALLOW) { - itemDefinition.toMutable().setCanAdd(false); + mutable(itemDefinition).setCanAdd(false); } if (modifyDecision != AuthorizationDecisionType.ALLOW) { - itemDefinition.toMutable().setCanModify(false); + mutable(itemDefinition).setCanModify(false); } if (anySubElementRead) { - itemDefinition.toMutable().setCanRead(true); + mutable(itemDefinition).setCanRead(true); } if (anySubElementAdd) { - itemDefinition.toMutable().setCanAdd(true); + mutable(itemDefinition).setCanAdd(true); } if (anySubElementModify) { - itemDefinition.toMutable().setCanModify(true); + mutable(itemDefinition).setCanModify(true); } } @@ -733,37 +760,9 @@ private void applyObjectTempla throw new SchemaException("No definition for "+desc); } - MutableItemDefinition mutableDef = itemDef.toMutable(); + TransformableItemDefinition mutableDef = TransformableItemDefinition.access(itemDef); - String displayName = templateItemDefType.getDisplayName(); - if (displayName != null) { - mutableDef.setDisplayName(displayName); - } - - String help = templateItemDefType.getHelp(); - if (help != null) { - mutableDef.setHelp(help); - } - - Integer displayOrder = templateItemDefType.getDisplayOrder(); - if (displayOrder != null) { - mutableDef.setDisplayOrder(displayOrder); - } - - Boolean emphasized = templateItemDefType.isEmphasized(); - if (emphasized != null) { - mutableDef.setEmphasized(emphasized); - } - - Boolean deprecated = templateItemDefType.isDeprecated(); - if (deprecated != null) { - mutableDef.setDeprecated(deprecated); - } - - Boolean experimental = templateItemDefType.isExperimental(); - if (experimental != null) { - mutableDef.setExperimental(experimental); - } + mutableDef.applyTemplate(templateItemDefType); List limitations = templateItemDefType.getLimitations(); if (limitations != null) { @@ -815,7 +814,7 @@ private VisibilityPolicyEntry(UniformItemPath path, UserInterfaceElementVisibili } } - void applyItemsConstraints(@NotNull MutablePrismContainerDefinition objectDefinition, + void applyItemsConstraints(@NotNull PrismContainerDefinition objectDefinition, @NotNull ArchetypePolicyType archetypePolicy) throws SchemaException { List visibilityPolicy = getVisibilityPolicy(archetypePolicy, objectDefinition); if (!visibilityPolicy.isEmpty()) { @@ -968,4 +967,8 @@ private boolean hasError(PrismObject object, Operation return false; } + public TransformableObjectDefinition transformableDefinition(PrismObjectDefinition definition) { + return TransformableObjectDefinition.of(definition); + } + } From 5ee17418fee5bc47c29de2375b12f3dcc910cdae Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Wed, 26 May 2021 21:55:44 +0200 Subject: [PATCH 11/23] ValueFilterValues: rename of to S is used as "schema type" elsewhere, it could have been confusing. --- .../sqlbase/filtering/ValueFilterValues.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/filtering/ValueFilterValues.java b/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/filtering/ValueFilterValues.java index c3afe7f2e4c..755dc161d1c 100644 --- a/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/filtering/ValueFilterValues.java +++ b/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/filtering/ValueFilterValues.java @@ -31,30 +31,30 @@ * from {@link PrismPropertyValue} to "real value" and then to convert it. * Both {@link #singleValue()} and {@link #allValues()} are handled the same way. * - * If {@link #conversionFunction} is used any {@link IllegalArgumentException} will be rewrapped + * If {@link #conversionFunction} is used any {@link IllegalArgumentException} will be re-wrapped * as {@link QueryException}, other runtime exceptions are not intercepted. * * @param type of filter value - * @param type of value after conversion (can by the same like T) + * @param type of value after conversion (can by the same like T) */ -public class ValueFilterValues { +public class ValueFilterValues { @NotNull private final PropertyValueFilter filter; - @Nullable private final Function conversionFunction; + @Nullable private final Function conversionFunction; public static ValueFilterValues from(@NotNull PropertyValueFilter filter) { return new ValueFilterValues<>(filter, null); } - public static ValueFilterValues from( + public static ValueFilterValues from( @NotNull PropertyValueFilter filter, - @Nullable Function conversionFunction) { + @Nullable Function conversionFunction) { return new ValueFilterValues<>(filter, conversionFunction); } private ValueFilterValues( @NotNull PropertyValueFilter filter, - @Nullable Function conversionFunction) { + @Nullable Function conversionFunction) { this.filter = Objects.requireNonNull(filter); this.conversionFunction = conversionFunction; } @@ -79,14 +79,15 @@ private ValueFilterValues( /** * Returns multiple values, all converted, or empty list - never null. */ - public @NotNull List allValues() { + public @NotNull List allValues() { if (filter.getValues() == null) { return Collections.emptyList(); } Stream realValueStream = filter.getValues().stream() .map(ppv -> ppv.getRealValue()); if (conversionFunction == null) { - return realValueStream.collect(Collectors.toList()); + //noinspection unchecked + return (List) realValueStream.collect(Collectors.toList()); } return realValueStream .map(conversionFunction) From 2ea93d2976232068198380a9359cdbbe021b7dcb Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Wed, 26 May 2021 23:29:13 +0200 Subject: [PATCH 12/23] Enum+UriItemFilterProcessor: both throw for other than EQ operation --- .../sqale/filtering/UriItemFilterProcessor.java | 13 +++++++++++++ .../filtering/item/EnumItemFilterProcessor.java | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/filtering/UriItemFilterProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/filtering/UriItemFilterProcessor.java index 2125d540458..9912c1d794d 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/filtering/UriItemFilterProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/filtering/UriItemFilterProcessor.java @@ -8,10 +8,13 @@ import java.util.function.Function; +import com.querydsl.core.types.Ops; import com.querydsl.core.types.Predicate; import com.querydsl.core.types.dsl.NumberPath; +import com.evolveum.midpoint.prism.query.EqualFilter; import com.evolveum.midpoint.prism.query.PropertyValueFilter; +import com.evolveum.midpoint.prism.query.ValueFilter; import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; import com.evolveum.midpoint.repo.sqlbase.QueryException; import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext; @@ -38,4 +41,14 @@ public Predicate process(PropertyValueFilter filter) throws QueryExcepti ValueFilterValues.from(filter, u -> ((SqaleRepoContext) context.repositoryContext()).searchCachedUriId(u))); } + + @Override + protected Ops operation(ValueFilter filter) throws QueryException { + if (filter instanceof EqualFilter && filter.getMatchingRule() == null) { + return Ops.EQ; + } else { + throw new QueryException("Can't translate filter '" + filter + "' to operation." + + " URI/QName value supports only equals with no matching rule."); + } + } } diff --git a/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/filtering/item/EnumItemFilterProcessor.java b/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/filtering/item/EnumItemFilterProcessor.java index 498c6e66382..f49af7926a1 100644 --- a/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/filtering/item/EnumItemFilterProcessor.java +++ b/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/filtering/item/EnumItemFilterProcessor.java @@ -8,10 +8,13 @@ import java.util.function.Function; +import com.querydsl.core.types.Ops; import com.querydsl.core.types.Predicate; import com.querydsl.core.types.dsl.EnumPath; +import com.evolveum.midpoint.prism.query.EqualFilter; import com.evolveum.midpoint.prism.query.PropertyValueFilter; +import com.evolveum.midpoint.prism.query.ValueFilter; import com.evolveum.midpoint.repo.sqlbase.QueryException; import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext; import com.evolveum.midpoint.repo.sqlbase.filtering.ValueFilterValues; @@ -39,4 +42,14 @@ public , R> EnumItemFilterProcessor( public Predicate process(PropertyValueFilter filter) throws QueryException { return createBinaryCondition(filter, path, ValueFilterValues.from(filter)); } + + @Override + protected Ops operation(ValueFilter filter) throws QueryException { + if (filter instanceof EqualFilter && filter.getMatchingRule() == null) { + return Ops.EQ; + } else { + throw new QueryException("Can't translate filter '" + filter + "' to operation." + + " Enumeration value supports only equals with no matching rule."); + } + } } From 84fbfd6c7b93bf62e28368c5059d734e5f8e3e53 Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Wed, 26 May 2021 23:32:41 +0200 Subject: [PATCH 13/23] added ArrayPathItemFilterProcessor for paths like subtypes + tests Support for subtypes (String[]) and policySituations (Integer[]). Added tests for enum value equality. --- .../ArrayPathItemFilterProcessor.java | 69 +++++ .../repo/sqale/qmodel/SqaleTableMapping.java | 30 +- .../qmodel/connector/QConnectorMapping.java | 2 +- .../sqale/qmodel/object/QObjectMapping.java | 6 +- .../sqale/func/SqaleRepoSearchObjectTest.java | 259 +++++++++++++++++- .../filtering/item/ItemFilterProcessor.java | 2 - .../sqlbase/mapping/QueryTableMapping.java | 2 +- 7 files changed, 353 insertions(+), 17 deletions(-) create mode 100644 repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/filtering/ArrayPathItemFilterProcessor.java diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/filtering/ArrayPathItemFilterProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/filtering/ArrayPathItemFilterProcessor.java new file mode 100644 index 00000000000..f24026e0c02 --- /dev/null +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/filtering/ArrayPathItemFilterProcessor.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010-2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.repo.sqale.filtering; + +import java.lang.reflect.Array; +import java.util.function.Function; + +import com.querydsl.core.types.Predicate; +import com.querydsl.core.types.dsl.ArrayPath; +import com.querydsl.core.types.dsl.Expressions; +import org.jetbrains.annotations.Nullable; + +import com.evolveum.midpoint.prism.query.EqualFilter; +import com.evolveum.midpoint.prism.query.PropertyValueFilter; +import com.evolveum.midpoint.repo.sqlbase.QueryException; +import com.evolveum.midpoint.repo.sqlbase.RepositoryException; +import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext; +import com.evolveum.midpoint.repo.sqlbase.filtering.ValueFilterValues; +import com.evolveum.midpoint.repo.sqlbase.filtering.item.SinglePathItemFilterProcessor; +import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; + +/** + * Filter processor for multi-value property represented by single array column. + * These paths support only value equality (of any value), which is "contains" in DB terminology. + * Our filter "contains" (meaning substring) is *not* supported. + */ +public class ArrayPathItemFilterProcessor + extends SinglePathItemFilterProcessor> { + + private final String dbType; + private final Class elementType; + @Nullable private final Function conversionFunction; + + /** + * Creates filter processor for array column. + * + * @param dbType name of the type for element in DB (without []) for the cast part of the condition + */ + public , R> ArrayPathItemFilterProcessor( + SqlQueryContext context, + Function> rootToPath, + String dbType, + Class elementType, + @Nullable Function conversionFunction) { + super(context, rootToPath); + this.dbType = dbType; + this.elementType = elementType; + this.conversionFunction = conversionFunction; + } + + @Override + public Predicate process(PropertyValueFilter filter) throws RepositoryException { + if (!(filter instanceof EqualFilter) || filter.getMatchingRule() != null) { + throw new QueryException("Can't translate filter '" + filter + "' to operation." + + " Array stored value supports only equals with no matching rule."); + } + + ValueFilterValues values = ValueFilterValues.from(filter, conversionFunction); + // valueArray can't be just Object[], it must be concrete type, e.g. String[], + // otherwise PG JDBC driver will complain. + //noinspection unchecked + E[] valueArray = values.allValues().toArray(i -> (E[]) Array.newInstance(elementType, i)); + return Expressions.booleanTemplate("{0} && {1}::" + dbType + "[]", path, valueArray); + } +} diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleTableMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleTableMapping.java index d5d836e7fb0..8100e20a876 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleTableMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleTableMapping.java @@ -21,6 +21,7 @@ import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; import com.evolveum.midpoint.repo.sqale.delta.item.*; +import com.evolveum.midpoint.repo.sqale.filtering.ArrayPathItemFilterProcessor; import com.evolveum.midpoint.repo.sqale.filtering.RefItemFilterProcessor; import com.evolveum.midpoint.repo.sqale.filtering.UriItemFilterProcessor; import com.evolveum.midpoint.repo.sqale.mapping.SqaleItemSqlMapper; @@ -210,6 +211,33 @@ public > SqaleItemSqlMapper enumMapper( rootToQueryItem); } + /** + * Returns the mapper creating string multi-value filter/delta processors from context. + * + * @param mapped schema type, see javadoc in {@link QueryTableMapping} + */ + protected SqaleItemSqlMapper multiStringMapper( + Function> rootToQueryItem) { + return new SqaleItemSqlMapper<>( + ctx -> new ArrayPathItemFilterProcessor( + ctx, rootToQueryItem, "TEXT", String.class, null), + ctx -> null); // TODO + } + + /** + * Returns the mapper creating integer multi-value filter/delta processors from context. + * + * @param mapped schema type, see javadoc in {@link QueryTableMapping} + */ + protected SqaleItemSqlMapper multiUriMapper( + Function> rootToQueryItem) { + return new SqaleItemSqlMapper<>( + ctx -> new ArrayPathItemFilterProcessor<>( + ctx, rootToQueryItem, "INTEGER", Integer.class, + ((SqaleRepoContext) ctx.repositoryContext())::searchCachedUriId), + ctx -> null); // TODO + } + @Override public S toSchemaObject(R row) { throw new UnsupportedOperationException("Use toSchemaObject(Tuple,...)"); @@ -339,7 +367,7 @@ protected , OR } } - protected String[] arrayFor(List strings) { + protected String[] listToArray(List strings) { if (strings == null || strings.isEmpty()) { return null; } diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnectorMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnectorMapping.java index 99c76974d9a..107ca0780cb 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnectorMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/connector/QConnectorMapping.java @@ -68,7 +68,7 @@ public MConnector newRowObject() { t -> row.connectorHostRefTargetType = t, r -> row.connectorHostRefRelationId = r); - row.targetSystemTypes = arrayFor(schemaObject.getTargetSystemType()); + row.targetSystemTypes = listToArray(schemaObject.getTargetSystemType()); return row; } diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/QObjectMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/QObjectMapping.java index 970a7ee9234..ae84724a91e 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/QObjectMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/object/QObjectMapping.java @@ -76,7 +76,9 @@ protected QObjectMapping( addItemMapping(F_LIFECYCLE_STATE, stringMapper(q -> q.lifecycleState)); // version/cidSeq is not mapped for queries or deltas, it's managed by repo explicitly - // TODO mapper for policySituations and subtypes + addItemMapping(F_POLICY_SITUATION, multiUriMapper(q -> q.policySituations)); + addItemMapping(F_SUBTYPE, multiStringMapper(q -> q.subtypes)); + // full-text is not item mapping, but filter on the whole object // TODO ext mapping can't be done statically addNestedMapping(F_METADATA, MetadataType.class) @@ -191,7 +193,7 @@ public R toRowObjectWithoutFullObject(S schemaObject, JdbcSession jdbcSession) { // complex DB fields row.policySituations = processCacheableUris(schemaObject.getPolicySituation()); - row.subtypes = arrayFor(schemaObject.getSubtype()); + row.subtypes = listToArray(schemaObject.getSubtype()); // TODO textInfo (fulltext support) // repo.getTextInfoItems().addAll(RObjectTextInfo.createItemsSet(jaxb, repo, repositoryContext)); // TODO extensions stored inline (JSON) - that is ext column diff --git a/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoSearchObjectTest.java b/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoSearchObjectTest.java index 6e343367d35..1d624d962fb 100644 --- a/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoSearchObjectTest.java +++ b/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoSearchObjectTest.java @@ -17,7 +17,6 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.prism.query.ObjectQuery; @@ -37,6 +36,7 @@ import com.evolveum.midpoint.schema.result.OperationResultStatus; import com.evolveum.midpoint.util.MiscUtil; import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.prism.xml.ns._public.query_3.QueryType; @@ -57,6 +57,7 @@ public class SqaleRepoSearchObjectTest extends SqaleRepoBaseTest { private String user3Oid; // another user in org private String user4Oid; // another user in org private String task1Oid; // task has more attribute type variability + private String task2Oid; // task has more attribute type variability private String shadow1Oid; // ditto private String service1Oid; // object with integer attribute private String case1Oid; // Closed case, two work items @@ -84,11 +85,13 @@ public void initObjects() throws Exception { org111Oid = repositoryService.addObject( new OrgType(prismContext).name("org-1-1-1") .parentOrgRef(org11Oid, OrgType.COMPLEX_TYPE, relation2) + .subtype("newWorkers") .asPrismObject(), null, result); org112Oid = repositoryService.addObject( new OrgType(prismContext).name("org-1-1-2") .parentOrgRef(org11Oid, OrgType.COMPLEX_TYPE, relation1) + .subtype("secret") .asPrismObject(), null, result); org12Oid = repositoryService.addObject( @@ -103,6 +106,7 @@ public void initObjects() throws Exception { new OrgType(prismContext).name("org-2-1") .costCenter("5") .parentOrgRef(org2Oid, OrgType.COMPLEX_TYPE) + .policySituation("situationC") .asPrismObject(), null, result); orgXOid = repositoryService.addObject( @@ -122,12 +126,17 @@ public void initObjects() throws Exception { .modifierRef(modifierOid, UserType.COMPLEX_TYPE, relation2) .modifyChannel("modify-channel") .modifyTimestamp(MiscUtil.asXMLGregorianCalendar(2L))) + .subtype("workerA") + .subtype("workerC") + .policySituation("situationA") + .policySituation("situationC") .asPrismObject(), null, result); user2Oid = repositoryService.addObject( new UserType(prismContext).name("user-2") .parentOrgRef(orgXOid, OrgType.COMPLEX_TYPE) .parentOrgRef(org11Oid, OrgType.COMPLEX_TYPE, relation1) + .subtype("workerA") .asPrismObject(), null, result); user3Oid = repositoryService.addObject( @@ -135,16 +144,26 @@ public void initObjects() throws Exception { .costCenter("50") .parentOrgRef(orgXOid, OrgType.COMPLEX_TYPE) .parentOrgRef(org21Oid, OrgType.COMPLEX_TYPE, relation1) + .policySituation("situationA") .asPrismObject(), null, result); user4Oid = repositoryService.addObject( new UserType(prismContext).name("user-4") .costCenter("51") .parentOrgRef(org111Oid, OrgType.COMPLEX_TYPE) + .subtype("workerB") + .policySituation("situationB") .asPrismObject(), null, result); task1Oid = repositoryService.addObject( - new TaskType(prismContext).name("task-1").asPrismObject(), + new TaskType(prismContext).name("task-1") + .executionStatus(TaskExecutionStateType.RUNNABLE) + .asPrismObject(), + null, result); + task2Oid = repositoryService.addObject( + new TaskType(prismContext).name("task-2") + .executionStatus(TaskExecutionStateType.CLOSED) + .asPrismObject(), null, result); shadow1Oid = repositoryService.addObject( new ShadowType(prismContext).name("shadow-1").asPrismObject(), @@ -218,18 +237,238 @@ public void test110SearchUserByName() throws Exception { } @Test - public void test180SearchCaseWorkitemByOutcome() throws Exception { - searchCaseWorkitemByOutcome("OUTCOME one", case1Oid); - searchCaseWorkitemByOutcome("OUTCOME two", case1Oid); - searchCaseWorkitemByOutcome("OUTCOME nonexist", null); + public void test120SearchObjectsBySubtype() throws Exception { + when("searching objects with subtype equal to value"); + OperationResult operationResult = createOperationResult(); + SearchResultList result = searchObjects(ObjectType.class, + prismContext.queryFor(ObjectType.class) + .item(ObjectType.F_SUBTYPE).eq("workerA") + .build(), + operationResult); + + then("only objects having the specified subtype are returned"); + assertThatOperationResult(operationResult).isSuccess(); + assertThat(result) + .hasSize(2) + .extracting(row -> row.getOid()) + .containsExactlyInAnyOrder(user1Oid, user2Oid); + } + + @Test + public void test121SearchObjectsBySubtypeWithMultipleValues() throws Exception { + when("searching objects with any subtype equal to any of the provided values"); + OperationResult operationResult = createOperationResult(); + SearchResultList result = searchObjects(ObjectType.class, + prismContext.queryFor(ObjectType.class) + .item(ObjectType.F_SUBTYPE).eq("workerA", "workerB") + .build(), + operationResult); + + then("objects with any of the subtypes are returned"); + assertThatOperationResult(operationResult).isSuccess(); + assertThat(result) + .hasSize(3) + .extracting(row -> row.getOid()) + .containsExactlyInAnyOrder(user1Oid, user2Oid, user4Oid); + } + + @Test + public void test122SearchObjectsHavingTwoSubtypeValuesUsingAnd() throws Exception { + when("searching objects with multiple subtype values equal to provided values"); + OperationResult operationResult = createOperationResult(); + SearchResultList result = searchObjects(ObjectType.class, + prismContext.queryFor(ObjectType.class) + .item(ObjectType.F_SUBTYPE).eq("workerA") + .and() + .item(ObjectType.F_SUBTYPE).eq("workerC") + .build(), + operationResult); + + then("only objects with all specified subtypes are returned"); + assertThatOperationResult(operationResult).isSuccess(); + assertThat(result) + .hasSize(1) + .extracting(row -> row.getOid()) + .containsExactlyInAnyOrder(user1Oid); + } + + @Test + public void test123SearchOrgsHavingTwoSubtypeValuesUsingAndButNoneMatches() throws Exception { + when("searching objects with multiple subtype values equal to provided values"); + OperationResult operationResult = createOperationResult(); + SearchResultList result = searchObjects(OrgType.class, + prismContext.queryFor(OrgType.class) + .item(ObjectType.F_SUBTYPE).eq("workerA") + .and() + .item(ObjectType.F_SUBTYPE).eq("workerB") + .build(), + operationResult); + + then("nothing is returned because no org matches the condition"); + assertThatOperationResult(operationResult).isSuccess(); + assertThat(result).isEmpty(); + } + + @Test + public void test125SearchObjectsBySubtypeContainsIsNotSupported() { + given("query for subtype containing (=substring) value"); + OperationResult operationResult = createOperationResult(); + ObjectQuery query = prismContext.queryFor(UserType.class) + .item(ObjectType.F_SUBTYPE).contains("worker") + .build(); + + expect("repository throws exception because it is not supported"); + assertThatThrownBy(() -> searchObjects(ObjectType.class, query, operationResult)) + .isInstanceOf(SystemException.class) + .hasMessageStartingWith("Can't translate filter"); + } + + @Test + public void test130SearchObjectsByPolicySituation() throws Exception { + when("searching objects with policy situation equal to value"); + OperationResult operationResult = createOperationResult(); + SearchResultList result = searchObjects(ObjectType.class, + prismContext.queryFor(UserType.class) + .item(ObjectType.F_POLICY_SITUATION).eq("situationC") + .build(), + operationResult); + + then("only objects having the specified policy situation are returned"); + assertThatOperationResult(operationResult).isSuccess(); + assertThat(result) + .hasSize(2) + .extracting(row -> row.getOid()) + .containsExactlyInAnyOrder(user1Oid, org21Oid); + } + + @Test + public void test131SearchOrgsByPolicySituation() throws Exception { + when("searching orgs with policy situation equal to value"); + OperationResult operationResult = createOperationResult(); + SearchResultList result = searchObjects(OrgType.class, + prismContext.queryFor(OrgType.class) + .item(ObjectType.F_POLICY_SITUATION).eq("situationC") + .build(), + operationResult); + + then("only orgs having the specified policy situation are returned"); + assertThatOperationResult(operationResult).isSuccess(); + assertThat(result) + .hasSize(1) + .extracting(row -> row.getOid()) + .containsExactlyInAnyOrder(org21Oid); + } + + @Test + public void test132SearchObjectsByPolicySituationWithMultipleValues() throws Exception { + when("searching objects with any policy situation equal to any of the provided values"); + OperationResult operationResult = createOperationResult(); + SearchResultList result = searchObjects(ObjectType.class, + prismContext.queryFor(UserType.class) + .item(ObjectType.F_POLICY_SITUATION).eq("situationA", "situationB") + .build(), + operationResult); + + then("objects with any of the policy situations are returned"); + assertThatOperationResult(operationResult).isSuccess(); + assertThat(result) + .hasSize(3) + .extracting(row -> row.getOid()) + .containsExactlyInAnyOrder(user1Oid, user3Oid, user4Oid); + } + + @Test + public void test135SearchObjectsByPolicySituationContainsIsNotSupported() { + given("query for policy situation containing (=substring) value"); + OperationResult operationResult = createOperationResult(); + ObjectQuery query = prismContext.queryFor(UserType.class) + .item(ObjectType.F_POLICY_SITUATION).contains("worker") + .build(); + + expect("repository throws exception because it is not supported"); + assertThatThrownBy(() -> searchObjects(ObjectType.class, query, operationResult)) + .isInstanceOf(SystemException.class) + .hasMessageStartingWith("Can't translate filter"); + } + + @Test + public void test140SearchTaskByEnumValue() throws Exception { + when("searching task with execution status equal to one value"); + OperationResult operationResult = createOperationResult(); + SearchResultList result = searchObjects(TaskType.class, + prismContext.queryFor(TaskType.class) + .item(TaskType.F_EXECUTION_STATUS).eq(TaskExecutionStateType.RUNNABLE) + .build(), + operationResult); + + then("tasks with the execution status with the provided value are returned"); + assertThatOperationResult(operationResult).isSuccess(); + assertThat(result) + .hasSize(1) + .extracting(row -> row.getOid()) + .containsExactlyInAnyOrder(task1Oid); + } + + @Test + public void test141SearchTaskByEnumWithMultipleValues() throws Exception { + when("searching task with execution status equal to any of provided value"); + OperationResult operationResult = createOperationResult(); + SearchResultList result = searchObjects(TaskType.class, + prismContext.queryFor(TaskType.class) + .item(TaskType.F_EXECUTION_STATUS).eq( + TaskExecutionStateType.RUNNABLE, TaskExecutionStateType.CLOSED) + .build(), + operationResult); + + then("tasks with execution status equal to any of the provided values are returned"); + assertThatOperationResult(operationResult).isSuccess(); + assertThat(result) + .hasSize(2) + .extracting(row -> row.getOid()) + .containsExactlyInAnyOrder(task1Oid, task2Oid); + } + + @Test + public void test145SearchObjectsByEnumValueContainsIsNotSupported() { + given("query for task's execution status containing (=substring) value"); + OperationResult operationResult = createOperationResult(); + ObjectQuery query = prismContext.queryFor(TaskType.class) + .item(TaskType.F_EXECUTION_STATUS).contains(TaskExecutionStateType.RUNNABLE) + .build(); + + expect("repository throws exception because it is not supported"); + assertThatThrownBy(() -> searchObjects(TaskType.class, query, operationResult)) + .isInstanceOf(SystemException.class) + .hasMessageStartingWith("Can't translate filter"); + } + + @Test + public void test146SearchTaskByEnumValueProvidedAsStringIsNotSupported() { + given("query for enum equality using string value"); + OperationResult operationResult = createOperationResult(); + ObjectQuery query = prismContext.queryFor(TaskType.class) + .item(TaskType.F_EXECUTION_STATUS).eq("RUNNABLE") + .build(); + + expect("repository throws exception because it is not supported, enum must be used"); + assertThatThrownBy(() -> searchObjects(TaskType.class, query, operationResult)) + .isInstanceOf(SystemException.class); + } + + @Test + public void test180SearchCaseWorkItemByOutcome() throws Exception { + searchCaseWorkItemByOutcome("OUTCOME one", case1Oid); + searchCaseWorkItemByOutcome("OUTCOME two", case1Oid); + searchCaseWorkItemByOutcome("OUTCOME nonexist", null); } - private void searchCaseWorkitemByOutcome(String wiOutcome, String expectedOid) throws Exception { + private void searchCaseWorkItemByOutcome(String wiOutcome, String expectedOid) throws Exception { when("searching case with query for workitem/output/outcome " + wiOutcome); OperationResult operationResult = createOperationResult(); SearchResultList result = searchObjects(CaseType.class, prismContext.queryFor(CaseType.class) - .item(ItemPath.create(CaseType.F_WORK_ITEM, CaseWorkItemType.F_OUTPUT, AbstractWorkItemOutputType.F_OUTCOME)).eq(wiOutcome) + .item(CaseType.F_WORK_ITEM, CaseWorkItemType.F_OUTPUT, + AbstractWorkItemOutputType.F_OUTCOME).eq(wiOutcome) .build(), operationResult); @@ -637,7 +876,7 @@ public void test921SearchAssignmentHolderTypeFindsAllObjectsExceptShadows() } @Test - public void test921SearchFocusTypeFindsOnlyFocusObjects() + public void test922SearchFocusTypeFindsOnlyFocusObjects() throws SchemaException { OperationResult operationResult = createOperationResult(); @@ -651,7 +890,7 @@ public void test921SearchFocusTypeFindsOnlyFocusObjects() then("only focus objects from repository are returned"); assertThat(result).hasSize((int) count(QFocus.CLASS)); // without additional objects the test would be meaningless - assertThat(result).hasSizeLessThan((int) count(QObject.CLASS)); + assertThat(result).hasSizeLessThan((int) count(QAssignmentHolder.CLASS)); } @Test diff --git a/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/filtering/item/ItemFilterProcessor.java b/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/filtering/item/ItemFilterProcessor.java index 4aa949778b0..01499af3635 100644 --- a/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/filtering/item/ItemFilterProcessor.java +++ b/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/filtering/item/ItemFilterProcessor.java @@ -89,8 +89,6 @@ protected Predicate createBinaryCondition( } } if (values.isMultiValue()) { - // TODO do we want Ops.EQ_IGNORE_CASE too? For one value, Querydsl takes care of - // ignore-case. For IN, we would have to do it ourselves. if (operator == Ops.EQ) { return ExpressionUtils.predicate(Ops.IN, path, ConstantImpl.create(values.allValues())); diff --git a/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/mapping/QueryTableMapping.java b/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/mapping/QueryTableMapping.java index a8d69609b3f..4760f1a64b1 100644 --- a/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/mapping/QueryTableMapping.java +++ b/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/mapping/QueryTableMapping.java @@ -57,7 +57,7 @@ * to the same schema type because of the nested mappings. * E.g. attribute `name` is part of the `S` object, but `metadata/createChannel` is based on nested * mapping for `metadata` for which `S` is `MetadataType`. - * That's why these methods have flexible schema type parameter. + * That's why these methods have flexible schema type parameter, typically designated `MS`. * Because such nested mapping still uses the same table, types `Q` and `R` remain the same. * * Mapping for tables is initialized once and requires {@link SqlRepoContext}. From 3b92c9fc0c758bedf750bcb6fefbbcc2848ca74f Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Wed, 26 May 2021 23:33:23 +0200 Subject: [PATCH 14/23] repo-sqale: SQL schema, added indexes using gin(subtypes) --- repo/repo-sqale/sql/pgnew-experiments.sql | 9 ++- repo/repo-sqale/sql/pgnew-repo.sql | 76 +++++++++++++++++++---- 2 files changed, 70 insertions(+), 15 deletions(-) diff --git a/repo/repo-sqale/sql/pgnew-experiments.sql b/repo/repo-sqale/sql/pgnew-experiments.sql index 35a2de16a03..f61e44a0258 100644 --- a/repo/repo-sqale/sql/pgnew-experiments.sql +++ b/repo/repo-sqale/sql/pgnew-experiments.sql @@ -86,7 +86,7 @@ SELECT 'resource-' || LPAD(r::text, 10, '0'), 1 from generate_series(1, 10) as r; -INSERT INTO m_user (nameNorm, nameOrig, fullobject, ext, policySituations, version) +INSERT INTO m_user (nameNorm, nameOrig, fullobject, ext, policySituations, subtypes, version) SELECT 'user-' || LPAD(r::text, 10, '0'), 'user-' || LPAD(r::text, 10, '0'), random_bytea(100, 2000), @@ -114,8 +114,13 @@ SELECT 'user-' || LPAD(r::text, 10, '0'), random_pick(ARRAY(SELECT a.n FROM generate_series(1, 100) AS a(n)), r % 10 / 100::decimal) -- ELSE NULL is default and redundant END, + CASE + WHEN r % 10 < random() * 2 THEN + random_pick(ARRAY['eating', 'books', 'music', 'dancing', 'walking', 'jokes', 'video', 'photo', 'writing', 'gaming'], 0.3) + -- ELSE NULL is default and redundant + END, 1 -from generate_series(100001,1000000) as r; +from generate_series(1, 50000) as r; EXPLAIN (ANALYZE, VERBOSE, BUFFERS) select oid, policysituations from m_user diff --git a/repo/repo-sqale/sql/pgnew-repo.sql b/repo/repo-sqale/sql/pgnew-repo.sql index b218c6c8faf..74ff58d2b6f 100644 --- a/repo/repo-sqale/sql/pgnew-repo.sql +++ b/repo/repo-sqale/sql/pgnew-repo.sql @@ -21,6 +21,7 @@ -- drop schema public cascade; CREATE SCHEMA IF NOT EXISTS public; CREATE EXTENSION IF NOT EXISTS intarray; -- support for indexing INTEGER[] columns +--CREATE EXTENSION IF NOT EXISTS pg_trgm; -- support for trigram indexes TODO for ext with LIKE and fulltext -- region custom enum types -- Some enums are from schema, some are only defined in repo-sqale. @@ -241,9 +242,9 @@ CREATE TABLE m_object ( version INTEGER NOT NULL DEFAULT 1, -- complex DB columns, add indexes as needed per concrete table, e.g. see m_user -- TODO compare with [] in JSONB, check performance, indexing, etc. first - policySituations INTEGER[], -- soft-references m_uri, add index per table as/if needed - subtypes TEXT[], - textInfo TEXT[], -- TODO not mapped yet, see RObjectTextInfo#createItemsSet + policySituations INTEGER[], -- soft-references m_uri, only EQ filter + subtypes TEXT[], -- only EQ filter + textInfo TEXT[], -- TODO not mapped yet, see RObjectTextInfo#createItemsSet, this may not be [] ext JSONB, -- metadata creatorRefTargetOid UUID, @@ -460,6 +461,7 @@ CREATE TRIGGER m_generic_object_oid_delete_tr AFTER DELETE ON m_generic_object -- No indexes for GenericObjectType#objectType were in old repo, what queries are expected? CREATE INDEX m_generic_object_nameOrig_idx ON m_generic_object (nameOrig); ALTER TABLE m_generic_object ADD CONSTRAINT m_generic_object_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_generic_object_subtypes_idx ON m_generic_object USING gin(subtypes); -- endregion -- region USER related tables @@ -503,6 +505,7 @@ CREATE INDEX m_user_fullNameOrig_idx ON m_user (fullNameOrig); CREATE INDEX m_user_familyNameOrig_idx ON m_user (familyNameOrig); CREATE INDEX m_user_givenNameOrig_idx ON m_user (givenNameOrig); CREATE INDEX m_user_employeeNumber_idx ON m_user (employeeNumber); +CREATE INDEX m_user_subtypes_idx ON m_user USING gin(subtypes); /* TODO JSON of polystrings? CREATE TABLE m_user_organization ( @@ -558,6 +561,7 @@ CREATE TRIGGER m_role_oid_delete_tr AFTER DELETE ON m_role CREATE INDEX m_role_nameOrig_idx ON m_role (nameOrig); ALTER TABLE m_role ADD CONSTRAINT m_role_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_role_subtypes_idx ON m_role USING gin(subtypes); -- Represents ServiceType, see https://wiki.evolveum.com/display/midPoint/Service+Account+Management CREATE TABLE m_service ( @@ -595,6 +599,7 @@ CREATE TRIGGER m_archetype_oid_delete_tr AFTER DELETE ON m_archetype CREATE INDEX m_archetype_nameOrig_idx ON m_archetype (nameOrig); ALTER TABLE m_archetype ADD CONSTRAINT m_archetype_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_archetype_subtypes_idx ON m_archetype USING gin(subtypes); -- endregion -- region Organization hierarchy support @@ -618,6 +623,7 @@ CREATE TRIGGER m_org_oid_delete_tr AFTER DELETE ON m_org CREATE INDEX m_org_nameOrig_idx ON m_org (nameOrig); ALTER TABLE m_org ADD CONSTRAINT m_org_nameNorm_key UNIQUE (nameNorm); CREATE INDEX m_org_displayOrder_idx ON m_org (displayOrder); +CREATE INDEX m_org_subtypes_idx ON m_org USING gin(subtypes); -- stores ObjectType/parentOrgRef CREATE TABLE m_ref_object_parent_org ( @@ -749,6 +755,7 @@ CREATE TRIGGER m_resource_oid_delete_tr AFTER DELETE ON m_resource CREATE INDEX m_resource_nameOrig_idx ON m_resource (nameOrig); ALTER TABLE m_resource ADD CONSTRAINT m_resource_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_resource_subtypes_idx ON m_resource USING gin(subtypes); -- stores ResourceType/business/approverRef CREATE TABLE m_ref_resource_business_configuration_approver ( @@ -798,6 +805,7 @@ CREATE TRIGGER m_shadow_oid_delete_tr AFTER DELETE ON m_shadow CREATE INDEX m_shadow_nameOrig_idx ON m_shadow (nameOrig); ALTER TABLE m_shadow ADD CONSTRAINT m_shadow_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_shadow_subtypes_idx ON m_shadow USING gin(subtypes); CREATE INDEX m_shadow_policySituation_idx ON m_shadow USING GIN(policysituations gin__int_ops); CREATE INDEX m_shadow_ext_idx ON m_shadow USING gin (ext); /* @@ -833,7 +841,7 @@ CREATE TRIGGER m_node_oid_delete_tr AFTER DELETE ON m_node CREATE INDEX m_node_nameOrig_idx ON m_node (nameOrig); ALTER TABLE m_node ADD CONSTRAINT m_node_nameNorm_key UNIQUE (nameNorm); --- not interested in ext index for this one, this table will be small +-- not interested in other indexes for this one, this table will be small -- Represents SystemConfigurationType, see https://wiki.evolveum.com/display/midPoint/System+Configuration+Object CREATE TABLE m_system_configuration ( @@ -850,6 +858,8 @@ CREATE TRIGGER m_system_configuration_update_tr BEFORE UPDATE ON m_system_config CREATE TRIGGER m_system_configuration_oid_delete_tr AFTER DELETE ON m_system_configuration FOR EACH ROW EXECUTE PROCEDURE delete_object_oid(); +ALTER TABLE m_system_configuration + ADD CONSTRAINT m_system_configuration_nameNorm_key UNIQUE (nameNorm); -- no need for the name index, m_system_configuration table is very small -- Represents SecurityPolicyType, see https://wiki.evolveum.com/display/midPoint/Security+Policy+Configuration @@ -867,7 +877,11 @@ CREATE TRIGGER m_security_policy_update_tr BEFORE UPDATE ON m_security_policy CREATE TRIGGER m_security_policy_oid_delete_tr AFTER DELETE ON m_security_policy FOR EACH ROW EXECUTE PROCEDURE delete_object_oid(); --- no need for the name index, m_security_policy table is very small +CREATE INDEX m_security_policy_nameOrig_idx ON m_security_policy (nameOrig); +ALTER TABLE m_security_policy ADD CONSTRAINT m_security_policy_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_security_policy_subtypes_idx ON m_security_policy USING gin(subtypes); +CREATE INDEX m_security_policy_policySituation_idx + ON m_security_policy USING GIN(policysituations gin__int_ops); -- Represents ObjectCollectionType, see https://wiki.evolveum.com/display/midPoint/Object+Collections+and+Views+Configuration CREATE TABLE m_object_collection ( @@ -886,6 +900,9 @@ CREATE TRIGGER m_object_collection_oid_delete_tr AFTER DELETE ON m_object_collec CREATE INDEX m_object_collection_nameOrig_idx ON m_object_collection (nameOrig); ALTER TABLE m_object_collection ADD CONSTRAINT m_object_collection_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_object_collection_subtypes_idx ON m_object_collection USING gin(subtypes); +CREATE INDEX m_object_collection_policySituation_idx + ON m_object_collection USING GIN(policysituations gin__int_ops); -- Represents DashboardType, see https://wiki.evolveum.com/display/midPoint/Dashboard+configuration CREATE TABLE m_dashboard ( @@ -904,6 +921,9 @@ CREATE TRIGGER m_dashboard_oid_delete_tr AFTER DELETE ON m_dashboard CREATE INDEX m_dashboard_nameOrig_idx ON m_dashboard (nameOrig); ALTER TABLE m_dashboard ADD CONSTRAINT m_dashboard_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_dashboard_subtypes_idx ON m_dashboard USING gin(subtypes); +CREATE INDEX m_dashboard_policySituation_idx + ON m_dashboard USING GIN(policysituations gin__int_ops); -- Represents ValuePolicyType CREATE TABLE m_value_policy ( @@ -922,6 +942,9 @@ CREATE TRIGGER m_value_policy_oid_delete_tr AFTER DELETE ON m_value_policy CREATE INDEX m_value_policy_nameOrig_idx ON m_value_policy (nameOrig); ALTER TABLE m_value_policy ADD CONSTRAINT m_value_policy_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_value_policy_subtypes_idx ON m_value_policy USING gin(subtypes); +CREATE INDEX m_value_policy_policySituation_idx + ON m_value_policy USING GIN(policysituations gin__int_ops); -- Represents ReportType, see https://wiki.evolveum.com/display/midPoint/Report+Configuration CREATE TABLE m_report ( @@ -942,6 +965,8 @@ CREATE TRIGGER m_report_oid_delete_tr AFTER DELETE ON m_report CREATE INDEX m_report_nameOrig_idx ON m_report (nameOrig); ALTER TABLE m_report ADD CONSTRAINT m_report_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_report_subtypes_idx ON m_report USING gin(subtypes); +CREATE INDEX m_report_policySituation_idx ON m_report USING GIN(policysituations gin__int_ops); -- TODO old repo had index on parent (boolean), does it make sense? if so, which value is sparse? -- Represents ReportDataType, see also m_report above @@ -964,6 +989,9 @@ CREATE TRIGGER m_report_data_oid_delete_tr AFTER DELETE ON m_report_data CREATE INDEX m_report_data_nameOrig_idx ON m_report_data (nameOrig); ALTER TABLE m_report_data ADD CONSTRAINT m_report_data_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_report_data_subtypes_idx ON m_report_data USING gin(subtypes); +CREATE INDEX m_report_data_policySituation_idx + ON m_report_data USING GIN(policysituations gin__int_ops); -- Represents LookupTableType, see https://wiki.evolveum.com/display/midPoint/Lookup+Tables CREATE TABLE m_lookup_table ( @@ -982,6 +1010,9 @@ CREATE TRIGGER m_lookup_table_oid_delete_tr AFTER DELETE ON m_lookup_table CREATE INDEX m_lookup_table_nameOrig_idx ON m_lookup_table (nameOrig); ALTER TABLE m_lookup_table ADD CONSTRAINT m_lookup_table_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_lookup_table_subtypes_idx ON m_lookup_table USING gin(subtypes); +CREATE INDEX m_lookup_table_policySituation_idx + ON m_lookup_table USING GIN(policysituations gin__int_ops); -- Represents LookupTableRowType, see also m_lookup_table above CREATE TABLE m_lookup_table_row ( @@ -1026,14 +1057,9 @@ CREATE TRIGGER m_connector_oid_delete_tr AFTER DELETE ON m_connector CREATE INDEX m_connector_nameOrig_idx ON m_connector (nameOrig); ALTER TABLE m_connector ADD CONSTRAINT m_connector_nameNorm_key UNIQUE (nameNorm); - --- TODO array/json in m_connector table --- CREATE TABLE m_connector_target_system ( --- connector_oid UUID NOT NULL, --- targetSystemType TEXT --- ); --- ALTER TABLE m_connector_target_system --- ADD CONSTRAINT fk_connector_target_system FOREIGN KEY (connector_oid) REFERENCES m_connector; +CREATE INDEX m_connector_subtypes_idx ON m_connector USING gin(subtypes); +CREATE INDEX m_connector_policySituation_idx + ON m_connector USING GIN(policysituations gin__int_ops); -- Represents ConnectorHostType, see https://wiki.evolveum.com/display/midPoint/Connector+Server CREATE TABLE m_connector_host ( @@ -1054,6 +1080,9 @@ CREATE TRIGGER m_connector_host_oid_delete_tr AFTER DELETE ON m_connector_host CREATE INDEX m_connector_host_nameOrig_idx ON m_connector_host (nameOrig); ALTER TABLE m_connector_host ADD CONSTRAINT m_connector_host_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_connector_host_subtypes_idx ON m_connector_host USING gin(subtypes); +CREATE INDEX m_connector_host_policySituation_idx + ON m_connector_host USING GIN(policysituations gin__int_ops); -- Represents persistent TaskType, see https://wiki.evolveum.com/display/midPoint/Task+Manager CREATE TABLE m_task ( @@ -1098,6 +1127,8 @@ CREATE INDEX m_task_parent_idx ON m_task (parent); CREATE INDEX m_task_objectRefTargetOid_idx ON m_task(objectRefTargetOid); ALTER TABLE m_task ADD CONSTRAINT m_task_taskIdentifier_key UNIQUE (taskIdentifier); CREATE INDEX m_task_dependentTaskIdentifiers_idx ON m_task USING GIN(dependentTaskIdentifiers); +CREATE INDEX m_task_subtypes_idx ON m_task USING gin(subtypes); +CREATE INDEX m_task_policySituation_idx ON m_task USING GIN(policysituations gin__int_ops); -- endregion -- region cases @@ -1132,6 +1163,8 @@ CREATE TRIGGER m_case_oid_delete_tr AFTER DELETE ON m_case CREATE INDEX m_case_nameOrig_idx ON m_case (nameOrig); ALTER TABLE m_case ADD CONSTRAINT m_case_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_case_subtypes_idx ON m_case USING gin(subtypes); +CREATE INDEX m_case_policySituation_idx ON m_case USING GIN(policysituations gin__int_ops); CREATE INDEX m_case_objectRefTargetOid_idx ON m_case(objectRefTargetOid); CREATE INDEX m_case_targetRefTargetOid_idx ON m_case(targetRefTargetOid); @@ -1154,10 +1187,12 @@ CREATE TABLE m_case_wi ( performerRefTargetType ObjectType, performerRefRelationId INTEGER REFERENCES m_uri(id), stageNumber INTEGER, + PRIMARY KEY (ownerOid, cid) ) INHERITS(m_container); +-- TODO INDEXES, old repo had no indexes either -- endregion -- region Access Certification object tables @@ -1185,6 +1220,9 @@ CREATE TRIGGER m_access_cert_definition_oid_delete_tr AFTER DELETE ON m_access_c CREATE INDEX m_access_cert_definition_nameOrig_idx ON m_access_cert_definition (nameOrig); ALTER TABLE m_access_cert_definition ADD CONSTRAINT m_access_cert_definition_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_access_cert_definition_subtypes_idx ON m_access_cert_definition USING gin(subtypes); +CREATE INDEX m_access_cert_definition_policySituation_idx + ON m_access_cert_definition USING GIN(policysituations gin__int_ops); CREATE INDEX m_access_cert_definition_ext_idx ON m_access_cert_definition USING gin (ext); -- TODO not mapped yet @@ -1217,6 +1255,9 @@ CREATE TRIGGER m_access_cert_campaign_oid_delete_tr AFTER DELETE ON m_access_cer CREATE INDEX m_access_cert_campaign_nameOrig_idx ON m_access_cert_campaign (nameOrig); ALTER TABLE m_access_cert_campaign ADD CONSTRAINT m_access_cert_campaign_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_access_cert_campaign_subtypes_idx ON m_access_cert_campaign USING gin(subtypes); +CREATE INDEX m_access_cert_campaign_policySituation_idx + ON m_access_cert_campaign USING GIN(policysituations gin__int_ops); CREATE INDEX m_access_cert_campaign_ext_idx ON m_access_cert_campaign USING gin (ext); CREATE TABLE m_access_cert_case ( @@ -1329,6 +1370,8 @@ CREATE TRIGGER m_object_template_oid_delete_tr AFTER DELETE ON m_object_template CREATE INDEX m_object_template_nameOrig_idx ON m_object_template (nameOrig); ALTER TABLE m_object_template ADD CONSTRAINT m_object_template_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_object_template_subtypes_idx ON m_object_template USING gin(subtypes); +CREATE INDEX m_object_template_policySituation_idx ON m_object_template USING GIN(policysituations gin__int_ops); -- stores ObjectTemplateType/includeRef CREATE TABLE m_ref_include ( @@ -1362,6 +1405,9 @@ CREATE TRIGGER m_function_library_oid_delete_tr AFTER DELETE ON m_function_libra CREATE INDEX m_function_library_nameOrig_idx ON m_function_library (nameOrig); ALTER TABLE m_function_library ADD CONSTRAINT m_function_library_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_function_library_subtypes_idx ON m_function_library USING gin(subtypes); +CREATE INDEX m_function_library_policySituation_idx + ON m_function_library USING GIN(policysituations gin__int_ops); -- Represents SequenceType, see https://wiki.evolveum.com/display/midPoint/Sequences CREATE TABLE m_sequence ( @@ -1380,6 +1426,8 @@ CREATE TRIGGER m_sequence_oid_delete_tr AFTER DELETE ON m_sequence CREATE INDEX m_sequence_nameOrig_idx ON m_sequence (nameOrig); ALTER TABLE m_sequence ADD CONSTRAINT m_sequence_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_sequence_subtypes_idx ON m_sequence USING gin(subtypes); +CREATE INDEX m_sequence_policySituation_idx ON m_sequence USING GIN(policysituations gin__int_ops); -- Represents FormType, see https://wiki.evolveum.com/display/midPoint/Custom+forms CREATE TABLE m_form ( @@ -1398,6 +1446,8 @@ CREATE TRIGGER m_form_oid_delete_tr AFTER DELETE ON m_form CREATE INDEX m_form_nameOrig_idx ON m_form (nameOrig); ALTER TABLE m_form ADD CONSTRAINT m_form_nameNorm_key UNIQUE (nameNorm); +CREATE INDEX m_form_subtypes_idx ON m_form USING gin(subtypes); +CREATE INDEX m_form_policySituation_idx ON m_form USING GIN(policysituations gin__int_ops); -- endregion -- region Assignment/Inducement table From 4bd20fe2a7ac245891ef00d230ea6fd87805a13b Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Thu, 27 May 2021 09:38:01 +0200 Subject: [PATCH 15/23] repo-sqale: fixes of messages in UnsupportedOperationException --- .../midpoint/repo/sqale/delta/ItemDeltaValueProcessor.java | 4 ++-- .../midpoint/repo/sqale/qmodel/common/QContainerMapping.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/ItemDeltaValueProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/ItemDeltaValueProcessor.java index cea2ba90bbf..e699e12f722 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/ItemDeltaValueProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/ItemDeltaValueProcessor.java @@ -80,7 +80,7 @@ public void addRealValues(Collection values) { } public void addValues(Collection values) { - throw new UnsupportedOperationException("deleteRealValues not implemented"); + throw new UnsupportedOperationException("addValues not implemented"); } /** Adds the provided real values to the database, implements ADD modification. */ @@ -89,7 +89,7 @@ public void deleteRealValues(Collection values) { } public void deleteValues(Collection values) { - throw new UnsupportedOperationException("deleteRealValues not implemented"); + throw new UnsupportedOperationException("deleteValues not implemented"); } /** Resets the database columns or deletes sub-entities like refs, containers, etc. */ diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/common/QContainerMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/common/QContainerMapping.java index b78cd02cdc5..289993c5738 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/common/QContainerMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/common/QContainerMapping.java @@ -76,6 +76,6 @@ public R initRowObject(S schemaObject, OR ownerRow) { @Override public R insert(S schemaObject, OR ownerRow, JdbcSession jdbcSession) { - throw new UnsupportedOperationException("insert not implemented in the subclass"); + throw new UnsupportedOperationException("insert must be implemented in the subclass"); } } From 00747ea635d328e57604d1da3daa2adcf2b42fee Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Thu, 27 May 2021 16:56:01 +0200 Subject: [PATCH 16/23] repo-sqale: added modify support for array columns Added ArrayItemDeltaProcessor to set array column. SqaleUpdateContext#findItem(path) returns item from root prism object; used to obtain new value (modification is applied before processor). Added missing mapping for assignment/policySituations. --- .../delta/DelegatingItemDeltaProcessor.java | 3 +- .../repo/sqale/delta/ItemDeltaProcessor.java | 3 +- .../sqale/delta/ItemDeltaValueProcessor.java | 10 +- .../delta/item/ArrayItemDeltaProcessor.java | 88 +++++++ .../item/ItemDeltaSingleValueProcessor.java | 2 + .../item/SinglePathItemDeltaProcessor.java | 2 + .../ArrayPathItemFilterProcessor.java | 5 + .../repo/sqale/qmodel/SqaleTableMapping.java | 8 +- .../qmodel/assignment/QAssignmentMapping.java | 2 + .../repo/sqale/update/RootUpdateContext.java | 11 +- .../repo/sqale/update/SqaleUpdateContext.java | 11 + .../sqale/func/SqaleRepoModifyObjectTest.java | 230 +++++++++++++++++- 12 files changed, 360 insertions(+), 15 deletions(-) create mode 100644 repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/ArrayItemDeltaProcessor.java diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/DelegatingItemDeltaProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/DelegatingItemDeltaProcessor.java index 73d0c59d724..43cc9d8429e 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/DelegatingItemDeltaProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/DelegatingItemDeltaProcessor.java @@ -20,6 +20,7 @@ import com.evolveum.midpoint.repo.sqlbase.mapping.ItemRelationResolver; import com.evolveum.midpoint.repo.sqlbase.mapping.ItemSqlMapper; import com.evolveum.midpoint.repo.sqlbase.mapping.QueryModelMapping; +import com.evolveum.midpoint.util.exception.SchemaException; /** * This is default item delta processor that decides what to do with the modification. @@ -40,7 +41,7 @@ public DelegatingItemDeltaProcessor(SqaleUpdateContext context) { } @Override - public void process(ItemDelta modification) throws RepositoryException { + public void process(ItemDelta modification) throws RepositoryException, SchemaException { QName itemName = resolvePath(modification.getPath()); if (itemName == null) { // This may indicate forgotten mapping, but normally it means that the item is simply diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/ItemDeltaProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/ItemDeltaProcessor.java index 51d96842baa..8b14f0beeb8 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/ItemDeltaProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/ItemDeltaProcessor.java @@ -8,6 +8,7 @@ import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.repo.sqlbase.RepositoryException; +import com.evolveum.midpoint.util.exception.SchemaException; /** * Essential contract for processing item delta modifications. @@ -16,5 +17,5 @@ */ public interface ItemDeltaProcessor { - void process(ItemDelta modification) throws RepositoryException; + void process(ItemDelta modification) throws RepositoryException, SchemaException; } diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/ItemDeltaValueProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/ItemDeltaValueProcessor.java index e699e12f722..c2a9b71f3e2 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/ItemDeltaValueProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/ItemDeltaValueProcessor.java @@ -15,6 +15,7 @@ import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.RepositoryException; +import com.evolveum.midpoint.util.exception.SchemaException; /** * Applies item delta values to an item and arranges necessary SQL changes using update context. @@ -39,9 +40,14 @@ protected ItemDeltaValueProcessor(SqaleUpdateContext context) { this.context = context; } - /** Default process implementation, most generic case covering especially multi-values. */ + /** + * Default process implementation, most generic case covering especially multi-values + * stored in separate rows. + * This works when implementations of {@link #deleteRealValues} and {@link #addRealValues} + * are independent, it's not usable for array update where a single `SET` clause is allowed. + */ @Override - public void process(ItemDelta modification) throws RepositoryException { + public void process(ItemDelta modification) throws RepositoryException, SchemaException { if (modification.isReplace()) { setRealValues(modification.getRealValuesToReplace()); return; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/ArrayItemDeltaProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/ArrayItemDeltaProcessor.java new file mode 100644 index 00000000000..fded02e3d11 --- /dev/null +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/ArrayItemDeltaProcessor.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010-2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.repo.sqale.delta.item; + +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.function.Function; +import java.util.function.IntFunction; + +import com.querydsl.core.types.dsl.ArrayPath; +import org.jetbrains.annotations.Nullable; + +import com.evolveum.midpoint.prism.Item; +import com.evolveum.midpoint.prism.PrismValue; +import com.evolveum.midpoint.prism.delta.ItemDelta; +import com.evolveum.midpoint.repo.sqale.delta.ItemDeltaValueProcessor; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; +import com.evolveum.midpoint.repo.sqlbase.RepositoryException; +import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; +import com.evolveum.midpoint.util.exception.SchemaException; + +/** + * Filter processor for multi-value property represented by single array column. + * These paths support only value equality (of any value), which is "contains" in DB terminology. + * Our filter "contains" (meaning substring) is *not* supported. + * + * @param type of value in schema + * @param type of element in DB (can be the same like `V`) + */ +public class ArrayItemDeltaProcessor extends ItemDeltaValueProcessor { + + private final ArrayPath path; + private final Class elementType; + @Nullable private final Function conversionFunction; + + /** + * @param entity query type from which the attribute is resolved + * @param row type related to {@link Q} + * @param elementType class of {@link E} necessary for array creation + * @param conversionFunction optional conversion function, can be null if no conversion is necessary + */ + public , R> ArrayItemDeltaProcessor( + SqaleUpdateContext context, + Function> rootToQueryItem, + Class elementType, + @Nullable Function conversionFunction) { + super(context); + this.path = rootToQueryItem.apply(context.path()); + this.elementType = elementType; + this.conversionFunction = conversionFunction; + } + + @Override + public void process(ItemDelta modification) throws RepositoryException, SchemaException { + Item item = context.findItem(modification.getPath()); + Collection realValues = item != null ? item.getRealValues() : null; + + if (realValues == null || realValues.isEmpty()) { + delete(); + } else { + // Whatever the operation is, we just set the new value here. + setRealValues(realValues); + } + } + + @Override + public void setRealValues(Collection values) { + //noinspection unchecked + IntFunction arrayConstructor = i -> (E[]) Array.newInstance(elementType, i); + + // valueArray can't be just Object[], it must be concrete type, e.g. String[], + // otherwise PG JDBC driver will complain. + //noinspection SuspiciousToArrayCall,unchecked + E[] valueArray = conversionFunction != null + ? ((Collection) values).stream().map(conversionFunction).toArray(arrayConstructor) + : values.toArray(arrayConstructor); + context.set(path, valueArray); + } + + @Override + public void delete() { + context.set(path, null); + } +} diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/ItemDeltaSingleValueProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/ItemDeltaSingleValueProcessor.java index 520f9d22923..3d0096382f1 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/ItemDeltaSingleValueProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/ItemDeltaSingleValueProcessor.java @@ -21,6 +21,8 @@ * * This hierarchy branch should not need {@link #addRealValues} and {@link #deleteRealValues}, * so it's not overridden and throws {@link UnsupportedOperationException}. + * + * @param expected type of the real value for the modification (after optional conversion) */ public abstract class ItemDeltaSingleValueProcessor extends ItemDeltaValueProcessor { diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/SinglePathItemDeltaProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/SinglePathItemDeltaProcessor.java index c5fbe97c07a..a4a4e0a4061 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/SinglePathItemDeltaProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/SinglePathItemDeltaProcessor.java @@ -14,6 +14,8 @@ import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; /** + * Processor for items represented by a single column (query path). + * * @param type of real value after optional conversion ({@link #convertRealValue(Object)} * to match the column (attribute) type in the row bean (M-type) * @param

type of the corresponding path in the Q-type diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/filtering/ArrayPathItemFilterProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/filtering/ArrayPathItemFilterProcessor.java index f24026e0c02..1ab65fa9629 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/filtering/ArrayPathItemFilterProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/filtering/ArrayPathItemFilterProcessor.java @@ -27,6 +27,9 @@ * Filter processor for multi-value property represented by single array column. * These paths support only value equality (of any value), which is "contains" in DB terminology. * Our filter "contains" (meaning substring) is *not* supported. + * + * @param type of value in schema + * @param type of element in DB (can be the same like `T`) */ public class ArrayPathItemFilterProcessor extends SinglePathItemFilterProcessor> { @@ -39,6 +42,8 @@ public class ArrayPathItemFilterProcessor * Creates filter processor for array column. * * @param dbType name of the type for element in DB (without []) for the cast part of the condition + * @param elementType class of {@link E} necessary for array creation + * @param conversionFunction optional conversion function, can be null if no conversion is necessary */ public , R> ArrayPathItemFilterProcessor( SqlQueryContext context, diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleTableMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleTableMapping.java index 8100e20a876..e1b2a775ba3 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleTableMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleTableMapping.java @@ -221,11 +221,12 @@ protected SqaleItemSqlMapper multiStringMapper( return new SqaleItemSqlMapper<>( ctx -> new ArrayPathItemFilterProcessor( ctx, rootToQueryItem, "TEXT", String.class, null), - ctx -> null); // TODO + ctx -> new ArrayItemDeltaProcessor( + ctx, rootToQueryItem, String.class, null)); } /** - * Returns the mapper creating integer multi-value filter/delta processors from context. + * Returns the mapper creating cached URI multi-value filter/delta processors from context. * * @param mapped schema type, see javadoc in {@link QueryTableMapping} */ @@ -235,7 +236,8 @@ protected SqaleItemSqlMapper multiUriMapper( ctx -> new ArrayPathItemFilterProcessor<>( ctx, rootToQueryItem, "INTEGER", Integer.class, ((SqaleRepoContext) ctx.repositoryContext())::searchCachedUriId), - ctx -> null); // TODO + ctx -> new ArrayItemDeltaProcessor<>(ctx, rootToQueryItem, Integer.class, + ((SqaleRepoContext) ctx.repositoryContext())::processCacheableUri)); } @Override diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/assignment/QAssignmentMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/assignment/QAssignmentMapping.java index b66cda08b24..da92b96f84a 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/assignment/QAssignmentMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/assignment/QAssignmentMapping.java @@ -98,6 +98,8 @@ private QAssignmentMapping( q -> q.tenantRefTargetOid, q -> q.tenantRefTargetType, q -> q.tenantRefRelationId)); + addItemMapping(F_POLICY_SITUATION, multiUriMapper(q -> q.policySituations)); + // TODO no idea how extId/Oid works, see RAssignment.getExtension // TODO ext mapping can't be done statically addNestedMapping(F_CONSTRUCTION, ConstructionType.class) diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/RootUpdateContext.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/RootUpdateContext.java index 2d137a9bccd..8f3b7a3dbf4 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/RootUpdateContext.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/RootUpdateContext.java @@ -13,10 +13,12 @@ import com.querydsl.core.types.Path; import com.querydsl.sql.dml.SQLUpdateClause; +import org.jetbrains.annotations.NotNull; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.equivalence.EquivalenceStrategy; +import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.repo.sqale.ContainerValueIdGenerator; import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; import com.evolveum.midpoint.repo.sqale.SqaleUtils; @@ -26,7 +28,7 @@ import com.evolveum.midpoint.repo.sqale.qmodel.object.QObjectMapping; import com.evolveum.midpoint.repo.sqlbase.JdbcSession; import com.evolveum.midpoint.repo.sqlbase.RepositoryException; -import com.evolveum.midpoint.repo.sqlbase.mapping.QueryTableMapping; +import com.evolveum.midpoint.repo.sqlbase.mapping.QueryModelMapping; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; @@ -68,7 +70,7 @@ public Q path() { } @Override - public QueryTableMapping mapping() { + public QueryModelMapping mapping() { return mapping; } @@ -156,6 +158,11 @@ protected void finishExecutionOwn() throws SchemaException, RepositoryException } } + @Override + public Item findItem(@NotNull ItemPath path) { + return object.asPrismObject().findItem(path); + } + public SQLUpdateClause update() { return update; } diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/SqaleUpdateContext.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/SqaleUpdateContext.java index 7cc1b9823f4..715b276a50d 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/SqaleUpdateContext.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/SqaleUpdateContext.java @@ -10,7 +10,10 @@ import java.util.Map; import com.querydsl.core.types.Path; +import org.jetbrains.annotations.NotNull; +import com.evolveum.midpoint.prism.Item; +import com.evolveum.midpoint.prism.PrismValue; import com.evolveum.midpoint.prism.path.ItemName; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.repo.sqale.SqaleRepoContext; @@ -149,4 +152,12 @@ protected final void finishExecution() throws SchemaException, RepositoryExcepti } protected abstract void finishExecutionOwn() throws SchemaException, RepositoryException; + + public Item findItem(@NotNull ItemPath path) { + if (parentContext == null) { + throw new UnsupportedOperationException( + "findItem() is unsupported on non-root update context"); + } + return parentContext.findItem(path); + } } diff --git a/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoModifyObjectTest.java b/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoModifyObjectTest.java index f9bb90c6d54..3802f29916f 100644 --- a/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoModifyObjectTest.java +++ b/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoModifyObjectTest.java @@ -1150,6 +1150,227 @@ public void test171DeletingMetadataContainerRemovesContainedRefs() r = QObjectReferenceMapping.getForModifyApprover().defaultAlias(); assertThat(count(r, r.ownerOid.eq(UUID.fromString(user1Oid)))).isZero(); } + + @Test + public void test180ReplacingSubtypeValuesSetsArrayColumn() throws Exception { + OperationResult result = createOperationResult(); + MUser originalRow = selectObjectByOid(QUser.class, user1Oid); + + given("delta to replace subtypes with a couple of values"); + ObjectDelta delta = prismContext.deltaFor(UserType.class) + .item(UserType.F_SUBTYPE).replace("subtype-1", "subtype-2") + .asObjectDelta(user1Oid); + + when("modifyObject is called"); + repositoryService.modifyObject(UserType.class, user1Oid, delta.getModifications(), result); + + then("operation is successful"); + assertThatOperationResult(result).isSuccess(); + + and("serialized form (fullObject) is updated and has provided subtypes"); + UserType userObject = repositoryService + .getObject(UserType.class, user1Oid, null, result) + .asObjectable(); + assertThat(userObject.getVersion()).isEqualTo(String.valueOf(originalRow.version + 1)); + assertThat(userObject.getSubtype()) + .containsExactlyInAnyOrder("subtype-1", "subtype-2"); + + and("column with subtypes is updated"); + MUser row = selectObjectByOid(QUser.class, user1Oid); + assertThat(row.version).isEqualTo(originalRow.version + 1); + assertThat(row.subtypes).containsExactlyInAnyOrder("subtype-1", "subtype-2"); + } + + @Test + public void test181AddingAndDeletingSubtypeValuesSetsArrayColumn() throws Exception { + OperationResult result = createOperationResult(); + + given("delta for subtypes with both delete and add values"); + ObjectDelta delta = prismContext.deltaFor(UserType.class) + .item(UserType.F_SUBTYPE).delete("subtype-2", "wrong").add("subtype-3", "subtype-4") + .asObjectDelta(user1Oid); + + when("modifyObject is called"); + repositoryService.modifyObject(UserType.class, user1Oid, delta.getModifications(), result); + + then("operation is successful"); + assertThatOperationResult(result).isSuccess(); + + and("serialized form (fullObject) is updated and has expected subtypes"); + UserType userObject = repositoryService + .getObject(UserType.class, user1Oid, null, result) + .asObjectable(); + assertThat(userObject.getSubtype()) + .containsExactlyInAnyOrder("subtype-1", "subtype-3", "subtype-4"); + + and("column with subtypes is updated"); + MUser row = selectObjectByOid(QUser.class, user1Oid); + assertThat(row.subtypes).containsExactlyInAnyOrder("subtype-1", "subtype-3", "subtype-4"); + } + + @Test + public void test182DeletingAllSubtypesByValuesSetsColumnToNull() throws Exception { + OperationResult result = createOperationResult(); + + given("delta deleting all subtype values"); + ObjectDelta delta = prismContext.deltaFor(UserType.class) + .item(UserType.F_SUBTYPE).delete("subtype-1", "subtype-3", "subtype-4") + .asObjectDelta(user1Oid); + + when("modifyObject is called"); + repositoryService.modifyObject(UserType.class, user1Oid, delta.getModifications(), result); + + then("operation is successful"); + assertThatOperationResult(result).isSuccess(); + + and("serialized form (fullObject) is updated and has no subtypes now"); + UserType userObject = repositoryService + .getObject(UserType.class, user1Oid, null, result) + .asObjectable(); + assertThat(userObject.getSubtype()).isNullOrEmpty(); + + and("column with subtypes is set to null"); + MUser row = selectObjectByOid(QUser.class, user1Oid); + assertThat(row.subtypes).isNull(); + } + + // this section tests two things: array in container, and integer[] requiring conversion (URIs) + @Test + public void test185AddingAssignmentWithPolicySituations() throws Exception { + OperationResult result = createOperationResult(); + MUser originalRow = selectObjectByOid(QUser.class, user1Oid); + + // Container tests are in 3xx category, but let's focus on policy situations. + given("delta adding assignment with policy situations"); + ObjectDelta delta = prismContext.deltaFor(UserType.class) + .item(UserType.F_ASSIGNMENT).add(new AssignmentType(prismContext) + .policySituation("policy-situation-1") + .policySituation("policy-situation-2")) + .asObjectDelta(user1Oid); + + when("modifyObject is called"); + repositoryService.modifyObject(UserType.class, user1Oid, delta.getModifications(), result); + + then("operation is successful"); + assertThatOperationResult(result).isSuccess(); + + and("serialized form (fullObject) is updated"); + UserType userObject = repositoryService + .getObject(UserType.class, user1Oid, null, result) + .asObjectable(); + assertThat(userObject.getVersion()).isEqualTo(String.valueOf(originalRow.version + 1)); + assertThat(userObject.getAssignment().get(0).getPolicySituation()) + .containsExactlyInAnyOrder("policy-situation-1", "policy-situation-2"); + + and("policySituation column is set in the assignment row"); + MUser row = selectObjectByOid(QUser.class, user1Oid); + assertThat(row.version).isEqualTo(originalRow.version + 1); + + QAssignment a = QAssignmentMapping.getAssignment().defaultAlias(); + MAssignment aRow = selectOne(a, a.ownerOid.eq(UUID.fromString(user1Oid))); + assertThat(aRow.policySituations) + .extracting(uriId -> cachedUriById(uriId)) + .containsExactlyInAnyOrder("policy-situation-1", "policy-situation-2"); + } + + @Test + public void test186AddingAndDeletingAssignmentPolicySituations() throws Exception { + OperationResult result = createOperationResult(); + MUser originalRow = selectObjectByOid(QUser.class, user1Oid); + long assignmentId = originalRow.containerIdSeq - 1; + + given("delta both adding and deleting assignment's policy situations"); + ObjectDelta delta = prismContext.deltaFor(UserType.class) + .item(UserType.F_ASSIGNMENT, assignmentId, AssignmentType.F_POLICY_SITUATION) + .delete("policy-situation-2", "wrong").add("policy-situation-3") + .asObjectDelta(user1Oid); + + when("modifyObject is called"); + repositoryService.modifyObject(UserType.class, user1Oid, delta.getModifications(), result); + + then("operation is successful"); + assertThatOperationResult(result).isSuccess(); + + and("serialized form (fullObject) is updated"); + UserType userObject = repositoryService + .getObject(UserType.class, user1Oid, null, result) + .asObjectable(); + assertThat(userObject.getAssignment().get(0).getPolicySituation()) + .containsExactlyInAnyOrder("policy-situation-1", "policy-situation-3"); + + and("column with subtypes is updated accordingly"); + QAssignment a = QAssignmentMapping.getAssignment().defaultAlias(); + MAssignment aRow = selectOne(a, a.ownerOid.eq(UUID.fromString(user1Oid))); + assertThat(aRow.policySituations) + .extracting(uriId -> cachedUriById(uriId)) + .containsExactlyInAnyOrder("policy-situation-1", "policy-situation-3"); + } + + @Test + public void test187ReplacingAssignmentPolicySituationsValues() throws Exception { + OperationResult result = createOperationResult(); + MUser originalRow = selectObjectByOid(QUser.class, user1Oid); + long assignmentId = originalRow.containerIdSeq - 1; + + given("delta replacing assignment's policy situations"); + ObjectDelta delta = prismContext.deltaFor(UserType.class) + .item(UserType.F_ASSIGNMENT, assignmentId, AssignmentType.F_POLICY_SITUATION) + .replace("policy-situation-a", "policy-situation-z") + .asObjectDelta(user1Oid); + + when("modifyObject is called"); + repositoryService.modifyObject(UserType.class, user1Oid, delta.getModifications(), result); + + then("operation is successful"); + assertThatOperationResult(result).isSuccess(); + + and("serialized form (fullObject) is updated"); + UserType userObject = repositoryService + .getObject(UserType.class, user1Oid, null, result) + .asObjectable(); + assertThat(userObject.getAssignment().get(0).getPolicySituation()) + .containsExactlyInAnyOrder("policy-situation-a", "policy-situation-z"); + + and("column with subtypes is updated accordingly"); + QAssignment a = QAssignmentMapping.getAssignment().defaultAlias(); + MAssignment aRow = selectOne(a, a.ownerOid.eq(UUID.fromString(user1Oid))); + assertThat(aRow.policySituations) + .extracting(uriId -> cachedUriById(uriId)) + .containsExactlyInAnyOrder("policy-situation-a", "policy-situation-z"); + } + + @Test + public void test188ReplacingAssignmentPolicySituationsWithNoValue() throws Exception { + OperationResult result = createOperationResult(); + MUser originalRow = selectObjectByOid(QUser.class, user1Oid); + long assignmentId = originalRow.containerIdSeq - 1; + + given("delta replacing assignment's policy situations with no value"); + ObjectDelta delta = prismContext.deltaFor(UserType.class) + .item(UserType.F_ASSIGNMENT, assignmentId, AssignmentType.F_POLICY_SITUATION) + .replace() + .asObjectDelta(user1Oid); + + when("modifyObject is called"); + repositoryService.modifyObject(UserType.class, user1Oid, delta.getModifications(), result); + + then("operation is successful"); + assertThatOperationResult(result).isSuccess(); + + and("serialized form (fullObject) is updated"); + UserType userObject = repositoryService + .getObject(UserType.class, user1Oid, null, result) + .asObjectable(); + assertThat(userObject.getAssignment().get(0).getPolicySituation()).isNullOrEmpty(); + + and("column with policy situations is set to null"); + QAssignment a = QAssignmentMapping.getAssignment().defaultAlias(); + MAssignment aRow = selectOne(a, a.ownerOid.eq(UUID.fromString(user1Oid))); + assertThat(aRow.policySituations).isNull(); + } + + // TODO test for multi-value (e.g. subtypes) with item delta with both add and delete lists + // But with current implementation this can go to the first hundred section...? // endregion // region nested (embedded) single-value containers (e.g. metadata) @@ -1631,16 +1852,16 @@ public void test213OverwritingParentOfDeeplyNestedEmbeddedContainer() // region multi-value containers (e.g. assignments) @Test - public void test300AddAssignmentStoresItAndGeneratesMissingId() + public void test300AddedAssignmentStoresItAndGeneratesMissingId() throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException { OperationResult result = createOperationResult(); MUser originalRow = selectObjectByOid(QUser.class, user1Oid); - given("delta adding assignment for user 1"); + given("delta replacing assignments for user 1 with a single one"); UUID roleOid = UUID.randomUUID(); ObjectDelta delta = prismContext.deltaFor(UserType.class) .item(UserType.F_ASSIGNMENT) - .add(new AssignmentType(prismContext) + .replace(new AssignmentType(prismContext) .targetRef(roleOid.toString(), RoleType.COMPLEX_TYPE)) // default relation .asObjectDelta(user1Oid); @@ -2112,9 +2333,6 @@ public void test399DeleteAllAssignments() } // endregion - // TODO test for multi-value (e.g. subtypes) with item delta with both add and delete lists - // But with current implementation this can go to the first hundred section...? - // TODO: photo test, should work fine, but it is kinda special, not part of full object // region other tests From a2e9412dc2c755ceefece5a5da600334d3a01fab Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Thu, 27 May 2021 17:17:37 +0200 Subject: [PATCH 17/23] repo-sqale: TODO refresh --- .../repo/sqale/func/SqaleRepoModifyObjectTest.java | 6 ++---- .../midpoint/repo/sqale/func/SqaleRepoSmokeTest.java | 8 +++++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoModifyObjectTest.java b/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoModifyObjectTest.java index 3802f29916f..955e6e79895 100644 --- a/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoModifyObjectTest.java +++ b/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoModifyObjectTest.java @@ -1368,9 +1368,6 @@ public void test188ReplacingAssignmentPolicySituationsWithNoValue() throws Excep MAssignment aRow = selectOne(a, a.ownerOid.eq(UUID.fromString(user1Oid))); assertThat(aRow.policySituations).isNull(); } - - // TODO test for multi-value (e.g. subtypes) with item delta with both add and delete lists - // But with current implementation this can go to the first hundred section...? // endregion // region nested (embedded) single-value containers (e.g. metadata) @@ -2333,7 +2330,8 @@ public void test399DeleteAllAssignments() } // endregion - // TODO: photo test, should work fine, but it is kinda special, not part of full object + // TODO: photo test, currently it puts it into fullObject and not into column. + // It should be other way around. // region other tests @Test diff --git a/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoSmokeTest.java b/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoSmokeTest.java index 309382e380a..2381e4b354a 100644 --- a/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoSmokeTest.java +++ b/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoSmokeTest.java @@ -88,10 +88,15 @@ public void test200GetObject() throws SchemaException, ObjectNotFoundException { then("object is obtained and performance monitor is updated"); assertThatOperationResult(result).isSuccess(); + assertThat(object).isNotNull(); assertSingleOperationRecorded(pm, RepositoryService.OP_GET_OBJECT); } - @Test(enabled = false) // TODO deleteObject not implemented yet + // TODO test for getObject() with typical options (here or separate class?) + // - ObjectOperationOptions(jpegPhoto:retrieve=INCLUDE) + // - ObjectOperationOptions(/:resolveNames) + + @Test public void test800DeleteObject() throws ObjectNotFoundException { OperationResult result = createOperationResult(); @@ -100,6 +105,7 @@ public void test800DeleteObject() throws ObjectNotFoundException { assertThat(deleteResult).isNotNull(); assertThatOperationResult(result).isSuccess(); + assertThat(selectNullableObjectByOid(QUser.class, sanityUserOid)).isNull(); } // region low-level tests From 43848222bae73ad0f7a7300edab2fc9953788744 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Thu, 27 May 2021 18:17:37 +0200 Subject: [PATCH 18/23] Introduce ItemDefinitionTransformer --- .../prism/ItemDefinitionTransformer.java | 22 +++++++++++++ .../midpoint/prism/PrismContainer.java | 1 + .../prism/deleg/ItemDefinitionDelegator.java | 10 ------ .../midpoint/prism/impl/ItemImpl.java | 18 +++++++++- .../prism/impl/PrismContainerValueImpl.java | 17 ++++++++++ .../prism/impl/PrismPropertyValueImpl.java | 6 ++++ .../prism/impl/PrismReferenceValueImpl.java | 33 ++++++++++++++++++- .../midpoint/prism/impl/PrismValueImpl.java | 4 ++- 8 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 infra/prism-api/src/main/java/com/evolveum/midpoint/prism/ItemDefinitionTransformer.java diff --git a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/ItemDefinitionTransformer.java b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/ItemDefinitionTransformer.java new file mode 100644 index 00000000000..5833bd64035 --- /dev/null +++ b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/ItemDefinitionTransformer.java @@ -0,0 +1,22 @@ +package com.evolveum.midpoint.prism; + + +public interface ItemDefinitionTransformer { + + > I transformItem(ComplexTypeDefinition parentDef, I currentDef); + + T applyValue(ComplexTypeDefinition parentDef, ItemDefinition itemDef, T valueDef); + + + public interface TransformableItem { + + void transformDefinition(ComplexTypeDefinition parentDef, ItemDefinitionTransformer transformer); + + } + + public interface TransformableValue { + + void transformDefinition(ComplexTypeDefinition parentDef, ItemDefinition itemDef, ItemDefinitionTransformer transformation); + } + +} diff --git a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/PrismContainer.java b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/PrismContainer.java index 3f5c607ccfd..e86249c13bd 100644 --- a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/PrismContainer.java +++ b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/PrismContainer.java @@ -224,6 +224,7 @@ > I findOr @Override PrismContainer cloneComplex(CloneStrategy strategy); + @Deprecated PrismContainerDefinition deepCloneDefinition(boolean ultraDeep, Consumer postCloneAction); @Override diff --git a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ItemDefinitionDelegator.java b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ItemDefinitionDelegator.java index 087de38feda..66bbe9e5bf3 100644 --- a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ItemDefinitionDelegator.java +++ b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/deleg/ItemDefinitionDelegator.java @@ -55,16 +55,6 @@ default int getMaxOccurs() { return delegate().getMaxOccurs(); } - @Override - default boolean isSingleValue() { - return delegate().isSingleValue(); - } - - @Override - default boolean isMultiValue() { - return delegate().isMultiValue(); - } - @Override default boolean isMandatory() { return delegate().isMandatory(); diff --git a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/ItemImpl.java b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/ItemImpl.java index e8a6b7ec1d6..bdbd7ad9b1c 100644 --- a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/ItemImpl.java +++ b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/ItemImpl.java @@ -26,6 +26,8 @@ import javax.xml.namespace.QName; import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.ItemDefinitionTransformer.TransformableItem; +import com.evolveum.midpoint.prism.ItemDefinitionTransformer.TransformableValue; import com.evolveum.midpoint.prism.util.CloneUtil; import com.evolveum.midpoint.util.annotation.Experimental; @@ -56,7 +58,7 @@ * * @author Radovan Semancik */ -public abstract class ItemImpl extends AbstractFreezable implements Item { +public abstract class ItemImpl extends AbstractFreezable implements Item, TransformableItem { private static final long serialVersionUID = 510000191615288733L; @@ -971,4 +973,18 @@ public Long getHighestId() { }); return highest.getValue(); } + + @Override + public void transformDefinition(ComplexTypeDefinition parent, ItemDefinitionTransformer transformation) { + D newDefinition = transformation.transformItem(parent, definition); + // Do not replace definition with null or run checks if definition is unmodified. + if (newDefinition != null && newDefinition != definition) { + setDefinition(newDefinition); + } + for (V pval : values) { + if (pval instanceof TransformableValue) { + ((TransformableValue) pval).transformDefinition(parent, definition, transformation); + } + } + } } diff --git a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/PrismContainerValueImpl.java b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/PrismContainerValueImpl.java index 59fce528ba3..edc1538ba79 100644 --- a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/PrismContainerValueImpl.java +++ b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/PrismContainerValueImpl.java @@ -22,6 +22,7 @@ import org.jetbrains.annotations.Nullable; import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.ItemDefinitionTransformer.TransformableItem; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.equivalence.EquivalenceStrategy; import com.evolveum.midpoint.prism.equivalence.ParameterizedEquivalenceStrategy; @@ -1825,6 +1826,22 @@ public void removeOperationalItems() { }); } + @Override + public void transformDefinition(ComplexTypeDefinition parentDef, ItemDefinition itemDef, + ItemDefinitionTransformer transformation) { + + ComplexTypeDefinition newDefinition = transformation.applyValue(parentDef, itemDef, complexTypeDefinition); + if (newDefinition != null && newDefinition != complexTypeDefinition) { + replaceComplexTypeDefinition(newDefinition); + } + + for(Item item : items.values()) { + if (item instanceof TransformableItem) { + ((TransformableItem) item).transformDefinition(complexTypeDefinition, transformation); + } + } + } + private static class FailOnAddList extends AbstractList> { public static final FailOnAddList INSTANCE = new FailOnAddList(); diff --git a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/PrismPropertyValueImpl.java b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/PrismPropertyValueImpl.java index 7b96bd95efd..a0bbabfd0f6 100644 --- a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/PrismPropertyValueImpl.java +++ b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/PrismPropertyValueImpl.java @@ -671,4 +671,10 @@ public void performFreeze() { return null; } } + + @Override + public void transformDefinition(ComplexTypeDefinition parentDef, ItemDefinition itemDef, + ItemDefinitionTransformer transformation) { + // NOOP + } } diff --git a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/PrismReferenceValueImpl.java b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/PrismReferenceValueImpl.java index 90ce45f884b..d23e23d13df 100644 --- a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/PrismReferenceValueImpl.java +++ b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/PrismReferenceValueImpl.java @@ -30,7 +30,6 @@ import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; /** @@ -80,6 +79,7 @@ public PrismReferenceValueImpl(String oid, OriginType type, Objectable source) { * * @return the target oid */ + @Override public String getOid() { if (oid != null) { return oid; @@ -90,6 +90,7 @@ public String getOid() { return null; } + @Override public void setOid(String oid) { checkMutable(); this.oid = oid; @@ -104,10 +105,12 @@ public void setOid(String oid) { * expect that the object can disappear when serialization boundary is crossed. * The client must expect that the object is null. */ + @Override public PrismObject getObject() { return object; } + @Override public void setObject(PrismObject object) { checkMutable(); this.object = object; @@ -121,6 +124,7 @@ public void setObject(PrismObject object) { * * @return the target type name */ + @Override public QName getTargetType() { if (targetType != null) { return targetType; @@ -131,6 +135,7 @@ public QName getTargetType() { return null; } + @Override public void setTargetType(QName targetType) { setTargetType(targetType, false); } @@ -138,6 +143,7 @@ public void setTargetType(QName targetType) { /** * @param allowEmptyNamespace This is an ugly hack. See comment in DOMUtil.validateNonEmptyQName. */ + @Override public void setTargetType(QName targetType, boolean allowEmptyNamespace) { checkMutable(); // Null value is OK @@ -158,6 +164,7 @@ public void setTargetType(QName targetType, boolean allowEmptyNamespace) { * mechanism. * @return cached name of the target object. */ + @Override public PolyString getTargetName() { if (targetName != null) { return targetName; @@ -168,11 +175,13 @@ public PolyString getTargetName() { return null; } + @Override public void setTargetName(PolyString name) { checkMutable(); this.targetName = name; } + @Override public void setTargetName(PolyStringType name) { checkMutable(); if (name == null) { @@ -183,11 +192,13 @@ public void setTargetName(PolyStringType name) { } // The PRV (this object) should have a parent with a prism context + @Override public Class getTargetTypeCompileTimeClass() { PrismContext prismContext = getPrismContext(); return prismContext != null ? getTargetTypeCompileTimeClass(prismContext) : null; } + @Override public Class getTargetTypeCompileTimeClass(PrismContext prismContext) { QName type = getTargetType(); if (type == null) { @@ -198,42 +209,51 @@ public Class getTargetTypeCompileTimeClass(PrismContext prismContext } } + @Override public QName getRelation() { return relation; } + @Override public void setRelation(QName relation) { checkMutable(); this.relation = relation; } + @Override public PrismReferenceValueImpl relation(QName relation) { setRelation(relation); return this; } + @Override public String getDescription() { return description; } + @Override public void setDescription(String description) { checkMutable(); this.description = description; } + @Override public SearchFilterType getFilter() { return filter; } + @Override public void setFilter(SearchFilterType filter) { checkMutable(); this.filter = filter; } + @Override public EvaluationTimeType getResolutionTime() { return resolutionTime; } + @Override public void setResolutionTime(EvaluationTimeType resolutionTime) { checkMutable(); this.resolutionTime = resolutionTime; @@ -311,6 +331,7 @@ public void applyDefinition(ItemDefinition definition, boolean force) throws Sch applyDefinition((PrismReferenceDefinition)definition, force); } + @Override public void applyDefinition(PrismReferenceDefinition definition, boolean force) throws SchemaException { super.applyDefinition(definition, force); if (object == null) { @@ -395,6 +416,7 @@ public boolean isEmpty() { * Returns a version of this value that is canonical, that means it has the minimal form. * E.g. it will have only OID and no object. */ + @Override public PrismReferenceValueImpl toCanonical() { PrismReferenceValueImpl can = new PrismReferenceValueImpl(); can.setOid(getOid()); @@ -407,6 +429,7 @@ public PrismReferenceValueImpl toCanonical() { return can; } + @Override public boolean equals(PrismValue other, @NotNull ParameterizedEquivalenceStrategy strategy) { return other instanceof PrismReferenceValue && equals((PrismReferenceValue) other, strategy); } @@ -550,6 +573,7 @@ public String toString() { return sb.toString(); } + @Override public Referencable asReferencable() { if (referencable != null) { return referencable; @@ -598,6 +622,7 @@ public String debugDump(int indent) { return debugDump(indent, false); } + @Override public String debugDump(int indent, boolean expandObject) { StringBuilder sb = new StringBuilder(); DebugUtil.indentDebugDump(sb, indent); @@ -709,4 +734,10 @@ public void accept(Visitor visitor) { object.accept(visitor); } } + + @Override + public void transformDefinition(ComplexTypeDefinition parentDef, ItemDefinition itemDef, + ItemDefinitionTransformer transformation) { + // NOOP + } } diff --git a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/PrismValueImpl.java b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/PrismValueImpl.java index 234e1527488..a5cdb664a30 100644 --- a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/PrismValueImpl.java +++ b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/PrismValueImpl.java @@ -7,6 +7,7 @@ package com.evolveum.midpoint.prism.impl; import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.ItemDefinitionTransformer.TransformableValue; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.equivalence.EquivalenceStrategy; import com.evolveum.midpoint.prism.equivalence.ParameterizedEquivalenceStrategy; @@ -28,7 +29,7 @@ * @author semancik * */ -public abstract class PrismValueImpl extends AbstractFreezable implements PrismValue { +public abstract class PrismValueImpl extends AbstractFreezable implements PrismValue, TransformableValue { private OriginType originType; private Objectable originObject; @@ -468,4 +469,5 @@ public boolean isTransient() { public void setTransient(boolean value) { isTransient = value; } + } From 5423dbd4c50ec4e762e61a802ceb81c33a8f0e4e Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Thu, 27 May 2021 18:19:11 +0200 Subject: [PATCH 19/23] Use ItemDefinitionTransformer in SchemaTransformator Implemented minimal subset of "MutableDefinition" contracts to satisfy GUI and other tests. --- .../impl/controller/SchemaTransformer.java | 33 +- .../transform/DefinitionsToTransformable.java | 48 +++ ...PartiallyMutableComplexTypeDefinition.java | 295 ++++++++++++++++++ .../PartiallyMutableItemDefinition.java | 282 +++++++++++++++++ .../TransformableComplexTypeDefinition.java | 105 ++++++- .../TransformableContainerDefinition.java | 97 +++++- .../TransformableItemDefinition.java | 240 ++++++++++---- .../TransformableObjectDefinition.java | 33 +- .../TransformablePropertyDefinition.java | 110 ++++++- .../TransformableReferenceDefinition.java | 26 +- 10 files changed, 1134 insertions(+), 135 deletions(-) create mode 100644 model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/DefinitionsToTransformable.java create mode 100644 model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/PartiallyMutableComplexTypeDefinition.java create mode 100644 model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/PartiallyMutableItemDefinition.java diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java index d01041dc035..7e1fe375953 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java @@ -15,11 +15,12 @@ import com.evolveum.midpoint.model.impl.lens.LensElementContext; import com.evolveum.midpoint.model.impl.lens.LensFocusContext; import com.evolveum.midpoint.model.impl.lens.LensProjectionContext; -import com.evolveum.midpoint.model.impl.schema.transform.TransformableContainerDefinition; +import com.evolveum.midpoint.model.impl.schema.transform.DefinitionsToTransformable; import com.evolveum.midpoint.model.impl.schema.transform.TransformableItemDefinition; import com.evolveum.midpoint.model.impl.schema.transform.TransformableObjectDefinition; import com.evolveum.midpoint.prism.*; -import com.evolveum.midpoint.prism.PrismItemAccessDefinition.Mutable; +import com.evolveum.midpoint.prism.ItemDefinitionTransformer.TransformableItem; +import com.evolveum.midpoint.prism.ItemDefinitionTransformer.TransformableValue; import com.evolveum.midpoint.prism.delta.ContainerDelta; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; @@ -47,6 +48,8 @@ import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; +import com.google.common.base.Preconditions; + import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; @@ -199,7 +202,8 @@ void applySchemasAndSecurity(PrismObject object, GetOp ObjectSecurityConstraints securityConstraints = compileSecurityConstraints(object, task, result); - PrismObjectDefinition objectDefinition = TransformableObjectDefinition.of(object); + transform(object, new DefinitionsToTransformable()); + PrismObjectDefinition objectDefinition = object.getDefinition(); if (phase == null) { if (!GetOperationOptions.isExecutionPhase(rootOptions)) { @@ -247,6 +251,11 @@ void applySchemasAndSecurity(PrismObject object, GetOp LOGGER.trace("applySchemasAndSecurity finishing"); // to allow folding in log viewer } + private void transform(Item object, ItemDefinitionTransformer transformation) { + Preconditions.checkArgument(object instanceof TransformableItem, "Value must be %s", TransformableValue.class.getSimpleName()); + ((TransformableItem) object).transformDefinition(null, transformation); + } + void applySchemasAndSecurity(LensContext context, AuthorizationPhaseType phase, Task task, OperationResult parentResult) throws SecurityViolationException, SchemaException, ConfigurationException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException { LOGGER.trace("applySchemasAndSecurity({}) starting", context); @@ -393,13 +402,10 @@ private void applySecurityConstraints(PrismContainerValue pcv, ObjectSecurity if (pcv.hasNoItems()) { return; } - // FIX PCV type for subtypes - TransformableContainerDefinition.ensureMutableType(pcv); List itemsToRemove = new ArrayList<>(); for (Item item : pcv.getItems()) { ItemPath itemPath = item.getPath(); - @SuppressWarnings({ "unchecked", "rawtypes" }) - ItemDefinition itemDef = ensureMutableDefinition((Item) item); + ItemDefinition itemDef = item.getDefinition(); if (itemDef != null && itemDef.isElaborate()) { LOGGER.trace("applySecurityConstraints(item): {}: skip (elaborate)", itemPath); continue; @@ -411,6 +417,7 @@ private void applySecurityConstraints(PrismContainerValue pcv, ObjectSecurity LOGGER.trace("applySecurityConstraints(item): {}: decisions R={}, A={}, M={}", itemPath, itemReadDecision, itemAddDecision, itemModifyDecision); if (applyToDefinitions && itemDef != null) { + itemDef = ensureMutableDefinition((Item) item); if (itemReadDecision != AuthorizationDecisionType.ALLOW) { mutable(itemDef).setCanRead(false); } @@ -457,6 +464,10 @@ private > D ensureMutableDefinition(Item item) if (TransformableItemDefinition.isMutableAccess(original)) { return original; } + if (true) { + throw new IllegalStateException("Transformer did not applied transformable properly"); + } + D replace = TransformableItemDefinition.publicFrom(original); try { item.applyDefinition(replace, true); @@ -466,8 +477,8 @@ private > D ensureMutableDefinition(Item item) return replace; } - private Mutable mutable(ItemDefinition itemDef) { - return TransformableItemDefinition.access(itemDef); + private MutableItemDefinition mutable(ItemDefinition itemDef) { + return itemDef.toMutable(); } private void applySecurityConstraints(ObjectDelta objectDelta, ObjectSecurityConstraints securityConstraints, AuthorizationPhaseType phase, @@ -849,6 +860,10 @@ private UserInterfaceElementVisibilityType reduceItems(PrismContainerDefinition< return containerVisibility; } + if (containerDefinition.getItemName().getLocalPart().equals("extension")) { + containerDefinition.getItemName(); + } + Collection itemsToDelete; if (containerVisibility == HIDDEN) { // Delete everything diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/DefinitionsToTransformable.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/DefinitionsToTransformable.java new file mode 100644 index 00000000000..f95185b5580 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/DefinitionsToTransformable.java @@ -0,0 +1,48 @@ +package com.evolveum.midpoint.model.impl.schema.transform; + +import com.evolveum.midpoint.prism.ComplexTypeDefinition; +import com.evolveum.midpoint.prism.ItemDefinition; +import com.evolveum.midpoint.prism.ItemDefinitionTransformer; +import com.evolveum.midpoint.prism.TypeDefinition; +import com.evolveum.midpoint.schema.processor.ResourceAttributeContainerDefinition; +import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; + +public class DefinitionsToTransformable implements ItemDefinitionTransformer { + + @Override + public T applyValue(ComplexTypeDefinition parentDef, ItemDefinition itemDef, + T valueDef) { + if (valueDef instanceof ComplexTypeDefinition) { + if (itemDef instanceof TransformableContainerDefinition) { + TransformableComplexTypeDefinition maybe = ((TransformableContainerDefinition) itemDef).getComplexTypeDefinition(); + if (valueDef.getTypeName().equals(maybe.getTypeName())) { + return (T) maybe; + } + } + return (T) TransformableComplexTypeDefinition.from((ComplexTypeDefinition) valueDef); + } + return valueDef; + } + + + @Override + public > I transformItem(ComplexTypeDefinition parentDef, I currentDef) { + if (currentDef == null || currentDef instanceof TransformableItemDefinition) { + return currentDef; + } + // Parent is transformable + if (parentDef instanceof TransformableComplexTypeDefinition) { + if (currentDef instanceof ResourceAttributeDefinition) { + return (I) TransformablePropertyDefinition.of((ResourceAttributeDefinition) currentDef); + } + if (currentDef instanceof ResourceAttributeContainerDefinition) { + return (I) TransformableContainerDefinition.of((ResourceAttributeContainerDefinition) currentDef); + } + ItemDefinition defFromParent = parentDef.findLocalItemDefinition(currentDef.getItemName()); + if (defFromParent != null) { + return (I) defFromParent; + } + } + return TransformableItemDefinition.publicFrom(currentDef); + } +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/PartiallyMutableComplexTypeDefinition.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/PartiallyMutableComplexTypeDefinition.java new file mode 100644 index 00000000000..6453c0e203b --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/PartiallyMutableComplexTypeDefinition.java @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2010-2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +package com.evolveum.midpoint.model.impl.schema.transform; + +import java.util.List; +import javax.xml.namespace.QName; + +import org.jetbrains.annotations.NotNull; +import com.evolveum.midpoint.prism.ComplexTypeDefinition; +import com.evolveum.midpoint.prism.ItemDefinition; +import com.evolveum.midpoint.prism.ItemProcessing; +import com.evolveum.midpoint.prism.MutableComplexTypeDefinition; +import com.evolveum.midpoint.prism.MutablePrismPropertyDefinition; +import com.evolveum.midpoint.prism.SchemaMigration; +import com.evolveum.midpoint.schema.processor.MutableObjectClassComplexTypeDefinition; +import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; +import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinitionImpl; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType; +import com.google.common.annotations.VisibleForTesting; + +interface PartiallyMutableComplexTypeDefinition extends MutableComplexTypeDefinition { + + @Override + default void setInstantiationOrder(Integer order) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setProcessing(ItemProcessing processing) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setDeprecated(boolean deprecated) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setExperimental(boolean experimental) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setEmphasized(boolean emphasized) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setDisplayName(String displayName) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setDisplayOrder(Integer displayOrder) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setHelp(String help) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setRuntimeSchema(boolean value) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setTypeName(QName typeName) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setDocumentation(String value) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void addSchemaMigration(SchemaMigration schemaMigration) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void add(ItemDefinition definition) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void delete(QName itemName) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default MutablePrismPropertyDefinition createPropertyDefinition(QName name, QName typeName) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + default MutablePrismPropertyDefinition createPropertyDefinition(String name, QName typeName) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + default @NotNull ComplexTypeDefinition clone() { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + default void setExtensionForType(QName type) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setAbstract(boolean value) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setSuperType(QName superType) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setObjectMarker(boolean value) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setContainerMarker(boolean value) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setReferenceMarker(boolean value) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setDefaultNamespace(String namespace) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setIgnoredNamespaces(@NotNull List ignoredNamespaces) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setXsdAnyMarker(boolean value) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setListMarker(boolean value) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void setCompileTimeClass(Class compileTimeClass) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void replaceDefinition(QName itemName, ItemDefinition newDefinition) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + + } + + @Override + default void addSubstitution(ItemDefinition itemDef, ItemDefinition maybeSubst) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + + public interface ObjectClassDefinition extends PartiallyMutableComplexTypeDefinition, MutableObjectClassComplexTypeDefinition { + + @Override + default void add(ItemDefinition definition) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + default void addPrimaryIdentifier(ResourceAttributeDefinition identifier) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + default void addSecondaryIdentifier(ResourceAttributeDefinition identifier) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + default void setDescriptionAttribute(ResourceAttributeDefinition descriptionAttribute) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + default void setNamingAttribute(ResourceAttributeDefinition namingAttribute) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + default void setNamingAttribute(QName namingAttribute) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + default void setNativeObjectClass(String nativeObjectClass) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + default void setAuxiliary(boolean auxiliary) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + default void setKind(ShadowKindType kind) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + default void setDefaultInAKind(boolean defaultAccountType) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + default void setIntent(String intent) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + default void setDisplayNameAttribute(ResourceAttributeDefinition displayName) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + default void setDisplayNameAttribute(QName displayName) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + @VisibleForTesting + default ResourceAttributeDefinitionImpl createAttributeDefinition(QName name, QName typeName) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + @VisibleForTesting + default ResourceAttributeDefinitionImpl createAttributeDefinition(String localName, QName typeName) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + @VisibleForTesting + default ResourceAttributeDefinition createAttributeDefinition(String localName, String localTypeName) { + throw new IllegalStateException("ComplexTypeDefinition is not modifiable"); + } + + @Override + @NotNull MutableObjectClassComplexTypeDefinition clone(); + } + + +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/PartiallyMutableItemDefinition.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/PartiallyMutableItemDefinition.java new file mode 100644 index 00000000000..5265a4f45b3 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/PartiallyMutableItemDefinition.java @@ -0,0 +1,282 @@ +package com.evolveum.midpoint.model.impl.schema.transform; + +import javax.xml.namespace.QName; + +import com.evolveum.midpoint.prism.ComplexTypeDefinition; +import com.evolveum.midpoint.prism.Containerable; +import com.evolveum.midpoint.prism.Item; +import com.evolveum.midpoint.prism.ItemProcessing; +import com.evolveum.midpoint.prism.MutableItemDefinition; +import com.evolveum.midpoint.prism.MutablePrismContainerDefinition; +import com.evolveum.midpoint.prism.MutablePrismPropertyDefinition; +import com.evolveum.midpoint.prism.MutablePrismReferenceDefinition; +import com.evolveum.midpoint.prism.PrismContainer; +import com.evolveum.midpoint.prism.PrismProperty; +import com.evolveum.midpoint.prism.PrismReference; +import com.evolveum.midpoint.prism.PrismReferenceValue; +import com.evolveum.midpoint.prism.SchemaMigration; +import com.evolveum.midpoint.schema.processor.MutableResourceAttributeDefinition; + +public interface PartiallyMutableItemDefinition> extends MutableItemDefinition { + + @Override + default void setProcessing(ItemProcessing processing) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setDeprecated(boolean deprecated) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setExperimental(boolean experimental) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setEmphasized(boolean emphasized) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setDisplayName(String displayName) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setDisplayOrder(Integer displayOrder) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setHelp(String help) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setRuntimeSchema(boolean value) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setTypeName(QName typeName) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setDocumentation(String value) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void addSchemaMigration(SchemaMigration schemaMigration) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setMinOccurs(int value) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setMaxOccurs(int value) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setCanRead(boolean val) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setCanModify(boolean val) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setCanAdd(boolean val) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setValueEnumerationRef(PrismReferenceValue valueEnumerationRef) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setOperational(boolean operational) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setDynamic(boolean value) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setItemName(QName name) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setReadOnly() { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setDeprecatedSince(String value) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setPlannedRemoval(String value) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setElaborate(boolean value) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setHeterogeneousListItem(boolean value) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setSubstitutionHead(QName value) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setIndexOnly(boolean value) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + public interface Container extends PartiallyMutableItemDefinition>, MutablePrismContainerDefinition { + + @Override + default void setCompileTimeClass(Class compileTimeClass) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default MutablePrismPropertyDefinition createPropertyDefinition(QName name, QName propType, int minOccurs, int maxOccurs) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default MutablePrismPropertyDefinition createPropertyDefinition(QName name, QName propType) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default MutablePrismPropertyDefinition createPropertyDefinition(String localName, QName propType) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default MutablePrismContainerDefinition createContainerDefinition(QName name, QName typeName, int minOccurs, int maxOccurs) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default MutablePrismContainerDefinition createContainerDefinition(QName name, ComplexTypeDefinition ctd, int minOccurs, int maxOccurs) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setInherited(boolean value) { + throw new IllegalStateException("Item Definition is not modifiable"); + + } + + @Override + default void setComplexTypeDefinition(ComplexTypeDefinition complexTypeDefinition) { + throw new IllegalStateException("Item Definition is not modifiable"); + } + } + + public interface Reference extends MutablePrismReferenceDefinition, PartiallyMutableItemDefinition { + + @Override + default void setTargetTypeName(QName typeName) { + throw new IllegalStateException("Item Definition is not modifiable"); + } + + @Override + default void setComposite(boolean value) { + throw new IllegalStateException("Item Definition is not modifiable"); + } + } + + public interface Property extends MutablePrismPropertyDefinition, PartiallyMutableItemDefinition> { + + @Override + default void setIndexed(Boolean value) { + throw new IllegalStateException("Item Definition is not modifiable"); + } + + @Override + default void setMatchingRuleQName(QName matchingRuleQName) { + throw new IllegalStateException("Item Definition is not modifiable"); + } + + @Override + default void setInherited(boolean value) { + throw new IllegalStateException("Item Definition is not modifiable"); + } + } + + public interface Attribute extends MutableResourceAttributeDefinition, Property { + + @Override + default void setReturnedByDefault(Boolean returnedByDefault) { + throw new IllegalStateException("Item Definition is not modifiable"); + } + + @Override + default void setNativeAttributeName(String nativeAttributeName) { + throw new IllegalStateException("Item Definition is not modifiable"); + } + + @Override + default void setFrameworkAttributeName(String frameworkAttributeName) { + throw new IllegalStateException("Item Definition is not modifiable"); + } + } +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableComplexTypeDefinition.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableComplexTypeDefinition.java index 8d02d469ce1..bd06969d47b 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableComplexTypeDefinition.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableComplexTypeDefinition.java @@ -11,6 +11,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Optional; import java.util.function.Consumer; @@ -28,12 +29,14 @@ import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition; import com.evolveum.midpoint.schema.processor.deleg.ObjectClassTypeDefinitionDelegator; -public class TransformableComplexTypeDefinition implements ComplexTypeDefinitionDelegator { +public class TransformableComplexTypeDefinition implements ComplexTypeDefinitionDelegator, PartiallyMutableComplexTypeDefinition { private static final long serialVersionUID = 1L; + private static final TransformableItemDefinition REMOVED = new Removed(); private final Map> overrides = new HashMap<>(); - private transient ComplexTypeDefinition delegate; + private final ComplexTypeDefinition delegate; + private transient List> definitionsCache; public TransformableComplexTypeDefinition(ComplexTypeDefinition delegate) { this.delegate = delegate; @@ -66,6 +69,9 @@ private > ID overriden(ID originalItem) { return null; } ItemDefinition overriden = overrides.computeIfAbsent(originalItem.getItemName(), k -> TransformableItemDefinition.from(originalItem)); + if (overriden instanceof Removed) { + return null; + } TransformableItemDefinition.apply(overriden, originalItem); return (ID) overriden; } @@ -105,11 +111,23 @@ public ID findNamedItemDefinition(@NotNull QName fir @Override public @NotNull List> getDefinitions() { - List> ret = new ArrayList<>(); - for (ItemDefinition originalItem : ComplexTypeDefinitionDelegator.super.getDefinitions()) { - ret.add(overriden(originalItem)); + + if (definitionsCache == null) { + List> ret = new ArrayList<>(); + for (ItemDefinition originalItem : ComplexTypeDefinitionDelegator.super.getDefinitions()) { + ItemDefinition wrapped = overriden(originalItem); + if (wrapped != null) { + ret.add(wrapped); + } + } + definitionsCache = ret; } - return ret; + return definitionsCache; + } + + @Override + public boolean isEmpty() { + return getDefinitions().isEmpty(); } @Override @@ -154,12 +172,32 @@ public void freeze() { @Override public @NotNull ComplexTypeDefinition deepClone(Map ctdMap, Map onThisPath, Consumer postCloneAction) { - throw new UnsupportedOperationException(); + if (ctdMap != null) { + ComplexTypeDefinition clone = ctdMap.get(this.getTypeName()); + if (clone != null) { + return clone; // already cloned + } + } + ComplexTypeDefinition cloneInParent = onThisPath.get(this.getTypeName()); + if (cloneInParent != null) { + return cloneInParent; + } + var copy = copy(); + if (ctdMap != null) { + ctdMap.put(this.getTypeName(), copy); + } + onThisPath.put(this.getTypeName(), copy); + for (Entry> entry : overrides.entrySet()) { + ItemDefinition item = entry.getValue().deepClone(ctdMap, onThisPath, postCloneAction); + copy.overrides.put(entry.getKey(), item); + } + onThisPath.remove(this.getTypeName()); + return copy; } @Override public MutableComplexTypeDefinition toMutable() { - throw new UnsupportedOperationException(); + return this; } /** @@ -169,10 +207,21 @@ public MutableComplexTypeDefinition toMutable() { * @param name * @param definition */ - public void replaceDefinition(QName name, ItemDefinition definition) { + @SuppressWarnings("rawtypes") + @Override + public void replaceDefinition(QName name, ItemDefinition definition) { overrides.put(name, definition); } + @Override + public void delete(QName itemName) { + ItemDefinition existing = findLocalItemDefinition(itemName); + if (existing != null) { + definitionsCache = null; + overrides.put(existing.getItemName(), REMOVED); + } + } + public TransformableComplexTypeDefinition copy() { TransformableComplexTypeDefinition copy = new TransformableComplexTypeDefinition(delegate()); copy.overrides.putAll(overrides); @@ -180,7 +229,8 @@ public TransformableComplexTypeDefinition copy() { } - public static class ObjectClass extends TransformableComplexTypeDefinition implements ObjectClassTypeDefinitionDelegator { + public static class ObjectClass extends TransformableComplexTypeDefinition + implements ObjectClassTypeDefinitionDelegator, PartiallyMutableComplexTypeDefinition.ObjectClassDefinition { private static final long serialVersionUID = 1L; @@ -194,8 +244,8 @@ public ObjectClassComplexTypeDefinition delegate() { } @Override - public ObjectClassComplexTypeDefinition clone() { - throw new UnsupportedOperationException(); + public MutableObjectClassComplexTypeDefinition clone() { + return copy(); } @Override @@ -205,16 +255,41 @@ public ObjectClass copy() { @Override public MutableObjectClassComplexTypeDefinition toMutable() { - throw new UnsupportedOperationException(); + return this; } - @SuppressWarnings("rawtypes") @Override public @NotNull ObjectClassComplexTypeDefinition deepClone(Map ctdMap, Map onThisPath, Consumer postCloneAction) { - throw new UnsupportedOperationException(); + return (ObjectClassComplexTypeDefinition) super.deepClone(ctdMap, onThisPath, postCloneAction); } } + @SuppressWarnings("rawtypes") + private static class Removed extends TransformableItemDefinition { + + private static final long serialVersionUID = 1L; + + protected Removed() { + super(null); + } + + @Override + protected ItemDefinition publicView() { + return null; + } + + + @Override + public String toString() { + return "REMOVED"; + } + + @Override + protected TransformableItemDefinition copy() { + return this; + } + } + } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableContainerDefinition.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableContainerDefinition.java index 38a2d452ec2..f1b1d4843ee 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableContainerDefinition.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableContainerDefinition.java @@ -8,7 +8,11 @@ package com.evolveum.midpoint.model.impl.schema.transform; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + import javax.xml.namespace.QName; import org.jetbrains.annotations.NotNull; @@ -21,13 +25,13 @@ import com.evolveum.midpoint.prism.PrismContainer; import com.evolveum.midpoint.prism.PrismContainerDefinition; import com.evolveum.midpoint.prism.PrismContainerValue; -import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismPropertyDefinition; import com.evolveum.midpoint.prism.PrismReferenceDefinition; import com.evolveum.midpoint.prism.deleg.ContainerDefinitionDelegator; import com.evolveum.midpoint.prism.delta.ContainerDelta; import com.evolveum.midpoint.prism.path.ItemName; import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.schema.processor.ResourceAttributeContainer; import com.evolveum.midpoint.schema.processor.ResourceAttributeContainerDefinition; import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; import com.evolveum.midpoint.schema.processor.deleg.AttributeContainerDefinitionDelegator; @@ -35,10 +39,9 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowAttributesType; import com.google.common.base.Preconditions; -public class TransformableContainerDefinition extends TransformableItemDefinition, PrismContainerDefinition> implements ContainerDefinitionDelegator { - - - +public class TransformableContainerDefinition + extends TransformableItemDefinition, PrismContainerDefinition> + implements ContainerDefinitionDelegator, PartiallyMutableItemDefinition.Container { private static final long serialVersionUID = 1L; @@ -56,6 +59,7 @@ public TransformableContainerDefinition(PrismContainerDefinition delegate, Co + @SuppressWarnings({ "rawtypes", "unchecked" }) public static TransformableContainerDefinition of(PrismContainerDefinition originalItem) { if (originalItem instanceof TransformableContainerDefinition) { return (TransformableContainerDefinition) originalItem; @@ -72,6 +76,7 @@ public static TransformableContainerDefinition of(P return complexTypeDefinition.getTypeName(); } + @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public Class getTypeClass() { return complexTypeDefinition.getTypeClass(); @@ -122,15 +127,8 @@ public ID findLocalItemDefinition(@NotNull QName nam public ID findNamedItemDefinition(@NotNull QName firstName, @NotNull ItemPath rest, @NotNull Class clazz) { if (complexTypeDefinition != null) { - ID maybe = complexTypeDefinition.findNamedItemDefinition(firstName, rest, clazz); - if (maybe != null) { - return maybe; - } + return complexTypeDefinition.findNamedItemDefinition(firstName, rest, clazz); } - if (complexTypeDefinition != null && complexTypeDefinition.isXsdAnyMarker()) { - throw new UnsupportedOperationException("Not implemented yet"); - } - return null; } @@ -175,6 +173,13 @@ public Class getCompileTimeClass() { public TransformableComplexTypeDefinition getComplexTypeDefinition() { return complexTypeDefinition; } + @Override + public boolean isEmpty() { + if (complexTypeDefinition == null) { + return true; + } + return complexTypeDefinition.isEmpty(); + } @Override public String getDefaultNamespace() { @@ -217,14 +222,33 @@ public ContainerDelta createEmptyDelta(ItemPath path) { @Override public @NotNull PrismContainerDefinition clone() { - throw new UnsupportedOperationException("Clone not supported"); + return new TransformableContainerDefinition<>(this, complexTypeDefinition); + } + + @Override + public ItemDefinition> deepClone(boolean ultraDeep, Consumer postCloneAction) { + return deepClone(new HashMap<>(), new HashMap<>(), postCloneAction); + } + + @Override + public ItemDefinition> deepClone(Map ctdMap, + Map onThisPath, Consumer postCloneAction) { + ComplexTypeDefinition ctd = getComplexTypeDefinition(); + if (ctd != null) { + ctd = ctd.deepClone(ctdMap, onThisPath, postCloneAction); + } + return copy(ctd); + } + + protected TransformableContainerDefinition copy(ComplexTypeDefinition def) { + return new TransformableContainerDefinition<>(this, def); } @Override public PrismContainerDefinition cloneWithReplacedDefinition(QName itemName, ItemDefinition newDefinition) { TransformableComplexTypeDefinition typeDefCopy = complexTypeDefinition.copy(); typeDefCopy.replaceDefinition(itemName, newDefinition); - return new TransformableContainerDefinition<>(this, typeDefCopy); + return copy(typeDefCopy); } @Override @@ -235,7 +259,7 @@ public void replaceDefinition(QName itemName, ItemDefinition newDefinition) { @Override public MutablePrismContainerDefinition toMutable() { - return null; + return this; } @Override @@ -249,6 +273,16 @@ public void freeze() { // FIXME: Intentional NOOP } + @Override + public PrismContainer instantiate() throws SchemaException { + return instantiate(getItemName()); + } + + @NotNull + @Override + public PrismContainer instantiate(QName elementName) throws SchemaException { + return this.getPrismContext().itemFactory().createContainer(elementName, this); + } @Override protected PrismContainerDefinition publicView() { @@ -278,12 +312,17 @@ public static class AttributeContainer extends TransformableContainerDefinition< /** * */ - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 2L; protected AttributeContainer(ResourceAttributeContainerDefinition delegate) { super(delegate); } + public AttributeContainer(AttributeContainer copy, + TransformableComplexTypeDefinition typeDef) { + super(copy, typeDef); + } + @Override public ResourceAttributeContainerDefinition delegate() { return (ResourceAttributeContainerDefinition) super.delegate(); @@ -300,10 +339,34 @@ public TransformableComplexTypeDefinition.ObjectClass getComplexTypeDefinition() return (TransformableComplexTypeDefinition.ObjectClass) super.getComplexTypeDefinition(); } + @Override + public PrismContainerDefinition cloneWithReplacedDefinition(QName itemName, ItemDefinition newDefinition) { + TransformableComplexTypeDefinition typeDefCopy = complexTypeDefinition.copy(); + typeDefCopy.replaceDefinition(itemName, newDefinition); + return new AttributeContainer(this, typeDefCopy); + } + @Override public @NotNull ResourceAttributeContainerDefinition clone() { throw new UnsupportedOperationException(); } + @Override + public ResourceAttributeContainer instantiate() { + return instantiate(getItemName()); + } + + @Override + public @NotNull ResourceAttributeContainer instantiate(QName elementName) { + ResourceAttributeContainer deleg = delegate().instantiate(elementName); + deleg.setDefinition(this); + return deleg; + } + + } + + @Override + protected TransformableContainerDefinition copy() { + return new TransformableContainerDefinition<>(this); } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableItemDefinition.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableItemDefinition.java index 5f3400f99da..4848b4d34bc 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableItemDefinition.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableItemDefinition.java @@ -1,8 +1,16 @@ package com.evolveum.midpoint.model.impl.schema.transform; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + +import javax.xml.namespace.QName; + +import com.evolveum.midpoint.prism.ComplexTypeDefinition; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.ItemDefinition; import com.evolveum.midpoint.prism.ItemProcessing; +import com.evolveum.midpoint.prism.MutableItemDefinition; import com.evolveum.midpoint.prism.PrismContainerDefinition; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismItemAccessDefinition; @@ -21,12 +29,31 @@ * and European Union Public License. See LICENSE file for details. */ -public abstract class TransformableItemDefinition,D extends ItemDefinition> implements ItemDefinitionDelegator, PrismItemAccessDefinition.Mutable { +public abstract class TransformableItemDefinition,D extends ItemDefinition> + implements ItemDefinitionDelegator, PrismItemAccessDefinition.Mutable, PartiallyMutableItemDefinition { private static final long serialVersionUID = 1L; private D delegate; + + private boolean allowAdd = true; + private boolean allowRead = true; + private boolean allowModify = true; + + private String displayName; + + private String help; + private Integer displayOrder; + private Boolean emphasized; + private Boolean deprecated; + private Boolean experimental; + + private Integer minOccurs; + private Integer maxOccurs; + private ItemProcessing processing; + private PrismReferenceValue valueEnumerationRef; + protected TransformableItemDefinition(D delegate) { if (delegate instanceof TransformableItemDefinition) { // CopyOf constructor @@ -36,27 +63,63 @@ protected TransformableItemDefinition(D delegate) { this.allowAdd = copyOf.allowAdd; this.allowRead = copyOf.allowRead; this.allowModify = copyOf.allowModify; - this.template = copyOf.template; this.minOccurs = copyOf.minOccurs; this.maxOccurs = copyOf.maxOccurs; this.processing = copyOf.processing; + + this.help = copyOf.help; + this.displayOrder = copyOf.displayOrder; + this.emphasized = copyOf.emphasized; + this.deprecated = copyOf.deprecated; + this.experimental = copyOf.experimental; + this.valueEnumerationRef = copyOf.valueEnumerationRef; this.delegate = copyOf.delegate(); } else { this.delegate = delegate; } + } - private boolean allowAdd = true; - private boolean allowRead = true; - private boolean allowModify = true; - private ObjectTemplateItemDefinitionType template; - private Integer minOccurs; - private Integer maxOccurs; - private ItemProcessing processing; - private PrismReferenceValue valueEnumerationRef; + @SuppressWarnings("unchecked") + public static > TransformableItemDefinition from(ID originalItem) { + if (originalItem == null) { + return null; + } + if (originalItem instanceof TransformableItemDefinition) { + return ((TransformableItemDefinition) originalItem); + } + if (originalItem instanceof PrismPropertyDefinition) { + return (TransformableItemDefinition) TransformablePropertyDefinition.of((PrismPropertyDefinition) originalItem); + } + if (originalItem instanceof PrismReferenceDefinition) { + return (TransformableItemDefinition) TransformableReferenceDefinition.of((PrismReferenceDefinition) originalItem); + } + if (originalItem instanceof PrismObjectDefinition) { + return (TransformableItemDefinition) TransformableObjectDefinition.of((PrismObjectDefinition) originalItem); + } + if (originalItem instanceof PrismContainerDefinition) { + return (TransformableItemDefinition) TransformableContainerDefinition.of((PrismContainerDefinition) originalItem); + } + throw new IllegalArgumentException("Unsupported item definition type " + originalItem.getClass()); + } + + + public static > ID publicFrom(ID definition) { + TransformableItemDefinition accessDef = from(definition); + if (accessDef != null) { + return accessDef.publicView(); + } + return null; + } + + + public static boolean isMutableAccess(ItemDefinition definition) { + return definition instanceof TransformableItemDefinition; + } + @Override public D delegate() { @@ -79,36 +142,39 @@ public boolean canRead() { } @Override - public void setCanAdd(boolean val) { - allowAdd = val; + public int getMinOccurs() { + return preferLocal(minOccurs, delegate().getMinOccurs()); } + @Override - public void setCanModify(boolean val) { - allowModify = val; + public int getMaxOccurs() { + return preferLocal(maxOccurs, delegate.getMaxOccurs()); } + @Override - public void setCanRead(boolean val) { - allowRead = val; + public ItemProcessing getProcessing() { + return preferLocal(processing, delegate.getProcessing()); } @Override - public int getMinOccurs() { - return preferLocal(minOccurs, delegate().getMinOccurs()); + public void setCanAdd(boolean val) { + allowAdd = val; } @Override - public int getMaxOccurs() { - return preferLocal(maxOccurs, delegate.getMaxOccurs()); + public void setCanModify(boolean val) { + allowModify = val; } @Override - public ItemProcessing getProcessing() { - return preferLocal(processing, delegate.getProcessing()); + public void setCanRead(boolean val) { + allowRead = val; } + @SuppressWarnings("unchecked") protected > ID apply(ID originalItem) { if (delegate == null) { @@ -117,37 +183,6 @@ protected > ID apply(ID originalItem) { return (ID) publicView(); } - @SuppressWarnings("unchecked") - public static > TransformableItemDefinition from(ID originalItem) { - if (originalItem == null) { - return null; - } - if (originalItem instanceof TransformableItemDefinition) { - return ((TransformableItemDefinition) originalItem); - } - if (originalItem instanceof PrismPropertyDefinition) { - return (TransformableItemDefinition) TransformablePropertyDefinition.of((PrismPropertyDefinition) originalItem); - } - if (originalItem instanceof PrismReferenceDefinition) { - return (TransformableItemDefinition) TransformableReferenceDefinition.of((PrismReferenceDefinition) originalItem); - } - if (originalItem instanceof PrismObjectDefinition) { - return (TransformableItemDefinition) TransformableObjectDefinition.of((PrismObjectDefinition) originalItem); - } - if (originalItem instanceof PrismContainerDefinition) { - return (TransformableItemDefinition) TransformableContainerDefinition.of((PrismContainerDefinition) originalItem); - } - throw new IllegalArgumentException("Unsupported item definition type " + originalItem.getClass()); - } - - public static > ID publicFrom(ID definition) { - TransformableItemDefinition accessDef = from(definition); - if (accessDef != null) { - return accessDef.publicView(); - } - return null; - } - protected abstract D publicView(); @Override @@ -172,70 +207,123 @@ public void revive(PrismContext prismContext) { delegate.revive(prismContext); } - public static boolean isMutableAccess(ItemDefinition definition) { - return definition instanceof TransformableItemDefinition; - } - public static TransformableItemDefinition access(ItemDefinition itemDef) { Preconditions.checkArgument(itemDef instanceof TransformableItemDefinition, "Definition must be %s", TransformableItemDefinition.class.getName()); return (TransformableItemDefinition) itemDef; } - public void applyTemplate(ObjectTemplateItemDefinitionType templateItemDefType) { - this.template = templateItemDefType; + public void applyTemplate(ObjectTemplateItemDefinitionType apply) { + if (apply.getDisplayName() != null) { + this.setDisplayName(apply.getDisplayName()); + } + if (apply.getHelp() != null) { + this.setHelp(apply.getHelp()); + } + if (apply.getDisplayOrder() != null) { + this.setDisplayOrder(apply.getDisplayOrder()); + } + if (apply.isEmphasized() != null) { + this.setEmphasized(apply.isEmphasized()); + } + if (apply.isDeprecated() != null) { + this.setDeprecated(apply.isDeprecated()); + } + if (apply.isExperimental() != null) { + this.setExperimental(apply.isExperimental()); + } } @Override public String getDisplayName() { - return preferLocal(template.getDisplayName(), delegate().getDisplayName()); + return preferLocal(this.displayName, delegate().getDisplayName()); } @Override public String getHelp() { - return preferLocal(template.getHelp(), delegate().getHelp()); + return preferLocal(this.help, delegate().getHelp()); } @Override public Integer getDisplayOrder() { - return preferLocal(template.getDisplayOrder(), delegate().getDisplayOrder()); + return preferLocal(this.displayOrder, delegate().getDisplayOrder()); } @Override public boolean isEmphasized() { - return preferLocal(template.isEmphasized(), delegate().isEmphasized()); + return preferLocal(this.emphasized, delegate().isEmphasized()); } @Override public boolean isDeprecated() { - return preferLocal(template.isDeprecated(), delegate().isDeprecated()); + return preferLocal(this.deprecated, delegate().isDeprecated()); } @Override public boolean isExperimental() { - return preferLocal(template.isExperimental(), delegate().isExperimental()); + return preferLocal(this.experimental, delegate().isExperimental()); } private T preferLocal(T fromTemplate, T fromDelegate) { return fromTemplate != null ? fromTemplate : fromDelegate; } - public void setMinOccurs(Integer value) { + @Override + public void setMinOccurs(int value) { this.minOccurs = value; } - public void setMaxOccurs(Integer value) { + @Override + public void setMaxOccurs(int value) { this.maxOccurs = value; } + @Override public void setValueEnumerationRef(PrismReferenceValue valueEnumerationRVal) { this.valueEnumerationRef = valueEnumerationRVal; } + @Override + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + + @Override + public void setHelp(String help) { + this.help = help; + } + + + @Override + public void setDisplayOrder(Integer displayOrder) { + this.displayOrder = displayOrder; + } + + + @Override + public void setEmphasized(boolean emphasized) { + this.emphasized = emphasized; + } + + + @Override + public void setDeprecated(boolean deprecated) { + this.deprecated = deprecated; + } + + + @Override + public void setExperimental(boolean experimental) { + this.experimental = experimental; + } + + @Override public PrismReferenceValue getValueEnumerationRef() { return preferLocal(valueEnumerationRef, delegate().getValueEnumerationRef()); } + @Override public void setProcessing(ItemProcessing itemProcessing) { this.processing = itemProcessing; } @@ -246,6 +334,24 @@ static void apply(ItemDefinition overriden, ItemDefinition originalItem) { } } + @Override + public MutableItemDefinition toMutable() { + return this; + } + + @Override + public ItemDefinition deepClone(boolean ultraDeep, Consumer postCloneAction) { + return deepClone(new HashMap<>(), new HashMap<>(), postCloneAction); + } + + @Override + public ItemDefinition deepClone(Map ctdMap, + Map onThisPath, Consumer postCloneAction) { + return copy(); + } + + protected abstract TransformableItemDefinition copy(); + @Override public String toString() { return "Transformable:" + delegate.toString(); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableObjectDefinition.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableObjectDefinition.java index 746d2d90a14..8e24ee751c7 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableObjectDefinition.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableObjectDefinition.java @@ -22,7 +22,8 @@ import com.evolveum.midpoint.prism.deleg.ObjectDefinitionDelegator; import com.evolveum.midpoint.util.exception.SchemaException; -public class TransformableObjectDefinition extends TransformableContainerDefinition implements ObjectDefinitionDelegator { +public class TransformableObjectDefinition extends TransformableContainerDefinition + implements ObjectDefinitionDelegator, MutablePrismObjectDefinition { public TransformableObjectDefinition(PrismObjectDefinition delegate) { super(delegate); @@ -48,7 +49,7 @@ protected PrismObjectDefinition publicView() { @Override public MutablePrismObjectDefinition toMutable() { - throw new UnsupportedOperationException(); + return this; } @Override @@ -65,21 +66,23 @@ public PrismObjectDefinition cloneWithReplacedDefinition(QName itemName, Item @Override public PrismObjectDefinition deepClone(boolean ultraDeep, Consumer postCloneAction) { - throw new UnsupportedOperationException(); + return (PrismObjectDefinition) super.deepClone(ultraDeep, postCloneAction); + } + + @Override + protected TransformableContainerDefinition copy(ComplexTypeDefinition def) { + return new TransformableObjectDefinition<>(this, def); } - public static PrismObjectDefinition of(PrismObject object) { - PrismObjectDefinition origDef = object.getDefinition(); - if (origDef instanceof TransformableObjectDefinition) { - return origDef; - } - TransformableObjectDefinition newDef = TransformableObjectDefinition.of(origDef); - try { - object.applyDefinition(newDef, true); - } catch (SchemaException e) { - throw new IllegalStateException("Can not replace definition for transformable one", e); - } - return newDef; + @Override + public PrismObject instantiate() throws SchemaException { + return instantiate(getItemName()); + } + + @Override + public @NotNull PrismObject instantiate(QName name) throws SchemaException { + // TODO Auto-generated method stub + return getPrismContext().itemFactory().createObject(name, this); } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformablePropertyDefinition.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformablePropertyDefinition.java index 927ffe862b8..c9b7cfa97eb 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformablePropertyDefinition.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformablePropertyDefinition.java @@ -7,8 +7,16 @@ package com.evolveum.midpoint.model.impl.schema.transform; +import java.util.Map; +import java.util.function.Consumer; + +import javax.xml.namespace.QName; + import org.jetbrains.annotations.NotNull; +import com.evolveum.midpoint.common.refinery.RefinedAttributeDefinition; +import com.evolveum.midpoint.common.refinery.deleg.RefinedAttributeDefinitionDelegator; +import com.evolveum.midpoint.prism.ComplexTypeDefinition; import com.evolveum.midpoint.prism.ItemDefinition; import com.evolveum.midpoint.prism.MutablePrismPropertyDefinition; import com.evolveum.midpoint.prism.PrismContext; @@ -19,7 +27,8 @@ import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; import com.evolveum.midpoint.schema.processor.deleg.AttributeDefinitionDelegator; -public class TransformablePropertyDefinition extends TransformableItemDefinition, PrismPropertyDefinition> implements PropertyDefinitionDelegator { +public class TransformablePropertyDefinition extends TransformableItemDefinition, PrismPropertyDefinition> + implements PropertyDefinitionDelegator, PartiallyMutableItemDefinition.Property { private static final long serialVersionUID = 1L; @@ -32,11 +41,13 @@ public static PrismPropertyDefinition of(PrismPropertyDefinition origi if (originalItem instanceof TransformablePropertyDefinition) { return originalItem; } + if (originalItem instanceof RefinedAttributeDefinition) { + return new RefinedAttribute<>(originalItem); + } if (originalItem instanceof ResourceAttributeDefinition) { return new ResourceAttribute<>(originalItem); } - return new TransformablePropertyDefinition<>(originalItem); } @@ -60,9 +71,24 @@ public void freeze() { throw new UnsupportedOperationException(); } + @Override + protected TransformablePropertyDefinition copy() { + return new TransformablePropertyDefinition<>(this); + } + @Override public MutablePrismPropertyDefinition toMutable() { - throw new UnsupportedOperationException(); + return this; + } + + @Override + public @NotNull PrismProperty instantiate() { + return instantiate(getItemName()); + } + + @Override + public @NotNull PrismProperty instantiate(QName name) { + return getPrismContext().itemFactory().createProperty(name, this); } @SuppressWarnings("unchecked") @@ -71,12 +97,14 @@ protected > ID apply(ID originalItem) { return (ID) publicView(); } + + @Override protected PrismPropertyDefinition publicView() { return this; } - public static class ResourceAttribute extends TransformablePropertyDefinition implements AttributeDefinitionDelegator { + public static class ResourceAttribute extends TransformablePropertyDefinition implements AttributeDefinitionDelegator, PartiallyMutableItemDefinition.Attribute { private static final long serialVersionUID = 1L; public ResourceAttribute(PrismPropertyDefinition delegate) { @@ -90,13 +118,85 @@ public ResourceAttributeDefinition delegate() { @Override public @NotNull ResourceAttributeDefinition clone() { - throw new UnsupportedOperationException(); + return copy(); + } + + @Override + protected ResourceAttribute copy() { + return new ResourceAttribute<>(this); } @Override public MutableResourceAttributeDefinition toMutable() { + return this; + } + + @Override + public @NotNull com.evolveum.midpoint.schema.processor.ResourceAttribute instantiate() { + return instantiate(getItemName()); + } + + @Override + public @NotNull com.evolveum.midpoint.schema.processor.ResourceAttribute instantiate(QName name) { + var deleg = delegate().instantiate(name); + deleg.setDefinition(this); + return deleg; + } + } + + public static class RefinedAttribute extends ResourceAttribute implements RefinedAttributeDefinitionDelegator { + + public RefinedAttribute(PrismPropertyDefinition delegate) { + super(delegate); + } + + @Override + public RefinedAttributeDefinition delegate() { + return (RefinedAttributeDefinition) super.delegate(); + } + + @Override + public @NotNull RefinedAttributeDefinition clone() { + return copy(); + } + + @Override + protected RefinedAttribute copy() { + return new RefinedAttribute<>(this); + } + + @Override + public RefinedAttributeDefinition deepClone(Map ctdMap, + Map onThisPath, Consumer postCloneAction) { throw new UnsupportedOperationException(); } + + @Override + public boolean canAdd() { + return delegate().canAdd(); + } + + @Override + public boolean canModify() { + return delegate().canModify(); + } + + @Override + public boolean canRead() { + return delegate().canRead(); + } + + @Override + public @NotNull com.evolveum.midpoint.schema.processor.ResourceAttribute instantiate() { + return instantiate(getItemName()); + } + + @Override + public @NotNull com.evolveum.midpoint.schema.processor.ResourceAttribute instantiate(QName name) { + var deleg = delegate().instantiate(name); + deleg.setDefinition(this); + return deleg; + } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableReferenceDefinition.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableReferenceDefinition.java index 5925f16d243..15f31f5c68e 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableReferenceDefinition.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/schema/transform/TransformableReferenceDefinition.java @@ -7,15 +7,17 @@ package com.evolveum.midpoint.model.impl.schema.transform; +import javax.xml.namespace.QName; + import org.jetbrains.annotations.NotNull; -import com.evolveum.midpoint.prism.MutableItemDefinition; -import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.MutablePrismReferenceDefinition; import com.evolveum.midpoint.prism.PrismReference; import com.evolveum.midpoint.prism.PrismReferenceDefinition; import com.evolveum.midpoint.prism.deleg.ReferenceDefinitionDelegator; -public class TransformableReferenceDefinition extends TransformableItemDefinition implements ReferenceDefinitionDelegator { +public class TransformableReferenceDefinition extends TransformableItemDefinition + implements ReferenceDefinitionDelegator, PartiallyMutableItemDefinition.Reference { private static final long serialVersionUID = 1L; @@ -33,17 +35,27 @@ protected PrismReferenceDefinition publicView() { } @Override - public void revive(PrismContext prismContext) { + public MutablePrismReferenceDefinition toMutable() { + return this; + } + @Override + public @NotNull PrismReference instantiate() { + return instantiate(getItemName()); } @Override - public MutableItemDefinition toMutable() { - throw new UnsupportedOperationException(); + public @NotNull PrismReference instantiate(QName name) { + return getPrismContext().itemFactory().createReference(name, this); } @Override public @NotNull PrismReferenceDefinition clone() { - throw new UnsupportedOperationException(); + return copy(); + } + + @Override + protected TransformableReferenceDefinition copy() { + return new TransformableReferenceDefinition(this); } } From f7d435d8540c9e28e8f90899ba4f0255350e1b30 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Thu, 27 May 2021 18:19:43 +0200 Subject: [PATCH 20/23] ResourceAttributes checks for schema application --- .../processor/ResourceAttributeContainerImpl.java | 12 ++++++++++++ .../schema/processor/ResourceAttributeImpl.java | 12 ++++++++++++ .../processor/SpecificAttributesDefinition.java | 3 +++ 3 files changed, 27 insertions(+) diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/ResourceAttributeContainerImpl.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/ResourceAttributeContainerImpl.java index d9641f0035e..a9f5b168d13 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/ResourceAttributeContainerImpl.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/ResourceAttributeContainerImpl.java @@ -17,6 +17,7 @@ import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.impl.PrismContainerImpl; import com.evolveum.midpoint.prism.path.ItemName; +import com.evolveum.midpoint.util.Checks; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowAttributesType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType; @@ -415,9 +416,20 @@ public void checkConsistenceInternal(Itemable rootItem, boolean requireDefinitio } } + @Override + public void applyDefinition(PrismContainerDefinition definition, boolean force) + throws SchemaException { + if (definition != null) { + Checks.checkSchema(definition instanceof ResourceAttributeContainerDefinition, "Definition should be %s not %s" , + ResourceAttributeContainerDefinition.class.getSimpleName(), definition.getClass().getName()); + } + super.applyDefinition(definition, force); + } + /** * Return a human readable name of this class suitable for logs. */ + @Override protected String getDebugDumpClassName() { return "RAC"; } diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/ResourceAttributeImpl.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/ResourceAttributeImpl.java index 1e697a9ff64..7e3bb24f233 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/ResourceAttributeImpl.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/ResourceAttributeImpl.java @@ -11,7 +11,10 @@ import com.evolveum.midpoint.prism.CloneStrategy; import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.PrismPropertyDefinition; import com.evolveum.midpoint.prism.impl.PrismPropertyImpl; +import com.evolveum.midpoint.util.Checks; +import com.evolveum.midpoint.util.exception.SchemaException; /** * Resource Object Attribute is a Property of Resource Object. All that applies @@ -95,8 +98,17 @@ protected void copyValues(CloneStrategy strategy, ResourceAttributeImpl clone /** * Return a human readable name of this class suitable for logs. */ + @Override protected String getDebugDumpClassName() { return "RA"; } + @Override + public void applyDefinition(PrismPropertyDefinition definition, boolean force) throws SchemaException { + if (definition != null) { + Checks.checkSchema(definition instanceof ResourceAttributeDefinition, "Definition should be %s not %s" , + ResourceAttributeDefinition.class.getSimpleName(), definition.getClass().getName()); + } + super.applyDefinition(definition, force); + } } diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/SpecificAttributesDefinition.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/SpecificAttributesDefinition.java index 337d3f296ae..1812c480b9e 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/SpecificAttributesDefinition.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/SpecificAttributesDefinition.java @@ -9,7 +9,10 @@ /** * @author mederly + * + * @deprecated Unused */ +@Deprecated public interface SpecificAttributesDefinition> { From 98286f13c7e58fc289461eb9d830fb52dd602f68 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Thu, 27 May 2021 18:20:30 +0200 Subject: [PATCH 21/23] Removed debug if statement Signed-off-by: Tony Tkacik --- .../midpoint/model/impl/controller/SchemaTransformer.java | 4 ---- .../midpoint/repo/sql/util/PrismIdentifierGenerator.java | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java index 7e1fe375953..ad2a4e840e9 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java @@ -860,10 +860,6 @@ private UserInterfaceElementVisibilityType reduceItems(PrismContainerDefinition< return containerVisibility; } - if (containerDefinition.getItemName().getLocalPart().equals("extension")) { - containerDefinition.getItemName(); - } - Collection itemsToDelete; if (containerVisibility == HIDDEN) { // Delete everything diff --git a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/util/PrismIdentifierGenerator.java b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/util/PrismIdentifierGenerator.java index 130b7e0667e..8ce70257c44 100644 --- a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/util/PrismIdentifierGenerator.java +++ b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/util/PrismIdentifierGenerator.java @@ -67,7 +67,7 @@ public IdGeneratorResult generate(Containerable containerable) { } // used both for PrismObjects nad PrismContainerValues - private List> listAllPrismContainers(Visitable object) { + private List> listAllPrismContainers(Visitable object) { List> values = new ArrayList<>(); object.accept(visitable -> { From f2041214e196762151f64feccdca80271cf97c8f Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Fri, 28 May 2021 23:13:37 +0200 Subject: [PATCH 22/23] StartupConfiguration: better/more sensitive values hidden + cleanup TODO about DEBUG dump on each getConfiguration(...) call added too, I believe DEBUG is too high (OK for one dump), maybe TRACE? Perhaps it's not needed on each getConf... call, just once. --- .../midpoint/init/StartupConfiguration.java | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/repo/system-init/src/main/java/com/evolveum/midpoint/init/StartupConfiguration.java b/repo/system-init/src/main/java/com/evolveum/midpoint/init/StartupConfiguration.java index 2b84f58caf8..0b571c3977a 100644 --- a/repo/system-init/src/main/java/com/evolveum/midpoint/init/StartupConfiguration.java +++ b/repo/system-init/src/main/java/com/evolveum/midpoint/init/StartupConfiguration.java @@ -12,7 +12,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.*; -import java.util.stream.Collectors; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; @@ -57,9 +56,10 @@ public class StartupConfiguration implements MidpointConfiguration { private static final Trace LOGGER = TraceManager.getTrace(StartupConfiguration.class); private static final List SENSITIVE_CONFIGURATION_VARIABLES = Arrays.asList( - "jdbcPassword", - "keyStorePassword" + "jdbcPassword", + "keyStorePassword" ); + public static final String SENSITIVE_VALUE_OUTPUT = "[*****]"; private boolean silent = false; @@ -120,18 +120,16 @@ public Configuration getConfiguration() { return config; } + // TODO do we want it for each getConfiguration call and on DEBUG level? + // getConfiguration(String) is called from 18 places + from more when getRootConfiguration() is considered + // This is better after the init of this class just once - or as trace if in getConfig calls. private void dumpConfiguration(String componentName, Configuration sub) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Configuration for {}:", componentName); Iterator i = sub.getKeys(); while (i.hasNext()) { String key = i.next(); - if (key != null - && !SENSITIVE_CONFIGURATION_VARIABLES.stream().filter(s -> key.contains(s)).collect(Collectors.toList()).isEmpty()) { - LOGGER.debug(" {} = [value]", key); - } else { - LOGGER.debug(" {} = {}", key, sub.getString(key)); - } + LOGGER.debug(" {} = {}", key, valuePrintout(key, sub.getString(key))); } } } @@ -293,10 +291,11 @@ private void resolveFileReferences() { try { String value = readFile(filename); overrideProperty(valueKey, value); - LOGGER.trace("Property '{}' was read from '{}': '{}'", valueKey, filename, value); + LOGGER.trace("Property '{}' was read from '{}': '{}'", + valueKey, filename, valuePrintout(key, value)); } catch (IOException e) { String message = "Couldn't read the value of configuration key '" + valueKey - + "' from the file '" + filename + "': " + e.toString(); + + "' from the file '" + filename + "': " + e; LoggingUtils.logUnexpectedException(LOGGER, message, e); System.err.println(message); throw new SystemException(e); @@ -305,16 +304,25 @@ private void resolveFileReferences() { }); } + /** + * Returns provided value for printing or string replacement for sensitive values (passwords). + */ + private String valuePrintout(String key, Object value) { + return SENSITIVE_CONFIGURATION_VARIABLES.stream().noneMatch(s -> key.contains(s)) + ? String.valueOf(value) + : SENSITIVE_VALUE_OUTPUT; + } + private String readFile(String filename) throws IOException { Path filePath = Path.of(filename.replace("${midpoint.home}", midPointHomePath)) - .toAbsolutePath(); // if missing this provides better diagnostics + .toAbsolutePath(); // this provides better diagnostics when the file is not found return Files.readString(filePath, StandardCharsets.UTF_8); } private void applyEnvironmentProperties() { Properties properties = System.getProperties(); properties.forEach((key, value) -> { - LOGGER.trace("Property {} = '{}'", key, value); + LOGGER.trace("Property {} = '{}'", key, valuePrintout(String.valueOf(key), value)); if (key instanceof String && ((String) key).startsWith("midpoint.")) { overrideProperty((String) key, value); } @@ -322,7 +330,7 @@ private void applyEnvironmentProperties() { } private void overrideProperty(String key, Object value) { - LOGGER.debug("Overriding property {} to '{}'", key, value); + LOGGER.debug("Overriding property {} to '{}'", key, valuePrintout(key, value)); config.setProperty(key, value); } From 978cd2140aeba0d9392a88d2cbd337345cd6c948 Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Mon, 31 May 2021 09:32:48 +0200 Subject: [PATCH 23/23] StartupConfiguration: hiding sensitive values in toString --- .../java/com/evolveum/midpoint/init/StartupConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repo/system-init/src/main/java/com/evolveum/midpoint/init/StartupConfiguration.java b/repo/system-init/src/main/java/com/evolveum/midpoint/init/StartupConfiguration.java index 0b571c3977a..117a11b18c4 100644 --- a/repo/system-init/src/main/java/com/evolveum/midpoint/init/StartupConfiguration.java +++ b/repo/system-init/src/main/java/com/evolveum/midpoint/init/StartupConfiguration.java @@ -400,7 +400,7 @@ public String toString() { String key = i.next(); sb.append(key); sb.append(" = "); - sb.append(config.getString(key)); + sb.append(valuePrintout(key, config.getString(key))); sb.append("; "); } return sb.toString();