|The OverDrive project is constructing a set of realistic "best practice" applications for the Nexus framework.|
|Presentation Layer||ASP.Net||Spring.Web||Nexus ViewControl||Nexus ViewHelper||(View)|
|Application Layer||Spring.Net||Nexus Catalog||Nexus Commands||Nexus Contexts||(Controller)|
|Persistence Layer||iBATIS.Net||DataMaps||Database||Web Services||(Model)|
The Nexus framework exposes the application layer to the presentation layer through one or more Helper objects. The Helpers are a facade. A ViewControl base class works with the Helpers to read values from the controls, invoke the application logic, and determine the result. The result may include error messages, a set of values, or a list of values – all ready to display.
By "ready to display", we mean that all the type conversions, text formatting, and localizations have already been done. The UI controls can wrap the text in markup without additional post-processing. Providing ready-to-display text is an essential feature, since Nexus is designed to be used with multiple presentation layers. And, yes, we do consider unit tests to be a presentation layer!
|Nexus does not replace presentation frameworks like ASP.NET or Struts. Nexus provides the missing link between presentation frameworks and the business logic that drives your application.|
The Nexus back-end is an extended version of the Commons Chain of Responsibility (CoRe). Our Agility product is a port of the original Jakarta Commons CoRe codebase. The Nexus product is our extension to Agility. Nexus adds the features we need to use a Chain of Responsiblity as a business facade.
|"Chain of Responsibility pattern"|
"Avoid coupling the sender of a request to its receivere by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it."
Design Patterns by Gamma, Helm, Johnson, and Vlissides (ISBN 0201633612).
The Nexus extensions to Agility feature an advanced Context with attributes common to most applications. There are attributes for storing an Exception, lists of Errors, and lists of generic Messages (Fault, Alerts, and Hints). A convenient "IsNominal" property tells us if there are Alerts or a Fault to display.
The Nexus Catalog makes it easy to retrieve a Context and Command in one call. The caller can pass a Command ID and get back a Context with the Command embedded as an attribute. After filling the Context with values, we can "execute" the Context. The Catalog retrieves the Command, and then passes the Context to its Command. For populating a page, we can also ask for a Command ID, and get back the Context after the Command has executed, in a single call.
The Context provides a "Criteria" attribute, which is used like a sandbox to store input and output values. The Helpers utilize the Criteria rather than the Context. Other framework Commands automatically convert or format the values between the Criteria and Context.
The Nexus Catalog is extended so that we can execute any given Command as part of a larger Chain of Commands. At runtime, the Catalog creates a Chain and wraps "pre-opt" and "post-op" chains around the instant Command (which could also be a Chain). The pre-op and post-opt chains are configured along with other Commands in the Catalog. In effect, the Catalog creates a "Back Controller" to ensure certain things always happen on each request (Command invocation). The pre-opt Chain, instant Command (or Chain), and post-op Chain work as a request processor.
The standard pre-op Chain converts input, and the standard post-op Chain formats output. But we can also do things like link a logger into the post-op Chain. It's very much like the way Subversion uses pre-commit and post-commit triggers, except that the "commit" is a Command.
Pluggable Processors handle the conversion and/or formatting for a kind of field. The "kind" might be a data type, like "integer", or a formatting type, like "telephone number", a combination of both, or even a calculated attribute.
The Processors are linked to a Field Table. Each field that needs special handling can be listed in the Field Table and associated with a Processor. The Field Table and Processors also contain the message templates that are used to create validation errors. For lists returned from a database, a special Processor can iterate over each row of the list, and call the Processor for each column, to create a formatted version in the Critiera.
When listing a Command in the Catalog, we can also list the input and output values the command expects. Input can be specified as "required" or as "related". A Chain automatically aggregates the input field list from its Commands, to insure that all required input is provided. We can also specify a command's output values, and the Chain will consider the output from one command valid input to a subsequent command.
The Helpers use the Command's list of input fields to to automatically read or bind values to the controls. The standard pre-op Chain also uses the field list and Field Table to generate validation errors.
Most often, you can read or bind an entire form with a single line of code. A complete block, including error checking, may take four or five lines.
Here is a typical idiom for populating a form:
IViewHelper helper = ExecuteBind(FIND_COMMAND); bool okay = helper.IsNominal; if (!okay) Page_Alert = helper;
Here is a typical idiom for reading input from a form:
IViewHelper helper = ReadExecute(SAVE_COMMAND); bool okay = helper.IsNominal; if (!okay) Page_Alert = helper;