use of eu.esdihumboldt.hale.common.align.model.transformation.tree.impl.SourceNodeImpl in project hale by halestudio.
the class TargetContext method duplicateTree.
/**
* Duplicates the transformation tree for the given source node to the given
* duplicate source node.
*
* @param source the original source node
* @param duplicate the duplication target
* @param info the duplication info object
* @param log the transformation log
* @param serviceProvider service provider for resolving functions
*/
private static void duplicateTree(SourceNode source, SourceNode duplicate, DuplicationInformation info, TransformationLog log, ServiceProvider serviceProvider) {
// Duplicate relations.
for (CellNode cell : source.getRelations(false)) {
// check whether the cell is eager for the source node
if (TransformationTreeUtil.isEager(cell, source, log, serviceProvider))
continue;
// Check whether the cell is ignored.
if (info.isIgnoreCell(cell.getCell()))
continue;
// XXX prioritize already created cell nodes (in this run) over old
// nodes?
// First check whether an old cell node with a missing source
// exists.
// If so, add this source to the first so found cell.
boolean usedOld = false;
for (IdentityWrapper<CellNode> wrapper : info.getOldCellNodes(cell.getCell())) {
CellNode oldCellNode = wrapper.getValue();
// Skip the cell if it's full.
if (oldCellNode.getSources().size() == cell.getSources().size())
continue;
// Check whether out duplicate source node is missing...
if (!oldCellNode.getSources().contains(duplicate)) {
usedOld = true;
// Has to be a cell created with the cell constructor.
((CellNodeImpl) oldCellNode).addSource(cell.getSourceNames(source), duplicate);
duplicate.addRelation(oldCellNode);
break;
}
}
// If no old cell was used, use a newly created one / create one.
if (!usedOld) {
CellNodeImpl duplicatedCell = info.getNewCellNode(cell.getCell());
if (duplicatedCell == null) {
// Create a new cell, augment it with existing sources, add
// it to info and duplicate targets.
duplicatedCell = new CellNodeImpl(cell.getCell());
augmentCell(cell, duplicatedCell, info);
info.addNewCellNode(cell.getCell(), duplicatedCell);
duplicateTree(cell, duplicatedCell, info, log);
}
// Add as relation/source.
duplicate.addRelation(duplicatedCell);
duplicatedCell.addSource(cell.getSourceNames(source), duplicate);
}
}
// Duplicate children.
for (SourceNode child : source.getChildren(false)) {
SourceNode duplicatedChild = new SourceNodeImpl(child.getEntityDefinition(), duplicate, true);
duplicatedChild.setContext(child.getContext());
duplicateTree(child, duplicatedChild, info, log, serviceProvider);
}
}
use of eu.esdihumboldt.hale.common.align.model.transformation.tree.impl.SourceNodeImpl in project hale by halestudio.
the class TargetContext method duplicateSource.
// /**
// * Checks whether the given source node is part of the context for the duplication.
// *
// * @param source the source node to check
// * @param info the context information
// * @return true, if the given node is in the context for the duplication, false otherwise
// */
// private boolean isInContext(SourceNode source, DuplicationInformation info) {
// Collection<SourceNode> contextNodes = info.getOldSourceNodes(source.getEntityDefinition());
// for (SourceNode node : contextNodes)
// if (node == source)
// return true;
// return false;
// }
// OLD STUFF!
// /**
// * Track back target nodes and duplicate any augmentation cells.
// * @param originalTarget the original target node
// * @param duplicationContext the duplication context
// */
// private void augmentationTrackback(TargetNode originalTarget,
// DuplicationContext duplicationContext) {
// // track back child augmentations
// for (TargetNode child : originalTarget.getChildren(false)) { //XXX should annotated children be included?
// augmentationTrackback(child, duplicationContext);
// }
//
// // track back augmentations
// for (CellNode originalAssignment : originalTarget.getAssignments()) {
// /*
// * Duplicated target does not contain an assignment representing
// * the same cell as originalAssignment.
// */
// if (originalAssignment.getSources().isEmpty()) {
// // the cell is an augmentation, thus we duplicate it
// duplicateCell(originalAssignment, null, duplicationContext);
// /*
// * it is automatically added to the target nodes (which are
// * retrieved from the duplication context or created as
// * necessary)
// */
// }
// }
// }
//
// /**
// * Track the graph back to sources that are missing in a cell node compared
// * to the original cell node.
// * @param cellNode the cell node
// * @param originalCell the original cell node the node was duplicated from
// */
// private void cellTrackback(CellNodeImpl cellNode, CellNode originalCell) {
// for (SourceNode originalSource : originalCell.getSources()) {
// if (!cellNode.getSources().contains(originalSource)) {
// /*
// * Duplicated cell does not contain a source representing the
// * same entity as originalSource.
// */
// SourceNode newSource = null;
//
// // now there are several possible cases
// // a) the original source has leftovers and we grab one
// Leftovers leftovers = originalSource.getLeftovers();
// if (leftovers != null) {
// newSource = leftovers.consumeValue(originalCell.getCell());
//
// if (newSource != null) {
// // interconnect both
// newSource.addRelation(cellNode);
// cellNode.addSource(originalCell.getSourceNames(originalSource),
// newSource);
// //XXX hard connections are OK here, as a leftover source is a duplicate
// }
// else {
// //TODO add an undefined source node in this case?
// }
// }
//
// // b) the original source has a parent (ot it has a parent etc.)
// // that has leftovers
// if (newSource == null) {
// //TODO
// }
//
// // c) we use the original source node
// if (newSource == null) {
// newSource = originalSource;
//
// // interconnect both
// newSource.addAnnotatedRelation(cellNode); //FIXME should be an augmentated relation!!!!
// cellNode.addSource(originalCell.getSourceNames(originalSource),
// newSource);
// }
// }
// }
// }
/**
* Duplicate a source node.
*
* @param source the source node to duplicate
* @param parent the parent of the new source node
* @param addToParent if the new source node should be added as child to the
* parent
* @param duplicationContext the duplication context
* @return the new duplicated source node or <code>null</code> if
* duplication was prohibited
*/
private SourceNode duplicateSource(SourceNode source, SourceNode parent, boolean addToParent, DuplicationContext duplicationContext) {
// create duplicate
SourceNode duplicate = new SourceNodeImpl(source.getEntityDefinition(), parent, addToParent);
duplicate.setContext(source.getContext());
return configureSourceDuplicate(source, duplicate, parent, duplicationContext, addToParent);
}
use of eu.esdihumboldt.hale.common.align.model.transformation.tree.impl.SourceNodeImpl 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;
}
}
}
Aggregations