package com.baidu.cms.thirtpart import util.parsing.combinator.JavaTokenParsers import java.io.FileReader import java.util.regex.Pattern import com.baidu.cms.thirtpart.TransferRuleContext._ import com.baidu.cms.thirtpart.TransferRuleContext.ActivityRef import com.baidu.cms.thirtpart.TransferRuleContext.FieldValueFilter import com.baidu.cms.thirtpart.TransferRuleContext.Rule import com.baidu.cms.thirtpart.TransferRuleContext.OperatorFetchStrategy import scala.collection.JavaConversions._ /** * * User: sunflower * Date: 12-9-14 * Time: 下午8:54 * */ class TransferParser extends JavaTokenParsers { def value: Parser[TransContext] = rep(statement) ^^ { case state => val context: TransContext = new TransContext() state foreach context.interpret context } def statement: Parser[AST] = varDefinition ^^ { case v => v } | rulesDefinition ^^ { case r => RulesDefinition(r) } def varDefinition: Parser[Var] = (ident <~ ":=") ~ (complexValue <~ ",") ^^ { case name ~ value => Var(name, value) } def complexValue: Parser[VarValue] = "class:" ~ """[a-zA-Z][a-zA-Z0-9.]*""".r ^^ { case "class:" ~ classpath => LocalClass(classpath) } | "spring:" ~ """[a-zA-Z][a-zA-Z0-9.]*""".r ^^ { case "spring:" ~ beanId => SpringManagedBean(beanId) } | varValue ^^ { case value => SimpleValue(value) } def varValue = """[^,][0-9a-zA-Z"_\p{InCJKUnifiedIdeographs}:+*/\\.-]*""".r def rulesDefinition: Parser[Set[Rule]] = ("transformRules" <~ ":=") ~ ("{" ~> repsep(ruleDef, ",") <~ "}") ^^ { case "transformRules" ~ rules => Set() ++ rules } def ruleDef: Parser[Rule] = from ~ to ~ opt(props) ^^ { case from ~ to ~ props => { if (props.isEmpty) Rule(from, to, collection.mutable.Map.empty[String, OperatorProp]) else Rule(from, to, props.get) } } def from = "from" ~> activityRef def to = "to" ~> activityRef def activityRef: Parser[ActivityRef] = ("(" ~> ident <~ ":") ~ (varValue <~ ")") ^^ { case id ~ name => ActivityRef(id, name) } def props: Parser[collection.mutable.Map[String, OperatorProp]] = "{" ~> repsep(prop, ",") <~ "}" ^^ { case props => val map = collection.mutable.Map.empty[String, OperatorProp] for (p <- props) { map.update(p.name, p) } map } def prop: Parser[OperatorProp] = "operator" ~ ("{" ~> executorArithmetic <~ "}") ^^ { case "operator" ~ expr => OperatorProp("operator", expr) } | "countersign-users" ~ ("{" ~> executorArithmetic <~ "}") ^^ { case "countersign-users" ~ expr => OperatorProp("countersign-users", expr) } def executorArithmetic: Parser[OperatorFetchExpr] = fetchStrategy ~ rep("+" ~ fetchStrategy | "-" ~ fetchStrategy) ^^ { case fs ~ ms => if (ms.isEmpty) { OperatorFactor(fs) } else { processOperatorArithmetic(ms, OperatorFactor(fs)) } } def fetchStrategy: Parser[OperatorFetchStrategy] = ident ~ repsep(filter,",") ^^ { case strategyName ~ filter => if (filter.isEmpty) OperatorFetchStrategy(strategyName) else { val map = collection.mutable.Map.empty[String, FieldValueFilter] for (f <- filter){ map.update(f.fieldName,f) } OperatorFetchStrategy(strategyName, map) } } def filter: Parser[FieldValueFilter] = ("[" ~> ident) ~ ("=" ~> restriction <~ "]") ^^ { case propName ~ pattern => FieldValueFilter(propName, pattern) } def restriction: Parser[Pattern] = ("Regex" <~ "@@") ~ ("""[^@][^@][a-zA-Z0-9(){}.$*/@+\\_-]+""".r <~ "@@") ^^ { case "Regex" ~ regex => Pattern.compile(regex) } def processOperatorArithmetic(tail: List[~[String, OperatorFetchStrategy]], expr: OperatorFetchExpr): OperatorFetchExpr = tail match { case head :: xs => head match { case "+" ~ strategy => processOperatorArithmetic(xs, OperatorAdd(expr, OperatorFactor(strategy))) case "-" ~ strategy => processOperatorArithmetic(xs, OperatorMinus(expr, OperatorFactor(strategy))) } case Nil => expr } } object ScriptParser extends TransferParser { def doParse(script: String): TransContext = { val reader: FileReader = new FileReader(script) try { parseAll(value, reader) match { case Success(r, next) => { r.checkMandatoryVars() r.init() r } case e@NoSuccess(msg, next) => throw new RuntimeException(e.toString) } } finally { reader.close() } } // test run def main(args: Array[String]) { val context: TransContext = doParse("普通流程-迁移.transfer") val rule: Rule = context.findRule("act64") println(rule) val instance: ActivityInstance = new ActivityInstance("123", "123", rule.from.id, context.processDef.id) val result: java.util.List[ActivityOperator] = OperatorExprEvaluator.evaluate(rule.props.get("countersign-users").fetch, rule,instance, context) println(result) } }