UIX Developer's Guide
Go to Table of Contents
Contents
Go to previous page
Previous
Go to next page
Next

3. Creating Pages in UIX

This chapter presents the core visual component of UIX: the page. It describes what "page" means in UIX, how to define pages, and how to render them as user interfaces. This chapter contains the following sections:

What "Page" Means in UIX

On the web, the concept of "page" can be fairly straightforward. The simplest pages are collections of HTML elements that are interpreted and rendered in a web browser. However, in the context of web application development, the concept of "page" can be more complex, depending on how the page is defined and rendered and depending on the device(s) used to present it.

In UIX, a page is the logical representation of a unit of an application's user interface. It is a logical representation because it defines many of the characteristics of the unit--such as the parts of a visible page and the relationships among them--but it does not necessarily define exactly how the page will be presented. For example, the same logical page can be presented as an HTML page, as a WML (Wireless Markup Language) page, or via a voice interface.

A UIX page is only one unit of a user interface, because an application generally consists of multiple units of related parts, each of which can be represented as a separate page. For example, a page might represent one step in an extended flow of tasks.

These distinctions are important in UIX, because different UIX technologies are available for developing different aspects of a web application. The primary UIX technology for creating pages is UIX Components, which is described in this chapter. The technology for managing application flow among pages is UIX Controller, which is covered in depth in the UIX Controller chapter. You can use these technologies by themselves if you only need the functionality provided by one or the other, or you can use them together to simplify development of all these aspects of a web application.

Pages as Hierarchies of User Interface Nodes

In UIX, a logical page consists of a hierarchical set of components known as user interface nodes. Some nodes define visible components, such as buttons, images, tables, and text fields, while others organize the layout and appearance of other nodes and may also manage their behavior. UIX provides many common nodes, but it is also possible to define and create custom nodes.

Nodes can have parents and children, and multiple nodes together form a tree-like structure used to represent a page's logical structure. For example, Figure 3-1 shows a logical hierarchy of user interface nodes. Figure 3-2 shows that hierarchy rendered as an HTML page. (For the sake of simplicity, this illustration leaves out some details of how to define this page. See About Layouts, Children, and Roles, below, for a more information about what is missing. Also see Example of Creating a User Interface Node Tree to see the actual code.)

Figure 3-1: Logical hierarchy of Nodes in a UIX Page

Logical hierarchy of UINodes shown in previous figure

Figure 3-2: Visual Hierarchy of Nodes in a UIX Page
Schematic drawing of parent nodes containing child nodes in UIX page

A note about terminology: All visual UIX user interface components, such as buttons and tabs, are user interface nodes. However, UIX provides other user interface nodes that are not familiarly understood to be user interface components. For example, the stackLayout node controls how its child nodes (such as the text and image user interface components) are laid out, but it is not itself visible. Therefore, some sections in this Guide use "user interface component" and "user interface node" interchangeably, while other sections talk about one or the other, depending on the context. "User interface node" is generally reserved for discussions about the nodes that comprise a logical page. "User interface component" is generally reserved for discussions about visible user interface components. When user interface nodes or components are discussed in a Java context, the terms "UINode" and "bean" may be used. See Creating User Interface Nodes in Java, below, for more information about these Java terms.

Characteristics of User Interface Nodes

While user interface nodes differ depending on their function, they share some common characteristics, described below.

Names and Namespaces

User interface nodes are uniquely typed by two properties: name and namespace. Nodes of the same type share the same functionality as all other nodes of that type, of which there can be many. For instance, all button nodes are the same type, but there can be many buttons.

The name property is self-explanatory: button nodes all share the name "button", and image nodes all share the name "image". But since you or other developers might define nodes with similar names, a mechanism is needed to make sure that all these names don't collide. That mechanism is namespaces, and it is part of the XML standard.

In short, a namespace is a unique string that is used to partition names into groups, or "spaces," whose members are unique. Each developer who defines user interface nodes must first define a unique namespace string. To ensure they are unique, the namespace strings are often chosen to be URLs that are owned by the developer defining the namespace. For instance, the UIX Components namespace is the string http://xmlns.oracle.com/uix/ui. That string was chosen by the UIX development team, because they know they are the only developers who could own that URL. There is no requirement that there be anything actually sitting at that URL or that the URL is accessible to the user. The choice of an URL is simply a convenient way to assure uniqueness.

The namespace and the name of an element in that namespace together form a unique pairing. A node named button in the UIX Components namespace (http://xmlns.oracle.com/uix/ui) is one such pairing. As such, it can be distinguished from the button node in any other namespace (such as http://www.example.org). Thus, developers can define elements without worrying about name collisions.

Namespaces are a standard XML technology. For more detailed information, consult the World Wide Web Consortium web site at http://www.w3.org.

Properties of Specific Node Instances

Aside from being uniquely identified by type, user interface nodes also have attributes or properties that describe a specific node instance. For example, a button node has attributes describing the text of the button, the destination the user might be taken to when the button is activated, and whether or not the button is enabled for use.

Parent and Child Nodes

As previously mentioned, nodes can have children (but are not required to do so). While it might not make sense for a button to have any children, a header component might have children representing all the nodes grouped under its heading.

Rendering of Nodes

Another core characteristic of a node is that it can be rendered. That is, a node—which is a logical entity—can generate output that will represent it to a user, such as HTML code. The mechanics behind rendering are discussed later in this chapter.

The UINode Java Interface

UIX includes Java classes corresponding to user interface nodes. These classes implement the base UINode interface in the oracle.cabo.ui package. The UINode interface contains methods corresponding to the characteristics already described, such as:

public String getNamespaceURI();
public String getLocalName();
public int getIndexedChildCount(RenderingContext context);
public UINode getIndexedChild(RenderingContext context, int childIndex);
public Enumeration getAttributeNames(RenderingContext context);
public Object getAttributeValue(RenderingContext context, AttributeKey attrKey);
public void render(RenderingContext context)
  throws IOException;

These UINode methods, and a few others not yet listed, are covered in more detail later on. However, it is worth noting that this interface is immutable, or read-only. This means that while UINodes must allow their names, namespaces, attributes, and children to be accessed, they cannot be changed through this interface. This immutability helps UIX work better in a multi-threaded server environment.

Creating User Interface Nodes in uiXML

Many (but not all) of the elements in a uiXML document are transformed into user interface nodes when the document is processed by UIX. The other elements are used to support the user interface node elements, such as to specify the data they will receive.

Here is an example of a uiXML element that defines a simple button:

<button xmlns="http://xmlns.oracle.com/uix/ui" text="OK"/>

where:

Examples of Simple Nodes

UIX provides many high-level user interface nodes that create advanced user interface components when a page is rendered. But the most basic UIX documents do not need to have any high-level nodes in them, because UIX provides simple nodes--the text node and various HTML nodes--for the lowest-level page content. The text node creates text in a page, and the HTML nodes allow HTML to be directly rendered into a page. Here is an example of using one of these simple nodes to create a simple uiXML document:

<text xmlns="http://xmlns.oracle.com/uix/ui"
          text="hello, world"/>

Here are a few things to note about this document:

  1. The root element of the document, a <text> element, is also the only element in the document.

  2. The xmlns="http://xmlns.oracle.com/uix/ui" attribute on the <text> element tells UIX that this element, and any sub-elements inside it, will default to being in the namespace "http://xmlns.oracle.com/uix/ui". This is the UIX Components namespace described earlier. Namespaces can be said to cascade, which means that elements which do not declare their own namespace adopt the namespace of their closest ancestor element.

  3. The <text> element contains one attribute, text="hello, world" which indicates to UIX what the text should actually be.

The following example shows uiXML that creates a page with some rudimentary HTML elements in it. (Note that the indented formatting is used to clarify that elements are children of other elements, but is not required.)

<div xmlns="http://www.w3.org/TR/REC-html40">
  Hello world.
  <ul>
    <li>First HTML list element</li>
    <li>Second HTML list element</li>
  </ul>
</div>

Here is what is new:

  1. New user interface nodes are used in this page. The <div> element is a standard HTML DIV element which groups its children in a block. It serves as the root node here, and it contains text and some additional HTML user interface nodes. These <ul> and <li> elements cause the generated page to include an HTML unordered list with two list items.

  2. A different namespace declaration is used in the root <div> element, which describes the HTML namespace xmlns:html="http://www.w3.org/TR/REC-html40". In the UIX page rendering framework, any element declared in the HTML namespace will be "passed through" directly to the output when rendered, after having its text transformed, or "escaped" by UIX to make it conform to HTML text rules.

  3. Notice that that <li> element requires a corresponding </li> element here, even though it does not according to HTML rules. This is because not closing an element tag would violate the XML rules for a well-formed document. Thus, HTML included in a UIX document must actually be XHTML, a form of HTML that is also well-formed XML.

Examples of Higher-level Nodes Provided by UIX Components

The above example shows the simplest user interface nodes declared in a UIX page--text and HTML--but the interesting content comes when higher-level nodes provided by UIX Components are added. The following shows one of the most basic UIX Components nodes, a button, added to the example:

<div xmlns="http://www.w3.org/TR/REC-html40"
     xmlns:ui="http://xmlns.oracle.com/uix/ui">
  Hello world.
 <ul>
   <li>First list element</li>
   <li>Second list element</li>
 </ul>
 <ui:button text="Push me" destination="http://www.example.org"/>
</div>

Here's what is new:

  1. A second namespace declaration has been added in the root <div> element. It is the UIX Components namespace "http://xmlns.oracle.com/uix/ui". Further, :ui has been added to the end of the name of the xmlns attribute, that is, xmlns:ui. While the first namespace declared on the <div> is still the default for it and its enclosed elements, any enclosed element that requires the UIX Components namespace can use it simply by prefixing ui:" to its name, according to namespace rules. This is merely a convenience mechanism which allows elements to declare different namespaces easily further down in the document without a lengthy attribute.

  2. A UIX Components <button> element with two attributes, text and destination, has been added. These attributes describe two properties for the button. Note that it is in the UIX Components namespace, even though the other elements are in the HTML namespace.

When this page is rendered, it will contain a visual button with the text "Push me" on it, which will activate the URL http://www.example.org when it is pushed.

The button is one of the simplest UIX Components user interface nodes available. Documentation on other, more complex nodes is included later in this Guide.

Creating User Interface Nodes in Java

While it is easy to create user interface nodes with uiXML, you can also create them directly with Java code. Every UIX release contains classes that can be used to create UINodes. (Remember, UINode is the Java interface used to define user interface nodes.) All of these classes reside in the oracle.cabo.ui.beans package and its subpackages, with a few exceptions: the simple text node resides in oracle.cabo.ui.TextNode, and the HTML UINode is located at oracle.cabo.ui.html.HTMLWebBean. To be more consistent with the Java terminology, most classes implementing the UINode interface in Java are referred to as "beans," in reference to the JavaBeans standard for discoverable code units.

To create UINodes in Java, you will generally construct an instance of a class representing the type of node you wish to create; for example, to create a button node, you will create an instance of a ButtonBean. To set attributes on the node, you should call any of the available "set" methods available on the bean which map to the attribute you wish to set. For instance, the following code shows the previous example page's content area created in Java instead of UIX:

import oracle.cabo.ui.TextNode;
import oracle.cabo.ui.html.HTMLWebBean;
import oracle.cabo.ui.beans.nav.ButtonBean;

// ... skipping class declaration

  HTMLWebBean div = new HTMLWebBean("div");

  // the text node is the first child of the "div"
  TextNode helloText = new TextNode("hello, world");
  div.addIndexedChild(helloText);

  // the unordered list is next
  HTMLWebBean unorderedList = new HTMLWebBean("ul");
  div.addIndexedChild(unorderedList);

  // the unordered list gets two list item children
  // note that the list item text is added as text nodes here
  HTMLWebBean firstListItem = new HTMLWebBean("li");
  firstListItem.addIndexedChild(new TextNode("First list element"));
  HTMLWebBean secondListItem = new HTMLWebBean("li");
  secondListItem.addIndexedChild(new TextNode("Second list element"));

  unorderedList.addIndexedChild(firstListItem);
  unorderedList.addIndexedChild(secondListItem);

  // finally create the UIX Components ButtonBean with our two attributes
  ButtonBean button = new ButtonBean();
  button.setText("Push me");
  button.setDestination("http://www.example.org");
  div.addIndexedChild(button);

As the next section shows, the result is the same, whether uiXML or Java code is used to create the nodes.

Creating a User Interface Node Tree

User interface nodes are the basic building blocks used to create a UIX page. The page itself is created by building a hierarchical "tree" of nodes. The remainder of this chapter discusses how to build such a tree (which represents a logical page) and render it as physical output.

Creating hierarchies of nodes is possible because many nodes can be parents to other nodes, which are then considered their children. An example earlier in this chapter showed the <button> element (which is a node) as a child of the <div> element. By making child nodes themselves parents of other nodes, more complex structures can be formed. Not every user interface node allows other nodes to become its children, however; this is largely dependent on the type of nodes in question. For instance, buttons in logical pages would not normally allow other content inside them, consequently the button node does not accept children, either.

Although some user interface nodes don't accept any child nodes, other nodes are designed specifically for managing a set of child nodes. Such nodes are often referred to as "layout nodes." Layout nodes may or may not cause any visible output on a generated page themselves, but they always manage the placement of any child nodes they contain. One common example of a layout node is a "stack layout" node, which takes multiple child nodes and lays them out in a vertical row from top to bottom on the page generated for the user. Other examples of layout nodes are discussed in the reference documentation for the UIX Components uiXML elements.

User interface node trees don't enforce that a given node has only one parent. Nodes can be added as children of other nodes at multiple places in the same tree, thereby allowing one section of a page's description to be easily replicated in another portion of the tree. This can be useful if you have identical content in multiple places in the same page.

Creating Trees as Java Objects on a Server

No matter how your node tree is defined, the result is the same: a set of Java objects residing on the server. Each of these objects is a oracle.cabo.ui.UINode. The actual tree of Java objects is created in one of the following ways:

About the Root Node in a Tree

The entry point for any tree is referred to as the "root" node. It is the highest parent in the node tree hierarchy, and it is also the UINode returned as a result of the UINodeUtils.createUINode() method. But most important, it is the node at which the rendering process starts, which is how a tree is used to generate output for an end user. Once a UINode tree is created, it should be kept in memory for the lifetime of the entire application. The UIX technology stack is designed to reuse the same tree for as many page renderings as is needed without having to recreate or alter it. Doing so reduces the performance cost for using UIX Components pages to generate a user interface. More information on the reuse of node trees is provided in this and subsequent chapters.

About Layouts, Children, and Roles

User interface nodes that manage the position of their children in a page are called layout nodes (or layout components, layout elements, or simply layouts, depending on the context). Examples include stackLayout, borderLayout, pageLayout, and table. UIX provides two primary ways to arrange children in a layout. In the first, the children are simply laid out one after another in a sequence. In the second, the children are placed in certain predetermined positions, for example, top, bottom, left, right, and so forth. Children that are laid out in a sequence are called "indexed children." Children that are laid out in specific, named positions are called "named children." These terms are convenient ways to refer to children in those positions, but they don't actually refer to any inherent property of the children themselves. For example, you can arrange four images in a vertical row, as indexed children, or you can arrange them at the top, bottom, left side, and right side of a layout, as named children. The images are still just images, but they are called indexed children or named children to identify the role they have in the layout.

To define a layout in uiXML, you must use one or more elements called role elements to tell the layout how it should arrange its children. The role element is not a user interface node. Rather, it serves to mediate between the parent node and its child nodes. For example, here is a listing of embedded uiXML elements:

<borderLayout>
  <top>
    <image ... />  
  </top>
  <left>
    <text ... />  
  </left>
  <right>
    <text ... />  
  </right>
</borderLayout>

Those elements form this hierarchy:

Figure 3-3: Tree of uiXML Parent, Role, and Child Elements

Schmatic drawing of tree of uiXML parent, role, and child elements

Here is the node tree that is created:

Figure 3-4: Tree of UIX User Interface Nodes

Schmatic drawing of tree of UIX user interface nodes

There is no equivalent to roles in the UIX Java API. Children are placed in position directly using methods such as setTop(), setBottom(), and addIndexedChild().

Adding Indexed Children to a Layout

Indexed children are used when a parent node needs to manage its child nodes based only on the order in which they are stored in the parent. Otherwise, the children are treated identically. An example of a node that supports indexed children is the stackLayout node. The stack layout places its children in a vertical row from top to bottom, and the only information it needs to accomplish this is the order of the children it manages.

To specify indexed children in uiXML, insert a <contents> element inside the parent element, then add the child elements inside <contents>. The <contents> element is the role element required for adding indexed children to a layout. It is also the only role element available for adding indexed children.

List the indexed child elements under <contents> in the order in which they should be laid out. For example, the following uiXML document shows a stack layout managing three indexed button children:

<stackLayout xmlns="http://xmlns.oracle.com/uix/ui">
 <contents>
   <button text="Indexed child 1"
            destination="http://www.example.org"/>
   <button text="Indexed child 2"
            destination="http://www.example.org"/>
   <button text="Indexed child 3"
            destination="http://www.example.org"/>
 </contents>
</stackLayout>

Using Java code, the same indexed children can be added using the addIndexedChild() method available on most beans.

  import oracle.cabo.ui.beans.layout.StackLayoutBean;
  import oracle.cabo.ui.beans.nav.ButtonBean;

  // ... skipping class declaration

    StackLayoutBean parentStack = new StackLayoutBean();
    parentStack.addIndexedChild(new ButtonBean("Indexed child 1",
                        "http://www.example.org"));
    parentStack.addIndexedChild(new ButtonBean("Indexed child 2",
                        "http://www.example.org"));
    parentStack.addIndexedChild(new ButtonBean("Indexed child 3",
                        "http://www.example.org"));

Adding Named Children to a Layout

Named children are used to create parent-child relationships that need more context than just the order of the child. For instance, a border layout node might lay out its children in regions like "top," "bottom," "left," and "right." Since the order of the children does not naturally imply which one would go in a particular region, these children must be added using roles to indicate their positions.

To specify named children in uiXML, insert the appropriate role element inside the parent and then insert the child element inside its role. While layout elements can contain only one <contents> role (for adding indexed children) they can contain multiple roles to indicate different named roles (for adding named children). Only one direct child can be placed in any named role.

A border layout node with named text children in four regions would appear as follows. The role elements in this example are <top>, <bottom>, <right>, and <left>,

<borderLayout xmlns="http://xmlns.oracle.com/uix/ui">
 <top>
   <text text="Top text"/>
 </top>
 <bottom>
   <text text="Bottom text"/>
 </bottom>
 <right>
    Right text
 </right>
 <left>
    Left text
 </left>
</borderLayout>

Note that the order the named children are listed in the parent is irrelevant. Also in this example, notice that text does not always have to be placed in a <text> node; as long as the text to display is properly inside a role element, it can just be entered directly into the uiXML file, as it is for the left and right text children.

Java code to accomplish the same takes advantage of the fact that beans will usually have special methods for setting named children:

import oracle.cabo.ui.TextNode;
import oracle.cabo.ui.beans.layout.BorderLayoutBean;

// ... skipping class declaration

  BorderLayoutBean parentBorder = new BorderLayoutBean();
  parentBorder.setTop(new TextNode("Top text"));
  parentBorder.setBottom(new TextNode("Bottom text"));
  parentBorder.setRight(new TextNode("Right text"));
  parentBorder.setLeft(new TextNode("Left text"));

Using Indexed Children and Named Children Together

Some layouts support both indexed and named children. The named children are laid out in their named locations, and the indexed children are laid out sequentially in the location appropriate for the layout. In the following example, the images are named children and are placed on the top, bottom, left side, and right side of the layout. The text strings are indexed children and are laid out left to right, in order, in the middle of the layout.

<borderLayout>
  <top>
    <image source="images/globalhelp.gif"/>
  </top>

  <bottom>
    <image source="images/warnl.gif"/>
  </bottom>

  <end>
    <image source="images/cobrand.gif"/>
  </end>

  <start>
    <image source="images/info.gif"/>
  </start>

  <contents>
    <text text="This is the first sentence. " />
    <text text="This is the second sentence. " />
    <text text="This is the third sentence. " />
  </contents>
</borderLayout>

Note: Why does UIX provide different means for identifying indexed and named children? Without named children, the only way to specify that a child should be placed at "right," for example, would be to choose an index number which stood for "right." Using recognizable names makes it more intuitive. Without indexed children, a predetermined name would have to be given to every child in a sequence, and that number could be boundless.

Example of Creating a User Interface Node Tree

This section presents a somewhat more extensive example of what is required to translate a visual page design to a tree of nodes. This example builds on the illustrations presented as Figure 3-1 and Figure 3-2.

First, it is important to study the desired layout of the target design and partition it into a logical node tree. Figure 3-5 shows a design containing a few "header" nodes for grouping content and some sample text and images that they might contain.

Figure 3-5: Visual Hierarchy of Nodes in a UIX Page

Schematic drawing of parent nodes containing child nodes in UIX page

In Figure 3-6, the same hierarchy of that design has been logically structured as a clear tree of nodes. Once the node tree is determined, it is time to develop the code to create this tree.

Figure 3-6: Logical hierarchy Nodes in a UIX Page

Logical hierarchy of UINodes shown in previous figure

The uiXML code to create such a tree follows. Remember, when you are using uiXML to define layouts with named or indexed children, you must use role elements to specify how to lay out the children. The following example shows only indexed children, so the role element <contents> is used for each layout element.

<header xmlns="http://xmlns.oracle.com/uix/ui"
        text="Header 1">
 <contents>
   <stackLayout>
     <contents>
        This is sample text. This is sample text.
       <header text="Header 2">
         <contents>
           <stackLayout>
             <contents>
                This is more sample text, for the
                purpose of the demonstration.
               <image source="shapes.gif" shortDesc="Three Shapes"/>
             </contents>
           </stackLayout>
         </contents>
       </header>
     </contents>
   </stackLayout>
 </contents>
</header>

The Java code to create the same node tree is as follows:

//        -- Create a tree of UIX Components Beans --

// Create the first header.
HeaderBean header1 = new HeaderBean("Header 1");

// Create the text for the first header.
TextNode text1 =
  new TextNode("This is sample text. This is sample text.");

// Create a stack layout for laying out the first header's
// children vertically.
StackLayoutBean stackLayout1 = new StackLayoutBean();

//Add the text as a child of the stack layout
stackLayout1.addIndexedChild(text1);

// Add the stack layout as the child of the fist header
header1.addIndexedChild(stackLayout1);

// Create the second, nested header
HeaderBean header2 = new HeaderBean("Header 2");

// Create the contents of the second header - some text and an image.
TextNode text2 =
  new TextNode("This is more sample text, for the purpose of the
                  demonstration.");
  ImageBean image = new ImageBean("shapes.gif", "Three Shapes");

  // Create a stack layout for laying out the children of the second
  // header.
  StackLayoutBean stackLayout2 = new StackLayoutBean();

  // Add the children to the second stack layout, and add the stack
  // layout as the child of the second header.
  stackLayout2.addIndexedChild(text2);
  stackLayout2.addIndexedChild(image);
  header2.addIndexedChild(stackLayout2);

  // Add the second header as a child of the first stack layout (which
  // is the child of the first header).
  stackLayout1.addIndexedChild(header2);

Rendering a User Interface Node Tree

Once a node tree is defined and created on a server, the tree must be rendered to a client so users can actually see (or hear) it. The UIX renderers can be used to render the node tree into HTML, WML, or some other form of output that an end user can experience.

Usually, the output sent to a client is much larger than the amount of UIX code used to specify a node tree. For example, UIX Components might render a brief UIX code segment as a complex group of HTML elements. This is one of the features of UIX: it transforms simple specifications into complex output code, and it hides this complexity from you, the developer.

To render a node tree that exists on a server, you must call the render() method on the root node of that tree, and you must pass it a RenderingContext:

UINode.render(RenderingContext context)

To do that, you must first create a RenderingContext and configure it properly.

About the RenderingContext

The oracle.cabo.ui.RenderingContext is a class used on the server to provide any stateful information to UIX Components for one render of a node tree. A node tree is created once and used on the server for the life of an application. The RenderingContext encapsulates all the per-render information that is short-lived.

The typical page rendering process is as follows:

  1. Create a tree of nodes describing a page.
  2. A request for a page render arrives, either from a servlet or other source.
  3. Create a RenderingContext based on information in that request.
  4. Pass the RenderingContext to the root node's render(RenderingContext context) method.
  5. UIX Components generates output for the request based on the node tree and the context.
  6. The RenderingContext is discarded.
  7. Return to step 2.

Once the render(RenderingContext context) method is called on the root node, the internal UIX Components renderer classes take over and do the work necessary to generate output. That process will be described more fully later in this chapter.

If you decide to use UIX Controller for managing your application flow, it will automatically create a RenderingContext for each request and use it to render the node tree for a page. If you do not use UIX Controller, you must perform these steps yourself or use the UIX test/demo classes during your debugging. One helpful class is oracle.cabo.ui.test.UIXTest, a Java application that takes the path to a .uix file as an argument and will open a browser window displaying the rendered result of that file.

However, if your development tasks are focused only on page creation, you may safely skip to the next chapter of this guide.

The RenderingContext Methods

The RenderingContext class essentially serves as a repository for other contexts and properties that will be needed during a page render. Many are described here, but there are additional methods that are either used only by the internal UIX Components code or that will be covered in chapters describing advanced UIX Components topics. Here is a summary of the RenderingContext methods discussed later in this chapter:

public interface RenderingContext
{
  // Some methods not listed...

  // ...

  public OutputMethod getOutputMethod() throws IOException;
  public Agent getAgent();
  public LocaleContext getLocaleContext();
  public ErrorLog getErrorLog();
  public DataObject getDataObject(String namespaceURI, String name);
  public RendererManager getRendererManager();

  // ...
}

OutputMethod

Every RenderingContext must supply to the UIX rendering code a destination for the generated output for that render. The oracle.cabo.ui.io.OutputMethod serves this purpose, as well as others.

The OutputMethod is an interface which the UIX rendering code utilizes when it generates output for one render. When created, an OutputMethod implementation is connected to some output destination, such as a web server response stream or a file on a file system. Then, any UIX renderer (for instance, the renderer which generates output for a button node) will access the OutputMethod from the RenderingContext and call the methods on it to write elements, comments, and text to that stream or file.

Some of the core OutputMethods perform special handling and text escaping that makes sure that any generated output is suitable for the destination. Examples of this are the oracle.cabo.ui.io.HTMLOutputMethod and the oracle.cabo.ui.io.XMLOutputMethod, which adjusts output from the renderers to make sure that they comply with the formatting rules of HTML and XML, respectively.

Other OutputMethods serve only as utilities and are intended to wrap the core implementations:

Both of these utility OutputMethods can be used at development time and then simply removed when an application is deployed on a production server, in order to avoid any associated performance penalty.

Here is some sample code that creates wrapped OutputMethods which will generate the result to an existing Java PrintWriter:

public OutputMethod createOutputMethod()
{
  // supply a print writer which will receive the rendering output
  PrintWriter myPrintWriter = getPrintWriter();

  OutputMethod coreOutputMethod = new HTMLOutputMethod(myPrintWriter);

  // wrap that core OutputMethod with utility methods if you desire
  return new PrettyPrinter(new DebugOutputMethod(coreOutputMethod));
}

Agent

The oracle.cabo.share.agent.Agent class stores all of the information about the target device for which this render is intended. That target can be a common web browser, a mobile device, or any other "agent" supported by the UIX Components project.

Like the OutputMethod, the Agent interface is also used by the UIX Components renderers when they are generating output. In order to provide the best rendering results, the UIX Components renderers commonly adjust the output they generate based on the Agent information they are given. For instance, a complex data table node will automatically be rendered in a more simple manner for less powerful browsers than for full-featured browser, and the quirks of the target platform can be taken into account.

Currently the Agent can account for variations in:

  1. Category/Type (such as browser, or wireless device)
  2. Specific application (such as Mozilla, Internet Explorer, or Palm VII)
  3. Application major version number
  4. Application operating system

However, it is up to the internal UIX Components rendering code to use this information if it is truly needed. For instance, many combinations of browsers and version numbers will probably render exactly the same.

LocaleContext

The LocaleContext is used by the internal UIX Components rendering classes to adjust the content based on the locale for which the current render is targeted. The most obvious example is that the UIX Components code will translate any of its own content to match the specified locale, but the LocaleContext also provides the UIX Components renderers information on the preferred date and time formats.

While the LocaleContext will default most of its settings based on the java.util.Locale that is passed into it when it is constructed, you can also override specific features of the locale if you would like a particular render to use a different date format, for instance.

ErrorLog

The ErrorLog is very similar to the OutputMethod, in that the UIX Components renderers use it as a central interface for logging any errors that they encounter when they try to render the page. UIX Components provides implementations of the ErrorLog interface that render to the console (oracle.cabo.share.error.BaseErrorLog) or to a servlet error log (oracle.cabo.share.error.ServletErrorLog).

Dynamic Data

The RenderingContext also contains methods for storing dynamic data that alters the contents of the node tree for a given render. This is the mechanism that allows different content to be generated to each user even though the node tree remains constant. See Data Binding for more information about this topic.

Implementations of RenderingContext

The two implementations of the RenderingContext interface provided by UIX Components are the oracle.cabo.ui.RootRenderingContext and the oracle.cabo.ui.ServletRenderingContext. Both of these classes default much of the context information but also allow you to customize the various subcontexts.

The RootRenderingContext should only be instantiated when you need complete control over the rendering information and you are not using a Java servlet to manage your web application. By default, it initializes itself in the following way:

However, you will probably always use the ServletRenderingContext (or let UIX Controller configure one for you), especially if you are using a Java servlet to run your web application or you are generating a Java Server Page (JSP). The ServletRenderingContext will default its contexts off of the information it can gather from a ServletRequest or a JSP PageContext:

Finally, here is some sample code that sets up and renders a page based in a Servlet for a given request:

public void renderStartPage(
  Servlet servlet,
  ServletRequest request,
  ServletResponse response,
  PrintWriter out
  ) throws IOException
{
  ServletRenderingContext context = new ServletRenderingContext(servlet, request, response, out);

  UINode rootNode = getStartPageTree();

  rootNode.render(context);
}

UIX Components Rendering Internals

This section describes the process by which UIX Components transforms a UINode tree and a RenderingContext into output for the end user. The material given here is provided mostly for informational purposes and is not required knowledge to use the UIX Components page rendering framework.

Although rendering starts with a call to UINode.render(), very little directly happens in that method. Instead, the UINode uses Renderers to write out its content. The Renderer class is a small Java interface that is responsible for:

So, how is a UINode attached to a Renderer? Remember that UINodes are identified by a pair of strings: a namespace and a name. Not coincidentally, the UIX RendererManager class can find a Renderer by namespace and name, and RenderingContext has a getRendererManager() method. So, in the vast majority of cases, all a UINode does to render is get the RendererManager, use it to get a Renderer, then hand off control to the Renderer.

Once the Renderer has control, it talks to the UINode to get attributes and children as needed, and calls the OutputMethod when it needs to write output. The UINode neither knows or cares what's in the output; it is only responsible for handing attributes and children to the Renderer when asked.

At any point, a Renderer may wish to render a child UINode. At this point, it calls either UINode.getIndexedChild() or UINode.getNamedChild() to get the child, then calls UINode.render() on that child. The process begins anew with that child - it gets its own Renderer, which gets grandchildren, etc.

This design has a number of implications:

More of the UIX features for rendering pages are covered in later chapters.