/* * Copyright (c) 2012 Data Harmonisation Panel * * All rights reserved. This program and the accompanying materials are made * available under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * HUMBOLDT EU Integrated Project #030962 * Data Harmonisation Panel <http://www.dhpanel.eu> */ package eu.esdihumboldt.hale.ui.common.graph.content; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Queue; import java.util.Set; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.zest.core.viewers.IGraphEntityContentProvider; import eu.esdihumboldt.hale.common.align.model.Alignment; import eu.esdihumboldt.hale.common.align.model.Cell; import eu.esdihumboldt.hale.common.align.model.Entity; import eu.esdihumboldt.hale.common.align.model.impl.TypeEntityDefinition; import eu.esdihumboldt.hale.common.align.model.transformation.tree.CellNode; import eu.esdihumboldt.hale.common.align.model.transformation.tree.SourceNode; import eu.esdihumboldt.hale.common.align.model.transformation.tree.TargetNode; import eu.esdihumboldt.hale.common.align.model.transformation.tree.TransformationTree; import eu.esdihumboldt.hale.common.align.model.transformation.tree.context.ContextMatcher; import eu.esdihumboldt.hale.common.align.model.transformation.tree.context.impl.matcher.AsDeepAsPossible; import eu.esdihumboldt.hale.common.align.model.transformation.tree.impl.TransformationTreeImpl; import eu.esdihumboldt.hale.common.align.model.transformation.tree.visitor.DuplicationVisitor; import eu.esdihumboldt.hale.common.align.model.transformation.tree.visitor.InstanceVisitor; import eu.esdihumboldt.hale.common.align.transformation.function.impl.FamilyInstanceImpl; import eu.esdihumboldt.hale.common.align.transformation.report.TransformationLog; import eu.esdihumboldt.hale.common.align.transformation.report.TransformationMessage; import eu.esdihumboldt.hale.common.align.transformation.report.impl.CellLog; import eu.esdihumboldt.hale.common.align.transformation.report.impl.DefaultTransformationReporter; import eu.esdihumboldt.hale.common.core.report.ReportLog; import eu.esdihumboldt.hale.common.instance.model.Instance; import eu.esdihumboldt.util.IdentityWrapper; import eu.esdihumboldt.util.Pair; /** * Transformation graph based on {@link TransformationTree} derived from an * {@link Alignment} * * @author Simon Templer */ public class TransformationTreeContentProvider extends ArrayContentProvider implements IGraphEntityContentProvider { /** * @see ArrayContentProvider#getElements(Object) */ @SuppressWarnings("unchecked") @Override public Object[] getElements(Object inputElement) { if (inputElement instanceof TransformationTree) return collectNodes((TransformationTree) inputElement).toArray(); Collection<Instance> instances = null; if (inputElement instanceof Pair<?, ?>) { Pair<?, ?> pair = (Pair<?, ?>) inputElement; inputElement = pair.getFirst(); if (pair.getSecond() instanceof Collection<?>) { instances = (Collection<Instance>) pair.getSecond(); } } if (inputElement instanceof Alignment) { Alignment alignment = (Alignment) inputElement; // input contained specific instances if (instances != null && !instances.isEmpty()) { Collection<Object> result = new ArrayList<Object>(); // create transformation trees for each instance for (Instance instance : instances) { // find type cells matching the instance Collection<? extends Cell> typeCells = alignment.getActiveTypeCells(); Collection<Cell> associatedTypeCells = new LinkedList<Cell>(); for (Cell typeCell : typeCells) for (Entity entity : typeCell.getSource().values()) { TypeEntityDefinition type = (TypeEntityDefinition) entity .getDefinition(); if (type.getDefinition().equals(instance.getDefinition()) && (type.getFilter() == null || type.getFilter() .match(instance))) { associatedTypeCells.add(typeCell); break; } } // for each type cell one tree for (Cell cell : associatedTypeCells) { TransformationTree tree = createInstanceTree(instance, cell, alignment); if (tree != null) result.addAll(collectNodes(tree)); } } return result.toArray(); } // input was alignment only, show trees for all type cells Collection<? extends Cell> typeCells = alignment.getActiveTypeCells(); Collection<Object> result = new ArrayList<Object>(typeCells.size()); for (Cell typeCell : typeCells) { // create tree and add nodes for each cell result.addAll(collectNodes(new TransformationTreeImpl(alignment, typeCell))); } return result.toArray(); } return super.getElements(inputElement); } /** * Create a transformation tree based on a source instance. * * @param instance the source instance * @param typeCell the type cell * @param alignment the alignment * @return the transformation tree or <code>null</code> */ private TransformationTree createInstanceTree(Instance instance, Cell typeCell, Alignment alignment) { TransformationTree tree = new TransformationTreeImpl(alignment, typeCell); ReportLog<TransformationMessage> reporter = new DefaultTransformationReporter( "Transformation tree", true); TransformationLog log = new CellLog(reporter, typeCell); // context matching // XXX instead through service/extension point? ContextMatcher matcher = new AsDeepAsPossible(null); matcher.findMatches(tree); // process and annotate the tree InstanceVisitor visitor = new InstanceVisitor(new FamilyInstanceImpl(instance), tree, log); tree.accept(visitor); // duplicate subtree as necessary DuplicationVisitor duplicationVisitor = new DuplicationVisitor(tree, log); tree.accept(duplicationVisitor); duplicationVisitor.doAugmentationTrackback(); return tree; } /** * Collect all nodes related to from a type node * * @param typeNode the type node * @return the nodes */ private Collection<? extends Object> collectNodes(TransformationTree typeNode) { Queue<IdentityWrapper<?>> toTest = new LinkedList<IdentityWrapper<?>>(); Set<IdentityWrapper<?>> nodes = new LinkedHashSet<IdentityWrapper<?>>(); IdentityWrapper<?> wrapper = new IdentityWrapper<Object>(typeNode); toTest.offer(wrapper); while (!toTest.isEmpty()) { IdentityWrapper<?> node = toTest.poll(); // add node nodes.add(node); // test children Iterable<? extends Object> children = getChilddren(node.getValue()); for (Object child : children) { if (!(child instanceof IdentityWrapper<?>)) { child = new IdentityWrapper<Object>(child); } if (!nodes.contains(child)) { toTest.offer((IdentityWrapper<?>) child); } } } return nodes; } /** * Get the children of a node * * @param node the node * @return the node's children */ private Collection<? extends Object> getChilddren(Object node) { if (node instanceof IdentityWrapper<?>) { node = ((IdentityWrapper<?>) node).getValue(); } if (node instanceof TransformationTree) { return wrapNodes(((TransformationTree) node).getChildren(true)); } if (node instanceof TargetNode) { List<Object> children = new ArrayList<Object>(); children.addAll(((TargetNode) node).getChildren(true)); children.addAll(((TargetNode) node).getAssignments()); return wrapNodes(children); } if (node instanceof CellNode) { return wrapNodes(((CellNode) node).getSources()); } if (node instanceof SourceNode) { SourceNode parent = ((SourceNode) node).getParent(); if (parent != null) { return Collections.singleton(new IdentityWrapper<Object>(parent)); } } return Collections.emptyList(); } private Collection<? extends Object> wrapNodes(Collection<? extends Object> nodes) { Collection<IdentityWrapper<?>> wrappers = new ArrayList<IdentityWrapper<?>>(nodes.size()); for (Object node : nodes) { wrappers.add(new IdentityWrapper<Object>(node)); } return wrappers; } /** * @see IGraphEntityContentProvider#getConnectedTo(Object) */ @Override public Object[] getConnectedTo(Object entity) { return getChilddren(entity).toArray(); } }