package eu.dnetlib.data.collective.transformation.rulelanguage.visitor; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import eu.dnetlib.data.collective.transformation.rulelanguage.Argument; import eu.dnetlib.data.collective.transformation.rulelanguage.Condition; import eu.dnetlib.data.collective.transformation.rulelanguage.IRule; import eu.dnetlib.data.collective.transformation.rulelanguage.Rules; import eu.dnetlib.data.collective.transformation.rulelanguage.RulesSet; import eu.dnetlib.data.collective.transformation.rulelanguage.Argument.Type; import eu.dnetlib.data.collective.transformation.rulelanguage.parser.ASTMyAssign; import eu.dnetlib.data.collective.transformation.rulelanguage.parser.ASTMyAttribute; import eu.dnetlib.data.collective.transformation.rulelanguage.parser.ASTMyCondition; import eu.dnetlib.data.collective.transformation.rulelanguage.parser.ASTMyCopy; import eu.dnetlib.data.collective.transformation.rulelanguage.parser.ASTMyEmpty; import eu.dnetlib.data.collective.transformation.rulelanguage.parser.ASTMyImport; import eu.dnetlib.data.collective.transformation.rulelanguage.parser.ASTMyNs; import eu.dnetlib.data.collective.transformation.rulelanguage.parser.ASTMyOp; import eu.dnetlib.data.collective.transformation.rulelanguage.parser.ASTMyPreprocess; import eu.dnetlib.data.collective.transformation.rulelanguage.parser.ASTMyScript; import eu.dnetlib.data.collective.transformation.rulelanguage.parser.ASTMyScript.SCRIPTTYPE; import eu.dnetlib.data.collective.transformation.rulelanguage.parser.ASTMySet; import eu.dnetlib.data.collective.transformation.rulelanguage.parser.ASTMySkip; import eu.dnetlib.data.collective.transformation.rulelanguage.util.Converter; import eu.dnetlib.data.collective.transformation.rulelanguage.util.FunctionCall; /** * Implementation of the visitor pattern; maps production rules into Java data structures * @author jochen * */ public class RuleLanguageVisitor extends AbstractVisitor{ private static final Log log = LogFactory.getLog(RuleLanguageVisitor.class); private String scriptName = ""; private ASTMyScript.SCRIPTTYPE scriptType; private Map> elementMappingRules = new LinkedHashMap>(); private Map variableMappingRules = new LinkedHashMap(); private Map templateMappingRules = new LinkedHashMap(); private List importedScriptList = new LinkedList(); private List functionCallList = new LinkedList(); private Map namespaceDeclMap = new HashMap(); private List> preprocessingMap = new LinkedList>(); /** * @return the name of the rule script */ public String getScriptName(){ return this.scriptName; } /** * @return the type of the script */ public SCRIPTTYPE getScriptType(){ return this.scriptType; } /** * @return the mapping of all rules */ public Map> getElementMappingRules(){ return this.elementMappingRules; } public Map getVariableMappingRules(){ return this.variableMappingRules; } public Map getTemplateMappingRules(){ return this.templateMappingRules; } /** * @return the list of function calls - this is a subset of the rule mapping */ public List getFunctionCalls(){ return this.functionCallList; } /** * @return the list of scripts that are declared as import */ public List getImportedScripts(){ return this.importedScriptList; } /** * @return the map of name-space declarations made in the script */ public Map getNamespaceDeclarations(){ return this.namespaceDeclMap; } /** * @return the map of preprocessings (functions, parameters) */ public List> getPreprocessings(){ return this.preprocessingMap; } public Object visit(ASTMyAssign node, Object data) { String attrValue = ""; String fieldExprValue = ""; Rules r = node.getRule(); if (node.isFieldExpression()){ // todo e.g. convert field-expression into a xpath-expression fieldExprValue = node.getFieldExpression(); if (fieldExprValue.startsWith("xpath:")){ fieldExprValue = Converter.getXpathFromXpathExpr(fieldExprValue); r.setXpath(fieldExprValue); }else if (fieldExprValue.startsWith("$") && !fieldExprValue.startsWith("$job.")){ // variable log.debug("ruleLangVisitor: assign variable:" + fieldExprValue); r.setAssignmentVariable(fieldExprValue); } }else if (node.isAttribute()){ attrValue = node.getValue(); }else { // shouldn't happen attrValue = "value not defined: " + node.getValue(); } r.setConstant(attrValue); if (r.getUniqueName().trim().length() > 0){ addRule(r, r.getUniqueName()); } return null; } @Override public Object visit(ASTMyCopy node, Object data) { Rules r = node.getRule(); r.setTemplateMatch(node.getTemplateMatchName()); r.getProperties().setProperty("applyTemplateSelectExpression", node.getApplyTemplateSelectExpression()); r.getProperties().setProperty("copySelectExpression", node.getCopySelectExpression()); addRule(r, r.getUniqueName()); return null; } @Override public Object visit(ASTMySet aNode, Object aData) { log.debug("called method: RuleLanguageVisitor.visit(ASTMySet)"); // check if the outputfield is the same in rules of this production Rules myRule = aNode.getRule(); if (aNode.isValueExpression()){ // todo e.g. convert field-expression into a xpath-expression String exprValue = aNode.getValueExpression(); if (exprValue.startsWith("xpath:")){ exprValue = Converter.getXpathFromXpathExpr(exprValue); myRule.setXpath(exprValue); }else if (exprValue.startsWith("$") && !exprValue.startsWith("$job.")){ // variable log.debug("ruleLangVisitor: assign variable:" + exprValue); myRule.setAssignmentVariable(exprValue); } } List rules = aNode.getRules(); RulesSet set = new RulesSet(); //set.setPrimaryRule(rules.get(0)); myRule.setRulesSet(set); log.debug("rulelangvisitor rule name: " + myRule.getUniqueName() + " , hasSet : " + myRule.hasSet()); set.getPendingRules().addAll(rules); addRule(myRule, myRule.getUniqueName()); return null; } @Override public Object visit(ASTMyEmpty node, Object data) { Rules r = node.getRule(); r.setEmpty(node.isEmpty()); addRule(r, r.getUniqueName()); return null; } /** * vist a production rule that is defined as an operation or external function call * @see eu.dnetlib.data.collective.transformation.rulelanguage.visitor.AbstractVisitor#visit(eu.dnetlib.data.collective.transformation.rulelanguage.parser.ASTMyOp, java.lang.Object) */ public Object visit(ASTMyOp node, Object data) { Rules r = node.getRule(); r.setFunctionCall(node.createFunctionCall(r.isStatic())); functionCallList.add(r.getFunctionCall()); log.debug("fc name: " + r.getFunctionCall().getExternalFunctionName()); for(int i =0; i < node.jjtGetNumChildren(); i++) { ASTMyAttribute sn = (ASTMyAttribute)node.jjtGetChild(i); Argument arg = null; if (sn.getAttributeValue() != null){ arg = new Argument(Type.VALUE, sn.getAttributeValue()); }else if (sn.getAttributeInputField() != null){ if (sn.getAttributeInputField().startsWith("xpath:")){ arg = new Argument(Type.INPUTFIELD, Converter.getXpathFromXpathExpr(sn.getAttributeInputField())); }else if (sn.getAttributeInputField().startsWith("$job.")){ // job constant arg = new Argument(Type.JOBCONST, sn.getAttributeInputField()); }else{ // variable arg = new Argument(Type.VAR, sn.getAttributeInputField()); } }else{ throw new IllegalStateException("Argument with neither value nor inputfield is not allowed."); } log.debug("argument: " + arg.getArgument()); r.getFunctionCall().addArgument(arg); } if (r.getFunctionCall().getParameters() != null){ Set keys = r.getFunctionCall().getParameters().keySet(); for (String key: keys){ log.debug("key: " + key + " , value: " + r.getFunctionCall().getParameters().get(key)); } } log.debug("add rule with declaration: " + r.getRuleDeclaration()); addRule(r, r.getUniqueName()); return null; } @Override public Object visit(ASTMyImport node, Object data) { importedScriptList.add(node.getScriptName()); return null; } @Override public Object visit(ASTMyNs node, Object data) { namespaceDeclMap.put(node.getNsPrefix(), node.getNsUri()); return null; } @Override public Object visit(ASTMyScript node, Object data) { this.scriptName = node.getScript(); this.scriptType = node.getScriptType(); return null; } @Override public Object visit(ASTMyCondition node, Object data) { Condition condition = new Condition(); if (node.getApplyExpression().length() > 0){ String applyExpr = Converter.getXpathFromXpathExpr(node.getApplyExpression()); condition.setApplyExpression(applyExpr); } String conditionalExpr = Converter.getXpathFromXpathExpr(node.getConditionalExpression()); condition.setConditionExpression(conditionalExpr); condition.setPrimaryRule(node.getPrimaryRule()); node.getPrimaryRule().setCondition(condition); condition.setSecondaryRule(node.getSecondaryRule()); node.getSecondaryRule().setCondition(condition); return null; } @Override public Object visit(ASTMyPreprocess node, Object data) { Map functionMap = new HashMap(); functionMap.put(node.getFunctionName(), node.getParameter()); preprocessingMap.add(functionMap); return null; } private void addRule(IRule rule, String key){ log.debug("add rule with key: " + key); Set ruleSet = null; if (rule.definesVariable()){ variableMappingRules.put(key, rule); }else if (rule.definesTemplate()){ templateMappingRules.put(key, rule); }else{ if (elementMappingRules.containsKey(key)){ ruleSet = elementMappingRules.get(key); }else{ ruleSet = new LinkedHashSet(); elementMappingRules.put(key, ruleSet); } ruleSet.add(rule); } } @Override public Object visit(ASTMySkip node, Object data) { Rules r = node.getRule(); r.setSkip(true); addRule(r, r.getUniqueName()); // ??? actually no targetField defined return null; } }