/* * 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.common.align.model.transformation.tree.impl; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map.Entry; import net.jcip.annotations.Immutable; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import eu.esdihumboldt.hale.common.align.model.Alignment; import eu.esdihumboldt.hale.common.align.model.AlignmentUtil; import eu.esdihumboldt.hale.common.align.model.Cell; import eu.esdihumboldt.hale.common.align.model.CellUtil; import eu.esdihumboldt.hale.common.align.model.ChildContext; import eu.esdihumboldt.hale.common.align.model.Entity; import eu.esdihumboldt.hale.common.align.model.EntityDefinition; import eu.esdihumboldt.hale.common.align.model.Type; 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.TransformationNode; import eu.esdihumboldt.hale.common.align.model.transformation.tree.TransformationNodeVisitor; import eu.esdihumboldt.hale.common.align.model.transformation.tree.TransformationTree; import eu.esdihumboldt.hale.common.schema.model.TypeDefinition; /** * Default {@link TransformationTree} implementation * * @author Simon Templer */ @Immutable public class TransformationTreeImpl extends AbstractGroupNode implements TransformationTree { // private static final ALogger log = ALoggerFactory.getLogger(TransformationTreeImpl.class); private final Cell typeCell; private final TypeDefinition type; private final SourceNodeFactory sourceNodes; private final List<TargetNode> children; /** * Create a transformation tree based on a type cell. * * @param alignment the alignment holding the cells * @param typeCell the type cell this tree is representing */ public TransformationTreeImpl(Alignment alignment, Cell typeCell) { super(null); this.typeCell = typeCell; this.type = ((Type) CellUtil.getFirstEntity(typeCell.getTarget())).getDefinition() .getDefinition(); sourceNodes = new SourceNodeFactory(); Collection<? extends Cell> cells = getRelevantPropertyCells(alignment, typeCell); // partition cells by child ListMultimap<EntityDefinition, CellNode> childCells = ArrayListMultimap.create(); for (Cell cell : cells) { cell = AlignmentUtil.reparentCell(cell, typeCell, true); if (cell == null) throw new IllegalStateException("Illegal cell found."); CellNode node = new CellNodeImpl(cell, sourceNodes); for (Entity target : cell.getTarget().values()) { EntityDefinition targetDef = target.getDefinition(); List<ChildContext> path = targetDef.getPropertyPath(); if (path != null && !path.isEmpty()) { // store cell with child childCells.put(AlignmentUtil.deriveEntity(targetDef, 1), node); } } } // create child cells List<TargetNode> childList = new ArrayList<TargetNode>(); for (Entry<EntityDefinition, Collection<CellNode>> childEntry : childCells.asMap() .entrySet()) { TargetNode childNode = new TargetNodeImpl(childEntry.getKey(), childEntry.getValue(), type, 1, this); childList.add(childNode); } children = Collections.unmodifiableList(childList); } /** * Get the property cells relevant for the transformation tree from the * given alignment. The default implementation returns all property cells * related to the type cell. * * @param alignment the alignment * @param typeCell the type cell type * @return the property cells */ protected Collection<? extends Cell> getRelevantPropertyCells(Alignment alignment, Cell typeCell) { return alignment.getPropertyCells(typeCell); } /** * @see TransformationNode#accept(TransformationNodeVisitor) */ @Override public void accept(TransformationNodeVisitor visitor) { if (visitor.visit(this)) { if (visitor.isFromTargetToSource()) { // visit children for (TargetNode child : getChildren(visitor.includeAnnotatedNodes())) { child.accept(visitor); } } else { // visit leafs for (SourceNode node : sourceNodes.getNodes()) { if (node.getParent() == null) { node.accept(visitor); } } } } visitor.leave(this); } /** * @see TransformationTree#getSourceNode(TypeEntityDefinition) */ @Override public SourceNode getSourceNode(TypeEntityDefinition type) { return sourceNodes.getSourceNode(type); } /** * @see AbstractGroupNode#getFixedChildren() */ @Override public List<TargetNode> getFixedChildren() { return children; } /** * @see TransformationTree#getType() */ @Override public TypeDefinition getType() { return type; } /** * @see TransformationTree#getRootSourceNodes(TypeDefinition) */ @Override public Collection<SourceNode> getRootSourceNodes(TypeDefinition type) { List<SourceNode> rootNodes = new ArrayList<SourceNode>(); for (SourceNode node : sourceNodes.getNodes()) if (node.getParent() == null && node.getDefinition().equals(type)) rootNodes.add(node); return rootNodes; } /** * @see TransformationTree#getRootSourceNodes() */ @Override public Collection<SourceNode> getRootSourceNodes() { List<SourceNode> rootNodes = new ArrayList<SourceNode>(); for (SourceNode node : sourceNodes.getNodes()) if (node.getParent() == null) rootNodes.add(node); return rootNodes; } /** * @see eu.esdihumboldt.hale.common.align.model.transformation.tree.TransformationTree#getTypeCell() */ @Override public Cell getTypeCell() { return typeCell; } }