Learn how to create WDK Controls.
Blue Fish Development Group
701 Brazos St. #700
Austin, TX 78701
(512) 469-9300
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.
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.
A Control is made up of three distinct, but related, pieces of content: the tag definition, the tag class, and the control class.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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:
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.
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.updateStateFromRequest()
to propogate values from a submitted form into
the control.getEventNames. If your control is complex enough to handle events, you
will need to override this method to return the event names it handles. 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 changedIn 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 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:
defaultonenter, your
setter should be setDefaultonenter.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.setControlProperties()
to correctly pass tag state along to an instance
of your control class. release()
, including a call to the super and code to release any
resources used by new attributes. 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. 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:
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.
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:
ColorInput.java) [ download ]ColorInputTag.java) [ download ]<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.
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.
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 componentAs you can see in the sample code, all member variables are initialized here.
ColorInput.java includes basic getter and setter methods for all five of the member
variables.
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.
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.
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.
Create a Java class that extends com.documentum.web.form.ControlTag.
In the example code, we call this class ColorInputTag.
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 componentYou 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().
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.
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.
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.
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.
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.
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().
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>
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:
Control
and/or ControlTag
Control
and/or ControlTag
ColorInputTag.DEFAULT_SIZE, which in the
example code is set to 5.Control and/or ControlTag
Control and/or ControlTag
Control and/or ControlTag,
this style is applied to all three component textboxes.Control and/or ControlTag,
this css class is applied to all three component textboxes.Float.parseFloat()).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 tagcom.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.
You may find it worthwhile to implement one or more of the items below to help solidify your understanding of the control model:
bars (boolean for whether or not to render color bars above input fields)nlsidRed, nlsidGreen, nlsidBlue (
to get starting values from NLS strings)size attributes for each component value
(sizeBlue, sizeGreen, sizeBlue)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.
Subscribe to our newsletter to be notified when new articles are posted. You can unsubscribe at any time.
You must be logged in to post a comment.