public class Executable extends Object
LanguageAdapter
). Outside of this definition, there is no real limit
to how executables are executed or what the language is. Execution can happen
in-process, out-of-process, or on a device somewhere in the network. A common
use case is to support various programming and templating languages that run
in the JVM, adapters for which are included in Scripturian. Another common
use case is for executing non-JVM services.
The primary design goal is to decouple the code asking for execution from the execution's implementation, while providing clear, predictable concurrent behavior. This abstraction thus lets you 1) plug in diverse execution technologies into your code, 2) dynamically load and execute source code in runtime.
Exact performance characteristics are left up to language implementations, but the hope is that this architecture will allow for very high performance, reusability of operational units, and scalability.
Source code can be conveniently provided by an implementation of
Scripturian's DocumentSource
, which is designed for concurrent use,
though you can use any system you like.
Usage is divided into three phases: creation, execution and entry.
1. Creation. In this phase, the source code is parsed and possibly otherwise analyzed for errors by the language implementation. The intent is for the implementation to perform the bare minimum required for detecting errors in the source code.
This phase supports an optional "preparation" sub-phase, with the intent of speeding up usage of later phases at the expense of higher cost during creation. It would be most useful if the executable is intended to be reused. In many implementations, "preparation" would involve compiling the code, and possibly caching the results on disk.
The creation phase supports a powerful "text-with-scriptlets" mode, in which
source code, wrapped in special delimiters, can be inserted into plain text.
"Scriptlets" written in several languages can be mixed into a single
executable. The plain text outside of the scriptlets is sent directly to the
ExecutionContext
writer.
The "text-with-scriptlets" functionality is implemented entirely in this class, and does not have to explicitly supported by language implementations.
2. Execution. This phase uses an ExecutionContext
for passing
state between the user and the executable, as well as maintaining
implementation-specific state. Concurrent reuse is allowed as long as each
calling thread uses its own context.
3. Entry. This phase allows fine-grained execution via well-defined
"entry points" created by the executable during its execution phase.
Depending on the language implementation, entry can mean calling a function,
method, lambda, closure or macro, or even sending a network request. This
phase follows a special execution phase via a call to
makeEnterable(Object, ExecutionContext, Object, ExecutionController)
, after which all entries use the same ExecutionContext
. Passing
state is handled differently in entry vs. execution: in entry, support is for
sending a list of "argument" states and returning a single state value.
Depending on the language implementation, entry can involve better performance than execution due to the use of a single execution context.
During the creation phase, the entire source code document is converted into
pure source code. When the code is executed, the non-scriptlet text segments
are sent to output via whatever method is appropriate for the language (see
LanguageAdapter
).
The exception to this behavior is when the first segment is text -- in such cases, just that first segment is sent to output from Java. This is just an optimization.
You can detect the trivial case of "text-with-scriptlets" in which no
scriptlets are used at all via getAsPureLiteral()
, and optimize
accordingly.
Executables can have scriptlets in multiple languages within the same source
code. You can specify a different language for each scriptlet in its opening
delimiter. If the language is not specified, whatever language was previously
used in the source code will be used. If no language was previously
specified, the defaultLanguageTag
value from the constructor is used.
An executable
service is exposed to executables for access to
this container environment. See ExecutableService
.
Modifier and Type | Field and Description |
---|---|
protected ConcurrentMap<Object,ExecutionContext> |
enterableExecutionContexts
The execution contexts to be used for calls to
enter(Object, String, Object...) . |
static String |
ON_THE_FLY_PREFIX
Prefix prepended to on-the-fly scriptlets stored in the document source.
|
Constructor and Description |
---|
Executable(String documentName,
long documentTimestamp,
String sourceCode,
String parserName,
ParsingContext parsingContext)
Parses source code into a compact, optimized, executable.
|
Modifier and Type | Method and Description |
---|---|
static Executable |
createOnce(DocumentDescriptor<Executable> documentDescriptor,
String parserName,
ParsingContext parsingContext)
If the executable does not yet exist in the document descriptor,
retrieves the source code and parses it into a compact, optimized,
executable.
|
static DocumentDescriptor<Executable> |
createOnce(String documentName,
String parserName,
ParsingContext parsingContext)
If the executable does not yet exist in the document source, retrieves
the source code and parses it into a compact, optimized, executable.
|
static String |
createOnTheFlyDocumentName()
Atomically creates a unique on-the-fly document name.
|
Object |
enter(Object enteringKey,
String entryPointName,
Object... arguments)
Enters the executable at a stored, named location, via the last language
adapter that used the enterable context.
|
void |
execute(ExecutionContext executionContext)
Executes the executable.
|
void |
execute(ExecutionContext executionContext,
Object containerService,
ExecutionController executionController)
Executes the executable.
|
void |
executeInThread(Object containerService,
ExecutionController executionController)
Executes the executable with the current execution context.
|
protected void |
finalize() |
String |
getAsPureLiteral()
Returns the source code in the trivial case of a "text-with-scriptlets"
executable that contains no scriptlets.
|
ConcurrentMap<String,Object> |
getAttributes()
User-defined attributes.
|
Object |
getContainerService(ExecutionContext executionContext)
The container service stored in the context, if it was set.
|
String |
getDocumentName()
The executable's document name.
|
long |
getDocumentTimestamp()
The executable's document timestamp.
|
ExecutionContext |
getEnterableExecutionContext(Object enteringKey)
The enterable execution context for an entering key.
|
String |
getExecutableServiceName()
The default name for the
ExecutableService instance. |
LanguageManager |
getLanguageManager()
The language manager used to parse, prepare and execute the executable.
|
long |
getLastUsedTimestamp()
Timestamp of when the executable last finished executing or entering
successfully, or 0 if it was never executed or entered.
|
ParserManager |
getParserManager()
The parser manager used to parse the executable.
|
String |
getPartition()
The executable partition.
|
boolean |
makeEnterable(Object enteringKey,
ExecutionContext executionContext)
Makes an execution context enterable, in preparation for calling
ExecutionContext.enter(String, Object...) . |
boolean |
makeEnterable(Object enteringKey,
ExecutionContext executionContext,
Object containerService,
ExecutionController executionController)
Makes an execution context enterable, in preparation for calling
ExecutionContext.enter(String, Object...) . |
void |
release()
Releases consumed execution contexts.
|
String |
toString() |
public static final String ON_THE_FLY_PREFIX
protected final ConcurrentMap<Object,ExecutionContext> enterableExecutionContexts
enter(Object, String, Object...)
.public Executable(String documentName, long documentTimestamp, String sourceCode, String parserName, ParsingContext parsingContext) throws ParsingException, DocumentException
LanguageAdapter
implementations to be
available in the language manager.documentName
- The document namedocumentTimestamp
- The executable's document timestampsourceCode
- The source codeparserName
- The parser to use, or null for the default parserparsingContext
- The parsing contextParsingException
- In case of a parsing error In case of a parsing or compilation
errorDocumentException
- In case of a document retrieval errorLanguageAdapter
public static DocumentDescriptor<Executable> createOnce(String documentName, String parserName, ParsingContext parsingContext) throws ParsingException, DocumentException
LanguageAdapter
implementations
to be available in the language manager.documentName
- The document nameparserName
- The parser to use, or null for the default parserparsingContext
- The parsing contextParsingException
- In case of a parsing errorDocumentException
- In case of a document retrieval errorpublic static Executable createOnce(DocumentDescriptor<Executable> documentDescriptor, String parserName, ParsingContext parsingContext) throws ParsingException, DocumentException
LanguageAdapter
implementations to be available in the language manager.documentDescriptor
- The document descriptorparserName
- The parser to use, or null for the default parserparsingContext
- The parsing contextParsingException
- In case of a parsing errorDocumentException
- In case of a document retrieval errorpublic static String createOnTheFlyDocumentName()
public String getDocumentName()
getPartition()
public String getPartition()
getDocumentName()
public LanguageManager getLanguageManager()
public ParserManager getParserManager()
public ConcurrentMap<String,Object> getAttributes()
public String getExecutableServiceName()
ExecutableService
instance.public long getDocumentTimestamp()
public long getLastUsedTimestamp()
public String getAsPureLiteral()
execute(ExecutionContext, Object, ExecutionController)
in some
situations.public ExecutionContext getEnterableExecutionContext(Object enteringKey)
enteringKey
- The entering keymakeEnterable(Object, ExecutionContext, Object,
ExecutionController)
,
ExecutionContext.enter(String, Object...)
public Object getContainerService(ExecutionContext executionContext)
executionContext
- The execution contextexecute(ExecutionContext, Object, ExecutionController)
public void execute(ExecutionContext executionContext) throws ParsingException, ExecutionException, IOException
executionContext
- The execution contextParsingException
- In case of a parsing errorExecutionException
- In case of an execution errorIOException
- In case of a writing errorpublic void execute(ExecutionContext executionContext, Object containerService, ExecutionController executionController) throws ParsingException, ExecutionException, IOException
executionContext
- The execution contextcontainerService
- The optional container serviceexecutionController
- The optional ExecutionController
to be applied to the
execution contextParsingException
- In case of a parsing errorExecutionException
- In case of an execution errorIOException
- In case of a writing errorpublic void executeInThread(Object containerService, ExecutionController executionController) throws ParsingException, ExecutionException, IOException
containerService
- The optional container serviceexecutionController
- The optional ExecutionController
to be applied to the
execution contextParsingException
- In case of a parsing errorExecutionException
- In case of an execution errorIOException
- In case of a writing errorExecutionContext.getCurrent()
public boolean makeEnterable(Object enteringKey, ExecutionContext executionContext) throws ParsingException, ExecutionException, IOException
ExecutionContext.enter(String, Object...)
.
Note that this can only be done once per entering key for an executable.
If it succeeds and returns true, the execution context should be
considered "consumed" by this executable. At this point it is immutable,
and can only be released by calling release()
on the executable.
enteringKey
- The entering keyexecutionContext
- The execution contextParsingException
- In case of a parsing errorExecutionException
- In case of an execution errorIOException
- In case of a writing errorpublic boolean makeEnterable(Object enteringKey, ExecutionContext executionContext, Object containerService, ExecutionController executionController) throws ParsingException, ExecutionException, IOException
ExecutionContext.enter(String, Object...)
.
Note that this can only be done once per entering key for an executable.
If it succeeds and returns true, the execution context should be
considered "consumed" by this executable. At this point it is immutable,
and can only be released by calling release()
on the executable.
enteringKey
- The entering keyexecutionContext
- The execution contextcontainerService
- The optional container serviceexecutionController
- The optional ExecutionController
to be applied to the
execution contextParsingException
- In case of a parsing errorExecutionException
- In case of an execution errorIOException
- In case of a writing errorpublic Object enter(Object enteringKey, String entryPointName, Object... arguments) throws ParsingException, ExecutionException, NoSuchMethodException
An execution context must have been previously made enterable by a call
to
makeEnterable(Object, ExecutionContext, Object, ExecutionController)
.
enteringKey
- The entering keyentryPointName
- The name of the entry pointarguments
- Optional state to pass to the entry pointParsingException
- In case of a parsing errorExecutionException
- In case of an execution errorNoSuchMethodException
- In case the entry point does not existExecutionContext.enter(String, Object...)
public void release()
Copyright © 2009-2015 Three Crickets LLC.