Image of car cockpit meters

Using an Embedded REPL to Accelerate Development (Example: Alfresco)

Waiting time during build and deployment phases of the code-build-deploy-test cycle can really be an annoying part of development. The amount of time “wasted” depends on various project “ingredients” – environment, experience, programming language, application bootstrap and system resources to name a few. The fact that PHP, Rails (and others) eliminate and/or keep these times at a minimum is a key factor of their success.

Long build/deployment times also have consequences. As a developer, you think twice whether you’ll “try out” something or not. But trying things out and exploring is important to get it right and gain experience.

Most Java based applications have a habit of making the developer wait. Today we have various approaches cutting this time on the JVM. JRebel is one, dynamic languages are another.

REPLs help exploring – and exploring is important

REPLs (Read-Eval-Print-Loops) are a beautiful tool to quickly explore and understand – very important as things tend to get more and more complex. On the JVM, most of the popular (dynamic) languages – Groovy, Ruby, Javascript, Scala and Clojure ship at least a console based one.

In order to explore your application you have to either bootstrap it within the REPL environment or embed the REPL in the JVM and provide it with access to your application. Grails supports this approach in general with its Shell and Console. Even though you can access and explore your bootstrapped application, it is not running within an appserver so you cannot use it with a browser.

REPL exploration approach has broad scope

Roughly a year ago, inspired by the Grails tools and the idea of embedding a Groovy REPL in an App-Server I was wondering if a similiar helpful solution could be quickly implemented for the Alfresco Repository.  I had a few tweets going back and forth with Peter Monks and a few others and started off using Groovy at that time. Altough it was working, the “quick shot solution” did not really prove to be useful. The main reason was that code was still too verbose. It then became clear to me what Peter had in mind talking about a CMS-DSL. Besides, Alfresco has special challenges like transaction and security to tackle. (Other) Alfresco centric approaches like the ones implemented by Peter and Florian Maul  (Javascript Console) avoid these by not keeping state on the server and wrapping code in a transaction.

So the overall story was a bit broader in scope than I realized at first glance a year ago. The idea of an embedded REPL can be applied in various dynamic languages, and there may be application dependent special challenges.

Alfresco implementation

Driven by demand to get something useful working for the Alfresco scenario, I started all over with Javascript (rhino) instead of Groovy (Alfresco ships with a proven Javascript environment) – keeping in mind that the REPL idea is far more general.

I remixed ideas (and code ;) from various sources in a quick hack solution to get something usable quickly.  The outcome Alfresco application is a telnet based Javascript REPL similiar to org.mozilla.javascript.tools.shell.Main with additional functions setUser, unsetUser, whoami, withTx and the usual Alfresco Javascript objects initialized.

Example Code:

// User guest is default otherwise
setUser('admin');
// Works w/o TX
for each (var f in companyhome.children) { print(f.name); }

// Needs TX
withTx(function() {
  companyhome.createFile("shell.txt").content = "Hallo World !";
});
// Restore default user guest
unsetUser();
whoami(); // guest

Below, you can find links to the source of the general Spring based REPL embedding code, the Alfresco extension (source and binary amp ready for deployment). At this time, the only “ready to use” application code is the Alfresco repository extension. But it should not be too hard hacking the code to implement a REPL based on another language (most ship a console application) or UI (in case you want to control the “security hole” it exposes at runtime – i.e. in a production system :).

The repository extension code should work with all community versions from 3.4 up to 4.0.a. Please remember that it is a quick hack so far. It works for me, but it may eat your system.

To try out the repository extension:

  • Deploy alfresco-scripting-tools-1.0.amp
  • Go to http://localhost:8080/alfresco/service/api/javascript/service and enable it
  • telnet localhost 6790
  • Type help(); and try some Javascript

I have a lot of potential ideas what to implement next with a Groovy based DSL on the very top of that list. But before going further, practice has to prove that I really eat my own dogfood. :)

I would appreciate if you drop me a line in case you find this useful.

Download Alfresco Scripting Tools Repository Extension

Resources

Andreas Steffan
Pragmatic ? Scientist and DevOps Mind @ Contentreich. Believes in Open Source, the Open Web and Linux. Freelancing in DevOps-, Cloud-, Kubernetes, JVM- and Contentland and speaks Clojure, Kotlin, Groovy, Go, Python, JavaScript, Java, Alfresco and WordPress. Built infrastructure before it was cool. ❤️ Emacs.

4 thoughts on “Using an Embedded REPL to Accelerate Development (Example: Alfresco)”

  1. Great stuff! I particularly like the telnet interface – that’s something I wanted to add to the Groovy library, but didn’t get around to it. If you’re ok with it, I may shamelessly plagiarise your code for that. ;-)

    Also one thing worth noting is that this kind of extension opens up a massive script-injection-attack hole in your Alfresco server, so it’s best not to deploy it to any environment that has important data in it.

    Javascript is a little safer than Groovy in this regard (due to Rhino’s sandboxing), but it’s still trivial to delete all of the content in the Alfresco repository, for example.

  2. Feel free to do whatever you want with the code.

    Regarding groovy, I already have code giving you the basic functionality (even the swing console ;). The only reason I didn’t release it is because I felt it is less useful due to “verbosity/noise”.

    If you want, you can have that as well. I would push it to github then.

  3. Great approach using telnet. I’m thinking it wouldn’t even be too hard to add a login/password to enable some security.

    It would be great to define some standardized extension commands (withTx, setUser, disableBehaviour, …) that can be used in your Scripting Shell, the Javascript Console and the standard repository scripts. For general use it would probably be best to add them using one global object instead of several global commands to reduce conflicts.

  4. Thanks for your feedback, Florian.

    For now, security as it stands is fine for me as I’m using it locally most of the time. But you are right: Shouldn’t be too hard working out something a little more advanced.

    Would indeed be nice to have withTx, setUser, disableBehaviour (good idea !) and the like in one shared place. Although I feel some of those may not really make sense in a webscript context – setUser and withTx for example somehow work around alfresco standard mechanisms. :)

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert