Using GroovyShell as “expression evaluator/engine” (or: How to reuse GroovyShell)

StackOverflow https://stackoverflow.com/questions/5323114

  •  24-10-2019
  •  | 
  •  

Question

I'm using GroovyShell as an "expression evaluator/engine" inside my program. It accepts two inputs: (a) one or more init scripts (b) user-defined script. Both are then concatenated at runtime as big chunk of script (text) and feed to the shell.

String initScripts = getFromDB()
String userScript = getFromUser()

def shell = new GroovyShell()
output = shell.evaluate(initScripts + userScript)

The above code will run in a loop, where the contents of userScript will vary.

So far, initScripts only contain variable definitions (e.g. def $yyyy = new Date().format('yyyy')) which might be referenced in userScript (e.g. print "$yyyy 001").

Is there any more efficient approach for this? (E.g. reusing the shell, how?) Because right now it's very slow.

Edit: Groovy is a must. Please don't recommend other scripting engine.

Edit: I'm thinking whether GroovyShell can do this (pseudo-code):

def shell = new GroovyShell()
shell.evaluate(initScripts)

for each userScript in DB {
    shell.put(userScript )
    def result = shell.evaluateThat()
    println "Result is $result"
}

Is this possible? (Last time I googled it's not possible, but I'm hoping I'm wrong)

Was it helpful?

Solution

You can cache the GroovyShell, you don't need to create a new one always:

final static GroovyShell shell = new GroovyShell()

Also if you run one Script many times you may cache them too. You can create a Script with GroovyShell.parse(String scriptText), use Script.run() to run the script.

This section of the documentation might help too, instead of scripts you can also create groovy objects dynamically.

OTHER TIPS

I guess you could avoid the weight of building a full groovy environment each time.

Since Java 6, there is a scripting API support in Java, which allows you to use lightweight scripting engines.

As an example, see this page in groovy website explaining how to start a groovy script in a Java application using GroovyScriptEngineImpl.

notice you may loose some groovy goodnesses, like maybe Groovy grape, but you'll be able to

  • reuse your script engine
  • ensure your script evals in application context (eventually benefitting from Java objects usage)

EDIT one important thing to notice is that neither GroovyScriptEngineImpl nor GroovyShell can guarantee you any kind of thread safety, as any groovy script is free to spawn any number of thread. In fact, the only way you could guarantte thread safety would be by installing a SecurityManager forbidding thread operations. In fact, even that wouldn't guarantee thread safety (as this thread safety could only be achieved by ensuring all your Java code base is thread safe).

I end up doing this:

def shell = new GroovyShell()
shell.evaluate(initScripts)

for( i in 1..count )
{
    output = shell.evaluate(userScripts);
}

And just to be safe, you can put shell in ThreadLocal or pool.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top