use of eu.esdihumboldt.hale.common.align.model.transformation.tree.SourceNode 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;
}
}
}
use of eu.esdihumboldt.hale.common.align.model.transformation.tree.SourceNode in project hale by halestudio.
the class TGraphFactory method create.
/**
* Create a transformation graph from a transformation tree.
*
* @param ttree the transformation tree
* @param functionService the function service
* @return an in-memory graph created from the transformation tree
*/
public static Graph create(TransformationTree ttree, FunctionService functionService) {
TreeToGraphVisitor graphVisitor = new TreeToGraphVisitor(functionService);
ttree.accept(graphVisitor);
SetMultimap<String, String> connections = graphVisitor.getAllConnections();
Set<String> ids = graphVisitor.getAllIds();
Graph graph = new TinkerGraph();
// add nodes to the graph
for (String key : ids) {
// create a vertex for each transformation node
TransformationNode node = graphVisitor.getNode(key);
Vertex vertex = graph.addVertex(key);
setVertexProperties(vertex, node);
}
for (String key : connections.keySet()) {
for (String value : connections.get(key)) {
Vertex targetSide = graph.getVertex(key);
Vertex sourceSide = graph.getVertex(value);
TransformationNode targetSideNode = graphVisitor.getNode(key);
TransformationNode sourceSideNode = graphVisitor.getNode(value);
String edgeLabel;
if (sourceSideNode instanceof SourceNode && targetSideNode instanceof SourceNode) {
edgeLabel = EDGE_CHILD;
} else if (sourceSideNode instanceof SourceNode && targetSideNode instanceof CellNode) {
edgeLabel = EDGE_VARIABLE;
} else if (sourceSideNode instanceof CellNode && targetSideNode instanceof GroupNode) {
edgeLabel = EDGE_RESULT;
} else if (sourceSideNode instanceof GroupNode && targetSideNode instanceof GroupNode) {
edgeLabel = EDGE_PARENT;
} else {
throw new IllegalStateException("Invalid relation in transformation tree");
}
Edge edge = graph.addEdge(null, sourceSide, targetSide, edgeLabel);
setEdgeProperties(edge, sourceSideNode, targetSideNode);
}
}
return graph;
}
use of eu.esdihumboldt.hale.common.align.model.transformation.tree.SourceNode in project hale by halestudio.
the class TransformationTreeLabelProvider method getText.
/**
* @see GraphLabelProvider#getText(Object)
*/
@Override
public String getText(Object element) {
if (element instanceof IdentityWrapper<?>) {
element = ((IdentityWrapper<?>) element).getValue();
}
if (element instanceof EntityConnectionData) {
// text for connections
EntityConnectionData connection = (EntityConnectionData) element;
Set<String> names = null;
Object source = connection.source;
if (source instanceof IdentityWrapper<?>) {
source = ((IdentityWrapper<?>) source).getValue();
}
Object dest = connection.dest;
if (dest instanceof IdentityWrapper<?>) {
dest = ((IdentityWrapper<?>) dest).getValue();
}
if (source instanceof TargetNode && dest instanceof CellNode) {
names = ((TargetNode) source).getAssignmentNames((CellNode) dest);
}
if (source instanceof CellNode && dest instanceof SourceNode) {
names = ((CellNode) source).getSourceNames((SourceNode) dest);
}
if (names != null && !names.isEmpty()) {
if (names.contains(null)) {
names = new HashSet<String>(names);
names.remove(null);
if (!names.isEmpty()) {
names.add("(unnamed)");
}
}
// build name string
Joiner joiner = Joiner.on(',');
return joiner.join(names);
}
return "";
}
if (hasTransformationAnnotations(element)) {
if (element instanceof SourceNode) {
SourceNode node = (SourceNode) element;
if (node.isDefined()) {
Object value = node.getValue();
if (value == null) {
// no value
return "(not set)";
} else if (value instanceof Instance) {
// use the instance value if present
value = ((Instance) value).getValue();
}
if (value != null && !(value instanceof Group)) {
// TODO shorten if needed?
return value.toString();
}
// otherwise, just display the definition name
}
}
}
element = TransformationTreeUtil.extractObject(element);
return super.getText(element);
}
use of eu.esdihumboldt.hale.common.align.model.transformation.tree.SourceNode in project hale by halestudio.
the class TreeGraphMLProvider method setVertexProperty.
/**
* sets the property of a [@link]Vertex from a [@link]TransformationNode
*
* @param node the node-object to get the name from
* @param vertex the vertex to set the property
*/
private void setVertexProperty(TransformationNode node, Vertex vertex) {
if (node instanceof TransformationTree) {
vertex.setProperty("name", ((TransformationTree) node).getType().getDisplayName());
vertex.setProperty("type", "root");
}
if (node instanceof TargetNode) {
vertex.setProperty("name", ((TargetNode) node).getDefinition().getDisplayName());
vertex.setProperty("type", "target");
}
if (node instanceof SourceNode) {
SourceNode snode = (SourceNode) node;
Object value = snode.getValue();
String name = ((SourceNode) node).getDefinition().getDisplayName();
if (value instanceof Group) {
vertex.setProperty("name", name);
vertex.setProperty("group", getChildrencountString(value));
vertex.setProperty("type", "source");
}
if (value instanceof Instance) {
if (((Instance) value).getValue() != null) {
vertex.setProperty("group", getChildrencountString(value));
vertex.setProperty("value", ((Instance) value).getValue().toString());
vertex.setProperty("type", "source");
}
} else {
vertex.setProperty("name", name);
vertex.setProperty("type", "source");
if (value instanceof String) {
vertex.setProperty("value", value);
}
}
}
if (node instanceof CellNode) {
vertex.setProperty("name", FunctionUtil.getFunction(((CellNode) node).getCell().getTransformationIdentifier(), null).getDisplayName());
vertex.setProperty("type", "cell");
}
}
use of eu.esdihumboldt.hale.common.align.model.transformation.tree.SourceNode in project hale by halestudio.
the class FunctionExecutor method executeTransformation.
/**
* Execute a property transformation.
*
* @param transformation the transformation factory
* @param cell the alignment cell
* @param sources the named source entities and nodes
* @param targets the named target entities and nodes
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void executeTransformation(PropertyTransformationFactory transformation, Cell cell, ListMultimap<String, Pair<SourceNode, Entity>> sources, ListMultimap<String, Pair<TargetNode, Entity>> targets) {
TransformationLog cellLog = new CellLog(reporter, cell);
PropertyTransformation<?> function;
try {
// TODO cache function objects?
function = transformation.createExtensionObject();
} catch (Exception e) {
cellLog.error(cellLog.createMessage("Error creating transformation function.", e));
return;
}
TransformationEngine engine = engines.get(transformation.getEngineId(), cellLog);
if (engine == null) {
// TODO instead try another transformation
cellLog.error(cellLog.createMessage("Skipping property transformation: No matching transformation engine found", null));
return;
}
// configure function
// set expected result
ListMultimap<String, PropertyEntityDefinition> expectedResult = ArrayListMultimap.create(targets.keySet().size(), 1);
for (Entry<String, Pair<TargetNode, Entity>> targetEntry : targets.entries()) {
EntityDefinition def = targetEntry.getValue().getSecond().getDefinition();
expectedResult.put(targetEntry.getKey(), toPropertyEntityDefinition(def));
}
function.setExpectedResult(expectedResult);
// set source variables
ListMultimap<String, PropertyValue> variables = ArrayListMultimap.create();
for (Entry<String, Pair<SourceNode, Entity>> sourceEntry : sources.entries()) {
EntityDefinition def = sourceEntry.getValue().getSecond().getDefinition();
SourceNode sourceNode = sourceEntry.getValue().getFirst();
if (TransformationTreeUtil.isEager(cell, sourceNode, cellLog, context.getServiceProvider())) {
// eager source - all values
Object[] values = sourceNode.getAllValues();
if (values != null) {
for (int i = 0; i < values.length; i++) {
PropertyValue propertyValue = new PropertyValueImpl(values[i], toPropertyEntityDefinition(def));
variables.put(sourceEntry.getKey(), propertyValue);
}
}
} else {
// non-eager source - one value
Object value = sourceNode.getValue();
PropertyValue propertyValue = new PropertyValueImpl(value, toPropertyEntityDefinition(def));
variables.put(sourceEntry.getKey(), propertyValue);
}
}
function.setVariables(variables);
// set parameters
function.setParameters(cell.getTransformationParameters());
// set context
function.setExecutionContext(context.getCellContext(cell));
// set target type
TypeDefinition targetType = null;
if (!targets.isEmpty()) {
TargetNode target = targets.values().iterator().next().getFirst();
targetType = target.getEntityDefinition().getType();
}
function.setTargetType(targetType);
function.setTypeCell(typeCell.get());
// execute function
try {
((PropertyTransformation) function).execute(transformation.getIdentifier(), engine, transformation.getExecutionParameters(), cellLog, cell);
} catch (Throwable e) {
// TODO instead try another transformation?
cellLog.error(cellLog.createMessage("Skipping property transformation: Executing property transformation failed.", e));
return;
}
// apply function results
ListMultimap<String, Object> results = function.getResults();
if (results != null) {
for (String name : results.keySet()) {
List<Object> values = results.get(name);
List<Pair<TargetNode, Entity>> nodes = targets.get(name);
if (nodes.size() > values.size()) {
cellLog.warn(cellLog.createMessage(MessageFormat.format("Transformation result misses values for result with name {0}", name), null));
}
if (values.size() > nodes.size()) {
cellLog.warn(cellLog.createMessage(MessageFormat.format("More transformation results than target nodes for result with name {0}", name), null));
}
int count = Math.min(values.size(), nodes.size());
// node...
for (int i = 0; i < count; i++) {
Object value = values.get(i);
TargetNode node = nodes.get(i).getFirst();
if (value instanceof MultiValue) {
MultiValue originalValue = (MultiValue) value;
MultiValue processedValue = new MultiValue(originalValue.size());
for (Object o : originalValue) {
processedValue.add(processValue(cellLog, function, o, node));
}
value = processedValue;
} else {
value = processValue(cellLog, function, value, node);
}
/*
* TODO
*
* set node value only if no result has already been set. If
* a value is already there and we are in a lower priority
* executor, we do not overwrite.
*/
if (!node.isDefined()) {
node.setResult(value);
}
}
}
}
}
Aggregations