Print Header

Related Topics

Related Case Studies

Contact Blue Fish

Blue Fish Development Group
701 Brazos St. #700
Austin, TX 78701
(512) 469-9300

Creating Simple WDK Controls

Author Photo

January 5, 2005 - Article by Jason Duke

Learn how to create WDK Controls.

Introduction

The WDK control framework, though at times inconsistent and difficult to decipher, provides a useful way of propagating state from the client browser to the application server. In fact, the way WDK is put together, the WDK controls are the only way to propogate data from the HTML form to the Component behavior class where processing takes place.

Although the WDK framework includes dozens of controls, including controls that correspond to every basic HTML input element, there still may be times when the existing controls do not adequately meet your needs. When this situation arises, it is good to know how to create your own WDK control from scratch.

Context and Overview

What is a Control?

A Control is a WDK construct for presenting and/or gathering information via a web browser and representing and processing that information (and any other relevant state) on the server. A Control is typically made up of a JSP tag, backed by a tag class to provide access to the behavior class and maintain state on the server.

A Control provides the ability to encapsulate and reuse UI constructs. Loosely, the word “control” can refer specifically to a control’s behavior class, but throughout this article the word “control” will refer more generally to all of the configuration and source code that goes into supporting the UI functionality of a single control.

The WDK framework includes a number of Controls that are used by the default Webtop framework. Any of these controls can also be used as part of custom Components as well. Sometimes, however, the existing controls do not provide the required functionality. In this case, it is useful to have an understanding of how a Control is defined, so that you can extend it (see the article Extending WDK Controls) or even create your own Control as a replacement.

In addition, there may be some portion of your user interface which is complex, but which you want to use in more than one place, as part of more than one Component. Rather than writing up a lot of complex Component methods and JSP code, it is sometimes a better idea to create a Control to encapsulate the behavior and the state that you need.

Control Files

A Control is made up of three distinct, but related, pieces of content: the tag definition, the tag class, and the control class.

Tag Definition

The tag definition is a piece of XML code which defines the syntax and behavior of the tag. It includes specification of the tag name, the various attributes that are defined for that tag, the name of the tag class, and more.

The tag definition exists as part of a tag library. Tag libraries typically contain a number of different tag definitions. There are several tag libraries included as part of WDK (e.g. dmform_1_0.tld, dmformext_1_0.tld, etc.). These and the other tag libraries contain tag definitions for all of the WDK controls. They are located in the WEB-INF/tlds folder. When you create a control, you may want to base it on the existing WDK tag definitions in these files, but it is recommended that you do not actually add your tag definitions to these files; instead, you will want to create your own tag library. More on this later.

Tag Class

The tag class is a Java class which encapsulates the state of the tag and propogates state from the JSP page to the Control class. It is also responsible for rendering the HTML that will be used to represent the control. All control tag classes should subclass from com.documentum.web.form.ControlTag.

Control Class

The control class is a Java class which encapsulates the state and behavior of the control. All control classes should subclass from com.documentum.web.form.Control. The Control object itself is a member of the Component that contains it. It is responsible for maintaining Control state across multiple requests, as well as any Control behavior.

Finding Control Files

Although this article focuses on creating your own control, it can sometimes be useful to have existing controls to look at as a guide. Many of the methods in Control and ControlTag are not entirely intuitive, so the more clues you can find in existing WDK controls, the better off you’ll be.

The best way to track down the files that make up an existing WDK control is to start with the JSP tag used to render it. The definitions for all WDK tags can be found in one of the several tag library definition (TLD) files included in the Webtop distribution. These are located in the WEB-INF/tlds directory.

It is easy to search these TLD files for the definition of the tag you are interested in. For example, let’s suppose you wanted to look at the definition of the <dmf:text> control. Looking through the TLD files for <name>text</name>, you find the tag definition in dmform_1_0.tld.

Determining the tag class is as simple as finding the <tagclass> element of the tag definition:

                
<tagclass>com.documentum.web.form.control.TextTag</tagclass>

            

From here we can usually assume that the corresponding control class will be com.documentum.web.form.control.Text, but to be sure, we can run a test and see what TextTag.getControlClass() returns.

When to Create a Control

There are a variety of situations that may require you to create a new WDK control. Some of the more common situations are presented below.

Provide a different control implementation for an HTML form element

Although WDK provides control implementations corresponding to each of the common HTML form elements, you may want to provide a different implementation than the one WDK provides. Creating your own control for a specific HTML form element enables you to control exactly how that element is rendered.

Present typed data in a consistent way across multiple components

Most applications have data types that are always displayed the same way, and whose values may lend themselves to specific HTML elements or formatting. When formatters and JSP code do not solve the problem, or you would simply prefer to simplify your JSP code by unifying common processing and formatting, it may be useful to create your own control. The WDK DateInput control is a good example of a Control solving this kind of problem. The Date is always displayed a certain way, without the need for wrapping the control in a formatter. One can easily imagine a MoneyInput control (currency and amount) with code to encapsulate the currency and the amount, as well as to display amounts consitently.

Provide a reusable control for gathering complex data

Sometimes you need to gather several pieces of data that are interdependent in some way. The WDK DateInput and the suggested MoneyInput control described above both fall under this category, because they provide a way to gather complex data. Other examples of this usage might include a ColorInput control (red, green, and blue), a TimeInput control (hours, minutes, seconds), or perhaps a CarModel control (year, make, and model). These are relatively simple examples. One might make use of a control to gather tabular data (rows and columns), or to render the HTML to load a Java applet in the client browser.

How to Create a Control

Creating a Control is fairly straightforward. As we discussed previously, there are three pieces that make up a WDK Control: the tag definition, the tag class, and the control class. In order to create a new control, you must implement each of these three pieces. The complexity of each of these three pieces will depend on how much state your Control encapsulates and how complex its behavior is. The key is knowing how what you want before you begin. Developing a simple control and quickly spiral into a lot more work than you initially anticipated, so it is best to have a clear idea of the behavior you want to implement before you begin.

Remember, creating a control is easy; creating a clean, robust control takes time.

The three pieces are presented one after the other in this part of the article to make it easier to structure the information. In practice, implementing a control may not be so straightforward. Unless you know exactly how you will implement your control and have implemented a few controls before, it is likely that you will spend your time jumping around from tag definition to control tag class and from tag class to control class as you learn and test.

Be sure to go through the Example at the end of the article in order to get a better idea of how each piece fits into the whole.

The Control Class

As stated previously, the control class encapsulates the state and behavior of the control. Each stateful attribute on the control probably has a corresponding member variable in the control class. The control class may have additional members responsible for keeping track of more nuanced state (for example, sort order).

The control class is typically made up of one or more fields (any data type). The state of a control class is typically modified in one of three ways:

  • The setControlProperties on the control tag object, which passes state from the control tag to the control.
  • The updateStateFromRequest method on the control object, which gathers state from the eventual submission of an HTML form containing the HTML form elements generated by the control tag.
  • Programmatically, using direct setter calls on the control object.

In order to extend the control class, simply create a Java class (in any package) which subclasses the control class for the control you wish to extend. Then you can add new members and methods as well as override any existing methods. Add new code to the extended class in order to support any new control attributes or functionality. This may include one or more of the following steps, but this list is certainly not exhaustive.

  • Create member variables to store Control state
  • Create a constructor, including a call to the superclass’s constructor and adding any additional code to initialize the new control attributes.
  • Create getters and setters for member variables. Even if a field is not a String, I usually create a setter which takes a String if that member data is ultimately based on the String value of a tag attribute. (For example, a method setAmount(String) that parses the String representation and stores a Double.) This makes it easier to propogate the tag state into the control when you write the setControlProperties() method on your control tag.
  • Override updateStateFromRequest() to propogate values from a submitted form into the control.
  • Override getEventNames. If your control is complex enough to handle events, you will need to override this method to return the event names it handles.
  • Override hasChanged. In the WDK Control class this returns false, but it may be useful for other WDK framework functionality if this method returns a meaningful value relating to whether or not the value has been changed
  • Override any other methods from the superclass as necessary. Typically you will want to including a call to the superclass implementation of the method, but not necessarily.
  • Add any other methods for manipulating control state. Depending on the complexity and usage of the control, this may require any number of new methods.

In order for this new control class to be used as part of the control, we must tie it to the tag using the tag class. See below.

The Tag Class

The tag class encapsulates the state of the tag and propogates state from the JSP page to the control class. It is also responsible for rendering the HTML that will be used to represent the control. The tag class is typically made up of one or more String fields, which usually correspond to the tag attributes. The fields don’t need to be Strings, but I have found this to be convenient, because although it is possible to pass typed data into a tag, it is usually safer to only use Strings, since the JSP tag language is String-based anyway.

In order to create the tag class, simply create a Java class which sublasses the ControlTag class. Then you can add new code and override methods from ControlTag as necessary. This may include one or more of the following steps:

  • Create member variables to store ControlTag state
  • - these are usually Strings in the Tag.
  • Create getters and setters for any new attributes. It is extremely helpful for any tag attributes in your tag definition to have corresponding String setters in the control tag class. Remember that tag attribute names are case-sensitive, so if your tag attribute name is defaultonenter, your setter should be setDefaultonenter.
  • Implement the abstract method getControlClass() so that it returns your new control class. The WDK framework uses the getControlClass() method to know what class to use for the control’s state and behavior.
  • Override setControlProperties() to correctly pass tag state along to an instance of your control class.
  • Override release() , including a call to the super and code to release any resources used by new attributes.
  • Override renderStart() and/or renderEnd() , providing code to render the HTML for your control. Usually, you can just render all of the HTML in renderEnd(). The renderStart() method is useful for tags which can contain other tags. It is recommended that your public rendering methods (renderStart, renderEnd) make one or more simple calls to other methods which render output to a StringBuffer, so that if you or anyone else ever wants to extend your tag class, it is fairly easy to leverage your existing code and add new code. Documentum failed to do this for most of their controls, and it is thus very difficult to extend or augment them.
  • Override and/or create any other methods as necessary. Depending on the functionality and complexity of your control, you may need to override other methods. (The javadocs for ControlTag can be helpful here.) You may also need to create other methods not discussed here.

The Tag Definition

The tag definition is a piece of XML code which defines the syntax and behavior of the tag. The tag definition exists as part of a tag library. All of the WDK controls include tag definitions in one of the WDK tag library files, which are stored in WEB-INF/tlds.

If you want to create a new tag definition, you have two options:

  • Add new tag definition to your own custom tag library file(s). This is the ideal way of making new control code available for your JSP pages to use. Adding a new tag definition to a new or existing custom tag library file enables you to use your new control while keeping all of your code separate from the WDK code base. However, you will need to explicitly include your new tag library on any JSP pages that use the new control.
  • Add new tag definitions to existing WDK tag library file(s). Modifying the WDK taglib files is not recommended, but adding new tag definitions to them is a low-risk way to make your new control code available with a different tag name, while avoiding the need to include a new tag library file reference in your JSP pages. This is really only recommended in cases where you are doing bulk search and replace to replace existing WDK tags with your new tags, and you don’t want to have to include a new taglib on every page.

Regardless of where you define your tag, your goal is the same: to define the behavior of a new tag. This includes the syntax of the tag (name, attributes, etc.) and the tag class to use to render the tag and encapsulate the tag’s state.

It is recommended that your tag definition be as simple and concise as possible. The more tag attributes you have, the more code you need to write and the more you have to test (and document). If you need more attributes with more values, by all means you should implement them, but keep in mind how quickly a wide range of attributes can increase the scope of your control. It is usually worth taking some time upfront to simplify your design as much as possible.

Example: ColorInput

This example illustrates how to build a simple WDK control to represent three separate floating point values which together constitute the concept of a “color”. The tag will be rendered as three separate text boxes for user input, but by the time that data gets to the component it is encapsulated in a single control class. The code discussed in this example consists of these three pieces:

  • a control class (ColorInput.java) [ download ]
  • a control tag class (ColorInputTag.java) [ download ]
  • a control tag definition (<bf:color>), defined in bluefish.tld [ download ]

The word “component” will be used in this example to describe one of the three floating point numbers that make up the color control. Red, green, and blue are considered “component” values. Don’t confuse this with the more familiar WDK component.

You may find it useful to familiarize yourself with the basic layout of the code before continuing, then reviewing it in more detail as you read the rest of the article.

The Control Class

Create a new Java class.

First, create a class that extends com.documentum.web.form.Control. In the example code, we call this class ColorInput, loosely following the naming convention used by WDK for DateInput.

Create member variables.

Control state is ultimately maintained in the control class, so anything about the control that needs to be stateful typically needs to be represented as a member variable in the control class. These usually correspond loosely to the tag class member variables and ultimately the tag attributes, although it is not uncommon for the control class to implement additional member variables for state that is not part of the tag definition.

For the ColorInput control, we implement the following member variables. The first two correspond to behavior that is found in several WDK controls as well. The last three are quite specific to ColorInput.

  • _defaultOnEnter (boolean) - whether or not pressing enter while the cursor is on this control (in the HTML form) should submit the form
  • _size (String) - the size attribute value to pass along to each of the component text boxes
  • _red (Float) - the value of the red component
  • _green (Float) - the value of the green component
  • _blue (Float) - the value of the blue component

Create a constructor.

As you can see in the sample code, all member variables are initialized here.

Create standard getters and setters.

ColorInput.java includes basic getter and setter methods for all five of the member variables.

Create String setters.

In addition to the standard typed setter and getter methods, we want to create String setters for the red, green, and blue component values. Why? Because these values can be set as tag attributes, and at that time they are Strings. The tag class (as you will soon see) stores those values as Strings as well, and propogates them to the control using the setControlProperties method. That method will make use of our String setters for red, green, and blue.

As you can see in the sample code, the String setters in ColorInput simply parse a floating point value out of the String. If the String can not be parsed as a floating point, then a null value is used. This is not ideal, since it means there is no way to capture or see invalid values, but it is sufficient for the purposes of this example.

Override canAcceptFocus()

This method returns false in the superclass Control, since some (in fact, most) WDK controls do not actually correspond to form elements that can receive focus. Our form elements can, though, so we override this to return true.

Override updateStateFromRequest()

When the JSP for your tag is first parsed, the ControlTag object is instantiated and setters are called to set up its state. The WDK framework uses setControlProperties to update the control object with any values that were initially set on the control tag using the tag attributes in the JSP page. But if your tag actually renders one or more HTML form elements, then at some point the data the user provides in those forms must be propogated back into your control. The updateStateFromRequest method is responsible for this, and without it your control state will never be updated based on the HTTP form post.

For ColorInput, this method is fairly straightforward. As you will see when we get into the ColorInputTag implementation, each component of our color is rendered as a separate text input element. Those three elements are then submitted as part of the form. Fortunately, WDK has a system for naming form elements and tying them back to the controls they belong to, and we make use of it here.

The code excerpt below shows how we get the values from the request. The PROPERTY constants are just names for each component. These names should be unique within the scope of our control; our tag class will use WDK methods to combine these with the control name for a truly unique name.

                
String redStr = getRequestParameter(getElementName(PROPERTY_RED));
String greenStr = getRequestParameter(getElementName(PROPERTY_GREEN));
String blueStr = getRequestParameter(getElementName(PROPERTY_BLUE));

            

As you can see, the Control method getElementName is used to determine the actual request parameter name for each component property. The rest of the code simply takes these values and sets them.

The Tag Class

Create a new Java class.

Create a Java class that extends com.documentum.web.form.ControlTag. In the example code, we call this class ColorInputTag.

Create member variables.

Although the control state is ultimately maintained in the control class, the typical control has some state that can be set using attributes on the JSP tag itself. When you set these attributes in the tag in your JSP, it is translated into direct calls to the setter methods on the tag class, which update the internal state of the tag object, typically its member variables. Therefore any state that needs to be passed along to the control needs to be internalized in the tag class using member variables.

For the ColorInput control tag class, we implement the following member variables (all Strings):

  • _defaultOnEnter - whether or not pressing enter while the cursor is on this control (in the HTML form) should submit the form
  • _size - the size attribute value to pass along to each of the component text boxes
  • _red - the value of the red component
  • _green - the value of the green component
  • _blue - the value of the blue component

You may have noticed that these correspond one-to-one with the member variables in our control class, ColorInput. This is not surprising, though it is certainly not always the case. You should always keeps in mind that the only purpose for this state in the tag class is as a holding place before it is passed along to the control class in setControlProperties().

Create getters and setters.

The setters are important, because they are used by the JSP framework to pass the tag attributes specified on the JSP page into the actual tag class. Getters are not strictly necessary on the tag class, since it has no public consumers that require getters, but some protected getters might be useful for private fields in case you ever want to extend your tag class and still have access to all of its state.

For the ColorInput control, we create setters for each of the five member variables.

Implement getControlClass()

In order for the WDK framework to know what control to instantiate when it processes your tag, the method getControlClass() must return the correct class. In the sample code, getControlClass() has been implemented to correctly return the new ColorInput class.

Override release()

The release() method should release any resources used by the control tag, and is called by the JSP framework when the tag is no longer needed. For more complex controls, this can be very important as otherwise resources may not be cleaned up, which can lead to performance problems. In the case of ColorInput, this method simply nulls out the member variables.

Override setControlProperties()

This method is used by the WDK framework to propogate the state of the tag into the control. The implementation for ColorTag is fairly straightforward, passing calling each of the String setters on the control using the member variable values in the control tag.

Override renderEnd()

For our ColorInput example, we do not need to create a renderStart() method, because the entire tag is rendered at once. Therefore, we only override renderEnd().

As you can see in the sample code, the renderEnd method is very simple. It gets the ColorInput control object (using the built-in getControl() method from the ControlTag superclass), checks if it is visible (since it does not need to be rendered if it is not visible), creates a StringBuffer (for output), then calls the protected method renderComponentInputs(), which writes the HTML output to the StringBuffer. Once that method returns, the StringBuffer is then written to output. This enables a subclass to easily override your methods and easily insert new attributes, render things differently, etc.

Implement renderComponentInputs() and renderComponentInput()

The renderComponentInputs() method builds most of the HTML used to format the three input textboxes (as an HTML table, with a row of color bars above each component). It gets the value for each component from the ColorInput control object that is passed in. It then calls renderComponentInput() for each of the three colors, passing in each of the three component values (red, green, and blue) and each of the PROPERTY constants from the ColorInput control class (which will be used by a WDK method, along with the control name, to give each form element a unique name that can be reconstructed in the updateStateFromRequest() method of the control class.

The renderComponentInput() method builds the HTML for each component textbox, which involves constructing the actual HTML input tag, including any attributes (size, name, id, value, etc.). The code for generating the name and id attributes includes a simple call to the ControlTag method renderNameAndId():

                
buf.append("<input type='text' ").append(renderNameAndId(colorInput, propertyName));

            

This code is closely related to the calls to getElementName in the updateStateFromRequest() method in the ColorInput control class. In this case it generates a unique name based on the property name (red, green, or blue) and the control name, which is then reconstructed in updateStateFromRequest().

The Tag Definition

Create a custom tag library file.

If you don’t have one already, create a custom tag library (taglib) file, which you can use for one or more custom tag definitions, including the new color tag. You may find it helpful to use one of WDK’s taglib files as a template. (See the section Finding Control Files above for a brief discussion on how to locate the files for existing WDK controls.).

Choose a unique value for the “shortname” element of your taglib. This value should match the prefix used in the taglib directive, and it will serve as a prefix for your tag name when you want to use it in JSP files. For example (see bluefish.tld, download links included above):

                
<taglib>
    <tlibversion>1.0</tlibversion>
    <jspversion>1.1</jspversion>
    <shortname>bf</shortname>

    <!-- tag definitions go here -->
</taglib>

            

Add your tag definition to the taglib.

It may be helpful to use the WDK tag definitions as a guide, since much of the functionality in some of their tags is included for free in your tag when you extend the base Control and ControlTag classes. Getting some of it to work is sometimes tricky without a detailed understanding of the inner workings of WDK code, but as you have seen in this example it is not impossible.

The definition of our color tag will include the following attributes:

  • id - the id for this control, implemented using methods from Control and/or ControlTag
  • name - the name for this control, implemented using methods from Control and/or ControlTag
  • size - this value is propogated to the size attribute for each of the component textboxes; if not set, it will default to ColorInputTag.DEFAULT_SIZE, which in the example code is set to 5.
  • enabled - implemented using methods from Control and/or ControlTag
  • visible - implemented using methods from Control and/or ControlTag
  • style - implemented using methods from Control and/or ControlTag, this style is applied to all three component textboxes.
  • cssclass - implemented using methods from Control and/or ControlTag, this css class is applied to all three component textboxes.
  • red - the starting value for the red component of the color (a floating point value that will ultimately be parsed by Float.parseFloat()).
  • green - the starting value for the green component of the color.
  • blue - the starting value for the blue component of the color.

The name attribute is required (as it is on all WDK controls), but all the other attributes are optional.

A tag definition is an XML element (<tag>) that consists of several child elements:

  • <name> - the name of the tag, used to refer to the tag in JSP code (color)
  • <tagclass> - the tag class associated with this tag
  • (com.bluefishgroup.bedrock.wdk.control.ColorInputTag)
  • <bodycontent> - JSP means that you can add more content, including more Java code or JSP tags, between the tag open and tag close for this particular tag; empty means that the tag can contain no extra content and is complete in itself, which is the case for the ColorInput control tag.
  • <attribute> - as many of these as you like, these define the tag attributes, using the following child elements:
    • <name> - the name of the attribute
    • <required> - true if the attribute must be included when using the tag, otherwise false
    • <rtexprvalue> - true if the attribute should be given a value when used, otherwise false. WDK controls typically require a value for all attributes, but it is possible to have an attribute without a value; in this case, simply including the attribute name itself when using the tag indicates that its value is true, and if it is not included its value is false.

Please review the example tag library bluefish.tld for the full tag definition.

We have now created a new tag library, and it contains our new tag definition, but in order to be able to use the new tag on a JSP page, that page must include a directive instructing it to use our new tag library. Assuming our taglib file is located in the place as the WDK taglibs (/WEB-INF/tlds), the following directive should be used near the top of any JSP pages which need to use our tag:

                
<%@ taglib uri="/WEB-INF/tlds/bluefish.tld" prefix="bf" %>

            

Once a JSP page has included our custom taglib, all the tags in that library are made available for use on that JSP page. At this point, usage of our custom tag is fairly straightforward:

                
<bf:color id='color1' name='color1' />

            

Here we explicitly specify the size for each of the component textboxes to be 6 characters wide:

                
<bf:color id='color2' name='color2' size='6' />

            

Here we set the starting values of rthe red, green, and blue components of the color.

                
<cdms:color id='color3' name='color3' size='10' red='100' green='150' blue='200' />

            

Notice that the tag prefix ‘bf’ has been used. This corresponds to the prefix attribute of the taglib directive, as well as the shortname attribute inside the tag library itself.

Suggested enhancements to the example ColorInput control

You may find it worthwhile to implement one or more of the items below to help solidify your understanding of the control model:

  • control tag attribute: bars (boolean for whether or not to render color bars above input fields)
  • control tag attributes: nlsidRed, nlsidGreen, nlsidBlue ( to get starting values from NLS strings)
  • separate size attributes for each component value (sizeBlue, sizeGreen, sizeBlue)
  • a validator to ensure reasonable values for component inputs (would need to change the control and tag to maintain bad strings values, for example, instead of eating them and setting value to null - dateinput does this (badly)

Conclusion

The WDK Control model is an effective way to encapsulate complex data and unify the rendering of data across multiple components. While it is not always an intuitive process, it is not rocket science and patience and fortitude will pay off when learning to create your own WDK controls.

Remember, a single tag library can contain multiple tag definitions. Don’t forget to include a JSP directive to your new tag library, and remember your tag prefix.

 Votes | Average: 0 out of 5 Votes | Average: 0 out of 5 Votes | Average: 0 out of 5 Votes | Average: 0 out of 5 Votes | Average: 0 out of 5 (0 votes, average: 0 out of 5)
Loading ... Loading ...

Comment on this article:

You must be logged in to post a comment.

Notification

Subscribe to our newsletter to be notified when new articles are posted. You can unsubscribe at any time.