dnet-core/dnet-data-services/src/main/java/eu/dnetlib/data/collective/transformation/rulelanguage/visitor/RuleLanguageVisitor.java

307 lines
11 KiB
Java

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<String, Set<IRule>> elementMappingRules = new LinkedHashMap<String, Set<IRule>>();
private Map<String, IRule> variableMappingRules = new LinkedHashMap<String, IRule>();
private Map<String, IRule> templateMappingRules = new LinkedHashMap<String, IRule>();
private List<String> importedScriptList = new LinkedList<String>();
private List<FunctionCall> functionCallList = new LinkedList<FunctionCall>();
private Map<String, String> namespaceDeclMap = new HashMap<String, String>();
private List<Map<String, String>> preprocessingMap = new LinkedList<Map<String,String>>();
/**
* @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<String, Set<IRule>> getElementMappingRules(){
return this.elementMappingRules;
}
public Map<String, IRule> getVariableMappingRules(){
return this.variableMappingRules;
}
public Map<String, IRule> getTemplateMappingRules(){
return this.templateMappingRules;
}
/**
* @return the list of function calls - this is a subset of the rule mapping
*/
public List<FunctionCall> getFunctionCalls(){
return this.functionCallList;
}
/**
* @return the list of scripts that are declared as import
*/
public List<String> getImportedScripts(){
return this.importedScriptList;
}
/**
* @return the map of name-space declarations made in the script
*/
public Map<String, String> getNamespaceDeclarations(){
return this.namespaceDeclMap;
}
/**
* @return the map of preprocessings (functions, parameters)
*/
public List<Map<String, String>> 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> 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<String> 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<String, String> functionMap = new HashMap<String, String>();
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<IRule> 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<IRule>();
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;
}
}