Tips and tricks for customizing composite components

Source: Internet
Author: User
Tags tld

JavaServer faces (JSF) provides scalable component models that developers can create reusable components and use these custom components to improve development efficiency and reduce development costs. Although the JSF component model is very powerful for customization and reuse, developers generally think that developing JSF custom components is not easy, because at least the internal mechanisms of JSF encode/decode and State holder need to be familiar with and overwrite the corresponding methods (refer to "Skeptical JSF: JSF component development"), as described in encodebegine (), decode (), savestate (), and restorestate (). For developing complex custom components, you even need to have a deep understanding of more interfaces, such as namingcontainer, stateholder, editablevalueholder, and actionsource.

However, reusing JSF standard components greatly simplifies the development of custom components, especially for custom composite components. In most cases, we can reuse the standard Renderer, State management, event listener, converter, and validators that the JSF framework already provides. There are few articles or books about how to reuse these standard functions. This article proposes the Principles and Techniques for developing JSF custom composite components quickly based on the Reuse Policy.

This article first summarizes the general principles of JSF component development, and then explains which standard functions can be reused and how to reuse them through the development of a value scroller custom composite component, to simplify the development of JSF custom composite components. Principles and skills

 

There are two main principles for developing JSF custom composite components: reusing existing standard components and ensuring that custom components are easy to reuse.

1. Reuse the functions and implementations of standard components as much as possible

We recommend that you fully implement the encode/decode logic for the traditional custom composite component development. However, this is time-consuming and error-prone. There is no doubt that we can reduce or even skip writing this part of code by reusing the Renderer of standard components. In addition, to achieve flexible configuration and use, custom composite components usually need to provide many attributes. We need to write a lot of code to process the read/write and State management of these attributes. In fact, we can simply pass the attributes of a custom composite component to its own standard components, and the existing standard code processes these attributes without repeating the code.

2. clearly separate component classes, label classes, and model classes

The component model of JSF is recommended to have clear responsibility distribution between component classes, tag classes, and model classes for reuse and extension. The component class should not depend on the javax.faces.component.html package, because the component class can be used not only in HTML, but also in other Markup languages (such as WML ). That is to say, the component class should not directly reference the HTML components in the javax.faces.component.html package. For example, creating an htmlcommandbutton instance in your component class is not advisable. You should consider using the uicommand in the javax. Faces. Component package. On the other hand, if you want your model class to be reused in different Web frameworks, your model class should not depend on any JSF package, that is, the model class only indicates the Business Object and does not contain any components, data, and status related to the user interface.

Based on these principles, we can compare the traditional methods with the techniques described in this article. We can find that the reuse-based development strategy greatly simplifies the compilation of JSF custom composite components. Generally, the following three steps are required to develop a JSF custom component (refer to the "Skeptical JSF: JSF component development ").

1. Extended uicomponent

· Traditional Method: create a class, extend uicomponent, save component Status, register component in faces-config.xml

Reuse tips:

· Select uipanel as the layout container and reuse the standard component as the child component of the composite component.

· Implement the internal action listener.

2. Define the Renderer or Inline implement it

Traditional Method: override implement encode/decode, register Renderer in faces-config.xml.

Reuse tips: reuse standard Renderer types.

3. Create a custom tag that inherits the uicomponenttag

Traditional Method: return the Renderer type and component type, and set the JSF expression attribute.

Reuse tips: Pass attribute values to the standard component that serves as a child component. Overview

The development steps of a custom composite component value scroller demonstrate how to reuse the functions and implementations of standard components using a variety of techniques to simplify development and make it easy to reuse. Value scroller allows you to enter a value by clicking the value-added or impairment button instead of manually typing it, as shown in figure 1. This example only contains the most basic functions. For example, only integer value input is supported, but the content described in this article is sufficient.

Figure 1. Value scroller on the test page

Figure 2 illustrates the basic class structure of value scroller, which follows the MVC pattern. The component class valuescroller extends uipanel and acts as a controller to interact with users. The tag class valuescrollertag inherits the uicomponenttag and is displayed on the view page. The value object bound to the value scroroller serves as a model to store the value you type.

Figure 2. Class Structure of value scroller

In the subsequent sections, this article describes how to quickly develop a JSF custom composite component by applying the principles and techniques mentioned above with the value scroller example. Select uipanel as container

The first step to creating a JSF custom composite component is to select a standard component class for extension. We usually consider using this component class as a container and embedding it into sub-components to form a composite component. Here, we choose to inherit uipanel as the container of value scroller, render the page as a grid, and include a uiinput and two uicommands, respectively as the value input box and the add-on button, as shown in Listing 1:

List 1. Extended class uipanel

Public class valuescroller extends uipanel {

/**

* The default constructor

*

*/

Public valuescroller (){

Super ();

Addchildrenandfaces ();

}

}

The standard components that serve as the value scroroller child components will be added to the layout container in the addchildrenandfaces method. Reuse standard Renderer type

Next, we start to create the child component of value scroller and implement the Renderer function. In the traditional method, the encodebegin () and decode () Methods of uicomponent must be overwritten. However, if the composite component we developed is composed of multiple standard components, we can add standard component base classes that do not depend on specific Markup languages to custom components and set a standard Renderer type for each standard component, you can complete the Renderer function to be implemented by the composite component. The advantages of reusing the standard component Renderer are that it reduces the development workload and the chance of errors, which is especially important for beginners of JSF; it does not need to implement the encode/decode logic related to a specific markup language, makes component classes easier to reuse.

This book titled "practice with JavaServer faces" lists the standard Renderer types provided by the JSF specifications.

Table 1. JSF standard Renderer

As shown in table 1, a component base class usually corresponds to multiple Renderer types (if HTML is used as the markup language, it corresponds to multiple HTML elements ), because the component base class only defines general data and behavior. For example, uicommand has two HTML subclasses: htmlcommandbutton and htmlcommandlink, which correspond to the Renderer types javax. Faces. Link and javax. Faces. Button respectively. To include a link in a composite component, you only need to create a uicommand instance and set its Renderer type to javax. faces. instead of overwriting the encodebegin () and decode () methods. Listing 2 lists how child components in value scroller are created in the component class valuescroller and how attributes such as Renderer are set.

Listing 2. Reuse the standard Renderer to create a custom composite component

Private Static final string panel_grid_renderer = "javax. Faces. Grid ";

Private Static final string input_text_renderer = "javax. Faces. Text ";

Private Static final string command_link_renderer = "javax. Faces. Link ";

Private Static final string graphic_image_renderer = "javax. Faces. Image ";

/**

* Add children to the base container

*

*/

Private void addchildrenandfaces (){

// Set attributes of the base container

This. setrenderertype (panel_grid_renderer );

This. getattributes (). Put (columns_attribute, new INTEGER (2 ));

// Add the input component

Input = new uiinput ();

Input. setid (input_id );

Input. setrenderertype (input_text_renderer );

This. getchildren (). Add (input );

// Add the container of the up and down links

Uipanel linkcontainer = new uipanel ();

Linkcontainer. setid (linkpanel_id );

Linkcontainer. setrenderertype (panel_grid_renderer );

Linkcontainer. getattributes (). Put (columns_attribute, new INTEGER (1 ));

Scrolleractionlistener listener = new scrolleractionlistener ();

// Add the up link

Uicommand uplink = new uicommand ();

Uplink. setid (uplink_id );

Uplink. setrenderertype (command_link_renderer );

Uplink. addactionlistener (listener );

Uigraphic upimage = new uigraphic ();

Upimage. setid (upimage_id );

Upimage. setrenderertype (graphic_image_renderer );

Upimage. seturl (upimage_url );

Uplink. getchildren (). Add (upimage );

Linkcontainer. getchildren (). Add (uplink );

// Add the down Link

Uicommand downlink = new uicommand ();

Downlink. setid (downlink_id );

Downlink. setrenderertype (command_link_renderer );

Downlink. addactionlistener (listener );

Uigraphic downimage = new uigraphic ();

Downimage. setid (downimage_id );

Downimage. setrenderertype (graphic_image_renderer );

Downimage. seturl (downimage_url );

Downlink. getchildren (). Add (downimage );

Linkcontainer. getchildren (). Add (downlink );

This. getchildren (). Add (linkcontainer );

}

Pass attribute values to standard components

Let's take a look at the attributes defined in the tag description file (TLD.

Listing 3. Defining attributes of a custom composite component in TLD

<Tag>
<Name> valuescroller </Name>
<Tag-class> component. taglib. valuescrollertag </Tag-class>
<Body-content> JSP </body-content>
<Attribute>
<Name> id </Name>
<Description> valuescroller id </description>
</Attribute>
<Attribute>
<Name> value </Name>
<Description> valuescroller value </description>
</Attribute>
<Attribute>
<Name> size </Name>
<Description> input field size </description>
</Attribute>
<Attribute>
<Name> min </Name>
<Description> Minimum value </description>
</Attribute>
<Attribute>
<Name> max </Name>
<Description> maximum value </description>
</Attribute>
<Attribute>
<Name> step </Name>
<Description> scrolling step </description>
</Attribute>
</Tag>

We can see that, except that min/max/step is a custom attribute, all other attributes belong to the JSF standard component and can be passed directly to the standard component processing that constitutes the value scroller, you do not need to overwrite the implementation methods savestate () and restorestate () for the properties of these standard components ().

There are usually two ways to pass attribute values. When you need to perform some extra operations on attributes (such as verification or conversion), you can pass the attributes to the custom component class in the tag class valuescrollertag, as shown below:

Listing 4. Passing Custom Attributes

/**
* Override the setproperties Method
*/
Protected void setproperties (uicomponent component ){
Super. setproperties (component );

Valuescroller Vs = (valuescroller) component;

Application APP = facescontext. getcurrentinstance (). getapplication ();
// Set Value Attribute
If (value! = NULL ){
If (isvaluereference (string) value )){
Valuebinding VB = app. createvaluebinding (string) value );
Vs. setvaluebinding ("value", VB );
} Else {
Throw new illegalargumentexception ("the value property must be a value" +
"Binding expression that points to a bean property .");
}
}

// Set ID attribute
If (ID! = NULL ){
Vs. setid (string) ID );
}

// Set other attributes
Vs. setmin (min );
Vs. setmax (max );
Vs. setstep (STEP );

}

Another method is to directly add the attribute values to the attribute map of the corresponding standard component in the tag class valuescrollertag. For example, pass the size attribute to the uiinput contained in the Custom composite component:

Listing 5. Passing standard attributes

Vs. findcomponent ("input"). getattributes (). Put ("size", new INTEGER (size); implement internal action listener

In value scroller, click the value-added or impairment button to increase or decrease the value in the input box. We can simply implement an internal action listener in the valuescroller component class and reuse the event processing logic of uicommand.

Listing 6. Implementing the value scroller action listener

/**
* Internal action listener for value scroller
* _ Cnnew1 @ author CLL
*
*/
Private class scrolleractionlistener implements actionlistener {
Public void processaction (actionevent e ){
// Only integer is supported for this demo
If (input. getvalue () instanceof integer ){
String commandid = (uicommand) E. getsource (). GETID ();
Int value = (integer) Input. getvalue (). intvalue ();
// Increase value if the up link is clicked
If (commandid. Equals (uplink_id )){
If (Value + getstep ()> MAX ){
Input. setvalue (New INTEGER (max ));
} Else {
Input. setvalue (New INTEGER (Value + getstep ()));
}
}
// Decrease value if the down link is clicked
Else if (commandid. Equals (downlink_id )){
If (value-getstep () <min ){
Input. setvalue (New INTEGER (min ));
} Else {
Input. setvalue (New INTEGER (value-getstep ()));
}
}
} Else {
Throw new illegalargumentexception (
"Unsupported binding type," +
"And only integer instance allowed for this demo .");
}
}
}

Finally, when the addchildrenandfaces method is called to create and add sub-components, add the Custom Action listener to the value-added and impairment components.

Listing 7. register the value scroller action listener

Scrolleractionlistener listener = new scrolleractionlistener ();

Uplink. addactionlistener (listener );

Downlink. addactionlistener (listener );

Use Value scroller

Value scroller development has been completed, the use is also very simple, first declare reference value scroller in the faces-config.xml, as shown below:

Listing 8. Declaring reference value scroller in faces-config.xml

<Component>
<Component-type> XYZ. valuescroller </component-type>
<Component-class>
Component. valuescroller
</Component-class>
</Component>

Then, the test. jsp page contains the label description file of value scroller.

Listing 9. TLD containing value scroller in JSP

<% @ Taglib uri = "/WEB-INF/lib/valuescroller. TLD" prefix = "XYZ" %>

Finally, use the value scroler label on the test. jsp page, specify the size/MIN/max/step attribute value, and deploy and run the label. The result shown in Figure 1 is displayed.

Listing 10. Create value scroller in JSP and set attributes

<XYZ: valuescroller value = "# {pc_test.itemcount}" size = "5" min = "-50" max = "10000" step = "2">
</XYZ: valuescroller>

Conclusion

We can see that the implementation of the custom composite component value scroller described in this article does not write the logic related to encode/decode and State/event management, which is simple, fast, and easy to reuse. The development skills of the JSF custom composite components summarized in this article greatly reduce the complexity and workload, and are better than the traditional development methods.

 

Author:IBM Chen Lilong ealine Zhan zikko 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.