package esl.cuenet.mapper.tree;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.vocabulary.RDF;
import esl.cuenet.query.QueryOperator;
import esl.cuenet.source.Adornment;
import esl.cuenet.source.Attribute;
import esl.cuenet.source.ISource;
import esl.datastructures.graph.relationgraph.IRelationGraph;
import esl.datastructures.graph.relationgraph.RelationGraphEdge;
import esl.datastructures.graph.relationgraph.RelationGraphNode;
import org.apache.log4j.Logger;
import java.util.Iterator;
public class ParseTreeInterpreter {
private IParseTree parseTree = null;
private Logger logger = Logger.getLogger(ParseTreeInterpreter.class);
private SourceMapper sourceMapper = new SourceMapper();
public ParseTreeInterpreter(IParseTree parseTree) {
this.parseTree = parseTree;
}
public void interpret() throws SourceParseException {
//process namespace mappings
IParseTreeNode document = parseTree.getDocument();
for (IParseTreeNode child : document.children()) {
if (child.getType() != IParseTreeNode.Type.OPERATOR) continue;
if (child.getLabel().equalsIgnoreCase(MappingOperators.NAMESPACE))
interpretNamespace(child);
}
for (IParseTreeNode child : document.children()) {
if (child.getType() != IParseTreeNode.Type.OPERATOR) continue;
if (child.getLabel().equalsIgnoreCase(MappingOperators.SOURCE))
interpretSourceDeclaration(child);
}
}
public void setOntologyModel(OntModel model) {
sourceMapper.setOntologyModel(model);
}
private void interpretSourceDeclaration(IParseTreeNode sourceNode) throws SourceParseException {
ISource source = null;
for (IParseTreeNode child : sourceNode.children()) {
if (child.getType() == IParseTreeNode.Type.OPERAND) {
source = sourceMapper.createSource(child.getLabel());
}
}
for (IParseTreeNode child : sourceNode.children()) {
if (child.getType() != IParseTreeNode.Type.OPERATOR) continue;
if (child.getLabel().equalsIgnoreCase(MappingOperators.RELATION))
associateRelations(source, child);
if (child.getLabel().equalsIgnoreCase(MappingOperators.SOURCE_IO))
associateIO(source, child);
if (child.getLabel().equalsIgnoreCase(MappingOperators.SOURCE_TYPE))
associateType(source, child);
if (child.getLabel().equalsIgnoreCase(MappingOperators.AXIOM))
associateAxioms(source, child);
if (child.getLabel().equalsIgnoreCase(MappingOperators.ATTRIBUTES))
associateAttributes(source, child);
}
}
private void associateRelations(ISource source, IParseTreeNode relationNode) {
IRelationGraph relGraph = source.getRelationGraph();
if (relationNode.children().size() != 3)
throw new RuntimeException("Relation node must contain exactly 3 children");
IParseTreeNode sub = relationNode.children().get(0);
IParseTreeNode pred = relationNode.children().get(1);
IParseTreeNode obj = relationNode.children().get(2);
boolean flag = false;
RelationGraphNode subNode = relGraph.getNodeByName(sub.getLabel());
if (subNode != null) {
for (RelationGraphEdge edge : relGraph.getOutgoingEdges(subNode)) {
if (relGraph.getDestinationNode(edge).name().compareTo(obj.getLabel()) == 0)
flag = true;
}
}
if (flag) {
throw new RuntimeException("Multiple Edges between same node pairs : "
+ sub.getLabel() + " -> " + obj.getLabel());
}
if (subNode == null) subNode = relGraph.createNode(sub.getLabel());
RelationGraphNode objNode;
if (relGraph.containsClass(obj.getLabel())) objNode = relGraph.getNodeByName(obj.getLabel());
else objNode = relGraph.createNode(obj.getLabel());
if (pred.getLabel().compareTo("type")==0)
relGraph.createEdge(RDF.type.getURI(), subNode, objNode);
else
relGraph.createEdge(pred.getLabel(), subNode, objNode);
}
private void associateAxioms(ISource source, IParseTreeNode axiomNode) {
for (IParseTreeNode child : axiomNode.children()) {
if (child.getType() == IParseTreeNode.Type.OPERAND)
throw new SourceInitializationException("Found an operand inside the Axiom Node");
if (child.getLabel().compareTo(MappingOperators.MAP) == 0) {
mapAttribute(source, child);
}
}
}
private void mapAttribute(ISource source, IParseTreeNode mapNode) {
boolean fContainsOperatorChildren = false;
for (IParseTreeNode child : mapNode.children())
if (child.getType() == IParseTreeNode.Type.OPERATOR) fContainsOperatorChildren = true;
if (!fContainsOperatorChildren) {
String[] operands = new String[mapNode.children().size()];
int ix = 0;
for (IParseTreeNode child : mapNode.children()) operands[ix++] = child.getLabel();
if (operands.length < 2) throw new SourceInitializationException("Insufficient Mapping Axiom");
else source.getMapper().map(operands[0], new Attribute(operands[1]));
for (int i = 2; i < operands.length; i++) {
if (operands[i].charAt(0) == '[') associateOperators(source, operands[0], operands[i]);
else associateAdornment(source, operands[0], operands[i]);
}
}
if (fContainsOperatorChildren) {
int count = 0;
for (IParseTreeNode child : mapNode.children())
if (child.getType() == IParseTreeNode.Type.OPERAND) count++;
String[] operands = new String[count];
int ix = 0;
for (IParseTreeNode child : mapNode.children())
if (child.getType() == IParseTreeNode.Type.OPERAND) operands[ix++] = child.getLabel();
if (operands.length == 1) source.getMapper().map(operands[0], null, null, null);
for (int i = 1; i < operands.length; i++) {
if (operands[i].charAt(0) == '[') associateOperators(source, operands[0], operands[i]);
else associateAdornment(source, operands[0], operands[i]);
}
//process operators
for (IParseTreeNode child : mapNode.children()) {
if (child.getType() == IParseTreeNode.Type.OPERATOR) {
if (child.getLabel().compareTo(MappingOperators.PROP) == 0) {
source.getMapper().map(operands[0] + "." + child.children().get(0).getLabel(),
new Attribute(child.children().get(1).getLabel()));
}
}
}
}
}
private void associateAdornment(ISource source, String pathExpression, String adornmentLabel) {
Adornment adornment;
if (adornmentLabel.compareTo("F") == 0) adornment = new Adornment(Adornment.AdornmentType.Free);
else if (adornmentLabel.compareTo("U") == 0) adornment = new Adornment(Adornment.AdornmentType.Unspecifiable);
else if (adornmentLabel.compareTo("B") == 0) adornment = new Adornment(Adornment.AdornmentType.Bound);
else if (adornmentLabel.compareTo("C") == 0) adornment = new Adornment(Adornment.AdornmentType.Constant);
else if (adornmentLabel.compareTo("O") == 0) adornment = new Adornment(Adornment.AdornmentType.Optional);
else throw new SourceInitializationException("Invalid Adornment: " + adornmentLabel);
source.getMapper().map(pathExpression, adornment);
}
private void associateOperators(ISource source, String pathExpression, String operatorLabelArray) {
QueryOperator queryOperator;
operatorLabelArray = operatorLabelArray.substring(1, operatorLabelArray.indexOf(']'));
if (operatorLabelArray.compareTo("EQUALS") == 0)
queryOperator = new QueryOperator(QueryOperator.Operators.EQUALS);
else if (operatorLabelArray.compareTo("T_STARTS") == 0)
queryOperator = new QueryOperator(QueryOperator.Operators.TEMPORAL_STARTS);
else if (operatorLabelArray.compareTo("T_FINISHES") == 0)
queryOperator = new QueryOperator(QueryOperator.Operators.TEMPORAL_FINISHES);
else if (operatorLabelArray.compareTo("T_INTERSECTS") == 0)
queryOperator = new QueryOperator(QueryOperator.Operators.TEMPORAL_INTERSECTS);
else if (operatorLabelArray.compareTo("S_OVERLAPS") == 0)
queryOperator = new QueryOperator(QueryOperator.Operators.SPATIAL_OVERLAPS);
else if (operatorLabelArray.compareTo("R_CONTAINS") == 0)
queryOperator = new QueryOperator(QueryOperator.Operators.STRING_CONTAINS);
else if (operatorLabelArray.compareTo("S_NEARBY") == 0)
queryOperator = new QueryOperator(QueryOperator.Operators.SPATIAL_NEARBY);
else if (operatorLabelArray.compareTo("R_FUZZY") == 0)
queryOperator = new QueryOperator(QueryOperator.Operators.STRING_FUZZY);
else throw new SourceInitializationException("Invalid Query Operator: " + operatorLabelArray);
source.getMapper().map(pathExpression, queryOperator);
}
private void associateAttributes(ISource source, IParseTreeNode attributeNode) {
Attribute[] srcAttributes = new Attribute[attributeNode.children().size()];
int ix = 0;
for (IParseTreeNode child : attributeNode.children()) {
srcAttributes[ix++] = new Attribute(child.getLabel());
}
source.setAttributes(srcAttributes);
}
private void associateType(ISource source, IParseTreeNode type) throws SourceParseException {
IParseTreeNode node = type.children().get(0);
if (node.getLabel().equalsIgnoreCase("personal")) source.setType(ISource.TYPE.PERSONAL);
else if (node.getLabel().equalsIgnoreCase("social")) source.setType(ISource.TYPE.SOCIAL);
else if (node.getLabel().equalsIgnoreCase("public")) source.setType(ISource.TYPE.PUBLIC);
else throw new SourceParseException("Unknown Source type associated with source " + source.getName());
}
private void associateIO(ISource source, IParseTreeNode io) {
IParseTreeNode node = io.children().get(0);
if (node.getLabel().equalsIgnoreCase("disk")) source.setIO(ISource.IO.DISK);
else if (node.getLabel().equalsIgnoreCase("network")) source.setIO(ISource.IO.NETWORK);
else throw new RuntimeException("Unknown IO method associated to source " + source.getName());
}
private void interpretNamespace(IParseTreeNode namespaceNode) {
if (namespaceNode.children().size() != 2) throw new RuntimeException("Bad namespace node");
Iterator<IParseTreeNode> children = namespaceNode.children().iterator();
IParseTreeNode uriNode = children.next(); // get the uri
IParseTreeNode shortHandNode = children.next(); // get the shorthand
sourceMapper.addNamespaceMapping(uriNode.getLabel(), shortHandNode.getLabel());
}
public SourceMapper getSourceMapper() {
return sourceMapper;
}
}