[1] Apparently Web Objects is no longer part of the Zoe framework, reducing the current info on this page to historical interest only.
Note from David Medinets: I took this information from an email on the Zoe Developer Mailing List.
- The basic unit in WebObjects? is a component. A component is typically made of three parts: an html template (.html), a definition file (.szd) that describe the bindings between the html and the Java code and finally a Java class (.java).
- One use composition (eg: a patchwork of component dumped together) to define a page or such. There is no html. HTML is generated by the underlying framework.
- To understand how ZOE's UI works, the most important concept to grasp is the notion of an "inspector". An inspector is a component that knows which object it can display. It also provides all UI information related to an object. What does it mean in practice? It means that the relationship between different components are resolve at runtime through an "object link" (aka SZLink). It means that there are no "hard coded" internal references (<a></a>) in ZOE. The "links" are resolved dynamically at runtime based on the type of object.
Lets take a closer look at
SZLink as an example of how an "inspector" works:
- SZLink component has only one mandatory binding which is what "object" you want to create a link for.
- From this object value, all the other informations are derived:
- Do I link to a external "href": SZInspector .hrefForObject
( this.value(), this.context() )
- Do I go to another internal "page":
SZInspector.inspectorNameForObject( this.value() )
- What description should I display for this link:
{{SZInspector .descriptionForObject( this.value() )}}
- And so on and so forth.
Example
The end result of all that would be, for example, a link to a "date" that could look like this:
Generated html rendered as "Sat Jul 27"
<a title="Saturday July 27th 2002"
href="/S/Z/ZO.E/SZ/98097B00010010D95D00EF005375CE55/2.0.5.1.1.1.
2.5.SZEnvelopeInspectorToolbar.5.1.0"><span class = "Label">Sat
Jul 27</span></a>
HTML template
<webobject name = "Date"></webobject>
The component definition
Date: SZLink
{
value = value.creationDate;
class = "Label";
};
So how does it work?
Lets take a look at
SZLink more closely:
- To figure out where to go, SZLink will ask SZInspector for a component name given an object: SZInspector.inspectorNameForObject() .
- SZInspector will query the runtime for the existence of a relevant component Class based on a naming convention: anObject.getClass() + aSuffix. In this case it will look for SZDateInspector? , the class of the value binding "SZDate", plus the standard inspector extension "Inspector". This is what SZInspector.inspectorClassWithObject() does
- with the help of SZRuntime.classForObjectInPackageWithSuffix() as I used this pattern quiet extensively.
- The same process will take place for all the other informations. For example to know what to display for a given link, SZLink will query SZInspector.descriptionForObject(). Again, {{SZInspector }} will retrieve which concrete inspector class handles a given object and ask this class for a description. Because there is no real class method in Java all this circus is done through the reflection API... :-( In any case, SZInspector will retrieve a concrete inspector class (SZDateInspector?) and invoke its descriptionForObject() class method.
All the other
SZLink methods follow the same pattern.
This turn out to be quiet a powerful setup as it let the system deal with how exactly links should be resolve and free the developer from such trivial matters. To handle a new type of object simply add a new concrete inspector and the entire system will know how do deal with it... A great time saver... :-)
This concept is used all over the places. For example there is a pretty useful table component that takes a collection of objects and a list of keys and automatically create a table out of all this information with all the right links at the right place thanks to
SZLink. So to get a full blown table you simply define:
Envelopes: SZTable
{
list = envelopes;
keysDescription = "self|recipientNames.iterator.next|sentDate";
headersDescription = "Subject|Recipient|Date";
};
This is the definition used in the name inspector (
SZNameInspector?.szd) to display a list of all the messages for a given "name". The "list" binding point to a collection of envelopes, "keysDescription" are the different keys (aka method names) that you want to display and the optional "headersDescription" is simply the display name for those keys. For each item in the list, the table will dynamically invoke each keys (through key value coding, check
SZKeyValue?) and create an
SZLink for it. In turn,
SZLink will query
SZInspector and figure out what should be displayed exactly... Et voila.
Now, lets take a look at a typical inspector:
SZDateInspector? . This concrete inspector handles, er, date objects. In ZOE, that basically all the stuff you get when clicking on a date, the main page (which is a subclass of
SZDateInspector? ), the SZListInspector
? and so on.
The html template don't have much stuff in it:
- there is a "PageLayout?"
- a "List" (which is really a table)
- a "Month" (which handles the calendar)
- and several List components that deal with displaying all the
information on the right side of a typical ZOE page (eg threads, contributors, ...)
The definition file (
SZDateInspector?.szd) tells you exactly what those components are and where they get their data from:
PageLayout: PageLayout
{
title = title;
page = name;
pathComponents = pathComponents;
};
This component provides the overall layout of every single pages. It handles the header with all its elements, the footer and the content layout. The page itself (eg
SZDateInspector? ) only provide the content.
List: SZEnvelopeList
{
list = envelopes;
};
SZEnvelopeList? is a "custom made" table for displaying envelopes. It's like a table but specifically tailored for envelopes.
Month: Month
{
month = value;
};
This is the calendar component.
ThreadList: SZList
{
title = "Thread";
list = threads;
minimumSize = 0;
};
Finally,
SZList is a simple "list" component that only display one value in a list. It also handles the "more..." link and so on.
And that's it. Those are the only things you need to define to have a fully functional inspector page. There is one more component associated to an inspector: its toolbar. Check
SZDateInspector? Toolbar for more details. The header component will look at runtime for a toolbar component given a page name: so for "
SZDateInspector? " it will try to find a "
SZDateInspector? toolbar".