Supporting Custom Components using Component Renderers and Updaters

Custom components can be supported using renderers and updaters. They can also be used to override HTML generation for standard components. Only one custom renderer per application is allowed in the Standard Edition, and if you need more renderers you need to purchase an appropriate commercial license. WebCream uses a map of class names and renderer classes. When iterating children a container such as Window to generate HTML page WebCream first determines the name of the class of each child component. Then it tries to lookup the renderer for this component in the map of renderers. If a renderer is found, it is instantiated and used. If a renderer is not found, WebCream tries to find a default renderer that can support this class. If no default renderers are found, WebCream issues the infamous "Unsupported Class" link on the generated page. Thus, the job of supporting your own components requires coding of a renderer class and then registering it with WebCream. Note that WebCream provides a universal SnapshotRenderer that can render any component as an image on a page.

 

Developing a custom renderer

Writing renderer is very much like writing a servlet. All renderers must implement creamtec.webcream.rendering.ComponentRenderer interface. If you look at ComponentRenderer interface, you would see that it is very simple and defines only one method

void renderComponent (Document document, Object component) throws Exception

This method is called when WebCream found the component that is supported by the renderer. The implementation must insert the appropriate HTML code that represents the component on the page. This code can be as simple as <IMG> tag or as complex as <IFRAME></IFRAME> section. The passed document is the output document that will be returned to the client. For HTML generatation it is an instance of creamtec.webcream.rendering.html.HTMLPage. Component is the instance of the component to be rendered. Since WebCream uses positioning of components and styles, it is highly recommended to invoke PageRenderer's appendComponentStyle() method which will append coordinates and size of the component. See JavaDoc and example below on specifics of what methods to use and required parameters.

 

Registering the custom renderer with WebCream

Once a custom renderer class has been developed, it has to be registered with WebCream. This is done by adding an entry to the application's properties file in the conf directory. The entry follows format <render>.<component_class_name>=<renderer_class_name>. For example, if you want WebCream to use your renderer test.CustomBannerRenderer for component acme.ui.MyFancyLogo in your application MyFirstApp you will add the following line to <WebCream>/conf/MyFirstApp.properties

render.acme.ui.MyFancyLogo=test.CustomBannerRenderer

Similarly, if you want to use your CustomBannderRenderer to render Swing's JSlider you can use

render.javax.swing.JSlider=test.CustomBannerRenderer


Example Implementation of Custom Renderer

Suppose that you have a Java applet that displays custom animation that is implemented by a class that extends JComponent. Since WebCream doesn't know how to render your class, by default it will generate Unsupported Class link. To solve this, you will create a class called CustomBannderRender and code it as follows

package test;
import creamtec.core.*;
import creamtec.webcream.core.*; 
import creamtec.webcream.rendering.*; 
import creamtec.webcream.rendering.html.*; 


public class CustomBannerRenderer implements ComponentRenderer 
{ 
    public CustomBannerRenderer() 
    { 
    } 


    public void renderComponent (Document document, Object component) throws Exception 
    { 
        if (document instanceof HTMLPage == false) 
           throw new WebCreamException("Internal error, only HTML rendering is supported"); 

        // Normally we would check the type of the class to be the right one; leave it out to keep the example generic 
        // if (component instanceof com.mypackage.myclass == false) 
        //    throw new WebCreamException("Internal error, unexpected component class " + component.getClass().getName()); 

        TraceMgr.trace(this, "Rendering custom page element"); 
        HTMLPage page = (HTMLPage)document; 

        // Render component as an animated image showing bannder.gif 
        page.append("<img src=\"");

        // Support themes by using a relative URL
        page.append(page.getThemeDocsURL());
        page.append("/banner.gif\"");

        // Pass on to the framework let WebCream append rendering style such as position, visibility etc.
        page.getPageRenderer().appendComponentStyle(page, component, false);

        page.appendln(" border=0>"); 
    }
}

For close integration with WebCream, be sure to read documentation on WebCreamManager class, which is a facade for WebCream. It allows you to obtain information about the current client instance and to register listeners that can be used to create and release resources for a client session.


Custom Updater

As you have learned, custom renderers allow you to extend WebCream by providing logic to render unsupported controls to HTML page. But what if the control is an input field such as a text field or a radio button? Generating HTML for it will allow the user to see it on the page, but if the user changes the value of the field how would it get propagated back to the UI element such as JTextField? The solution for this is to add a custom ComponentUpdater. Component updaters are used by WebCream engine to set values received from the browser to the UI elements. It can be as simple as calling a setText() on a JTextField and as complicated as synchronizing the JTable model to match the new values received from the HTML table. Just like custom renderers, updaters need to be registered for the controls that they support. For example, the line below tells WebCream to use CustomControlProcessor to update CustomControl

update.creamtec.webcream.ui.CustomControl=creamtec.webcream.examples.CustomControlProcessor

Custom updaters must implement ComponentUpdater interface and provide implementation for updateComponent method. The implementation is specific to the control and the rendering that was used to represent it on HTML page. The parameter values submitted by the browser are available thru HttpRequestData structure. See Javadoc for more information.

Implementation Example for a Custom Control

WindowsThemeDemo includes a custom control and a processor which acts as the renderer and updater for it to support the control in HTML. The source files are provided for your reference and as a guideline for implementation. Custom control in this demo extends JComponent and contains a JCheckBox and a JLabel. The checkbox specifies whether the label should be drawn with "3D" effect or not. Run WindowsThemeDemo as a stand alone Java application to see how the control works (go to Dialogs->Fixed Dialog in the menu). If you try to run the demo as-is in WebCream you would see familiar "Unsupported class" link saying that creamtec.webcream.ui.CustomControl is not supported. To solve this problem we provide CustomControlProcessor which implements both ComponentRenderer and ComponentUpdater, and register it in conf/WindowsThemeDemo.properties file. CustomControlProcessor does in HTML what CustomControl does in GUI - draws a shade under the label to make it look 3D-like. It's a simple but a complete real life example.

CustomControl.java
CustomControlProcessor.java