fbpx

Creating Simple 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 xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>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 xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>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.

  • xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>_defaultOnEnter ( xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>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.

Like this article?

Share on facebook
Share on Facebook
Share on twitter
Share on Twitter
Share on linkedin
Share on Linkdin
Share on pinterest
Share on Pinterest

Leave a comment

© 2019 Blue Fish, All Rights Reserved.

Powered by Groundwork.