4

We have an application that allows users to enter conditionals in the form bound op x op bound2, we store this as a string, and then parse it at runtime to evaluate it.

It is a decent amount of work, for a very limited conditional statement.

We are looking for a way to serialize and then evaluate complex conditions, with at least a switch statement level of complexity.

I saw in this question How to serialize and deserialize lambda expression in F#? that in f# you can just serialize a lambda (and I assume that there is some way to get a lambda from a text string), but:

  1. We need to do this in Java
  2. I know that we can compile java code on the fly, and make it "safe" by stripping out keywords, and disallowing things like System. but even if its not a security nightmare, it is prohibitively computationally expensive to do thousands of times.

Does anyone know of a small language out there whose interpreter can do just the basics (conditionals, loops, variable assignment) and be run in/as java, or any way to run those types of expression as they are defined at runtime and need to be persisted.

Update: To be clear, the minimum functionality I need is an if else chain. I don't just need to evaluate one condition. The one condition is what I have now already.

10
  • 1
    Probably you can use Groovy scripts for that purpose. (But please be aware that running a script that the user defines can be a security issue, despite the programming language you use)
    – Andy
    Jan 17 '17 at 14:13
  • 1
    or any lightweight scripting language with built-in sandbox like lua. Jan 17 '17 at 14:14
  • @Andy and ratchet, is this the normal way people solve this problem, or am I reaching for the wrong tool here?
    – soandos
    Jan 17 '17 at 14:17
  • I don't have much experience with that kind of requirements, but I would avoid storing a script in DB and run it at runtime. It depends on the project context, and what problem you are trying to solve. Maybe a workflow engine (e.g. Camunda) or a rules engine (e.g. drools) fits your needs.
    – Andy
    Jan 17 '17 at 14:26
  • The issue is that 90% of the time, we just need an if else if chain, and those types of products come with their own dependencies, and associated "stuff" that is not needed. If there are no security issues, and we can do syntax checking, does it make sense?
    – soandos
    Jan 17 '17 at 14:39
4

You could also create a really simple expression language, and then evaluate it on the fly. Expression are trees, so it can be serialized as XML, JSON, s-expressions or whatever you prefer. Eg. a + b * c could be expressed in JSON as ["+", "a", ["*", "b", "c"]]. It is also really easy to write an evaluator for such a tree.

An if-chain like:

if a then x 
else if b then y
else if c then z
else q

Could be expressed in Json like:

["if", "a", "x", ["if", "b", "y", ["if", "c", "z", "q"]]]

An interpreter in pseudocode:

def eval(args):
  operator = args[0]
  if operator=="+":
    return eval(args[1]) + eval(args[2])
  elif operator =="*":
    return eval(args[1]) * eval(args[2])
  elif operator=="<":
    return eval(args[1]) < eval(args[2])
  elif operator=="if":
    if (eval(arg[1])):
        return eval(arg[2]) 
    else:
        return eval(arg[3])

And so on...

Of course, as soon as you add lambdas or functions it becomes much more complex, and then I would recommend using an off-the shelf scripting engine. But if you only need to support expressions, it might be simpler to just write your own evalator.

6
  • Minimally I need an else if chain. Is a parser for that so easy to write?
    – soandos
    Jan 17 '17 at 19:59
  • @soandos: Yes that is pretty easy also. Is the users entering these expression through a GUI or are they writing them as code?
    – JacquesB
    Jan 17 '17 at 20:07
  • They are entering it as code
    – soandos
    Jan 17 '17 at 20:09
  • @sonados: OK if they are entering it as code, then you don't need to "serialize" the code. You just store the code! But you need a simple parser to read the code into a data structure.
    – JacquesB
    Jan 17 '17 at 20:21
  • I need something that turns the text they enter into an expression that I can evaluate. I don't want to write an interpreter
    – soandos
    Jan 17 '17 at 20:22
1

"Conditions, loops, variable assignment" is already enough to consume arbitrary amounts of CPU, unless you're careful.

If all what's needed is just arithmetic expressions, it's easy to write an interpreter for them, with a few predefined operations / functions. It's also easy to understand the execution time of the expression, because it cannot have loops.

If I were in your shoes and I needed a Turing-complete scripting language, the first thing I would do would be to avoid rolling my own.

Java 6 introduced a scripting API. There's a JavaScript implementation for it. There's also Mozilla Rhino JavaScript implementation in Java.

As far as I can tell, both implementations allow to limit the initial namespace of the JS program so that facilities not explicitly passed are not accessible.

Then there's LuaJ that implements the Lua VM in JVM, with the finer execution control / sandboxing expected from Lua.

You could also consider Groovy, Jython and JRuby, but these must be significantly heavier-weight and harder to sandbox. Or maybe you could consider Golo (no idea about sandboxing it).

In any case, I would execute a script in a separate thread and kill any script that takes longer than some allocated time to run.

I would also look at ways to track and limit the amount of heap allocations coming from such a thread, but this seems impossible in Java.

If strict performance considerations / DoS protection were important, I'd probably run LuaJ, or maybe even a C Lua VM via JNI, and completely control the amount of CPU and RAM available, and only exposed a (small) proxy to the objects to be scripted.

2
  • Minimally I need an else if chain. Is a parser for that so easy to write?
    – soandos
    Jan 17 '17 at 19:59
  • @soandos: Depending in your syntax; I can easily imagine a syntax that is trivial to parse in this case (and all others), that is, S-expressions. I can suspect that even if <cond> then <expr> else <expr> is not really hard to parse.
    – 9000
    Jan 18 '17 at 1:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.