Technology

Sage is an application rendering engine that renders applications in real-time. Sage is similar to a web browser in that Sage applications are described using a markup language, accessed via URLs, and controlled via a scripting language. However, Sage does not use HTML and can support any number of scripting languages. In addition, because Sage is backed by a rich programming environment, in this case Java, Sage applications can extend/enhance the sage engine dynamically.
Sage is built using Java, and the JIDESoft Component Suite. It requires Java 1.6 or greater; however a large portion of the functionality will work under Java 1.5.

URLs

Sage is URL centric. That is, all resources are accessed via URLs, whether the resource resides on disk, on a web server, or as a piece of computer memory. Sage treats them all the same. What it does with the data the URL points to is determined by context and the MIME type of the data. If there is no context then Sage will use the MIME type of the URL to decide how to present the data to the user. If there is context then the URL is interpreted within the specified context. Sage also allows the MIME types to be overridden. Thus, context-less URLs can force a MIME type on a URL regardless of what is returned by the host server. Another key feature of Sage is its support for inline URLs. An inline URL is a URL whose data is defined inline with the configuration of the widget that the URL is meant to populate. You will see these used a lot in the demo applications.

Components and Interactions

Sage provides a rich component set. The Swing and JIDESoft components have been augmented and instrumented to provide the basic functionality that one would expect for these types of components. The added functionality is to numerous to detail, and some are things you would naturally expect, yet were not provided as part of any comprehensive toolset. See the MS Outlook Clone demo application for some of the multitude of table enhancements that are now easily accessible and useable.

Markup Language

Sage comes with its own markup language for describing the applications' user interface, as well as configuring standard actions and interactions. The primary data format for the markup language is the Sage Data Format (SDF). This is an easily readable structured format, very similar to CSS. XML is also supported and an XML schema definition is available. A language called Sparse Notation is use to define the objects that are used for both the SDF, and XML formats. See the Configuration Objects section in the developer documentation to view the object definitions. SDF is the preferred format due to its ease of readability and a couple of special features that are supported by the runtime parser. The first of these is the ability to use import statements to create composite definitions from multiple SDF files. Going hand in hand with this feature, is the ability to inherit and augment definitions. The SDF format allows for the naming of definitions and the referencing of those named definitions later in the same document. This allows for the creation of common component sets that can be reused by simply importing the file containing the definitions and referencing the name of the component that you want to use. You can then customize the referenced definition as you see fit. The runtime parser can also be invoked from the command line to resolve all imports and references and then spit out a clean composite definition (without any imports or references). Below is an example of the SDF file for a simple table with the data included via an inline URL:
 Table {
  titleLocation: top_left
  alternatingHighlightType: row
  alternatingHighlightColor: "green+45" //adjust luminance to lighten the color
  borders: shadow [ thickness=7 ]
  gridLineType: both
  selectionMode: single
  boldColumnHeaders: true
  title: "Vitals"
  popupMenu {
    {
      value: "Show Vital"
    } [ onAction="window.alert(widget.selection.get(0))" ]
  }
  columns {
    {title: "Type"; fgColor: "#1C0B5A"; width: 5ch }
    {title: "Result"; width: 5ch }
    {
      title: "Date/Time"
      valueType: date_time_type
      valueContext: "MMM dd, yyyy HH:mm"
    }
  }
  dataURL: <<
    TEMP|99.5 F|T-1@13:45
    PULSE|93|T-1@13:11
    RESP|22|T-1@13:11
    BP{tooltip: "Blood Pressure"}|150/110|T-1@16:08
    HEIGHT|64|T-1@16:04
    WEIGHT|125/110|T-1@16:08
    PN|10|T-1@13:45
    >>
}
Note: To run this example simply copy the above definition to a text file with an .sdf extension (e.g. table.sdf) launch sage with the URL path for the file (e.g. sage table.sdf ). Sage will create all the necessary wrapper configurations (application, main window, etc) in order to launch the file.

Data Model

Sage provides a simple but powerful data model. Sage wraps data in an entity called a Renderable Data Item. This item is highly attributed, allowing the developer to specify standard things like fonts and colors, to more complex things like drag and drop support, column/row spanning, and even sub-items for nested hierarchies. This item is the basic building block for all data items and widgets within Sage. In addition, all items are filterable and searchable by default. There are two formats for specifying data items. One is the SDF format, the other is you typical comma separated list of values (CSV). The SDF format allows for greater control when specifying complex nested hierarchies. The CSV format allows for rows and columns to be easily specified. In addition to the standard CSV layout, individual columns can be attributed (e.g. color, font, tooltip, etc.) by embedding single line SDF definitions within the column. This allows the CSV format to be used while still being able to attribute individual row and column items. Also supported is the ability to specify a hierarchy level for individual rows within the CSV format. This makes populating tree type components very easy without having to resort to a full SDF format.

Skinning

Sage supports under-skinning via the use of context specific templates. An object type /class combination (e.g. TextField/widget) is matched against the same object type/class within the current template context, for a matching template name attribute value. If the two objects are of the same type/class and have the same template name attribute value, then the instance within the template is used to skin the object. There is also an auto skin feature that will skin any object type/class combination without a specified template name value, with a predefined default value (from the current template context). This allows global skinning and named skinning to happily coexist. And, because Sage supports the marking up of data, data can also be skinned using this same methodology.

The under-skinning approach allows values defined in a concrete object to always override/augment the values specified in a template (thus the term under-skinning).

Scripting

Sage applications are event driven. Developers use event handlers to handle events and control application flow. The default scripting language is JavaScript (a.k.a. ECMAScript). If the target JVM environment is Java 1.6 or later then any supported scripting language can be used, including both Python and Ruby. The default scripting language is controlled via the defaultScriptingLanguage property in the Application configuration. This language will be utilized to invoke all event handlers. Sage comes with the JavaScript engine already embedded. Other scripting languages must be configured to have their jars in the Java classpath, when Sage is launched. Scripts can be attached to the main application and to all viewers via a scriptURL property. The MIME type of the script determines the engine that will be used to load the script. Once the script is loaded, it becomes globally accessible. By default, the same script is only loaded and executed once when sage is not running in debug mode. For inline scripts, a hash is used to determine if the specified inline script matches a currently loaded inline script. For scripts loaded via a standard URL, the URL is checked to see if a script with the same URL has already been loaded. This behavior can be changed by changing the runonce attribute on the scriptURL property.

Event Handling

When an event is fired Sage finds and executes the handler for the event. The execution environment is populated with global constants and some context specific objects. The context specific objects are as follows:
widget - the widget that triggered the event
form - the form the widget is part of
window - the window that the widget belong to

Embedded Variables and Functions

Sage also support the embedding of variables and functions within a string. Configuration strings containing a non-escaped curly brace pair will have the value within the curly braces interpreted and resolved. Within the curly braces you can have system variables, system functions, resource strings, and application defined attributes.

  • System variable references are references that are prefixed with a percent sign (%). See the System Variables section for more information on system variables.
  • System functions references are references that are prefixed with a dollar sign ($). See the System Functions section for the list of available functions.
  • Resource references are references that are prefixed with the string literal 'resource:'. See the System Resources section for the list of available system resources.

All other references are resolved from attributes that are configured for a viewer and are resolved within the context of the current viewer. If the attribute is prefixed with an "at" sign (@) then the attribute is resolved as an application level attribute. Attributes are configured at the application level or the viewer level via the "attributes" property.

Scripting Shell

A scripting shell is available for Sage. The shell is not part of the standard runtime and has to be downloaded and installed separately. Basically this shell is a telnet server that when connected to, provides a shell that allows script code to be executed via a command-line interface. The scripting shell is part of the running applications' scripting environment and can be used to execute code within the context of the application. You can type "help" at the command prompt to see a list of the available shell commands. See the readme for information on installing and enabling the shell. The shell can also be built from the provided source code.