Code gluse

Today's post targets an API, which has been released on Dec. 11, 2006; the javax.scripting package [1] and a lot of good articles that have been written around it.
The intention for this post is not about 'how to use the scripting packaging', but about gluse. So what do I mean with the phrase gluse? Gluse is a coinage
for glue and (re)usage. As many of the Java developer know about the plenty of good libraries from maven central / github and the integration process, a few of them
might ask how to integrate libraries from other languages as well. As many of the every day problems have already bean addressed, there is a good chance that someone else has done the job for you and is willing to share.

Sometimes it's written in pure Java, sometimes in a different language. Let's see how to integrate the latter libraries. (StackOverflow lists a dozen [2] btw.)

The next parts will give you some information in form of three examples. The first and second example will address Javascript, as Javascript is getting more and more into the focus of developers and Oracle will ship their new engine 'Nashorn' with the next Java 8 release, while the third example will target a more complex example using JRuby. All examples can be downloaded from [3]. So it's up to you if you want to read the sources in parallel, afterwards, or by playing with the code in your IDE instantly.
All code examples have been written to be compatible with Java 1.6. See the note in example two, when it comes to the bind function.

Proxy

Lets discuss the first example: We want to replace parts of a string using a regular expression, but hook into the process of manipulating the matching elements, before the replacement eventually takes place - by adding some new content or returning something completely different.

In Java you would probably end up using the java.util.regex.Pattern, creating a matcher and iterating over the matched groups and so on. There's nothing wrong about it, but Javascript already defines that kind of behaviour [4].

    "first 000 second".replace (/[a-zA-Z]+/g, function (match) { return "[" + match.toUpperCase() + "]"; } )

As both, Rhino and Nashorn, support the javax.script.Invocable type, we will create an interface to address the problem - you'll find the whole documentation in the mentioned project [3], but for the sake of completeness:
Apply the 'pattern' on the 'sequence' and call the 'callback' on each matched element. Either on 'all' matching elements, or on 'any' (first makes sense here).

    public interface Replacement {

        public abstract CharSequence any (Pattern pattern, CharSequence sequence, Function<CharSequence, CharSequence> callback);

        public abstract CharSequence all (Pattern pattern, CharSequence sequence, Function<CharSequence, CharSequence> callback);

    }

The final Java code would look like the following (Java 8 users will flavour the new lambda syntax: (match) -> { return "[" + match + "]"; }):

    Replacement replacement;

                            replacement = replacement ();
    CharSequence enclosed = replacement.all (Pattern.compile ("\\d+"), "could you please enclose 1234, 789, 345 with brackets?", new Function<CharSequence, CharSequence> () {

        @Override
        public CharSequence apply (CharSequence sequence) {
            return "[" + sequence + "]";
        }

    });
    
    /* replacement () returns a proxy of the type Replacement, using the shipped js scripting engine. the evaluated script returns an instance, which can be encapsulated using the Invocable#getInterface signature */

The Javascript implementation would look like:

(function () {

    function replace (regex, content, callback) {
        ...
    }

    var Replacement = function () {};
        Replacement.prototype.any = function (regex, content, callback) {
            return replace (new RegExp (regex),      content, callback);
        };

        Replacement.prototype.all = function (regex, content, callback) {
            return replace (new RegExp (regex, 'g'), content, callback);
        };

    return new Replacement ();

}) ();    

The Java code for this example would probably be less - measured in LOC - but the basic steps needed for an integration can be shown pretty good and two worlds might benefit from your certainly approved works ­čÖé

One nice feature about this kind of mechanism is, that you can quickly prototype your functionality, while still able to change parts of the implementation using pure Java afterwards.

Modularity

Let's come to the second example. You may have written a bunch of Javascript files in a modular way or just don't want to put everything in a single file. While the first example showed how to proxy your implementation, the second example will show you a basic approach for dynamically loading further resource and/or code files. The following signature should be provided and accessible from all scripts.

    require ('org.geonames.reverse');

The similarity to requirejs [5] is intentional and you may want to extend the signature to be fully compliant, but this will be left for your curiosity ­čÖé
Loading resources from 'unknown', or from 'at runtime unknown' sources is by nature critical, as the code is executed in the same JVM which hosts your application as well. Therefore, you should only load resources you really trust.
You could achieve this by verifying the signature of the reviewed files using a PKI [6] infrastructure - javax.crypto is your friend here and fortunately you can implement this in Java and/or use a security library to accomplish this task.
Simply spoken: Always check the integrity if you provide a way for modifications.

If you are already familiar with the scripting engine API, you might have noticed that require is a function and not an 'object'.
Even when functions in Javascript are objects, there is no semantic way to say that "this object is a function and can be invoked" if you share it between the environment.
There might be support for some engines, but not for the others and javax.script API is designed for general purpose - depending on engine internal interfaces is not desired.

    obj.require ('org.geonames.reverse'); /* nah, okay but requires additional knowledge obj. */

Fortunately there is a solution. You can attach a script context to the evaluation process and reuse the context later on, but you shouldn't use the internal context as it could leak if your engine leaks.

Pseudo Algorithm:

  1. create a java function object which can load your resources from the classpath, internet, local filesystem, ... with a method signature you know. (a function/SAM object) like: void apply (String)
  2. create a script context and attach the object from 1. to it with a variable called 'whatever' (really whatever name you like)
  3. evaluate an inline require function before you evaluate your business code, which puts your require function into the scope of the context from 2.
  4. evaluate your business codes which relies on the require function with the same scope from 2.
  5. have fun
  6. var require = function (library) { whatever.apply (library); }

    The above code would be sufficient, but has some drawbacks as it only works if the 'whatever' object is in the correct execution scope and if it provides the correct signature - someone could overwrite the binding or does something you simply don't want him/her to do. We need some slight improvements to correct this.

    var require = function (library) { this.apply (library); }.bind (whatever); delete whatever;
    


    "The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called." [7]


    If the bind function is not available by your Rhino environment, you may want to look at the implementation from Prototype [8] et al. and add it manually with the same procedure.

    We delete the 'whatever' object from the script context afterwards.

    You need the following Java code as glue:

    // internal context for variables
    final Bindings bindings = scripting.newBindings ();
                   bindings.put (Importer, new Function<String, Void> () {
    
        // load a library 'argument' from the 'lib' directory
        @Override
        public Void apply (String argument) {
            // trusting returns either a valid stream object or throws an 'untrusted code' exception
            
            String resource;
    
                                          resource = String.format ("/lib/%s.js", argument);
            scripting.evaluate (trusting (resource), context);
    
            return null;
        }
    
    });
    
    context.setBindings (bindings, ScriptContext.ENGINE_SCOPE);
    
    // add require function to the scope before the application script is loaded
    scripting.evaluate (requirejs (Importer), context);
    // execute the script ultimately
    scripting.evaluate (applicationjs (), context);
    

    That's it!

    Reporting

    In the last example I want to explain how to integrate a script engine, which is not shipped by default - JRuby [9]. The idea behind is to embed code of ruby gems into your application, especially PDFKit [10] for this example. PDFKit describes itself with

    "Create PDFs using plain old HTML+CSS. Uses wkhtmltopdf on the back-end which renders HTML using Webkit."


    Mostly you don't want to handle HTML content directly, as your data is often stored in form of a 'model'. Our solution should therefore target the transformation from: Model -> HTML -> PDF, which can be achieved using e.g. the nice Jade [11] language for the rendering process, especially Jade4j [12].
    Instead of writing the integration code for wkhtmltopdf, we will base on the work of PDFKit and write some JRuby glue.
    If you need some information about 'gem bundling' I would recommend the articles/examples from Sieger [13] and Harada [14] as a starting point.

    You will find a local file-based repository in the project, as I wanted Maven [15] to handle all the dependencies, but any other repository might work fine. It simply depends on your infrastructure and what suits you best.

    Pseudo Algorithm:

    1. put jruby-complete on your classpath, as the library ships the jsr223 implementation
    2. put the converted pdfkit bundle on your classpath
    3. put any other needed library on your classpath [jade4j, guava, ...]
    4. write some jruby code to instantiate a configured pdfkit object
    5. proxy the returned jruby object from 4. with a java interface
    6. convert a jade (or differently) generated html stream to pdf using the proxy from 5.

    I'll show you the glue for the proxy only. Please download the project under [3] if you want to see the remaining parts.

    public interface Pdfy {
    
        public boolean convert (InputStream streamin, OutputStream streamout);
    
        public boolean convert (InputStream streamin, OutputStream streamout, Map<String, String> options);
    
    }
    
    class Pdfy
    
      def initialize(stylesheet)
        @stylesheet = stylesheet
      end
    
      def convert(streamin, streamout, options = {})
        begin
                           html = streamin.to_io.read
          kit = PDFKit.new(html, options)
    
          if                   @stylesheet
            kit.stylesheets << @stylesheet
          end
    
          out = streamout.to_io
          out.binmode << kit.to_pdf
          out.flush
        rescue
          return false
        end
    
        true
      end
    
    end
    

    Maven will produce an assembly as zip file, which can be extracted elsewhere with a shell script for windows and *nix based systems.
    You need to provide the full qualified path for wkhtmltopdf as first argument and the full qualified path of the output file with file extension as second argument.
    I did not implement any special CLI handling for this prototype.

    You need to install wkhtmltopdf [16] as a consequence. I installed wkhtmltopdf 0.11.0 rc2 on windows 7 x64 and wkhtmltopdf 0.9.9 on ubuntu 13.10 x64 (virtualization).

    Even if writing some boilerplate is not that interesting, writing less boilerplate is! So instead of writing your own wheel, you might want to spend your energy on making another wheel feel more rounded.
    Whether a script engine can be used in your production environment depends on your configuration, of course, but writing some glue to reuse another solutions might be worth thinking about it.
    The effort could be less in comparison to a full rewrite. Stick to a separation of interfaces and implementations and let the environment decide.

    The devs. from Rhino/Nashorn/JRuby did quite a good job! As well as the devs. from the mentioned libraries. You should compile the project with Java 1.6(!), 1.7 and 1.8 and look at the results.

    [ 1]
    http://en.wikipedia.org/wiki/Scripting_for_the_Java_Platform
    [ 2]
    http://stackoverflow.com/questions/11838369/where-can-i-find-a-list-of-available-jsr-223-scripting-languages
    [ 3]
    https://blog.synyx.de/wp-content/uploads/2014/01/synyx.sample.zip
    [ 4]
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace
    [ 5]
    http://requirejs.org/
    [ 6]
    http://de.wikipedia.org/wiki/Public-Key-Infrastruktur
    [ 7]
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
    [ 8]
    http://prototypejs.org/doc/latest/language/Function/prototype/bind/
    [ 9]
    http://www.jruby.org/
    [10]
    https://github.com/pdfkit/pdfkit
    [11]
    http://jade-lang.com/
    [12]
    https://github.com/neuland/jade4j
    [13]
    http://blog.nicksieger.com/articles/2009/01/10/jruby-1-1-6-gems-in-a-jar/
    [14]
    http://yokolet.blogspot.de/2010/10/gems-in-jar-with-redbridge.html
    [15]
    http://maven.apache.org/
    [16]
    https://code.google.com/p/wkhtmltopdf/


Schreibe einen Kommentar

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