Introduction
Sometimes the existing WDK controls do not provide all the functionality you require, but they provide
most of it. Rather than having to duplicate the functionality they do have just to support the
functionality they don’t, you can leverage the existing functionality and add to it by extending the
control.
WDK does not provide an extension model for controls as it does for components, but the way controls are
implemented allows for various levels of extension nonetheless. The phrase “extending a control” is used in
this document to loosely describe a variety of methods for augmenting existing control functionality with
your additional functionality.
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 and how to extend its functionality. Most of the existing WDK controls can be
extended, some more easily than others. Knowing how to extend WDK controls will enable you to add new
functionality and overcome deficiencies in the existing WDK controls.
It is important to understand that a Control is not a Component, and the method for extending a Control
is not related at all to the WDK mechanism for extending a Component. All WDK Control classes inherit from
the class xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>com.documentum.web.form.Control. Note that the base xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>Component class
extends the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>Form class, which extends xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>Control. Although the argument might be
made that a Form is a Control, a Component is definitely not a Control in the general sense, because it
does not have an associated tag definition.
What it Means to Extend a Control
You may already be familiar with WDK’s Component model. If so, you know that WDK provides a
straightforward mechanism for extending Components, via the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>extends attribute in the component
definition XML file. This mechanism for extending Components makes it relatively simple to augment an
existing Component with new or different behavior, just by changing the JSP the Component uses, or by
changing the Component behavior class, etc.
Extending a Control is not quite so straightforward. There is no simple mechanism for augmenting the
behavior of an existing Control. While a Component has an XML file that dictates its behavior, a Control
does not. Instead, a Control is defined as part of a tag library, which may contain other controls (or,
indeed, tags that are not controls at all). A Control’s behavior is defined by a tag class which is used to
generate the HTML, and a behavior class which maintains Control state and supplies the meat of its
functionality.
Extending a control, therefore, could mean altering the control’s tag definition to use a completely
different tag class or control class, so that any JSP already using this tag would automatically use the
new control without requiring any changes to the JSP. It could mean subclassing the tag class and/or the
control class to add/change functionality, then creating a new tag definition that refers to the
subclasses, so that JSP pages can refer to the old control or the newly “extended” control. It could simply
mean altering the existing tag definition in order to obscure (and therefore prevent use of) existing tag
functionality. Each of these methods will be discussed, but it is important to recognize the difference
between extending a Control and extending a Component.
Some Commonly Used WDK Controls
WDK includes dozens of controls for hundreds of possible applications, including controls that correspond
to most, if not all, of the common HTML elements (e.g. xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><input>,
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><select>, xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><img>, etc.), which enables you to render an HTML element
whose content and state is tied back to the WDK control on the server. Many controls, however, are more
complex and specific in their functionality (e.g. xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:datagrid>,
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:celllist>, xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:panel>, etc.).
Any WDK control can be extended, if necessary. Some of the more commonly used controls are listed below.
(For a full list, please consult the WDK reference manual.)
- Label ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:label>) – Text label control that can be used to label an image, user
input control, or other UI element; typically renders plain text in the HTML output. - Image ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:image>) – Generates an HTML image tag ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><image>).
- Link ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:link>) – Generates a hyperlink to a client-side or server-side event
handler ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><a href=…>). - Text ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:text>) – Renders an HTML text box ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><input
type=text>) - Checkbox ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:checkbox>) – Generates an HTML checkbox ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><input
type=checkbox>) - Radio ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:radio>) – Generates an HTML radio button ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><input
type=radio>) - Button ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:button>) – Generates an HTML button ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><input
type=button>). or a link which looks like a button, including ability to leverage custom
button images. - DropDownList ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:dropdownlist>) – Generates an HTML drop-down list
( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><select>). - Option – Generates an HTML option tag ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><option>); contains a single static
name/value pair entry; used inside a dropdownlist, listbox, datadropdownlist, or datalistbox
control. - Menu ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:menu>), MenuItem ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:menuitem>), MenuSeparator
( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:menuseparator>), MenuGroup ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:menugroup>) – Used to
construct menus, these render complex JavaScript and HTML for a multi-tiered menu system that is
displayed on top of the content of a page. - Datagrid ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:datagrid>), DatagridRow ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:datagridrow>) –
Displays results of a query or recordset as a table, generating opening and closing
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><table> tags. - Panel ( xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:panel>) – Wraps a group of controls as a mechanism for hiding or displaying the group.
- Validators – All WDK validators are simply a specific kind of Control, and can be extended
the same way. Look for a Blue Fish article about WDK validators.
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. xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>dmform_1_0.tld,
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>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 xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>WEB-INF/tlds folder. When you extend a control, you
may want to alter its tag definition in these files, but it is more likely that you would create a new tag
library and add a new tag definition to it. 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 xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>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 xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>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
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 xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>WEB-INF/tlds directory.
It is relatively straightforward to search these TLD files for the definition of the tag you
are interested in. For example, let’s suppose you wanted to extend the <dmf:text> control.
Looking through the TLD files for xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><name>text</name>, you find the
tag definition in xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>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 xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>com.documentum.web.form.control.Text,
but to be sure, we can run a test and see what TextTag.getControlClass() returns.
When to Extend a Control
There are a variety of situations that may require you to extend existing WDK controls.
Implement common HTML attributes not included in WDK version of the tag.
One of the most common is the problem of missing HTML attributes. Many of the WDK controls are meant to
provide user input fields as part of an HTML form element. For example, the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>text control
(represented by the tag xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:text>, is rendered as an HTML xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><input>
element. However, there are several attributes defined for the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><input> element which are
not defined in the WDK xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>text control, and therefore there is no way to get that behavior.
For example: The tag definition for the WDK xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>text control can be found in
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>dmform_1_0.tld. The definition includes a variety of attributes. Some of these are simply
passed through to be included on the HTML element, but most are WDK-specific attributes whose values are
used to control WDK behavior. For example, the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>onchange attribute on the control tag is used
to define the value of the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>onchange attribute on the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><input> tag.
Unfortunately, the tag definition, tag class, and control class for the WDK xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>text control does
not include an xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>onblur attribute. The xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>onblur attribute is defines the JavaScript
to be executed when a form element loses focus. If your application requires the use of the
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>onblur event on a control, it is necessary to extend the existing xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>text control.
Similarly, if your applications requires any standard HTML attribute that is not included as part of the
existing WDK tag definition, it will be necessary to extend the existing control.
Add other new functionality
It may be the case that the existing tag definition includes all the HTML attributes you may require, but
there is some special custom functionality that you would like to include as part of the control. Rather
than create a completely new Control, duplicating the existing control functionality and adding your own as
well, it is easier to simply extend the existing Control, if possible.
Modify existing functionality
Similarly, it may be that the existing Control has everything you need, but some of its behavior is not
quite what you want. It is sometimes useful to extend the control and override and/or modify existing
functionality to better suit your needs. This could be something as simple as making a previously
non-required tag attribute required, which involves changing only the tag definition, not any of the
classes.
Hide existing functionality
Although rare, a situation may arise where you wish to hide some of a control’s functionality. This would
be extremely easy to accomplish by extending a control and changing its tag definition to obscure that
functionality and prevent it from being used.
How to Extend a Control
Extending a Control is fairly straightforward. It can be as simple as changing the tag definition in the
tag library, or more involved, with new tag and/or control classes (which may or may not inherit from the
current ones). The key to knowing how to extend the Control is knowing what you want.
Extending 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).
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:
-
Override the 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 any new attributes.
-
Modify existing setters, getters, and other methods, either by overriding and including a call
to the super, or else by completely replacing the method in the extended class (i.e. no call to the
super). -
Add any other methods for manipulating control state. If new functionality is being added, it
may require any number of new methods. -
Duplicate private functionality. WDK has a nasty habit of making various methods private
throughout the control classes, and thus there is no way to call those methods from a subclass. It is
therefore sometimes necessary to somehow duplicate the private method’s behavior in a method that is
available in the subclass. It may be necessary to decompile the existing control class code in order to
duplicate the behavior of a private method. This is not encouraged, but at times it is necessary.
In order for this new control class to be used as part of a control, it is necessary to extend the tag
class to return the new control class. See below.
Extending 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.
In order to extend the tag class, simply create a Java class (in any package, though it is recommended
that you keep it with your extended control class, if any) which sublasses the tag class for the control
you wish to extend. Then you can add new code and override existing methods. This may include one or more
of the following steps:
-
Override getControlClass()
to return the new control class, if you extended the
control class. The WDK framework uses the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>getControlClass() method to know what class to
use for the control’s state and behavior. It is imperative that this method be overridden to return to
the correct class; if the control class has not been extended, this is not necessary. - Create getters and setters for any new attributes.
-
Override setControlProperties()
to correctly pass tag state along to an instance
of the control class. -
Override release()
, including a call to the super and code to release any
resources used by new attributes. -
Override renderEnd()
to include additional code to render any new attributes as
part of HTML for control. Actually, overriding xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>renderEnd() is usually somewhat
challenging. Rather than including all the code for rendering the control in a separate method, most
WDK control tag classes put all the code directly into xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>renderEnd(), which operates
directly on the JSP output writer (as opposed to, returning a xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>String or operating on a
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>StringBuffer). Since the HTML for the tag is therefore being generated atomically inside
of xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>renderEnd(), there is no way to easily override xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>renderEnd(), call the
super, and insert the new HTML midstream. Therefore, if you want to include something in the middle of
the output from the superclass’s xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>renderEnd(), you must decompile the existing tag code and
include it in your xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>renderEnd() method, which then gives you full control over the HTML
that is being generated. - Override and/or create any other methods as necessary.
-
Duplicate private functionality. As discussed under Extending the Tag Class, it is
sometimes necessary to duplicate behavior that was scoped as private in the superclass.
In order for this new tag class to be used as part of a control, it is necessary to extend the tag
definition to use the new tag class. See below.
Extending 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 xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>WEB-INF/tlds.
If you want to add or remove attributes from the tag definition, you have several options:
-
Add new tag definitions 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 custom
tag library file enables you to use the extended control and still have access to the original base
control, and it keeps all of your code separate from the WDK code base. However, because you have not
actually changed the classes used by the original tag, any uses of the original tag in your JSP pages
will still use the original tag definition and thus the old control classes. You will need to
explicitly include your new tag library on any JSP pages that use the extended controls, and you will
have to use the extended tag prefix and name instead of the standard WDK tag. -
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. It also avoids the need of including a new tag library file
reference in your JSP pages. -
Modify existing tag definitions in existing WDK tag library file(s). This practice is strongly
discouraged, but it could be useful if you wish to change behavior of standard WDK control tags already
in use throughout your application. Modifying the existing tag definitions means that any JSP pages
which already use the tags will automatically use the new taglib definition, and there is no need to
alter all the JSPs to use your new tag.
Regardless of how you extend the tag library, your goal is the same. To define the behavior of a tag
(either a new one, or the existing one). 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. If the tag class was never
extended, then the tag would be configured to use the original tag class. For example, if all you wanted to
do was change an attribute from non-required to required, you could simply modify the tag definition (or
create a new tag with the new syntax definition) in the tag library and continue using the original tag
class and control class, as in Example 1 below.
Examples
The three examples below illustrate how to extend the WDK text control in different ways. Each example
builds on the one before it, so it is recommended that you go through them in order.
Example 1: Changing an attribute from non-required to required
The xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>size attribute is a non-required attribute on the WDK xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>text control which is
used to set the length of the HTML input element. This example shows how to extend the WDK
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>text control to make xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>size a required attribute.
Extend the tag definition
In order to make the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>size attribute required, the tag definition must be changed.
Here is the definition of the WDK xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>text control from xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>dmform_1_0.tld:
<tag>
<name>text</name>
<tagclass>com.documentum.web.form.control.TextTag</tagclass>
<bodycontent>empty</bodycontent>
<attribute>
<name>id</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>name</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>size</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>value</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>datafield</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>nlsid</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>enabled</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>visible</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>onchange</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>style</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>cssclass</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>defaultonenter</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>runatclient</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>tooltipnlsid</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>focus</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
We are only interested in the definition of the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>size attribute:
<attribute>
<name>size</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
The change to make the attribute required is a simple one:
<attribute>
<name>size</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
Changing the definition directly in xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>dmform_1_0.tld would mean that any JSP page which uses
the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:text> tag would now be required to specify the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>size attribute.
Rather than make a change that will affect all usages of the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>text control, we want to
extend the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>text control, give it a new tag name, and have our new, extended tag be
the one that requires the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>size attribute.
The new tag, however, will depend on the same tag class (and therefore on the same control class) as the
original control. Therefore, all we will be extending is the tag definition.
First, we create a custom tag library (taglib) file, which we can use for one or more custom tag
definitions, including the new xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>text tag. You may find it helpful to use one of WDK’s taglib
files as a template. Choose a unique value for the “shortname” element. 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:
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>bf</shortname>
<!-- tag definitions go here -->
</taglib>
Next, we copy the existing tag definition from the WDK taglib into our custom taglib. For convenience and
consistency, it is ideal to keep the same tag name (text).
We can now make any necessary changes to the new tag definition. In this example, the change is minor and
we are still using the same tag class and control class, so the new definition is only slightly different
from the old one.
When completed, our custom tag library file xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>ArgonDigital.tld looks like this:
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>bf</shortname>
<tag>
<name>text</name>
<tagclass>com.documentum.web.form.control.TextTag</tagclass>
<bodycontent>empty</bodycontent>
<attribute>
<name>id</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>name</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>size</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>value</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>datafield</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>nlsid</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>enabled</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>visible</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>onchange</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>style</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>cssclass</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>defaultonenter</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>runatclient</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>tooltipnlsid</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>focus</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
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/ArgonDigital.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:text id=’username’ name=’username’ size=’40’ />
Notice that the tag prefix ‘bf’ has been used. This corresponds to the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>prefix attribute of
the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>taglib directive, as well as the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>shortname attribute inside the tag library
itself.
Because we really just created a new tag for our extended control, we still have access to the original
control. A JSP page which references xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:text> would be using the old tag definition,
and therefore would not require the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>size attribute. Only JSP pages using our new
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><bf:text> tag will require the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>size attribute.
(If you wanted to make the size attribute required for all usages of the original
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:text> tag, you would need to modify the definition of that tag in the original WDK
tag library file, xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>dmform_1_0.tld, instead of creating a new tag definition in a custom tag
library, as we did.)
Example 2: Adding an attribute which affects already-existing control state
The xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatclient attribute is a non-required field on the WDK xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>text control which
is used to define whether or not the event handler for the control should run on the client (as JavaScript)
or on the server (as Java methods). This example shows how to add the attribute xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatserver to
the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>text control tag as an alias for the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatclient attribute, such that setting
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatserver to xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>true has the same effect as setting xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatclient to
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>false.
Extend the tag class
In order for the value of our new attribute to affect the actual state of the control, we must make
changes to the tag class. Remember, the tag class encapsulates the state of the tag and propogates state
from the JSP page to the Control class. We want the value of our new attribute xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatserver to
affect the state of the control the same way (almost) that the value of the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatclient
attribute does.
To do this, we must extend the existing tag class, xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>TextTag, and add the code for the
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatserver attribute:
package com.organization.package;
/**
* Extends WDK’s TextTag to include support for additional attributes.
*
* @author Jason Duke
*/
public class TextTag extends com.documentum.web.form.control.TextTag {
/**
* Construct a TextTag.
*/
public TextTag() {
super();
}
/**
* Set the value of the ‘runatserver’ attribute, which is just an alias
* for the ‘runatclient’ attribute. (Setting ‘runatserver’ to
* <code>true</code> effectively sets runatclient to <code>false</code>.)
*
* @param strRunatclient ‘runatclient’ attribute.
*/
public void setRunatserver(String strRunatserver) {
// Convert String to Boolean
Boolean bRunAtServer = new Boolean(strRunatserver);
// Convert runatserver Boolean to runatclient Boolean – runatclient
// should simply be set to the opposite of the runatserver value.
Boolean bRunAtClient = new Boolean(! bRunAtServer.booleanValue());
// Get String value of runatclient boolean, since setter takes a String
String strRunAtClient = bRunAtClient.toString();
// Call super’s setter for runatclient String
setRunatclient(strRunAtClient);
}
}
As you can see, the only method we needed to add was xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>setRunatserver(). This method
will be called by the JSP infrastructure to pass the value specified on the JSP page for the
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatserver attribute into the tag class. But we are really just using this attribute
to modify the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatclient state in the tag class and the control class.
You may have noticed that we skipped most of the steps described under How to Extend: Extending the
Tag Class above. Our extended tag class does not require much code, since the new attribute simply
modifies state in the tag class. We didn’t extend the Control class, so we don’t need to override
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>getControlClass() or xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>setControlProperties(). The WDK class did not have a
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>getRunatclient() method, so we have not included a xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>getRunatserver() method. We
did not need to override xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>release(), since we created no new member variables or other
resources that require cleanup. We did not need to override xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>renderEnd(), since our new
attribute does not need to be rendered as part of the final HTML.
Extend the tag definition
As in Example 1, we need a new tag definition which includes the new attribute xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatserver.
Picking up where we left off in Example 1, we modify the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>text tag definition in our new tag
library xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>ArgonDigital.tld to include the new attribute:
<attribute>
<name>runatserver</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
The attribute definition consists of three elements:
- name – the name of the attribute
-
required – xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>true if the attribute must be included when using the tag, otherwise
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>false -
rtexprvalue – xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>true if the attribute should be given a value when used, otherwise
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>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 xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>true, and if it is not included its value is
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>false.
The definition of our new xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatserver attribute is similar to the definition of the
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatclient attribute (and other attributes): not required, but when used it must have a value
(i.e. xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatserver=’true’, or xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatserver=’false’, as opposed to
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatserver with no value.
Since we have also extended the tag class, we need to modify the tag definition so the tag will
use our extended class instead of the original WDK class:
<tagclass>com.organization.package.TextTag</tagclass>
When completed, our custom tag library file xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>ArgonDigital.tld now looks like this:
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>bf</shortname>
<tag>
<name>text</name>
<tagclass>com.organization.package.TextTag</tagclass>
<bodycontent>empty</bodycontent>
<attribute>
<name>id</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>name</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>size</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>value</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>datafield</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>nlsid</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>enabled</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>visible</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>onchange</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>style</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>cssclass</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>defaultonenter</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>runatclient</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>tooltipnlsid</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>focus</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>runatserver</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
Using our new attribute is simple. As in Example 1, we must be sure to include a JSP directive to our
custom tag library at the top of the JSP page:
<%@ taglib uri=”/WEB-INF/tlds/ArgonDigital.tld” prefix=”bf” %>
Now we can use the new attribute in our tag. Be sure to use the extended tag
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><bf:text>, not the original xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:text> tag.
<bf:text id='username' name='username' size='40' onchange='validateUsername' runatserver='false' />
Now that we’ve extended the control, setting xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatserver=’false’ has the same effect as
setting xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>runatclient=’true’, which is that the onchange event is now processed by client-side
JavaScript instead of a server-side Java event handler method. Remember, the new attribute will only work
when using our new xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><bf:text> tag; the original xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><dmf:text> tag is
still the same.
Example 3: Adding a new control attribute to support a standard HTML attribute
The HTML input element supports an xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>onblur event, which is usually a piece of JavaScript code
that is called when the element loses focus in the client browser. WDK provides no way to set this event
handler on the HTML element that is generated by the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>text control. This example shows how to
extend the WDK xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>text control to support the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>onblur attribute.
Extend the control class
In order for the state of the onblur attribute to be maintained as part of the Control (and
therefore be available for programmatic changes), we must extend the existing WDK control
class (Text) and add member variable and accessors:
package com.organization.package;
/**
* The Text class extends the WDK contral class Text to include support for an
* “onblur” attribute. The purpose is simply to expose the existing HTML form
* element attribute “onblur”.
*
* @author Jason Duke
*/
public class Text extends com.documentum.web.form.control.Text {
/** The onblur code to call */
private String m_onBlur = null;
/**
* Construct a Text.
*/
public Text() {
super();
m_onBlur = null;
}
/**
* Set the javascript code to call when focus is lost.
*
* @param method the javascript code to call when focus is lost
*/
public void setOnBlur(String method) {
m_onBlur = method;
}
/**
* Get the javascript code to call when focus is lost.
*
* @return the javascript code to call when focus is lost
*/
public String getOnBlur() {
return m_onBlur;
}
Extend the tag class
As in the previous example, we must modify the tag class so that it:
- renders the proper HTML for
the new attribute, - propagates the tag state to the control and back
We need to create a new class which extends the WDK TextTag class and adds the code for the
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>onblur attribute. This time, we will be performing more of the steps listed under How to
Extend: Extending the Tag Class than we did in Example 2.
package com.organization.package;
/**
* Extends WDK’s TextTag to include support for additional attributes.
*
* @author Jason Duke
*/
public class TextTag extends com.documentum.web.form.control.TextTag {
/** The onblur value */
private String m_onblur = null;
/**
* Construct a TextTag.
*/
public TextTag() {
super();
m_onblur = null;
}
/**
* Get the value of the onblur, which is typically some JavaScript
* code to be called when focus is lost.
*
* @return the value of the onblur
*/
public String getOnblur() {
return m_onblur;
}
/**
* Set the value of the onblur, which is typically some JavaScript
* code to be called when focus is lost.
*
* @param onblur the value of the onblur
*/
public void setOnblur(String onblur) {
m_onblur = onblur;
}
/**
* Release resources.
*/
public void release() {
super.release();
m_onblur = null;
}
/**
* Redefine the getControlClass() method to return our version of the Text
* Control class.
*
* @return the Class of the control associated with this tag
*/
protected Class getControlClass() {
return com.organization.package.Text.class;
}
/**
* Propagate the values from this tag object to the underlying Control
* object. This is invoked by the framework.
*
* @param control the Control to set values on
*/
protected void setControlProperties(Control control)
{
try {
// Let the super propagate all its state first.
super.setControlProperties(control);
// Now propagate any custom state
com.organization.package.Text text = (com.organization.package.Text) control;
text.setOnBlur(getOnblur());
} catch (Exception e) {
// (log the exception, perhaps)
}
}
/**
* The renderEnd() method, modified to include the onblur handler.
*
* @param jspwriter the JspWriter used to render the HTML
* @throws IOException if any errors are encountered
*/
protected void renderEnd(JspWriter jspwriter)
throws IOException
{
try
{
Text text = (Text)getControl();
if(text.isVisible())
{
StringBuffer stringbuffer = new StringBuffer(128);
// Start the tag.
beginTag(stringbuffer);
// Append the attribute list from the superclass.
appendAttributeList(stringbuffer);
// Append onblur attribute.
String onblur = StringUtils.trimmedEmptyToNull(text.getOnBlur());
if(onblur != null)
stringbuffer.append(” onblur='”).append(Util.encode(formatValue(onblur))).append(“‘”);
// Finish the tag off.
endTag(stringbuffer);
// Output it to the jsp writer.
jspwriter.print(stringbuffer.toString());
}
}
catch (Exception e) {
// (log the exception, escalate it, etc.)
}
}
}
We have added a new member variable xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>m_onblur, along with getters and setters. We have added
the necessary initialization and cleanup of this variable to the constructor and the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>release()
method. Because we have extended the control class (Text) as well, we have overridden
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>getControlClass() to return our extended control class and xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>setControlProperties()
to propagate the onblur state to the control.
That covers the part of the control tag that pushes the state down to the control, but what about
rendering the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>onblur attribute? The whole point of this example was to add support for the
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>onblur attribute of the HTML xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><input> tag. In order for the
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>onblur attribute to be rendered as part of the HTML generated by the tag, we needed to
override xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>renderEnd()
Ideally, we would like to extend renderEnd(), call some method in the superclass to render everything it
knows how to render, then render our new onblur attribute. If the superclass renders this:
<input name=”username” size=”40″>
then our class should render this:
<input name=”username” size=”40″ onblur=”…”>
Our xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>onblur attribute needs to be inserted into the middle of the HTML already rendered
by the tag.
Unfortunately, the code for the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>renderEnd() method in the WDK xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>TextTag class
writes all the HTML directly to the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>JspWriter as it is produced, so there is no way for our
tag class to call a method in the superclass to render the rest of the tag and then insert our attribute at
the appropriate place.
If there was a method such as xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>appendAttributeList() which operated on a
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>StringBuffer, it might be possible to simply override that method to call the super
and then tack on our attribute. But because the WDK tag classes do not separate the construction
of the HTML from the actual outputting of it, this becomes more challenging.
For the purposes of this exercise, therefore, we have assumed that such a xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>appendAttributeList()
method already exists or could be constructed based on an examination of the behavior
of the existing WDK class, and we have used it, along with hypothetical beginTag() and
endTag() methods, in our override of the renderEnd() method.
Extend the tag definition
As in the previous examples, we need a new tag definition which includes the new attribute
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>onblur. Picking up where we left off in Example 2, we modify the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>text tag
definition in our new tag library xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>ArgonDigital.tld to include the new attribute:
<attribute>
<name>onblur</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
And point it to the extended tag class.
<tagclass>com.organization.package.TextTag</tagclass>
Here is the complete tag library after all three examples:
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>bf</shortname>
<tag>
<name>text</name>
<tagclass>com.organization.package.TextTag</tagclass>
<bodycontent>empty</bodycontent>
<attribute>
<name>id</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>name</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>size</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>value</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>datafield</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>nlsid</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>enabled</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>visible</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>onchange</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>style</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>cssclass</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>defaultonenter</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>runatclient</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>tooltipnlsid</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>focus</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>runatserver</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>onblur</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
Now that we have modified the xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”><bf:text> tag definition to include an
xmlns:xsi=”https://www.w3.org/2001/XMLSchema-instance”>onblur attribute, we can specify a value for that attribute when we use the tag.
The value for the new onblur attribute will be propagated through the tag class into
the control class, and any changes made to the control class (by a component, for example)
will be propagated back to the HTML input element’s onblur attribute.
Conclusion
Technically, you can extend any WDK control. Realistically, you may be limited by the
complexity and/or design of the existing control classes (which methods/members are private
or public, what behavior was abstracted or not, etc.). But for quick changes to the more simple
controls, the techniques described above should suffice.
Remember, a single tag library can contain multiple tag definitions. Multiple controls can all
be extended using the same tag library. Don’t forget to include a JSP directive to your new tag
library, and remember your tag prefix.
(Note: Some of the definitions in this file were taken in part from the WDK Reference Manual.)