Contains various utility classes that utilize the spiralcraft.lang subsystem in the context of other core interfaces
The purpose of the spiralcraft.lang package is to provide an EL based integration layer that can tie together application components that have not been built to be aware of each other. The integration layer is geared towards maximizing expressive power and minimizing coupling, from a developer's perspective, while maximining concurreny and minimizing per-thread resource utilization.
The EL is implemented through the creation of Channels from compiled Expressions. These Channels are bound to data sources exposed by the application via a hierarchy of Focus objects.
A Channel is a bidirectional "pipe" through which data moves. A Channel is linked to other Channels as an analog of the Expression structure, and as defined by "pseutotypes" called Reflectors.
A Reflector resolves "parameterized names", and is a fascade for whatever typing system (or lack thereof) is being exposed. A Reflector for java.lang.Class is included, which provides a java.beans "default" mapping and provides access to Object methods and properties.
A common use of this package is to provide a reusable set of View-Controller components, such as WebUIs, GUIs, templates, monitors, etc., with a means to interoperate with different Model architectures, often in the same system, using Expressions and "psuedotypes" (spiralcraft.lang.Reflector) to map query and input Channels (spiralcraft.lang.Channel) into a given application model.
The spiralcraft.lang package has two modes of extension.
Specifically, the spiralcraft.lang package supports the following characteristics:
Expressions are used by user interfaces or other controllers to dereference, update and perform computations on components of an application object model via bidirectional Channels.
Expressions are linked to metadata in the binding stage, and are not inherently stateful (ie. they do not "hold" data). The actual data is typically passed through the thread stack. Therefore the Expression container may implement concurrency strategies where multiple operations defined by the same set of metadata occur simultaneously on different threads. This is not visible to the end user or scripter, who simply writes expressions without concern for the underlying "data referencing" method.
Expressions are parsed into a parse-tree of Nodes (spiralcraft.lang.parser.Node) only once when they are loaded. The parse tree may also be created or manipulated directly to efficiently generate Expressions from language oriented components or a user interface.
The Expression parse-tree of Nodes is resolved against an application object model at runtime to produce a Channel which is bound to the data source. The Channel is associated with a strong (fixed) datatype, but it may be repeatedly queried, listened to or updated to the extent supported by the actual composition of the target application model.
The runtime binding process enables the use of Expressions as configuration elements, as user-supplied customization elements, or in other external resources.
All of the name resolution and reflection based logic is handled at the bind stage and is "compiled" into a Binding tree (spiralcraft.lang.spi.Binding) which comprises the data access and computation operations that feed a Channel. Each leaf of the Binding tree references a "variable", or a window on a specific data value that may change.
Once "compiled", an expression can be repeatedly evaluated as the underlying data changes, or it may listen for changes if this mode is supported. This behavior is geared towards the efficient processing or filtering of large datasets.
Channels comprise a set of operations, and are not inherently stateful, so they may be shared by multiple threads simultaneously. They may do this even while examining different data through the use of "thread local storage" via the ThreadLocalBinding (spiralcraft.lang.spi.ThreadLocalBinding), which eliminates the creation of a redundant Binding tree for each thread.
The namespace accessible to an Expression is configurable by the expression container to expose various entry points into the application model(s) under consideration. A chain of Focus objects addressable by URI provides access to various external entities and often to the expression container itself, providing loose coupling between multiple application layers. As the expressions are expressed within the context they are used and pull in relevant non-local context, an inversion of control effect is achieved. This feature is of use from application configuration and user interface construction perspectives.
Expressions can be used efficiently in situations where a limited namespace is exposed if the expression container chooses to use local names instead of URIs when setting up the Focus chain. This feature is of use from a data processing perspective.
The Reflector interface is implemented to map names and operations into a specific model architecture. Channels supported by different Reflector implementations can coexist in the same application and reference different model architectures, such as database data represented as Tuples, for instance, and Java object models.
A Channel with a custom type system (database data, for example) can support a property accessor defined by a different type system. A Java reflection based Reflector implementation gives any custom type system the ability to return Java objects and boxed primitives.
Expressions may be parsed from text into a parse tree made up of Nodes (spiralcraft.lang.parser.Node). See Expression.parse().
The Node Tree may be programatically created by direct manipulation of Nodes to avoid text processing. Likewise, a Note Tree tree may be analyzed to determine the logic being performed and optimize it or translate it into another language (for example, SQL).
A static cache is maintained to avoid parsing the same Expression more than once. Identical text will always result in an identical Node tree.
An Expression is bound to a Focus to create a Channel.
A Channel is a bidirectional data window or pipe which supports a simple get() and set() interface. Calling get() is equivalent to evaluating the expression. Calling set() is applicable if the expression is "reversible"- for instance a data element that is retrieved may sometimes be altered.
The data handled by the Channel is defined by a Reflector, a pseudo-type which describes the set of names and operations available to the EL specific to the data provided by the channel. Since different containers may provide access to different typing systems (ie. Beans, SQL, etc), the Reflector serves as a "fascade" so the the spiralcraft.lang package can use the "services" provided by a type system in a standard fashion.
A Focus is a "starting point" provided by a container for EL evaluation. It exposes the set of data sources available to an Expression. It normally references some "default" Channel called a "subject", which is the primary target against which the expression will be evaluated. This subject Channel is usually provided by the container, which sets up the environment and scenario for the use of the spiralcraft.lang package.
An Expression may specify, using a qualified Focus specifier enclosed in square brackets, an alternate Focus against which to evaluate the expression. The name may map to a URI mapped from the type or supertype of the subject of the focus, and/or to a URI set up by the container to identify the integration point represented by the Focus. It may additionally identify an application layer associated with this integration point.
The focus Specifier is resolved by virtue of the primary Focus delegating to a "parent" Focus or to other referenced Focus objects to search for the alternate Focus name. The specific organization of Focus objects is intimately related to the structure of the actual application.