This document describes basic requirements
for the Barracuda Component Model model layer.
- Overview
- Key Differences
- Presuppositions
- High Level Goals
- Component Requirements
- Open Issues
Overview
Developers who come from a client-server background are probably familiar with
component models used in those environments (Swing, AWT, MFC, etc). In such a context, a
component model provides a convenient series of "widgets" which make it easy to
get data onto the screen--put the data into the component, and it will take care of the
rendering. In addition, many client-server component models address other issues as well:
- event handling (ie. getting notified when various things happen to a component)
- layout (ie. Layout Managers control how components are placed on a screen)
- RAD development (ie. components which facilitate GUI design tools, like Visual Basic or
other "drag & drop" style tools)
- containment (ie. Swing introduces a powerful notion for components, whereby any
component can contain any number of other components)
- data binding (ie. how components can be bound to data sources, like a JDBC ResultSet or
database Cursor)
It is worth noting that the client-server view of components presented here tends to be
fairly low-level, where specific components are often concretely defined by a handful of
classes and interfaces.
We should point out that there are other, higher-level definitions, which tend to view
components from a much looser perspective. When approached from this angle, a
"component" can really be any block of semi-reusable code--people often speak of
a package, framework, or even an entire application as a "business component",
even though it may be composed of hundreds of classes and may not actually implement any
kind of "component" interface. (As an example, there are no standards defining a
"Logon Component" or "User Component"...these are high level terms,
and as such the component terminology is appropriate in a much looser sense than we find
at the "UI Widget" level).
Interestingly, most of the component work being done in the web-app paradigm today is
taking place at this higher level; J2EE for instance, touts itself as an "enterprise
component model"--this is certainly true, but in a broad,
high-level sense. There are
very few approaches to building web-apps that are seeking to create a "component
model" in the more traditional, "widget" level sense of the word.
With Barracuda, our goal is too create a set of low-level widgets whose primary purpose
is to facilitate the rendering of client-views from within the presentation layer of a web
app. As such, the Barracuda component model will follow the lead of traditional
client-server component models--especially that of Swing--to create strongly typed classes
that implement a series of well-defined interfaces specific to this problem domain.
Consequently, when you hear us talk about the "Barracuda Component Model" it
is imperative to remember our definition--we are speaking of a low-level, well
specified,
UI widget framework that is tailored for the intricacies of the web-app paradigm.
Key Differences
While it is true that most web-app development work tends to view components in a high
level (more abstract) sense, there have been some interesting
experiments in trying to
apply existing client-server models directly to the web-app approach. Hammock, WingS, and
several others provide notable examples of these attempts. The results, however, have been
fairly disappointing.
While some will conclude from this the impossibility of making "widget"
components work in a web-app environment, we believe the problems come from failing to
recognize--and account for--the differences between the client-server and web-app
paradigms. In fact, there are a number of important differences which must be considered
when designing a component model.
multiple clients using the same server - in traditional
client-server applications, client's were usually "fat", meaning that the
component layer could live on the client. In the web-app model, however, the client is
usually limited to simple markup. As such the component model must live on the server.
stateless connection - we also face a problem in the stateless
nature of the web-app paradigm: because clients interact with the server using the
req-resp paradigm, there is no real clean mechanism for bi-directional communication
(something which traditional component models rely on)
different memory models - traditional widget models tend to rely
on "heavier weight" components, since the components tend to live on "fat
clients". In the web model, components live on the server, and as such much be as
light as possible in order to scale for a large number of clients (this is one of the
reasons why it is difficult to port existing component models like Swing--which is
actually relatively light--to the server). There may well be cases where some components
may be shared between clients.
different lifecycle models - in addition, component lifecycle
varies--in the client-server model, components were typically instantiated at client
startup and retained for the duration of the application. In the web-app model, components
may need to be scoped to a per-request, per-session, or even a per-application
lifecycle, depending on the specific problem domain.
Consequently, we need to be able to handle all of these different scenarios.
data vs. layout rendering roles - in client-server models, a
component is responsible for rendering not only data, but also the actual user interface
that corresponds to the widget; in the web-app model, the user interface rendering is
usually delegated to client-specific markup. As such, a component's sole task is really
just rendering the data into the markup.
component packaging - since web-app components are only concerned
with rendering data, it becomes much more difficult to package a "component"
into a single reusable jar/zip. In the client-server paradigm, this was fairly
straightforward since everything pertaining to the UI was contained in class files. In the
web-app paradigm, we have a complex mix of classes, HTML templates, images files, etc.
This makes packaging very difficult.
???
Presuppositions
Given the difference in rendering roles identified above (data vs. layout), we can
identify several core presuppositions:
Since application layout and design is delegated to client side markup
technologies (HTML, WML, XML, etc), the primary responsibility for components will
be to render data into the markup structure. The server puts data into the markup
templates; the client container renders the resulting templates into the actual client
interface.
The best way for the component model to interact with the client
templates is through the DOM interfaces, since these provide a standard object
model that can be used to process a wide variety of specific file formats. In the future
we may also want to support components' rendering into flat file structures as well.
XMLC provides an excellent mechanism for compiling client side
templates into DOM structures which may be manipulated through the DOM
interfaces. Such DOM "precompiling" yields significant performance benefits.
Consequently, Barracuda will use XMLC as the default template-to-DOM conversion mechanism.
The general rendering cycle will probably look something like
this:
- load a DOM template
- assemble a hierarchy of Barracuda components, each of which may be bound to a specific
node in the DOM template
- render the Barracuda component hierarchy (thereby inserting data into the DOM)
- render the DOM template (thereby sending the results back to the client)
The actual implementation specifics of such a rendering cycle could vary dramatically
(ie. a programmer could invoke each of the steps manually (ie. push-mvc), or a
"template engine" might perform all of the steps in the proper order, allowing
the developer to simply respond with components as individual data points are encountered
in the template (ie. pull-mvc), or there might be some combination of the two).
We think Swing is a great client-server component framework,
and as such expect our web-app component model to share a great deal of commonality where
appropriate, especially in defining strongly typed Model interfaces (which are themselves
persistence layer neutral).
Because of the data vs. layout distinction inherent in the web-app
paradigm, however, we expect components will be tailored more
towards data rather than representation. As an example, in Swing we encounter a
number of Button components (JButton, JToggleButton, JCheckBox, JRadioButton, etc). The
distinction between these components lies primarily in how they look and feel to the user.
In a web-app paradigm (where the user-interface is markedly simpler), we might easily be
able to handle all these scenarios with a simple "Action" component that allows
the developer to set text and specify an action to be fired. This means we will
probably have a smaller number of UI widgets than we might find in a
client-server component model like Swing.
???
High Level Goals
There are several high level goals.
- Create a set of basic components that can be used to
manipulate/populate the dynamic portions of a template
"View".
- Look to the Swing model for guidance, while recognizing the
unique aspects of the web-app paradigm
- Ensure that the templates remain 100% valid markup and free
from server-side presentation logic.
- Support both "push" and "pull" mvc
approaches.
- Make it possible for developers to avoid the low-level programming details inherent with
the DOM interfaces.
- Provide strongly typed "Model" interfaces where
appropriate (ie. for more complex data structures)
- Allow components to support the notion of listeners, which are
capable of handling "events" that are generated on the
client.
- Support the notion of component reusability (where a
"component" could be a high level assemblage of
Barracuda components, as well as static resources like
templates, images, etc). Allow for such reusable components to
be packaged into standalone JAR files.
- Support the notion of custom renderers to handle different
types of clients. For example, a given component hierarchy
should be able to render either HTML, WML, or XML, depending on
the client (and its capabilities). Such renderers should be able
to be set dynamically, without requiring compilation changes to
the base components.
- Implement the components in such a way as to facilitate
integration with IDEs (again, similar to Swing).
- ???
Component Requirements
Given our goals and presuppositions, we can identify a number of basic requirements.
In General...
- Components - should support the notion of ...
- Name - should be able to name components
- Hierarchy -
- All components should have a parent, except for the root component (whose parent will be
null)
- A component should be able to contain any number of other components (as in Swing)
- Rendering a component consists of rendering that component plus all of its child
components
- Views -
- A component may have 1 or more views
- When the component renders, it is responsible for representing its data in each view
towhich it is bound
- Validity -
- "Invalidating" a component causes the component and all its parents to be
marked invalid (just like in AWT)
- "Validating" a component cause the component and all its children to be marked
invalid (just like in AWT)
- A component is considered invalid until it has been rendered
- A validated component does not need to be re-rendered
- Visibility -
- A component may be visible or invisible
- If a component is invisible, the views to which the component is bound should not be
displayed when the DOM is rendered
- When setting a component's visibility, it should be configurable as to whether that
setting applies to just that component or to all its child components as well
- Enabled/Disabled -
- A component may be enabled or disabled
- If a component is disabled, it may (or may not!) affect how the views are rendered
(depending on the specific nodes to which each view is bound)
- When enabling or disabling a component, it should be configurable as to whether that
setting applies to just that component or to all its child components as well
- Data - (opt)
- Most components will be associated with some kind of data
- Simple data can be stored directly in the component
- More complex data will often be stored in a component's Model
- Rendering -
- Render all data associated with the component into each of the component views
- This rendering should occur in light of client/request specifics identified in the
ViewContext
- Components should take advantage of custom renderers to handle different client types
- Render all child components as well
- State -
- All components should be capable of carrying additional "state" information
(key-value pairs) which is distinct from a components' data.
- This allows developers (or tools!) to associate information with a particular component
without actually modifying the component's data
- Single-threaded -
- components should generally be considered single threaded; they should not be expected
to render in a threadsafe fashion (ie. to support multiple render requests simultaneously)
- Q's - Open issues...
- what about making components Cloneable? Serializable?
- what about the supports() method?
- Models -
- A model's primary responsibility is to act as a data store for the component; a
developer puts data into the model, and the component takes data out when it is time to
render
- When a model is updated it should notify the component (which usually causes it to be
invalidated)
- A model should be able to return several different kinds of data (just like in Swing):
- String data
- DOM Nodes (markup)
- Other components
- Every model should contain a reference to the current view context (except a
ListSelectionModel)
- A model will generally only service one component at a time (not asynchronous, so even
if you have multiple components using the same model, those components could not both be
rendering at the same time).
- Views -
- A view is bound to exactly one Node in the DOM
- In the future we may want to support views bound to other types of data structures (ie.
flat files)
- As with components, views should be nameable
- Every view should be Cloneable
- Every view should provide an ElementFactory (for the view context; allows the model
implementations to extract information from the DOM if necessary)
- Some components may require specific types of views which have added functionality (ie.
TableView, TemplateView)
- Q's - Open issues...
- what about making views Serializable?
- View Context -
- A ViewContext is an object that encapsulates information about the context of the render
request. Specifically, it must identify:
- Client capabilities
- The event context (if the request to render resulted from an event)
- The element factory
- The template node the current view is bound too
- The general idea is that when you want to render a component hierachy you must provide
it with a ViewContext...this information may be needed by the component or the component's
models in order to correctly render the component into a view
- Each component then will pass the view context information into each of its models prior
to the component actually rendering
Specifics...
- Components - There are a number of specific components...
- BComponent -
- this component is the base class from which all other components must extend
- in terms of rendering, there is no visible representation of data (except for basic
component visiblity)
- Components w/ Models -
- BList -
- Takes a ListModel
- Push-mvc approach to rendering--the component clears the view, then takes data from the
model and pushes it in place
- The basic idea is to try and render the data into a list structure appropriate to the type
of node to which the list is bound.
- Can be used to render into a variety of DOM elements: [TODO--link to
list]
- BSelect -
- Extends BList, takes a ListSelection model in addition to the basic ListModel
- Uses this selection model to keep track of what's selected in the component
- Also provides the ability to specify the view size (ie. in the case of an HTML select
element, how many rows are visible; if not set, render defaults this value to what's in the
markup)
- Can be used to render into a variety of DOM elements: [TODO--link to
list]
- Allow for any number of EventListener's to be notified when the underlying markup element
is activated on the client (interfaces with Barracuda's event model to add event handler
support)
- BTable -
- Takes a TableModel -OR- can take 2 table madels (for header, body, and footer,
respectively)
- Push-mvc approach to rendering--the component clears the view, then takes data from the
model and pushes it in place
- In practice, this has proved to be one of the least useful components (much easier just to
use BTemplate with directives)
- BTemplate -
- Supports 1 or more TemplateModels, which are accessed by name
- Pull-mvc approach to rendering--instead of populating the view by looking at the model,
the component instead processes the view looking for directives. When it finds a directive it
attempts to map it to the appropriate model, which then returns some kind of data, and the
template component figures out how to render it in view
- Only a very simplistic directive set should be supported:
- Get_Data (and add it as an element to the view)
- Set_Data (as an element attribute)
- Iterate_Start (start an iteration)
- Iterate_Next (move to the next item in an iteration)
- Iterate_End (repeat the current iteration)
- In many cases, a template model will not only return text but may very well return other
complex Barracuda components (ie. BAction, BLink, BList, etc)
- Components w/out Models -
- BAction -
- Has a notion of an "Action" (either a URL or a Barracuda event) to be invoked on
the client
- Should allow key/value parameters to be added onto this action (ie. as URL params when
finally rendered)
- Should support the notion of disabling the back button [TODO--link
to doc]
- Can be used to render into a variety of DOM elements: [TODO--link to
list]
- Allow for any number of EventListener's to be notified when the underlying markup element
is activated on the client (interfaces with Barracuda's event model to add event handler
support)
- BLink -
- Extends BAction; used primarily to render "links"
- Adds notions of "link text" and "link target"
- Can be used to render into a variety of DOM elements: [TODO--link to
list]
- BInput -
- Adds notion of Input type (Text, Password, Submit, Reset, File, Hidden, Image, Button,
Radio, Checkbox)
- Adds the notion of Input value (ie. text to go in the input control)
- If either of these values are not set, the component rendering process defaults to what's
in the template
- Can be used to render into Input DOM elements: [TODO--link to list]
- Allow for any number of EventListener's to be notified when the underlying markup element
is activated on the client (interfaces with Barracuda's event model to add event handler
support)
- BToggleButton -
- Extends BInput; used primarily to render toggle buttons (Radio, Checkbox)
- Adds notion of selected/unselected
- Can be used to render into Input DOM elements: [TODO--link to list]
- BText -
- Used to render text into a variet of DOM elements: [TODO--link to
list]
- BScript -
- Used to ensure that a require script is available on the client
- Models - There are several distinct types of models...
- ListModel -
- Allows a component to iterate over a set of data
- Must return the size of the set
- Must return items based on position in the set
- Should be able to be "reset" to a pre-iterated state
- ListSelectionModel -
- Used to keep track of selected items in a list
- Supports notions of single and multiple selections
- Very similar to Swing's ListSelection model
- TableModel -
- Allows a component to iterate over a tabular set of data
- Must return the row count
- Must return the column count
- Must return items based on a row/col position in the set
- Should be able to be "reset" to a pre-iterated state
- TemplateModel -
- Must have a name (String data) to distinguish it from other models...directives will
typically target a model by name
- Must provide a method for the model to determine whether or not it will process a
directive (ie. based on view context)
- Must return data based on key name (String data)
- A template model may optionally implement IterativeModel if it services a collection of
data
- IterativeModel -
- Provides a simple mechanism to iterate over a collection of data
- Defines 4 basic methods:
- preIterate
- hasNext
- loadNext
- postIterate
- When a template component renders, it may use these methods (in response to directives)
to iterate over a collection of data in the model
- Views - There a also several distinct types of views...
- View - the default view class which is used for all components except
BTemplate and BTable
- TableView - a view that can optionally be bound to multiple nodes (for
header, body, and footer)
- TemplateView - extends the basic view to add support for template
specific notions (ie. directives)
Open Issues
- scripting components (ie. for client side validation)
- component identifying what it can be bound to (ie. what types
of markup, what elements in a given type of markup)
|