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.
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.
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
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.
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.
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