Hosted by Three Crickets

Scripturian
Scalable Alternative to JSR-223

Scripturian logo: kitten in shawl

Manual

Next chapter: Threads and Execution Contexts
Or, go back to the manual's table of contents

Part 2: Executing Documents

Let's first look at the code, and then explain it in detail:

File baseDir = new File( "/mydirectory/" );
DocumentFileSource<Executable> documentSource =
	new DocumentFileSource<Executable>( baseDir, "default", "js", 1000 );

ParsingContext parsingContext = new ParsingContext();
parsingContext.setLanguageManager( new LanguageManager() );
parsingContext.setDocumentSource( documentSource );
parsingContext.setPrepare( true );

String documentName = "/run/";
DocumentDescriptor<Executable> documentDescriptor =
	Executable.createOnce( documentName, false, parsingContext );

Executable executable = documentDescriptor.getDocument();
ExecutionContext executionContext = new ExecutionContext();
try {
	executable.execute( executionContext );
}
finally {
	executionContext.release();
}

The Document Source

We started with setting up a reusable document source. A "document source" is in charge of retrieving (and storing) textual documents in a thread-safe, scalable manner according to their URIs. In this case, we are dealing with documents that are source code files, to parsed/compiled/interpreted by a language engine.

Scripturian's most basic document source is based on files, where URIs are mapped to file paths, and the documents are the files themselves. You can also create your own implementations of DocumentSource to store your executables in distributed caches, databases, or even have them generated on-the-fly. The document source is also used internally by executables, for example in order to execute other documents (what some languages call "including", "requiring", "importing", etc.)

In this example, you can see that our default document will be called "default", meaning that if we specify a URI pointing to a directory, and the directory has a document named "default.*" in it, then that document would be mapped to that URI. (This might remind you of how the Apache web server maps directory URLs to the "index.html" document.) Our (optional) preferred extension is "js". Finally, we won't allow hitting the file system more than once per second (1000 milliseconds) to check if a requested document has changed.

You very much want to reuse the same document source instance throughout your application. It is optimized for concurrency, and caches wherever possible.

The Parsing Context

We then set up a reusable "parsing context," which we will use to turn a document into an "executable." Note that we are attaching our document source to it. We are also setting "prepare" to true. "Preparation" in Scripturian refers to any early optimization of the executable. For many languages which support it, this means compiling the source code into JVM byte code. Note that prepared code is stored in Scripturian's cache, so that the document will not be re-prepared unless it is changed. You'll want to set "prepare" to true when performance is important, though it is at the expense of startup time. See the ParsingContext documentation for more options.

The Document Descriptor

Another small step is the creation of the "document descriptor." Document descriptors are lightweight wrappers used to refer to documents without actually instantiating them. In this case, we aren't doing anything interesting with the descriptors, but must still at least retrieve them.

The Executable

Finally we create an "executable" from our document and execute it. An "executable" is Scripturian's most important abstraction: it is an encapsulated, persistent, stateful entity which has one or more entry points. It can be something as simple as a Java "Callable", or as complex as a set of scripts written in various JVM languages. There is actually a lower-level abstraction beneath the executable, the "program": an executable can be composed of "programs" written in several languages, which will be run in order. "Programs," however, are implementation-specific and you will rarely need to access them directly.

The Execution Context

We'll explain the use of this in length in the next tutorial section. For now, just know that you have to release the context when you're done using it.

The Document Name

Our document name was "/run/". This means that Scripturian will look for the document in this order: first, it will look for "/mydirectory/run.js" (because we specified "js", for JavaScript, as our preferred extension), and then for any file that matches "/mydirectory/run.*", where the extension will be mapped to the correct language implementation: for example, "run.py" will be run as Python code. Finally, if the previous two options aren't found, then Scripturian will look for "/mydirectory/default.*", again with a preference for ".js".

Summary

Fourteen lines of code might seem like a lot for the simple task of delegating to a script, but behind the scenes we have a very scalable, concurrent system for delegation. The "createOnce" guarantees that if we run the code in multiple threads on the same document source, we will be reusing the same document. And the executable itself can be safely called concurrently (more on that below). This makes Scripturian ideally suited for server applications, for example to delegate a user request to a script. Many concurrent requests can be happily handled by the same "run.js" file.


Next chapter: Threads and Execution Contexts
Or, go back to the manual's table of contents