/src_docs/architecture/comp/overview.html, v125
Component Model Requirements
This is something of a legacy document - it describes the initial set of
requirements for the Barracuda Component Model model layer, and may be
helpful in understanding the underlying philosophy which drove subsequent
design/implementation decisions.
-
Overview
-
Key Differences
-
Presuppositions
-
High Level Goals
-
Component Requirements
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.
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.
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.
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).
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)
Last Modified: 2006-01-02 15:59:13 -0500 (Mon, 02 Jan 2006)