Skip to content

Commit

Permalink
Add built-in metadata mappings support
Browse files Browse the repository at this point in the history
Still very preliminary and incomplete implementation.
Support for storage/creationTimestamp is provided.

Related to MID-6275.
  • Loading branch information
mederly committed Jun 30, 2020
1 parent 9885ab2 commit 3160ce6
Show file tree
Hide file tree
Showing 16 changed files with 951 additions and 608 deletions.
Expand Up @@ -12,7 +12,7 @@
*/
public enum ItemProcessing {

IGNORE("ignore"), MINIMAL("minimal"), AUTO("auto");
IGNORE("ignore"), MINIMAL("minimal"), AUTO("auto"), FULL("full");

private final String stringValue;

Expand Down
Expand Up @@ -172,4 +172,15 @@ public static <T> T getFromMap(Map<UniformItemPath, T> map, UniformItemPath item
}
return null;
}

// The code is the same as for UniformItemPath. We should perhaps unify these two.
// (Defeating the purpose of UniformItemPath...)
public static <T> T getFromMap(Map<ItemPath, T> map, ItemPath itemPath) {
for (Map.Entry<ItemPath, T> entry : map.entrySet()) {
if (entry.getKey().equivalent(itemPath)) {
return entry.getValue();
}
}
return null;
}
}

Large diffs are not rendered by default.

Expand Up @@ -8370,14 +8370,25 @@
<xsd:enumeration value="auto">
<xsd:annotation>
<xsd:documentation>
All usual processing of the item is applied. Or automated presentation,
transformation or any other processing will take place.
All usual processing of the item is applied.
</xsd:documentation>
<xsd:appinfo>
<jaxb:typesafeEnumMember name="AUTO"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="full">
<xsd:annotation>
<xsd:documentation>
Full processing of the item is applied. For GUI this means that
automated presentation takes place. For metadata the meaning is that
built-in mappings are applied.
</xsd:documentation>
<xsd:appinfo>
<jaxb:typesafeEnumMember name="FULL"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>

Expand Down
Expand Up @@ -7,11 +7,17 @@

package com.evolveum.midpoint.model.common.mapping;

import com.evolveum.midpoint.model.common.mapping.builtin.BuiltinMetadataMapping;

import com.evolveum.midpoint.model.common.mapping.builtin.BuiltinMetadataMappingsRegistry;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.evolveum.midpoint.prism.PrismContext;

import java.util.Collection;

/**
* Evaluates metadata mappings.
*/
Expand All @@ -20,5 +26,9 @@ public class MetadataMappingEvaluator {

@Autowired MappingFactory mappingFactory;
@Autowired PrismContext prismContext;
@Autowired BuiltinMetadataMappingsRegistry builtinMetadataMappingsRegistry;

Collection<BuiltinMetadataMapping> getBuiltinMappings() {
return builtinMetadataMappingsRegistry.getMappings();
}
}
Expand Up @@ -7,6 +7,7 @@

package com.evolveum.midpoint.model.common.mapping;

import com.evolveum.midpoint.model.common.mapping.builtin.BuiltinMetadataMapping;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple;
Expand All @@ -16,17 +17,12 @@
import com.evolveum.midpoint.schema.metadata.MidpointValueMetadataFactory;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.util.exception.*;
import com.evolveum.midpoint.xml.ns._public.common.common_3.MetadataMappingType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ValueMetadataType;

import com.evolveum.midpoint.xml.ns._public.common.common_3.VariableBindingDefinitionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import org.jetbrains.annotations.NotNull;

import javax.xml.namespace.QName;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.*;
import java.util.Objects;

/**
Expand Down Expand Up @@ -58,17 +54,19 @@ class ValueMetadataComputation {

public ValueMetadata execute() throws CommunicationException, ObjectNotFoundException, SchemaException,
SecurityViolationException, ConfigurationException, ExpressionEvaluationException {
for (MetadataMappingType mappingBean : computer.processingSpec.getMappings()) {
processMapping(mappingBean);
}
processCustomMappings();
processBuiltinMappings();
return MidpointValueMetadataFactory.createFrom(outputMetadata);
}

private void processMapping(MetadataMappingType mappingBean) throws CommunicationException, ObjectNotFoundException,
SchemaException, SecurityViolationException, ConfigurationException, ExpressionEvaluationException {
MetadataMappingImpl<?, ?> mapping = createMetadataMapping(mappingBean);
mapping.evaluate(computer.dataMapping.getTask(), result);
appendValues(mapping.getOutputPath(), mapping.getOutputTriple());
private void processCustomMappings()
throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException,
ConfigurationException, ExpressionEvaluationException {
for (MetadataMappingType mappingBean : computer.processingSpec.getMappings()) {
MetadataMappingImpl<?, ?> mapping = createMapping(mappingBean);
mapping.evaluate(computer.dataMapping.getTask(), result);
appendValues(mapping.getOutputPath(), mapping.getOutputTriple());
}
}

private void appendValues(ItemPath outputPath, PrismValueDeltaSetTriple<?> outputTriple) throws SchemaException {
Expand All @@ -79,7 +77,7 @@ private void appendValues(ItemPath outputPath, PrismValueDeltaSetTriple<?> outpu
itemDelta.applyTo(outputMetadata);
}

private MetadataMappingImpl<?, ?> createMetadataMapping(MetadataMappingType mappingBean) throws SchemaException {
private MetadataMappingImpl<?, ?> createMapping(MetadataMappingType mappingBean) throws SchemaException {
MetadataMappingBuilder<?, ?> builder = computer.metadataMappingEvaluator.mappingFactory.createMappingBuilder(mappingBean,
"metadata mapping in " + computer.dataMapping.getMappingContextDescription());
createSources(builder, mappingBean);
Expand Down Expand Up @@ -141,4 +139,16 @@ private ItemPath getSourcePath(VariableBindingDefinitionType sourceDef) {
private String getContextDescription() {
return computer.getContextDescription(); // TODO indication of value tuple being processed
}

private void processBuiltinMappings() throws SchemaException {
for (BuiltinMetadataMapping mapping : computer.metadataMappingEvaluator.getBuiltinMappings()) {
if (isApplicable(mapping)) {
mapping.apply(valuesTuple, outputMetadata, computer.dataMapping, result);
}
}
}

private boolean isApplicable(BuiltinMetadataMapping mapping) throws SchemaException {
return computer.processingSpec.isFullProcessing(mapping.getTargetPath());
}
}
Expand Up @@ -7,19 +7,17 @@

package com.evolveum.midpoint.model.common.mapping;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.*;

import com.evolveum.midpoint.model.common.util.ObjectTemplateIncludeProcessor;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.path.ItemPathCollectionsUtil;
import com.evolveum.midpoint.repo.common.ObjectResolver;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.MiscUtil;
import com.evolveum.midpoint.util.exception.*;
import com.evolveum.midpoint.xml.ns._public.common.common_3.MetadataItemDefinitionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.MetadataMappingType;

import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTemplateType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import org.jetbrains.annotations.NotNull;

Expand All @@ -36,6 +34,11 @@ public class ValueMetadataProcessingSpec {
@NotNull private final Collection<MetadataMappingType> mappings = new ArrayList<>();
@NotNull private final Collection<MetadataItemDefinitionType> itemDefinitions = new ArrayList<>();

/**
* Item processing for given metadata items. Lazily evaluated.
*/
private Map<ItemPath, ItemProcessingType> itemProcessingMap;

public boolean isEmpty() {
return false;
}
Expand Down Expand Up @@ -90,4 +93,58 @@ public Collection<MetadataMappingType> getMappings() {
public Collection<MetadataItemDefinitionType> getItemDefinitions() {
return itemDefinitions;
}

private void computeItemProcessingMapIfNeeded() throws SchemaException {
if (itemProcessingMap == null) {
computeItemProcessingMap();
}
}

private void computeItemProcessingMap() throws SchemaException {
itemProcessingMap = new HashMap<>();
for (MetadataItemDefinitionType item : itemDefinitions) {
if (item.getRef() == null) {
throw new SchemaException("No 'ref' in item definition: " + item);
}
ItemProcessingType processing = getProcessingOfItem(item);
if (processing != null) {
itemProcessingMap.put(item.getRef().getItemPath(), processing);
}
}
}

/**
* Extracts processing information from specified item definition.
*/
private ItemProcessingType getProcessingOfItem(MetadataItemDefinitionType item) throws SchemaException {
Set<ItemProcessingType> processing = new HashSet<>();
for (PropertyLimitationsType limitation : item.getLimitations()) {
if (limitation.getLayer().isEmpty() || limitation.getLayer().contains(LayerType.MODEL)) {
if (limitation.getProcessing() != null) {
processing.add(limitation.getProcessing());
}
}
}
return MiscUtil.extractSingleton(processing,
() -> new SchemaException("Contradicting 'processing' values for " + item + ": " + processing));
}

/**
* Looks up processing information for given path. Proceeds from the most specific to most abstract (empty) path.
*/
private ItemProcessingType getProcessing(ItemPath itemPath) throws SchemaException {
computeItemProcessingMapIfNeeded();
while (!itemPath.isEmpty()) {
ItemProcessingType processing = ItemPathCollectionsUtil.getFromMap(itemProcessingMap, itemPath);
if (processing != null) {
return processing;
}
itemPath = itemPath.allExceptLast();
}
return null;
}

boolean isFullProcessing(ItemPath itemPath) throws SchemaException {
return getProcessing(itemPath) == ItemProcessingType.FULL;
}
}
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2020 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.common.mapping.builtin;

import javax.annotation.PostConstruct;

import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;

import com.evolveum.midpoint.prism.PrismContainerValue;
import com.evolveum.midpoint.prism.PrismProperty;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.util.exception.SchemaException;

/**
* TODO
*/
abstract class BaseBuiltinMetadataMapping implements BuiltinMetadataMapping {

@NotNull private final ItemPath targetPath;
// private ItemDefinition<?> targetDefinition;

// @Autowired private PrismContext prismContext;
@Autowired private BuiltinMetadataMappingsRegistry registry;

BaseBuiltinMetadataMapping(@NotNull ItemPath targetItem) {
this.targetPath = targetItem;
}

@PostConstruct
void register() {
registry.registerBuiltinMapping(this);
// targetDefinition = Objects.requireNonNull(
// prismContext.getSchemaRegistry().getValueMetadataDefinition().findItemDefinition(targetPath),
// () -> "No definition for metadata item " + targetPath);
}

@Override
@NotNull
public ItemPath getTargetPath() {
return targetPath;
}

void addPropertyRealValue(PrismContainerValue<?> outputMetadata, Object value) throws SchemaException {
if (value != null) {
PrismProperty property = outputMetadata.findOrCreateProperty(targetPath);
//noinspection unchecked
property.addRealValue(value);
}
}
}
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2020 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.common.mapping.builtin;

import com.evolveum.midpoint.model.common.mapping.MappingImpl;
import com.evolveum.midpoint.prism.PrismContainerValue;
import com.evolveum.midpoint.prism.PrismValue;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ValueMetadataType;

import org.jetbrains.annotations.NotNull;

import java.util.List;

/**
* TODO
*/
public interface BuiltinMetadataMapping {

void apply(List<PrismValue> valuesTuple, PrismContainerValue<ValueMetadataType> outputMetadata,
MappingImpl<?, ?> dataMapping, OperationResult result) throws SchemaException;

@NotNull
ItemPath getTargetPath();
}
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2020 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.common.mapping.builtin;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Component;

/**
* Registry for built-in metadata mappings.
*/
@Component
public class BuiltinMetadataMappingsRegistry {

private final List<BuiltinMetadataMapping> mappings = new ArrayList<>();

public List<BuiltinMetadataMapping> getMappings() {
return mappings;
}

void registerBuiltinMapping(BaseBuiltinMetadataMapping mapping) {
mappings.add(mapping);
}
}

0 comments on commit 3160ce6

Please sign in to comment.