Custom component development

The foundation of the swingweb framework is to allow the developer to customize how a component render and accept input. With this foundation, a lot of default implementation of most commonly used component in java.awt.* and javax.swing.* package are also provided with the swingweb distribution so that the developer can focus their attention on the application development right away. However, there would be occasions that the developer would need to control the look and event behavior of a component. This section shows you how to implement custom render and event input for a component.



Component Render Development

In Swingweb, each component uses one or more jxptemplates to render the corresponding web presentation of the component to the web. The templates are collectively grouped to be a template set. For example, the "common" template set is a collection of templates that contains default html/css/javascript representation for the components in java.awt.* and javax.swing.*.

The Configuration

The templates are associated with the components through the following setting in Swingweb configuration: (full configuration can be found in the distribution under samples/config/WEB-INF/classes/swingweb-config.xml)





line 43: Swingweb is using jxp template engine (we will get to jxp syntax later).

line 50: multisource means that there can be multiple template set.

line 52: configures the "common" template set. streamsource means the templates are loaded from classpath (using ClassLoader.getResourceAsStream()) with "common" as prefix. For example, for java.awt.Component, Swingweb will look for the template "/common/java/awt/Component.template" in classpath resources to render the component. The caching attribute control whether jxp template engine to cache parsed syntax which will speed performance. But if you are doing template development, you can leave this off so that it will reparse your template file everytime so you don't have to restart the webserver to test your new changes on the template

line 55: example configuration the uses filesource, which loads templates from file system path. For example, if you want to development a template (e.g. com/acme/MyButton.template) for "com.acme.MyButton" which resides in /home/joe/my-template-set, you can configure a filesource with prefix "/home/joe/my-template-set" so that Swingweb will pick up the template for rendering MyButton.



One thing to note is that the templates are resolved by the order they appears in the multisource. E.g. if you want to replace the presentation of java.awt.Button with your own template, you need to configure the filesource/streamsource before line 52 which configure the "common" template set.



The template



As an example of a jxp template, the template in "common/java/awt/Label.template" looks like this:







As you can see from the template, a jxp template is basically a file with a mix of text/java code (like jsp except several differences). Line 2 is the java code that uses a build-in function in swingweb template "getStyle" to get the necessary CSS style information regarding the component. The fourth line uses html "div" to render the label with the style and the actual text in the label. Inside the pairs of backquotes are java expressions that render to output stream.

There are some built-in variables for Swingweb component template:
com the component to be rendered
_com the BridgePeer of the component, which contains a unique id for identifying the component in a swingweb application
renderdelegate the RenderDelegate of the component
context the SwingwebContext
rendercontext the TemplateRenderContext


Below is a more complicated example for the template in "common" template set which is used to represent JButton





line 2: how simple import in jxp is compare to jsp ;)

line 4: css style, as usual

line 8-12: register an image to context (hint: the SwingwebContext) and get an url in return to construct the img html element

line 18 : include "JTooltip.template", which return "tt_action" variable that show the tooltip

line 20-23: The actual button html. Line 21 use checkButton() javascript function that is included in "common.js" in Frame component template



There are plenty of image buttons in screenshots section so you can take a look. Not much logic inside the template for a button, really. And you only need to implement it once, an all the buttons (including all the subclasses of JButton) will just works (presentation-wise) in Swingweb.

The best way to learn developing component template is to look into the common template set (swingweb-template-common-${version}.jar) for more interesting examples including Container, JTable, JTree etc.

Finally, there is a close relation between the presentation and the InputDelegate: the presentation must include necessary form "input" element that will submit information necessary for the InputDeleagte expects.

Component Input development

In Swingweb, the behavior of each component is controlled by a MapInputDelegate associated with the peer of the component. Based on the information from a java.util.Map transformed from web form/servlet request, the MapInputDelegate is responsible to set the component to correct state and also fire necessary events to simulate the behavior of the component in the desktop environment.

For example, when the TextFieldInputDelegate founds from the given input map that the text has been altered by the user in the web form (passed from browser), it will first change the text in the corresponding component in the Swing application, and then fire an ActionEvent indicating the TextField has been changed.

The configuration

An InputDelegate is glued to the BridgePeer of a Component through the following configuration:





line 7: start of input delegate configuration

line 12: the default InputDelegate to use if there's none found

line 15: the class name pattern that Swingweb will use to resolve the InputDelegate of a component

line 18-19: a hard setting for the InputDelegate of a particular type of component



The implementation

The following shows the implementation of JTextComponentInputDelegate (for JTextComponent)





line 7: detecting whether there's an event on the text component using the input map (check hasEvent method line 20-31)

line 10: set the text of the component to changed text

line 11: create necessary event. In this case, none since JTextComponent does not accept ActionListener or TextListener.



Below shows how the JTextFieldInputDelegate that extends from JTextComponentInputDelegate fire events for ActionListener