Skip to end of metadata
Go to start of metadata

Multiple scripting languages in the CLI

The CLI has been refactored to support multiple languages and includes support for javascript and python as of RHQ 4.5.0.

Adding the support for a new scripting language has become an easy task that doesn't require the knowledge of many RHQ internals and so is ready for 3rd parties to get involved.

On this page I'll try to explain what's in it to make RHQ understand your language of choice.

For scripting RHQ uses the standard Java way of executing scripts in other languages - JSR 223, aka ScriptEngine. Therefore any language that an interpreter or compiler/executor written in Java and that has support for JSR 223 (or for which such support could be implemented) is a candidate for an RHQ scripting language. Languages with such support include javascript, python, ruby, groovy, clojure and I'm sure there are many others.

Once installed into RHQ, the scripting runtime is provided with the same "bindings" to RHQ regardless of the scripting language. All the same variables of the same types are available in each language.

ScriptEngineProvider

RHQ finds out about language modules using the Java services mechanism. You need to implement an org.rhq.scripting.ScriptEngineProvider interface and let Java know about your implementation by leaving the full class name of your implementation in the META-INF/services/org.rhq.scripting.ScriptEngineProvider file in the jar you're distributing.

Let's take a look at the implementation for python:

That is rather simple, isn't it? Granted, the provider doesn't support code completion for RHQ's interactive CLI, but hey... This is just a demo

You may have noticed the PythonScriptEngineInitializer class in there and you are right to think that that's where the meat of the implementation lies. Let's take a look at that class:

That's a little bit more of a mouthful but still it's not too bad I think with cca 60 lines of code. Additional code of course exists to support source code providers (the PythonSourceProvider class), but let me just tell you that it, too, is not more than 100 lines (jython has quite nice APIs).

So what do all those methods do?

  • instantiate() does just that - it instantiates a new script engine and initializes it. It tries to pre-import the supplied java packages (this is so that certain RHQ classes are available by default) and optionally secures the script engine using the given set of permissions that the scripts should run with (the SandboxedScriptEngine class is a ScriptEngine decorator provided by RHQ that runs all the eval methods with the specified java security permissions).
  • installScriptSourceProvider() enhances the script engine so that it is able to locate scripts with assistance of the provided ScriptSourceProvider instance. Usually this requires deep interaction with the underlying script engine implementation because Java's APIs don't support such functionality.
  • generateIndirectionMethods returns a set of function source codes that will make functions on a certain object accessible as "top level" methods. This is to support RHQ's standard variables and methods that are made available to the scripts.
  • extractUserFriendlyErrorMessage is there to extract an error message out of an exception thrown by the script engine during a script evaluation. This method exists because some script engines (like Rhino that RHQ uses for javascript support) have the habit of wrapping the exceptions thrown during script evaluation in a rather weird way.

You can see that with less than a 200 lines of code in 3 files I was able to implement a usable support for python in RHQ's CLI. The only thing missing is support for code completion in RHQ's interactive CLI console (but that's actually something I don't find particularly important, even though it would good to have).

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.