Custom tags: lightweight, cheap, replaceable - Web Services
Learn about an adaptable approach which separates programming tasks from Web page design tasks. This strong conceptual model encourages good design, enables re-use of data definitions, and is well-suited to the construction of dynamic user interfaces. The authors also illustrate the particular challenges you might encounter when you dynamically change the analysis performed by Web pages. (This intermediate-level article was first published by IBM developerWorks, August 5, 2004, at http://www.ibm.com/developerWorks).
One benefit of using suitable interfaces to enable contained tags to find their appropriate containers is that it avoids having tag handlers explicitly looking for other classes of tag handler. This ensures a greater flexibility of design. Custom tags are the interface between the function that the programmer is providing and the page author who will use that function. So, the custom tag sets should be adapted to the needs of the page author and not encapsulate too much of the implementation detail that lies behind them.
Ideally, a custom tag handler is:
Lightweight: inexpensive to instantiate and destroy, maintaining low overhead in terms of memory and other resources.
Cheap to develop: most of the effort of the development team can be focused on ensuring the back-end function works smoothly.
Easy to replace: as the needs of the page authors change, the design of the custom tag set might change, and this should be quick and easy to do as the tag handlers do not embody the back-end function but only provide access to it.
Several custom tags have been shown which must reference the data tag, which has been configured with all the details of the data to be fetched. These tags then have to get the data and work with it in various ways. Note that it is not the data tag handler itself which does the data fetching: following the principles just outlined, the data tag handler simply acts as an interface to the appropriate data fetching function produced by the programmer or sourced from a third party.
As well as allowing other tag handlers to access stored values by using the findAttribute method, a tag can also make stored values available to Java code embedded directly into the JSP (sometimes fragments of Java code included in a JSP in this way are called scriptlets). This requires the use of a TagExtraInfo class, which supplements the tag handler and can be used to specify extra validations and also to create scripting variables. When this is done, the id value becomes the name of the Java variable which can be used to refer to the object from within Java code in the JSP.
Suppose, for example, that a back-end class called DataProvider can be suitably configured and then used to fetch the required data. The data tag handler creates and configures an instance of DataProvider using all the details specified in the contained tags. It then needs to make that instance of DataProvider available to other tags which might need it. This is accomplished by setting an id attribute on the data tag, and then using this id as a key to save the instance of DataProvider into a suitable store.
The setAttribute and findAttribute methods provide the means to save values into a suitable store and then retrieve them later. The setAttribute method can be given the value of the id attribute as the key value, the instance of DataProvider as the value to save, and the scope (request scope, page scope, session scope, or application scope) in which the value is to be saved. For most purposes, page scope is appropriate. If necessary, a scope attribute could also be included on the data tag to specify which scope the instance of DataProvider should be saved in.
Custom tags, such as the forSlices tag (see Listing 2) and the satisfactionChart tag (see Listing 3), have a dataRef attribute which allows the id of a data tag to be supplied. When the tag handler needs to obtain data, it can use the findAttribute method, supplying the dataRef attribute value as the key to search for. This method will attempt to locate a stored value in request scope, page scope, session scope, and finally in application scope with a return value. The tag handler now has access to the instance of DataProvider, which it can use to fetch data and work with it as appropriate.