/*
* 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.context.impl.matcher;
import java.util.Stack;
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.TransformationNodeVisitor;
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.TransformationContext;
import eu.esdihumboldt.hale.common.align.model.transformation.tree.context.impl.TargetContext;
import eu.esdihumboldt.hale.common.align.model.transformation.tree.visitor.AbstractTargetToSourceVisitor;
import eu.esdihumboldt.hale.common.core.service.ServiceProvider;
import eu.esdihumboldt.hale.common.schema.model.ChildDefinition;
import eu.esdihumboldt.hale.common.schema.model.DefinitionUtil;
import eu.esdihumboldt.hale.common.schema.model.constraint.property.Cardinality;
/**
* Simple context matching strategy that looks for connected
*
* @author Simon Templer
*/
public class AsDeepAsPossible implements ContextMatcher {
/**
* Builds a stack of target node candidates that while traversing the
* transformation tree, assigning the last candidate to source nodes as a
* transformation context.
*/
private class ContextVisitor extends AbstractTargetToSourceVisitor {
private final Stack<TargetNode> candidates = new Stack<TargetNode>();
@Override
public boolean visit(TargetNode target) {
if (isCandidate(target)) {
candidates.push(target);
}
return true;
}
@Override
public void leave(TargetNode target) {
if (isCandidate(target)) {
candidates.pop();
}
}
@Override
public boolean visit(SourceNode source) {
if (!candidates.isEmpty()) {
// Do not always override the context information!
// Each path leading to this source can have different
// candidates.
TransformationContext context = source.getContext();
if (context == null) {
TargetContext newContext = new TargetContext(serviceProvider);
source.setContext(newContext);
newContext.addContextTargets(candidates);
}
else if (context instanceof TargetContext) {
((TargetContext) context).addContextTargets(candidates);
}
else {
throw new IllegalStateException("Unknown TransformationContext present.");
}
}
return true;
}
/**
* Determines if a target node is a candidate for a context match. For
* this the cardinality of the corresponding definition is checked.
*
* @param target the target node to check
* @return if the target node is a candidate for a context match
*/
private boolean isCandidate(TargetNode target) {
ChildDefinition<?> def = target.getDefinition();
Cardinality cardinality = DefinitionUtil.getCardinality(def);
if (cardinality != null) {
return cardinality.getMaxOccurs() == Cardinality.UNBOUNDED
|| cardinality.getMaxOccurs() > 1;
}
return false;
}
/**
* @see TransformationNodeVisitor#includeAnnotatedNodes()
*/
@Override
public boolean includeAnnotatedNodes() {
// if there are any, just deal with them also
// though in reality, annotated nodes only should be there AFTER
// context matching
return true;
}
}
private final ServiceProvider serviceProvider;
@SuppressWarnings("javadoc")
public AsDeepAsPossible(ServiceProvider serviceProvider) {
this.serviceProvider = serviceProvider;
}
/**
* @see eu.esdihumboldt.hale.common.align.model.transformation.tree.context.ContextMatcher#findMatches(eu.esdihumboldt.hale.common.align.model.transformation.tree.TransformationTree)
*/
@Override
public void findMatches(TransformationTree tree) {
tree.accept(new ContextVisitor());
}
}