Search in sources :

Example 41 with EntityDefinition

use of eu.esdihumboldt.hale.common.align.model.EntityDefinition in project hale by halestudio.

the class InstanceVisitor method visit.

/**
 * @see AbstractSourceToTargetVisitor#visit(SourceNode)
 */
@Override
public boolean visit(SourceNode source) {
    if (source.getDefinition() instanceof TypeDefinition) {
        if (instance == null)
            return false;
        // source root
        if (source.getDefinition().equals(instance.getDefinition())) {
            // check type filter (if any)
            Filter filter = source.getEntityDefinition().getFilter();
            if (filter != null && !filter.match(instance)) {
                // instance does not match filter, don't descend further
                return false;
            /*
					 * XXX What about merged instances? Will this be OK for
					 * those? A type filter should only apply to the original
					 * instance if it is merged - but most filters should
					 * evaluate the same
					 */
            } else {
                // also sets the node to defined
                source.setValue(instance);
                for (FamilyInstance child : instance.getChildren()) {
                    // Find fitting SourceNodes.
                    Collection<SourceNode> candidateNodes = tree.getRootSourceNodes(child.getDefinition());
                    if (candidateNodes.isEmpty()) {
                        /*
							 * No node found - but this may be because no
							 * property of the type is mapped, but there still
							 * might be child instances (in a Join) that have
							 * types with associated relations. To prevent those
							 * being skipped we add an artificial node
							 * representing the instance.
							 */
                        candidateNodes = new ArrayList<>();
                        EntityDefinition entityDef = new TypeEntityDefinition(child.getDefinition(), SchemaSpaceID.SOURCE, null);
                        candidateNodes.add(new SourceNodeImpl(entityDef, null, false));
                    }
                    for (SourceNode candidateNode : candidateNodes) {
                        filter = candidateNode.getEntityDefinition().getFilter();
                        if (filter == null || filter.match(child)) {
                            // XXX add to all candidates!?
                            if (candidateNode.getValue() == null) {
                                candidateNode.setAnnotatedParent(source);
                                source.addAnnotatedChild(candidateNode);
                            } else {
                                // Duplicate here, because there is no
                                // guarantee, that the Duplication
                                // Visitor will visit candidateNode after
                                // this node.
                                SourceNodeImpl duplicateNode = new SourceNodeImpl(candidateNode.getEntityDefinition(), candidateNode.getParent(), false);
                                duplicateNode.setAnnotatedParent(source);
                                source.addAnnotatedChild(duplicateNode);
                                TransformationContext context = candidateNode.getContext();
                                duplicateNode.setContext(context);
                                if (context != null) {
                                    context.duplicateContext(candidateNode, duplicateNode, Collections.<Cell>emptySet(), log);
                                } else {
                                    /*
										 * Not sure what this really means if we
										 * get here.
										 * 
										 * Best guess: Probably that we weren't
										 * able to determine how the duplication
										 * of this source can be propagted to
										 * the target. Thus the duplicated node
										 * will probably not have any
										 * connection.
										 */
                                    log.warn(log.createMessage("No transformation context for duplicated node of source " + candidateNode.getDefinition().getDisplayName(), null));
                                }
                                candidateNode = duplicateNode;
                            }
                            // run instance visitor on that annotated child
                            InstanceVisitor visitor = new InstanceVisitor(child, tree, log);
                            candidateNode.accept(visitor);
                        }
                    }
                }
                return true;
            }
        } else
            return false;
    } else {
        Object parentValue = source.getParent().getValue();
        if (parentValue == null || !(parentValue instanceof Group)) {
            source.setDefined(false);
            return false;
        } else {
            Group parentGroup = (Group) parentValue;
            Definition<?> currentDef = source.getDefinition();
            Object[] values = parentGroup.getProperty(currentDef.getName());
            if (values == null) {
                source.setDefined(false);
                return false;
            }
            // check for contexts
            EntityDefinition entityDef = source.getEntityDefinition();
            // index context
            Integer index = AlignmentUtil.getContextIndex(entityDef);
            if (index != null) {
                // only use the value at the given index, if present
                if (index < values.length) {
                    // annotate with the value at the index
                    Object value = values[index];
                    source.setValue(value);
                    return true;
                } else {
                    source.setDefined(false);
                    return false;
                }
            }
            // condition context
            Condition condition = AlignmentUtil.getContextCondition(entityDef);
            if (condition != null) {
                if (condition.getFilter() == null) {
                    // assume exclusion
                    source.setDefined(false);
                    return false;
                }
                // apply condition as filter on values and continue with
                // those values
                Collection<Object> matchedValues = new ArrayList<Object>();
                for (Object value : values) {
                    // determine parent
                    Object parent = null;
                    SourceNode parentNode = source.getParent();
                    if (parentNode != null && parentNode.isDefined()) {
                        parent = parentNode.getValue();
                    }
                    // test the condition
                    if (AlignmentUtil.matchCondition(condition, value, parent)) {
                        matchedValues.add(value);
                    }
                }
                values = matchedValues.toArray();
            }
            // default behavior (default context)
            if (values.length >= 1) {
                // annotate with the first value
                Object value = values[0];
                source.setValue(value);
                source.setAllValues(values);
            } else {
                source.setDefined(false);
                return false;
            }
            if (values.length > 1) {
                // handle additional values
                Object[] leftovers = new Object[values.length - 1];
                System.arraycopy(values, 1, leftovers, 0, leftovers.length);
                source.setLeftovers(new LeftoversImpl(source, leftovers));
            }
            return true;
        }
    }
}
Also used : Condition(eu.esdihumboldt.hale.common.align.model.Condition) Group(eu.esdihumboldt.hale.common.instance.model.Group) ArrayList(java.util.ArrayList) TransformationContext(eu.esdihumboldt.hale.common.align.model.transformation.tree.context.TransformationContext) TypeDefinition(eu.esdihumboldt.hale.common.schema.model.TypeDefinition) SourceNodeImpl(eu.esdihumboldt.hale.common.align.model.transformation.tree.impl.SourceNodeImpl) TypeEntityDefinition(eu.esdihumboldt.hale.common.align.model.impl.TypeEntityDefinition) EntityDefinition(eu.esdihumboldt.hale.common.align.model.EntityDefinition) SourceNode(eu.esdihumboldt.hale.common.align.model.transformation.tree.SourceNode) TypeEntityDefinition(eu.esdihumboldt.hale.common.align.model.impl.TypeEntityDefinition) Filter(eu.esdihumboldt.hale.common.instance.model.Filter) LeftoversImpl(eu.esdihumboldt.hale.common.align.model.transformation.tree.impl.LeftoversImpl) FamilyInstance(eu.esdihumboldt.hale.common.instance.model.FamilyInstance)

Example 42 with EntityDefinition

use of eu.esdihumboldt.hale.common.align.model.EntityDefinition in project hale by halestudio.

the class EntityAccessorUtil method createEntity.

/**
 * Create an entity definition from a path.
 *
 * @param path the path, the topmost element has to represent an
 *            {@link EntityDefinition}, all other elements must represent
 *            {@link ChildContext}s
 * @return the created entity definition or <code>null</code> if the path
 *         was <code>null</code>
 */
public static EntityDefinition createEntity(Path<PathElement> path) {
    if (path == null) {
        return null;
    }
    List<PathElement> elements = new ArrayList<>(path.getElements());
    // create entity definition
    PathElement top = elements.remove(0);
    if (top.getRoot() == null) {
        throw new IllegalArgumentException("Topmost path element must be an entity definition");
    }
    EntityDefinition entity = top.getRoot();
    // collect type information
    TypeDefinition type = entity.getType();
    SchemaSpaceID schemaSpace = entity.getSchemaSpace();
    Filter filter = entity.getFilter();
    List<ChildContext> contextPath = new ArrayList<>(entity.getPropertyPath());
    for (PathElement element : elements) {
        ChildContext cc = element.getChild();
        if (cc == null) {
            throw new IllegalArgumentException("All child elements must be defined by a child context");
        }
        contextPath.add(cc);
    }
    return AlignmentUtil.createEntity(type, contextPath, schemaSpace, filter);
}
Also used : EntityDefinition(eu.esdihumboldt.hale.common.align.model.EntityDefinition) PathElement(eu.esdihumboldt.hale.common.align.groovy.accessor.PathElement) Filter(eu.esdihumboldt.hale.common.instance.model.Filter) ArrayList(java.util.ArrayList) ChildContext(eu.esdihumboldt.hale.common.align.model.ChildContext) SchemaSpaceID(eu.esdihumboldt.hale.common.schema.SchemaSpaceID) TypeDefinition(eu.esdihumboldt.hale.common.schema.model.TypeDefinition)

Example 43 with EntityDefinition

use of eu.esdihumboldt.hale.common.align.model.EntityDefinition in project hale by halestudio.

the class AbstractMergeCellMigratorTest method assertCellTargetEquals.

// test helpers
/**
 * Check if the given cell's target matches the expected target.
 *
 * @param cell the cell to check
 * @param targetDef the expected target entity (simple definition as name
 *            list)
 */
protected void assertCellTargetEquals(Cell cell, List<String> targetDef) {
    Entity entity = CellUtil.getFirstEntity(cell.getTarget());
    assertNotNull("Target entity", entity);
    EntityDefinition def = entity.getDefinition();
    assertDefEquals(targetDef, def);
}
Also used : Entity(eu.esdihumboldt.hale.common.align.model.Entity) EntityDefinition(eu.esdihumboldt.hale.common.align.model.EntityDefinition)

Example 44 with EntityDefinition

use of eu.esdihumboldt.hale.common.align.model.EntityDefinition in project hale by halestudio.

the class JoinMergeMigrator method addSources.

private void addSources(MutableCell cell, EntityDefinition source, Cell match, SimpleLog log, boolean transferContext) {
    if (match.getSource() != null) {
        ListMultimap<String, Entity> sources = ArrayListMultimap.create(cell.getSource());
        for (Entry<String, ? extends Entity> entry : match.getSource().entries()) {
            Entity entity = entry.getValue();
            if (transferContext) {
                // transfer filter and contexts if possible
                EntityDefinition withContexts = AbstractMigration.translateContexts(source, entity.getDefinition(), log);
                entity = AlignmentUtil.createEntity(withContexts);
            }
            if (!sources.containsEntry(entry.getKey(), entity)) {
                // add if not already present
                sources.put(entry.getKey(), entity);
            }
        }
        cell.setSource(sources);
    } else {
        log.error("Match for source {0} is invalid and does not have a source", source.getDefinition());
        return;
    }
}
Also used : Entity(eu.esdihumboldt.hale.common.align.model.Entity) TypeEntityDefinition(eu.esdihumboldt.hale.common.align.model.impl.TypeEntityDefinition) EntityDefinition(eu.esdihumboldt.hale.common.align.model.EntityDefinition)

Example 45 with EntityDefinition

use of eu.esdihumboldt.hale.common.align.model.EntityDefinition in project hale by halestudio.

the class AbstractMergeCellMigrator method mergeSources.

/**
 * Update the cell sources.
 *
 * @param sources the old sources
 * @param mergeIndex the merge index
 * @param originalCell the original cell
 * @param migration the alignment migration (may be useful for cases where
 *            only entity replacement needs to be done)
 * @param getCellMigrator functions that yields a cell migrator for a
 *            function (may be useful for cases where only entity
 *            replacement needs to be done)
 * @param log the migration process log
 * @return the merged cell or cells
 */
protected Iterable<MutableCell> mergeSources(ListMultimap<String, ? extends Entity> sources, MergeIndex mergeIndex, Cell originalCell, AlignmentMigration migration, Function<String, CellMigrator> getCellMigrator, SimpleLog log) {
    // XXX relevant here at all?
    boolean transferBase = true;
    if (sources.size() == 1) {
        EntityDefinition source = sources.values().iterator().next().getDefinition();
        List<Cell> matches = mergeIndex.getCellsForTarget(source);
        List<String> storedMessages = new ArrayList<>();
        boolean inaccurateMatch = false;
        if (matches.isEmpty()) {
            // try to find match via parent (in specific cases)
            matches = findParentMatch(source, mergeIndex);
            if (!matches.isEmpty()) {
                inaccurateMatch = true;
            // message may not be added in every case, because it may be
            // a duplicate
            // storedMessages.add(MessageFormat
            // .format("Inaccurate match of {0} via parent entity", source));
            }
        }
        if (!matches.isEmpty()) {
            List<MutableCell> cells = new ArrayList<>();
            for (Cell match : matches) {
                // the original cell
                if (isDirectMatch(match)) {
                    MigrationOptions replaceSource = new MigrationOptionsImpl(true, false, transferBase);
                    cells.add(getCellMigrator.apply(originalCell.getTransformationIdentifier()).updateCell(originalCell, migration, replaceSource, log));
                } else // matching cell
                if (isDirectMatch(originalCell)) {
                    MigrationOptions replaceTarget = new MigrationOptionsImpl(false, true, transferBase);
                    AlignmentMigration cellMigration = new AbstractMigration() {

                        @Override
                        protected Optional<EntityDefinition> findMatch(EntityDefinition entity) {
                            Entity target = CellUtil.getFirstEntity(originalCell.getTarget());
                            if (target != null) {
                                return Optional.ofNullable(target.getDefinition());
                            }
                            return Optional.empty();
                        }
                    };
                    MutableCell newCell = getCellMigrator.apply(match.getTransformationIdentifier()).updateCell(match, cellMigration, replaceTarget, log);
                    SimpleLog cellLog = SimpleLog.all(log, new CellLog(newCell, CELL_LOG_CATEGORY));
                    // source of original cell may have
                    // filters/conditions/contexts that are not applied by
                    // changing the target
                    // try to apply source contexts
                    Entity originalSource = CellUtil.getFirstEntity(originalCell.getSource());
                    applySourceContexts(newCell, originalSource, cellLog);
                    cells.add(newCell);
                } else {
                    // otherwise, use custom logic to try to combine cells
                    MutableCell newCell = new DefaultCell(originalCell);
                    SimpleLog cellLog = SimpleLog.all(log, new CellLog(newCell, CELL_LOG_CATEGORY));
                    C context = newContext(originalCell);
                    // reset source
                    newCell.setSource(ArrayListMultimap.create());
                    if (inaccurateMatch) {
                        cellLog.warn(MessageFormat.format("Inaccurate match of {0} via parent entity", source));
                    }
                    mergeSource(newCell, sources.keys().iterator().next(), source, match, originalCell, cellLog, context, migration, mergeIndex);
                    finalize(newCell, migration, context, cellLog);
                    cells.add(newCell);
                }
            }
            if (!cells.isEmpty() && !storedMessages.isEmpty()) {
                // add stored messages
                cells.forEach(cell -> {
                    CellLog cLog = new CellLog(cell, CELL_LOG_CATEGORY);
                    storedMessages.forEach(msg -> cLog.warn(msg));
                });
            }
            return cells;
        } else {
            // no match -> remove?
            // rather add original + documentation
            MutableCell newCell = new DefaultCell(originalCell);
            SimpleLog cellLog = SimpleLog.all(log, new CellLog(newCell, CELL_LOG_CATEGORY));
            cellLog.warn("No match for source {0} found, unable to associate to new source schema", source);
            return Collections.singleton(newCell);
        }
    } else {
        // handle each source
        // collects messages in case all matches are direct matches
        List<String> directMessages = new ArrayList<>();
        // determine if all matches are direct
        boolean allDirect = sources.entries().stream().allMatch(source -> {
            List<Cell> matches = mergeIndex.getCellsForTarget(source.getValue().getDefinition());
            if (matches.isEmpty()) {
                directMessages.add(MessageFormat.format("No match was found for source {0}, please check how this can be compensated.", source.getValue().getDefinition()));
                // if there is no match, treat it as direct match
                return true;
            } else {
                if (matches.size() > 1) {
                    directMessages.add(MessageFormat.format("Multiple matches for source {0}, only one was taken into account", source.getValue().getDefinition()));
                }
                return isDirectMatch(matches.get(0));
            }
        });
        MutableCell newCell;
        if (allDirect) {
            // if the matching are all Retype/Rename, replace sources of
            // the original cell
            MigrationOptions replaceSource = new MigrationOptionsImpl(true, false, transferBase);
            newCell = getCellMigrator.apply(originalCell.getTransformationIdentifier()).updateCell(originalCell, migration, replaceSource, log);
            // add messages from match check
            SimpleLog cellLog = SimpleLog.all(log, new CellLog(newCell, CELL_LOG_CATEGORY));
            directMessages.forEach(msg -> cellLog.warn(msg));
        } else {
            // handle each source separately
            newCell = new DefaultCell(originalCell);
            SimpleLog cellLog = SimpleLog.all(log, new CellLog(newCell, CELL_LOG_CATEGORY));
            C context = newContext(originalCell);
            // reset source
            newCell.setSource(ArrayListMultimap.create());
            for (Entry<String, ? extends Entity> source : sources.entries()) {
                List<Cell> matches = mergeIndex.getCellsForTarget(source.getValue().getDefinition());
                if (!matches.isEmpty()) {
                    Cell match = matches.get(0);
                    mergeSource(newCell, source.getKey(), source.getValue().getDefinition(), match, originalCell, cellLog, context, migration, mergeIndex);
                    if (matches.size() > 1) {
                        // FIXME how can we deal w/ multiple matches?
                        cellLog.warn("Multiple matches for source {0}, only one was handled", source.getValue().getDefinition());
                    }
                } else {
                    // no match, just not add source?
                    cellLog.warn("No match was found for source {0}, please check how this can be compensated.", source.getValue().getDefinition());
                }
            }
            finalize(newCell, migration, context, cellLog);
        }
        return Collections.singleton(newCell);
    }
}
Also used : SimpleLog(eu.esdihumboldt.hale.common.core.report.SimpleLog) Entity(eu.esdihumboldt.hale.common.align.model.Entity) MutableCell(eu.esdihumboldt.hale.common.align.model.MutableCell) Optional(java.util.Optional) ArrayList(java.util.ArrayList) EntityDefinition(eu.esdihumboldt.hale.common.align.model.EntityDefinition) DefaultCell(eu.esdihumboldt.hale.common.align.model.impl.DefaultCell) MigrationOptionsImpl(eu.esdihumboldt.hale.common.align.migrate.impl.MigrationOptionsImpl) AlignmentMigration(eu.esdihumboldt.hale.common.align.migrate.AlignmentMigration) Cell(eu.esdihumboldt.hale.common.align.model.Cell) DefaultCell(eu.esdihumboldt.hale.common.align.model.impl.DefaultCell) MutableCell(eu.esdihumboldt.hale.common.align.model.MutableCell) CellLog(eu.esdihumboldt.hale.common.align.model.annotations.messages.CellLog) MigrationOptions(eu.esdihumboldt.hale.common.align.migrate.MigrationOptions)

Aggregations

EntityDefinition (eu.esdihumboldt.hale.common.align.model.EntityDefinition)99 TypeEntityDefinition (eu.esdihumboldt.hale.common.align.model.impl.TypeEntityDefinition)39 PropertyEntityDefinition (eu.esdihumboldt.hale.common.align.model.impl.PropertyEntityDefinition)37 ChildContext (eu.esdihumboldt.hale.common.align.model.ChildContext)23 ArrayList (java.util.ArrayList)22 Entity (eu.esdihumboldt.hale.common.align.model.Entity)21 TypeDefinition (eu.esdihumboldt.hale.common.schema.model.TypeDefinition)20 Cell (eu.esdihumboldt.hale.common.align.model.Cell)18 IStructuredSelection (org.eclipse.jface.viewers.IStructuredSelection)13 PropertyDefinition (eu.esdihumboldt.hale.common.schema.model.PropertyDefinition)11 MutableCell (eu.esdihumboldt.hale.common.align.model.MutableCell)10 HashSet (java.util.HashSet)10 QName (javax.xml.namespace.QName)10 HashMap (java.util.HashMap)9 Condition (eu.esdihumboldt.hale.common.align.model.Condition)8 SimpleLog (eu.esdihumboldt.hale.common.core.report.SimpleLog)7 ISelection (org.eclipse.jface.viewers.ISelection)7 List (java.util.List)6 TreePath (org.eclipse.jface.viewers.TreePath)6 AlignmentMigration (eu.esdihumboldt.hale.common.align.migrate.AlignmentMigration)5