Oracle® Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework 11g Release 1 (11.1.1) B31973-05 |
|
![]() Previous |
![]() Next |
This chapter describes how to create custom ADF Faces rich client components.
This chapter includes the following sections:
The ADF Faces component library provides a comprehensive set of UI components that covers most of your requirements. However, there are situations when you will want to create a custom rich component that is specific to your application. A custom rich component will allow you to have custom behavior and perform actions that best suit the needs of your application.
Note: Creating custom standard JSF components is covered in many books, articles, web sites, and the JavaServer Faces specification, therefore, it is not covered in this guide. This chapter is intended to describe how to create ADF Faces components. |
JSF technology is built to allow self-registering components and other framework parts. The core JSF runtime at web application startup accomplishes this by inspecting all JAR files in the class path. Any JAR files whose /META-INF/faces-config.xml
file contains JSF artifacts will be loaded. Therefore, you can package custom ADF Faces components in a JAR file and simply add it into the web project.
For each ADF Faces component, there is a server-side component and there can also be a client-side component. On the server, for JSPs, a render kit provides a base to balance the complex mixture of markup language and JavaScript. The server-side framework also adds a custom lifecycle to take advantage of the API hooks for partial page component rendering. On the client, ADF Faces provides a structured JavaScript framework for handling various nontrivial tasks. These tasks include state synchronization using partial page rendering. For more information about the ADF Faces architecture, see Chapter 3, "Using ADF Faces Architecture."
ADF Faces components are derived from the Apache MyFaces Trinidad component library. Because of this, many of the classes you extend when creating a custom ADF Faces component are actually MyFaces Trinidad classes. For more information about the history of ADF Faces, including its evolution, see Chapter 1, "Introduction to ADF Faces Rich Client."
Between the JSP and the JSF components is the Application
class. The tag library uses a factory method on the application
object to instantiate a concrete component instance using the mnemonic referred to as the componentType
.
A component can render its own markup but this is not considered to be a best practice. The preferred approach is to define a render kit that focuses on a strategy for rendering the presentation. The component uses a factory method on the render kit to get the renderer associated with the particular component. If the component is consumed in an application that uses Facelets, then a component handler creates the component.
In addition to functionality, any custom component you create must use an ADF Faces skin to be able to be displayed properly with other ADF Faces components. To use a skin, you must create and register the skinning keys and properties for your component. This chapter describes only how to create and register skins for custom components. For more information about how skins are used and created in general, see Chapter 20, "Customizing the Appearance Using Styles and Skins."
Tip: To work with ADF Faces components, your custom component must use at least the ADF Facessimple skin, because the FusionFX , blafplus-rich , and blafplus-medium skins inherit from the simple skin. Additionally, if there is any chance your component will be used in an Oracle WebCenter application, then your skin must also be registered with the simple.portlet skin. |
An ADF Faces component consists of both client-side and server-side resources. On the client side, there is the client component, the component peer (the component presenter), and any events associated with the client component.
On the server side, there is the server component, server component events, and event listeners. Also, there is a component renderer, a component JSP tag, a composite resource loader, a JavaScript resource loader, and a resource bundle.
The component also has several configuration and support files. Together, these classes, JavaScripts, and configuration files are packaged into a JAR file, which can be imported as a library into an application and used like other components.
You can use JDeveloper to set up the application workspace and project in which you develop the custom component. After you have created the workspace and project, you add starter working files for the required classes, JavaScript files, and configuration files that make up the custom component. During development, you edit and add code to each of these files, specific for the custom component.
The development process is as follows:
Create an application, workspace, and project as an environment for development. This includes adding library dependencies and registering XML schemas. You should not create the component in the same application in which you plan to use the component.
Create a deployment profile for packaging the component into a JAR file.
Create the following starter configuration and support files:
faces-config.xml
: Used to register many of the artifacts used by the component.
trinidad-skins.xml
: Used to register the skins that the component uses.
Cascading style sheet: Used to define the style properties for the skins.
Render kit resource loader: Allows the application to load all the resources required by the component.
adf-js-features.xml
: Allows the component to become part of a JavaScript partition. For more information about partitions, see Section 1.2.1.2, "JavaScript Library Partitioning."
JSP tag library descriptor (TLD) (for JSP): Defines the tag used on the JSF page.
Component handler (for Facelets): Defines the handler used to render the component.
Create the following client-side JavaScript files:
Client Component: Represents the component and its attributes on the client.
Client Peer: Manages the document object model (DOM) for the component.
Client Event: Invokes processing on the client and optionally propagates processing to the server.
Create the following server-side Java files:
Server Component class: Represents the component on the server.
Server Event Listener class: Listens for and responds to events.
Server Events class: Invokes events on the server.
Server Renderer class: Determines the display of the component.
Resource Bundle class: Defines text strings used by the component.
Further develop the component by testing and debugging the JavaScript and Java code. You can use the JDeveloper debugger to set breakpoints and to step through the code. You can also use Java logging features to trace the execution of the component.
Deploy the component into a JAR file.
Test the component by adding it into an application.
Table 30-1 lists the client-side and server-side component artifacts for a custom component. The configuration and support files are not included in the table.
Table 30-1 Client-Side and Server-Side Artifacts for a Custom Component
Client | Server |
---|---|
Component class:
Extends:
|
Component:
Extends:
|
Event:
Extends:
|
Event:
Extends:
|
Event Listener:
Extends:
|
|
Component Peer:
Extends:
|
|
Component Renderer:
Extends:
|
|
Component JSP Tag (JSP only):
Extends:
|
|
Composite Resource Loader:
Extends:
|
|
JavaScript Resource Loader:
Extends:
|
|
Resource Bundle:
Extends:
|
To help illustrate creating a custom component, a custom component named tagPane
will be used as an example throughout the procedures. The tagPane
custom component is created for reuse purposes. Although the tagPane
presentation might have been implemented using a variety of existing components, having a single custom component simplifies the work of the page developer. In this case, there may be a trade-off of productivity between the component developer and the page developers. If this particular view composition were needed more than once, the development team would reduce costs by reducing the lines of code and simplifying the task of automating a business process.
The tagPane
component displays a series of tags and their weighted occurrences for a set of files. Tags that are most frequently used are displayed in the largest font size, while the least used tags are displayed in the smallest font size. Each tag is also a link that triggers an event, which is then propagated to the server. The server causes all the files that contain an occurrence of that tag to then be displayed in a table. Figure 30-1 shows how the tagPane
component would be displayed if it was added below the Search pane in the File Explorer application.
The tagPane
component receives a collection of tags in a Java Map
collection. The key of the map is the tag name. The value is a weight assigned to the tag. In the File Explorer application, the weight is the number of times the tag occurs and in most cases, the number of files associated with the tag. The tag name is displayed in the body text of a link and the font size used to display the name represents the weight. Each tag's font size will be proportionally calculated within the minimum and maximum font sizes based upon the upper and lower weights assigned to all tags in the set of files. To perform these functions, the tagPane
custom component must have both client-side and server-side behaviors.
On the server side, the component displays the map of tags by rendering HTML hyperlinks. The basic markup rendering is performed on the server. A custom event on the component is defined to handle the user clicking a link, and then to display the associated files. These server-side behaviors are defined using a value expression and a method expression.
For example, the tagPane
component includes:
A tag
property for setting a Map<String, Number>
collection of tags.
A tagSelectionListener
method-binding event that is invoked on the server when the user clicks the link for the tag.
An orderBy
property for displaying the sequence of tags from left to right in the order of descending by weight or alternatively displaying the tag links ascending alphabetically.
To allow each tag to be displayed in a font size that is proportional to its weight (occurrences), the font size is controlled using an inline style. However, each tag and the component's root markup node also uses a style class.
Example 30-1 shows how the tagPane
component might be used in a JSF page.
Example 30-1 tagPane Custom Component Tag in a JSF Page
<acme:tagPane id="tagPane" tags="#{explorer.navigatorManager.tagNavigator.tags}" tagSelectListener="#{explorer.navigatorManager.tagNavigator.onTagSelect}" orderBy="alpha" partialTriggers="tagCountLabel"/>
Because the tagPane
component must be used with other ADF Faces components, it must use the same skins. Therefore, any styling is achieved through the use of cascading style sheets (CSS) and corresponding skin selectors. For example, the tagPane
component needs skin selectors to specify the root element, and to define the style for the container of the links and the way the hyperlinks are displayed. Example 30-2 shows a sample set of style selectors in the CSS file for the tagPane
component.
Example 30-2 CSS Style Selectors for the Sample Custom Component
acme|tagPane - root element acme|tagPane::content - container for the links acme|tagPane::tag - tag hyperlink
You may need to specify the HTML code required for the custom component on the server side.
Example 30-3 shows HTML server-side code used for the tagPane
component.
Example 30-3 HTML Code for the Server Side
<div class=" acme|tagPane"> <span class=" acme|tagPane::content "> <a class=" acme|tagPane::tag" href="#" style="font-size:9px;">Tag1</a> <a class=" acme|tagPane::tag" href="#" style="font-size:10px;">Tag2</a> </span> </div>
On the client side, the component requires a JavaScript component counterpart and a component peer that defines client-side behavior. All DOM interaction goes through the peer (for more information, see Chapter 3, "Using ADF Faces Architecture"). The component peer listens for the user clicking over the hyperlinks that surround the tag names. When the links are clicked, the peer raises a custom event on the client side, which propagates the event to the server side for further processing.
Table 30-2 lists the client-side and server-side artifacts for the tagPane
component. Referencing the naming conventions in Table 30-1, the component_package
is com.adfdemo.acme
and the prefix
is Acme
.
Table 30-2 Client-Side and Server-Side Artifacts for the tagPane Custom Component
Client | Server |
---|---|
Component:
Extends:
|
Component
Extends:
|
Event:
Extends:
|
Event:
Extends:
|
Event Listener:
Extends:
|
|
Component Peer:
Extends:
|
|
Component Renderer:
Extends:
|
|
Component JSP Tag:
Extends:
|
|
Composite Resource Loader:
Extends:
|
|
JavaScript Resource Loader:
Extends:
|
|
Resource Bundle:
Extends:
|
Use JDeveloper to set up an application and a project to develop the custom component. After your skeleton project is created, you can add a deployment profile for packaging the component into a JAR file.
During the early stages of development, you create starter configuration and support files to enable development. You may add to and edit these files during the process. You create the following configuration files:
META-INF/faces-config.xml
: The configuration file required for any JSF-based application. While the component will use the faces-config.xml
file in the application into which it is eventually imported, you will need this configuration file for development purposes.
META-INF/trinidad-skins.xml
: The configuration information for the skins that the component can use. Extend the simple skin provided by ADF Faces to include the new component.
META-INF/
package_directory
/styles/
skinName.css
: The style metadata needed to skin the component.
META-INF/servlets/resources/
name
.resources
: The render kit resource loader that loads style sheets and images from the component JAR file. The resource loader is aggregated by a resource servlet in the web application, and is used to configure the resource servlet. In order for the servlet to locate the resource loader file, it must be placed in the META-INF/servlets/resources
directory.
META-INF/adf-js-features.xml
: The configuration file used to define a feature. The definition usually includes a component name or description of functionality that a component provides, and the files used to implement the client-side component.
META-INF/
prefix_name
.tld
(for JSP): The tag definition library for the component. If the consuming web application is using JSP, the custom component requires a defined TLD. The TLD file will be located in the META-INF
folder along with the faces-config.xml
and trinidad-skins.xml
files.
META-INF/
prefix_name
.taglib.xml
(for Facelets): The tag library definition for the component when the consuming application uses Facelets. This file defines the handler for the component.
For example, for the tagPane
component, the following configuration files are needed:
META-INF/faces-config.xml
META-INF/trinidad-skins.xml
META-INF/acme/styles/acme-simple-desktop.css
META-INF/servlets/resources/acme.resources
META-INF/acme.tld
META-INF/acme.taglib.xml
META-INF/adf-js-features.xml
After the files are set up in JDeveloper, you add content to them. Then, you create the client-side files nd server-side files. For more information, see Section 30.3, "Client-Side Development," and Section 30.4, "Server-Side Development."
This chapter assumes you have experience using JDeveloper and are familiar with the steps involved in creating and deploying an application. For more information about using JDeveloper to create applications, see Chapter 2, "Getting Started with ADF Faces." For more information about deployment, see the "Deploying Fusion Web Applications" chapter of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
To set up the custom component development environment in JDeveloper:
Create an application to serve as a development container for the component. Use JDeveloper to create a workspace and project. For procedures on creating an application, see Section 2.2, "Creating an Application Workspace." When selecting an application template, select the Generic Application template.
Note: Do not select any other application template, or add any technologies to your application. Because the custom component will be packaged into a JAR file, you do not need to create unnecessary folders such aspublic_html that JDeveloper creates by default when you use a template specifically for web applications, or add web technologies. Instead, create the starter configuration file from the XML schemas. |
Prepare the project to be deployed as a JAR file by creating a new deployment profile.
In the Application Navigator, right-click the project and choose New.
In the New Gallery, select Deployment Profile and then ADF Library JAR File, and click OK.
In the Create Deployment Profile dialog, enter a name for the Deployment Profile name. For example, the tagPane
component might use adf-richclient-demo-acme
.
In the Edit JAR Deployment Profile Properties dialog, click OK.
In the Project Properties dialog, add library dependencies.
Select Libraries and Classpath in the left pane.
Click Add Library.
In the Add Library dialog, select ADF Faces Runtime 11, Facelets Runtime (if using Facelets), JSF 1.2, and JSP Runtime, and click OK.
Click OK to close the Project Properties dialog.
Register XML schemas.
The custom component requires several XML configuration files. You can use JDeveloper to register the XML schemas associated with these configuration files. You must add schemas for three configuration files: faces-config.xml
, trinidad-skins.xml
, and trinidad-config.xml
. By preregistering these schemas, you can create a template XML configuration file without having to know the specifics about the markup structure. The names and locations of the schemas are assumed by the base installation of JDeveloper.
Select Tools > Preferences. In the Preferences dialog, select XML Schemas in the left pane, and click Add.
In the Add Schema dialog, click Browse to navigate to the XML schemas included in your JDeveloper build, as shown in Table 30-3.
Note: In the Add Schema dialog, make sure Extension is set to.xml . If you change it to XSD, when you later create XML files, you will not be able to use the XML schema you have created. |
Table 30-3 XML Schema Locations
XML Configuration File | Schema Location |
---|---|
|
|
|
|
|
|
|
|
Although the custom component will be registered in the consuming application's faces-config.xml
file, during development, the workspace requires a faces-config.xml
file.
Note: Do not use any of JDeveloper's declarative wizards or dialogs to create thefaces-config.xml file. These declarative methods assume you are creating a web application, and will add uneccessary artifacts to your custom component application. |
To create a faces-config.xml file for the custom component:
In the Application Navigator, right-click the project and select New.
In the New Gallery, expand General, select XML, and then Select XML Document from XML Schema, and click OK.
In the Create XML from XML Schema dialog:
XML File: Enter faces-config.xml
.
Directory: Append \src\META-INF
to the end of the directory entry.
Select Use Registered Schemas and click Next.
Enter the following:
Target Namespace: Select http://java.sun.com/xml/ns/javaee
.
Root Element: Select faces-config
.
Leave the defaults for the other fields, and click Finish.
The new file will automatically open in the XML editor.
Add the following schema information after the first line in the file:
<?xml version="1.0" encoding="US-ASCII"?> <faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee">
Adding a schema provides better WYSIWYG tool support.
Add a MyFaces Trinidad skins file to register the component's CSS file, which is used to define the component's styles.
To create a trinidad-skins.xml file for the custom component:
In the Application Navigator, right-click the project and select New.
In the New Gallery, expand General and select XML.
Select XML Document from XML Schema and click OK.
In the Create XML from XML Schema dialog:
XML File: Enter trinidad-skins.xml.
Directory: Append \
src\META-INF
to the end of the Directory entry.
Select Use Registered Schemas, and click Next.
Enter the following:
Target Namespace: Select http://myfaces.apache.org/trinidad/skin.
Root Element: Select skins
.
Click Finish. The new file will automatically open in the XML editor.
Add a cascading style sheet to define component's style.
To create a cascading style sheet for the custom component:
In the Application Navigator, right-click the project and select New.
In the New Gallery, expand General, select File and click OK.
In the Create File dialog:
Enter a file name, for example, acme-simple-desktop.css
.
Append \src\META-INF\
component_prefix
\styles
to the end of the Directory entry, where component_prefix
is the prefix that will be used in the component library. For example, for the tagPane
component, acme
is the prefix, therefore, the string to append would be \META-INF\acme\styles
.
Create an empty file and add the fully qualified classpath to the custom resource loader.
To create a resource loader for the custom component:
In the Application Navigator, right-click the project and select New.
In the New Gallery, expand General and then File, and click OK.
In the Create File dialog:
Enter component_prefix
.resources
for File Name, where component_prefix
will be the prefix used in the component library. For example, for the tagPane
component, acme
is the prefix, therefore, the string to enter is acme.resources
.
Append \src\META-INF\sevlets\resources\
to the end of the Directory entry.
You need a JSP TLD file to work with JSF pages.
To create a JavaServer Pages TLD file for the custom component:
In the Application Navigator, right-click the project and select New.
In the New Gallery, expand Web Tier and select JSP.
Select JSP Tag Library and click OK.
In the Create JavaServer Page Tag Library dialog, select Deployable and click Next.
Enter the following:
Tag Library Descriptor Version: Select 2.1.
Short Name: A name. For example, for the tagPane component, you would enter acme
.
Tag Library URI: A URI for the tag library. For example, for the tagPane component, you would enter http://oracle.adfdemo.acme
.
Click Next and optionally enter additional tag library information, then click Finish.
Add a features file to define the JavaScript files associated with the custom component, including the files for the client component, the client peer, and the client events.
To create an adf-js-features.xml file for the custom component:
In the Application Navigator, right-click the project and select New.
In the New Gallery, expand General and select XML.
In the right pane, select XML Document from XML Schema and click OK.
In the Create XML from XML Schema dialog:
XML File: Enter adf-js-features.xml.
Directory: Append \
src\META-INF
to the end of the Directory entry.
Select Use Registered Schemas, and click Next.
Do the following:
Target Namespace: Select http://xmlns.oracle.com/adf/faces/feature
.
Root Element: Select features.
Click Finish. The new file will automatically open in the XML editor.
If a consuming application uses Facelets, then you must define the handler for the component.
To create a Facelets tag library file:
In the Application Navigator, right-click the project and select New.
In the New Gallery, expand General and select XML.
In the right pane, select XML Document and click OK.
In the Create XML file dialog, enter the following:
File Name: Enter prefix_name
.taglib.xml
Directory: Append \
src\META-INF
to the end of the Directory entry.
Copy and paste the code shown in Example 30-4:
Example 30-4 Code for Facelets Tag Library Configuration File
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE facelet-taglib PUBLIC "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN" "http://java.sun.com/dtd/facelet-taglib_1_0.dtd"> <facelet-taglib xmlns="http://java.sun.com/JSF/Facelet"> <namespace>http://xmlns.oracle.adfdemo/acme</namespace> <tag> <tag-name>tagPane</tag-name> <handler-class> oracle.adfinternal.view.faces.facelets.rich.RichComponentHandler </handler-class> </tag> </facelet-taglib>
Replace the namespace and tag-name code shown in bold with code appropriate for your application.
After the JDeveloper workspace and configuration files have been created, you can create and code the client-side JavaScript files. When you have finished with the client-side development, create the server-side files, as described in Section 30.4, "Server-Side Development."
Client components hold state for properties that are not defined within the corresponding DOM element. These properties are bound to an associated DOM element using the clientId
. The clientId
uniquely defines a server-side component within the component tree representing a page. The DOM element holds the clientId
within the Id
attribute.
Note: Place each JavaScript object in its own separate source file for best practice and consistency. |
Developing the client-side component requires creating a JavaScript file for the component, the peer, and the component event.
In addition to the client component, client-side events must be defined. The tagPane
component's client-side event is fired and propagated to the server when the user clicks one of the three file types. The client event passed to the server is queued so that the target server-side component can take the appropriate action.
Finally, the custom component requires a client peer. The peer is the component presenter. Peers act as the links between a client component and an associated DOM element. Client peers add client behaviors. A peer must be bound to a component through a registration method.
As with the client component, the associated peer is bound to a DOM element using the component's clientId
. There are two types of peers, statefull and stateless.
Some complex client components require the peer to hold state and thereby need to use a statefull peer. This type of peer is always bound to a DOM element. Statefull peers are less common than stateless peers.
Stateless peers do not hold state and one peer can be bound to multiple components. Stateless peers are the best performance option because they reduce the client footprint. This type of peer performs lazy content delivery to the component.
Peers add behavior to the component by dynamically registering and listening for DOM events. Conceptually, a peer's function is similar to the role of a managed bean. However, the client component is not bound to the peer using EL like the server-side component is bound to a view model (#{backingbean.callback}
). The peer registers client component events in the InitSubclass (AdfRichUIPeer.addComponentEventHandlers("click"))
callback method. The callback is assumed by using a naming convention of (<Peer>.prototype.HandleComponent<Event>
). The peer manages DOM event callbacks where the server-side component handles the linking using EL bindings to managed beans. For more information about client-side architecture, including peers, see Section 3.1, "Introduction to Using ADF Faces Architecture."
The following section assumes you have already set up a custom component development template environment. This development environment includes the setting up of application workspace, projects, deployment profiles, and registering schemas. If you have not done so, see Section 30.2, "Setting Up the Workspace and Starter Files."
Use JDeveloper to create a JavaScript file for the component. In it, you will define the component type for the component.
To create the component JavaScript file:
In the Application Navigator, right-click the project and click New.
In the New Gallery, expand Web Tier and select HTML.
Select JavaScript File and click OK.
In the Create JavaScript File dialog, do the following:
File Name: Enter the name of the client-side component. For example, for the tagPane
component, you might enter AcmeTagPane.js
.
Tip: To prevent naming collisions, start the name with the component prefix. |
Directory: Enter the directory path of the component in a subdirectory under the src
directory. For example, for the tagPane
component, you might enter adfrichclient-demo-acme\src\oracle\adfdemo\acme\js\component
.
Open the JavaScript File in the editor and add the component code to define the component type. Example 30-5 shows the code that might be used for the tagPane
component.
Use JDeveloper to create a JavaScript file for the event. Add code to the JavaScript to perform the functions required when a event is fired, such as a mouse click.
To create the JavaScript for the event:
In the Application Navigator, right-click the project and select New.
In the New Gallery, expand Web Tier and select HTML.
Select JavaScript File and click OK.
In the Create JavaScript File dialog, do the following:
File Name: Enter the name of the client-side event. For example, for the tagPane
component, you might enter AcmeTagSelectEvent.js
.
Tip: To prevent naming collisions, start the name with the component prefix. |
Directory: Enter the directory path of the event in a subdirectory under the src
directory. For example, for the tagPane
component, you might enter adf-richclient-demo-acme\src\oracle\adfdemo\acme\js\event
.
Open the JavaScript File in the editor and add the event code. Example 30-6 shows the event code that might be added for the tagPane
component.
Example 30-6 tagPane Event JavaScript
/** * Fires a select type event to the server for the source component * when a tag is clicked. */ function AcmeTagSelectEvent(source, tag) { AdfAssert.assertPrototype(source, AdfUIComponent); AdfAssert.assertString(tag); this.Init(source, tag); } // make AcmeTagSelectEvent a subclass of AdfComponentEvent AdfObject.createSubclass(AcmeTagSelectEvent, AdfComponentEvent); /** * The event type */ AcmeTagSelectEvent.SELECT_EVENT_TYPE = "tagSelect"; /** * Event Object constructor */ AcmeTagSelectEvent.prototype.Init = function(source, tag) { AdfAssert.assertPrototype(source, AdfUIComponent); AdfAssert.assertString(tag); this._tag = tag; AcmeTagSelectEvent.superclass.Init.call(this, source, AcmeTagSelectEvent.SELECT_EVENT_TYPE);} /** * Indicates this event should be sent to the server */ AcmeTagSelectEvent.prototype.propagatesToServer = function() { return true; } /** * Override of AddMarshalledProperties to add parameters * sent server side. */ AcmeTagSelectEvent.prototype.AddMarshalledProperties = function( properties) { properties.tag = this._tag; } /** * Convenient method for queue a AcmeTagSelectEvent. */ AcmeTagSelectEvent.queue = function(component, tag) { AdfAssert.assertPrototype(component, AdfUIComponent); AdfAssert.assertString(tag); AdfLogger.LOGGER.logMessage(AdfLogger.FINEST, "AcmeTagSelectEvent.queue(component, tag)"); new AcmeTagSelectEvent(component, tag).queue(true); } /** * returns the selected file type */ AcmeTagSelectEvent.prototype.getTag = function() { return this._tag;} /** * returns a debug string */ AcmeTagSelectEvent.prototype.toDebugString = function() { var superString = AcmeTagSelectEvent.superclass.toDebugString.call(this); return superString.substring(0, superString.length - 1) + ", tag=" + this._tag + "]"; } /* * * Make sure that this event only invokes immediate validators * on the client. */ AcmeTagSelectEvent.prototype.isImmediate = function() { return true; }
Use JDeveloper to create a JavaScript file for the peer. Add code to register the peer and bind it to the component.
To create the peer JavaScript file:
In the Application Navigator, right-click the project and select New.
In the New Gallery, expand Web Tier and select HTML.
Select JavaScript File and click OK.
In the Create JavaScript File dialog, do the following:
File Name: Enter the name of the client-side peer. For example, for the tagPane
component, you might enter AcmeTagPanePeer.js
.
Tip: To prevent naming collisions, start the name with the component prefix. |
Directory: Enter the directory path of the event in a subdirectory under the src
directory. For example, for the tagPane
component, you might enter adf-richclient-demo-acme\src\oracle\adfdemo\acme\js\component
.
Open the JavaScript file in the editor and add code for the peer. In this code, you must create the peer, add event handling with respect to the DOM, and register the peer with the component. Example 30-7 shows the code that might be added for the tagPane
component.
Example 30-7 tagPane JavaScript Peer
AdfRichUIPeer.createPeerClass(AdfRichUIPeer, "AcmeTagPanePeer", true); AcmeTagPanePeer.InitSubclass = function() { AdfLogger.LOGGER.logMessage(AdfLogger.FINEST, "AcmeTagPanePeer.InitSubclass()"); AdfRichUIPeer.addComponentEventHandlers(this, AdfUIInputEvent.CLICK_EVENT_TYPE); } AcmeTagPanePeer.prototype.HandleComponentClick = function(componentEvent) { AdfLogger.LOGGER.logMessage(AdfLogger.FINEST, "AcmeTagPanePeer.HandleComponentClick(componentEvent)"); // if the left mouse button was pressed if (componentEvent.isLeftButtonPressed()) { // find component for the peer var component = this.getComponent(); AdfAssert.assertPrototype(component, AcmeTagPane); // find the native dom element for the click event var target = componentEvent.getNativeEventTarget(); if (target && target.tagName == "A") { AdfLogger.LOGGER.logMessage(AdfLogger.FINEST, "File type element (A) found: " + componentEvent.toString()); var tag = target.firstChild.nodeValue; AdfAssert.assertString(tag); AdfLogger.LOGGER.logMessage(AdfLogger.FINEST, "tag :" + tag); // fire a select event AcmeTagSelectEvent.queue(component, tag); //cancel the native dom onclick to prevent browser actions based on the //'#' hyperlink. The event is of type AdfIEUIInputEvent. This event //will cancle the native dom event by calling //AdfAgent.AGENT.preventDefault(Event) componentEvent.cancel(); } // event has dom node } } // Register the peer with the component. This bit of script must // be invoked after the AcmeTagPane and AcmeTagSelectEvent objects // are created. This is enforced by the ordering of the script files // in the oracle.asfdemo.acme.faces.resource.AcmeResourceLoader. AcmeScriptsResourceLoader.AdfPage.PAGE.getLookAndFeel() .registerPeerConstructor("oracle.adfdemo.acme.TagPane", "AcmeTagPanePeer");
Now that you have created all the JavaScript files for the component, you can add the component to the adf-js-features.xml file you created. Follow the procedures documented in Section A.9.1, "How to Create a JavaScript Feature," omitting the steps for creating the XML files, as you have already done so. Example 30-8 shows the adf-js-features.xml
file used for the tagPane
component.
Example 30-8 adf-js-features.xml File for the tagPane Component
<?xml version="1.0" encoding="UTF-8" ?> <features xmlns="http://xmlns.oracle.com/adf/faces/feature"> <feature> <feature-name>AcmeTagPane</feature-name> <feature-class> oracle/adfdemo/acme/js/component/AcmeTagPane.js </feature-class> <feature-class> oracle/adfdemo/acme/js/event/AcmeTagSelectEvent.js </feature-class> <feature-class> oracle/adfdemo/acme/js/component/AcmeTagPanePeer.js </feature-class> </feature> </features>
Server-side development involves creating Java classes for:
Event listener: This class listens for events and then invokes processing logic to handle the event.
Events: You create an event in order to invoke the logic in the associated listener.
Component: This class holds the properties that define behavior for the component.
Resource bundle: This class holds text strings for the component.
Renderer: This class determines how the component will be displayed in the client.
Resource loader: This class is required only if your component contains images needed for skinning.
After you have created the classes, add the component class and the renderer class to the faces-config.xml
file. Then, complete the configuration files started in Section 30.2, "Setting Up the Workspace and Starter Files."
The ADF Faces event API requires an event listener interface to process the event. The custom component has a dependency with the event and the event has a dependency with an event listener interface. The Java import statements must reflect these dependencies. You also must define the componentType
for the component.
To create the EventListener class:
In the Application Navigator, right-click the project and select New.
In the New Gallery, expand General and select Java.
Select Java Interface and click OK.
In the Create Java Interface File dialog, do the following:
Name: Enter a listener name. For example, for the tagPane
component, you might enter TagSelectListener
.
Package: Enter a name for the package. For example, for the tagPane
component, you might enter oracle.adfdemo.acme.faces.event
.
Open the Java file in the editor and add the following:
Have the listener extend the javax.faces.event.FacesListener
interface.
Add an import
statement, and import the FacesListener
class and any other classes on which your event is dependent.
Add a method signature that will process the new event. Even though you have not created the actual event, you can enter it now so that you will not have to enter it later.
Example 30-9 shows the code for the tagPane
event listener.
Example 30-9 tagPane Event Listener Java Code
package oracle.adfdemo.acme.faces.event; import javax.faces.event.AbortProcessingException; import javax.faces.event.FacesListener; public interface TagSelectListener extends FacesListener { /** * <p>Process the {@link TagSelectEvent}.</p> * @param event fired on click of a tag link * @throws AbortProcessingException error processing {@link TagSelectEvent} */ public void processTagSelect(TagSelectEvent event) throws AbortProcessingException; }
You must create a server-side event that will be the counter representation of the JavaScript event created in Section 30.3.2, "How to Create a Javascript File for an Event." Server-side JSF events are queued by the component during the Apply Request Values lifecycle phase. Events propagate up to the UIViewRoot
class after all the phases but the Render Response phase. Queued events are broadcast to the associated component.
The server-side Java component must raise the server-side event, so you must create the event source file first to resolve the compilation dependency.
To create the server-side event class:
In the Application Navigator, right-click the project and select New.
In the New Gallery, expand General and select Java.
Select Java Class and click OK.
In the Create Java Class File dialog, do the following:
Name: Enter an event name. For example, for the tagPane
component, you might enter TagSelectEvent
.
Package: Enter the package name. For example, for the tagPane
component, you might enter oracle.adfdemo.acme.faces.event
.
Extends: Enter a name for the class that the event class extends. This is usually javax.faces.event.FacesEvent
.
In the Optional Attributes section, select the following:.
In the Access Modifiers section, select public.
At the bottom, select Constructors from Superclass and Implement Abstract Methods.
Example 30-10 shows the code for the event class.
Example 30-10 tagPane Event Java Code
package oracle.adfdemo.acme.faces.event; import javax.faces.component.UIComponent; import javax.faces.event.FacesEvent; import javax.faces.event.FacesListener; public class TagSelectEvent extends FacesEvent { /** * <p>Tag selected on the client.</p> */ private String tag = null; /** * <p>Overloade constructor passing the <code>source</code> * {@link oracle.adfdemo.acme.faces.component.TagPane} component and the * selected <code>tag</code>. * </p> * @param source component firing the event * @param tag selected tag link type */ public TagSelectEvent(UIComponent source, String tag) { super(source); this.tag = tag; } /** * <p>Returns <code>true</code> if the <code>facesListener</code> is a * {@link TagSelectListener}.</p> * * @param facesListener listener to be evaluated * @return <code>true</code> * if <code>facesListener</code> instancof {@link TagSelectListener} */ public boolean isAppropriateListener(FacesListener facesListener) { return (facesListener instanceof TagSelectListener); } /** * <p>Delegates to the <code>processTagSelect</code> * method of a <code>FacesListener</code> * implementing the {@link TagSelectListener} interface. * * @param facesListener target listener realizing {@link TagSelectListener} */ public void processListener(FacesListener facesListener) { ((TagSelectListener) facesListener).processTagSelect(this); } /** * @return the tag that was selected triggering this event */ public String getTag() { return tag; } }
A JSF component can be described as a state holder of properties. These properties define behavior for rendering and how a component responds to user interface actions. When you are developing the component class, you identify the types of the needed properties. You also define the base component that it will extend from the MyFaces Trinidad Framework. For example, the tagPane
component extends the UIXObject
in MyFaces Trinidad.
Most components will have several properties that should be implemented. Some of the properties are inherited from the base class, and some are required for the rich client framework. Other properties are required because they are best practice. And finally, some properties are specific to the functionality of the custom component.
For example, the tagPane
component has the properties shown in Table 30-4.
Table 30-4 Component Properties for the tagPane Custom Component
Origin | Property | Data Type | Description |
---|---|---|---|
Inherited |
|
|
The identifier for a component. |
|
S |
The logical identifier registered as a component renderer. |
|
|
|
True or false flag that determines if the component is rendered. |
|
|
|
A binding value expression to store a component instance in a managed bean. |
|
Rich Client Framework |
|
|
True or false flag that determines whether a client-side component will be generated. |
|
|
A binding expression that registers a client listener on a component. |
|
|
|
A client attribute on a component. The attribute is added both to the server-side JSF component as well as the client-side equivalent. |
|
|
|
A CSS style applied to the root component's class attribute. |
|
|
|
A CSS style added to the component's class attribute. |
|
|
|
True or false flag that returns the visibility of the component. The visible property is not the same as the rendered property. The visible attribute affects the CSS style on the CSS root of the component. |
|
|
|
The IDs of the components that should trigger a partial page update. |
|
Specific to tagPane |
|
|
The map of weighted tags. The key represents the tag name and the value as a number. |
|
|
The order that the tags are rendered. The valid enumerations are |
|
|
|
The |
ADF Faces and MyFaces Trinidad component libraries are defined differently from other libraries. A JSF component has a collection called attributes
that provides access to component properties (using the Java simple beans specification) through a MAP
interface. The collection also holds value pairs that do not correspond to a component's properties. This concept is called attribute transparency. The JSF runtimes (both MyFaces Trinidad and the JSF reference implementation) implement this concept using the Java reflection API.
My Faces Trinidad defines its own internal collection, which does not use the Java reflection API. This difference means that it is more efficient than the base implementation. The solution in MyFaces Trinidad collects more metadata about the component properties. This metadata declares state properties, which allows the base class to fully implement the StateHolder
interface in a base class.
My Faces Trinidad extends the javax.faces.component.UIComponent
class with the org.apache.trinidad.component.UIXComponent
class, followed by a complete component hierarchy. To ease code maintenance, the framework has a strategy for generating code based on configuration files and templates.
This component strategy is a trade-off in terms of development. It requires more coding for defining properties, but you will not have to code the two methods (saveState
, restoreState
) for the StateHolder
interface for each component.
Note: Do not have your custom component extend from any ADF Faces implementation packages. These implementations are private and might change. |
Use JDeveloper to create a Java file for the component. Create a Type
bean to hold property information and define a PropertyKey
for each property. Then, generate accessors for the private attributes.
To create the component class:
In the Application Navigator, right-click the project and select New.
In the New Gallery, expand General and select Java.
Select Java Class. Click OK.
In the Create Java Class File dialog, do the following:
Name: Enter a component name. For example, for the tagPane
component, you might enter TagPane
.
Package: Enter a name for the package. For example, for the tagPane
component, you might enter oracle.adfdemo.acme.faces.component
.
Extends: Enter a name for the class the component class extends. For example, for the tagPane
component, you would enter org.apache.myfaces.trinidad.component.UIXObject
.
In the Optional Attributes section, select the following:.
In the Access Modifiers section, select public.
At the bottom, select Constructors from Superclass, and Implement Abstract Methods.
In the source editor, create a Type
bean that contains component property information. This static class attribute shadows an attribute with the same name in the superclass. The type
attribute is defined once per component class. Through the Type
constructor, you pass a reference to the superclass's Type
bean, which copies property information. For example, the tagPane
class would contain the following constructor:
static public final FacesBean.Type TYPE = new FacesBean.Type(UIXObject.TYPE);
For each property, define a static PropertyKey
that is used to access the properties state. Use the TYPE
reference to register a new attribute. Specify the property type using the class reference. The component data type should correspond to the component property. There is another overload of the registerKey
method that allows you to specify state information. The default assumes the property is persistent
. Example 30-11 shows the PropertyKey
methods for the tagPane
component.
Example 30-11 PropertyKey Definition
/** * <p>Custom CSS applied to the style attribute of the root markup node.</p> */ static public final PropertyKey INLINE_STYLE_KEY = TYPE.registerKey("inlineStyle", String.class); /** * <p>Custom CSS class to the class attribute of the root markup node.</p> */ static public final PropertyKey STYLE_CLASS_KEY = TYPE.registerKey("styleClass", String.class);
Right-click in the editor and choose Generate Accessors. In the Generate Accessors dialog, click Select All, ensure the Scope is set to Public, and click OK. This allows JDeveloper to generate get
and set
methods for the private attributes.
Then, remove the private attribute and replace with calls to getProperty(PropertyKey)
and getProperty(PropertyKey)
.
Example 30-12 shows the code after replacing the private attribute.
Example 30-12 Component Properties
public void setInlineStyle(String newinlineStyle) { // inlineStyle = newinlineStyle; setProperty(INLINE_STYLE_KEY, newinlineStyle); } /** * <p>CSS value applied to the root component's style attribute.</p> * * @return newinlineStyle CSS custom style text */ public String getInlineStyle() { // return inlineStyle; return (String) getProperty(INLINE_STYLE_KEY); }
You may need to override any methods to perform specific functions in the component. For example, to allow your component to participate in partial page rendering (PPR), you must override the getBeanType
method, as shown in Example 30-13.
Example 30-13
/** * <p>Exposes the <code>FacesBean.Type</code> for this class through a protected * method. This method is called but the <code>UIComponentBase</code> superclass * to setup the components <code>ValueMap</code> which is the container for the * <code>attributes</code> collection.</p> * * @return <code>TagPane.TYPE</code> static property */ @Override protected FacesBean.Type getBeanType() { return TYPE; }
Refer to the ADF Faces JavaDoc
for more information about the class your component extends, and the methods you may need to override.
For the tagPane
component, the component must act on the event fired from the client component. A reference to the source component is passed as a parameter to the event's constructor.
For the tagPane
component, the broadcast
method checks if the event passed in using the formal parameter is a TagSelectEvent
. If it is, the broadcast
method invokes the method expression held by the tagSelectListener
attribute.
Most events have an immediate
boolean property that specifies the lifecycle phase in which the event should be invoked. If the immediate
attribute is true
, the event is processed in the Apply Values phase; otherwise, the event is processed in the Invoke Application phase. For more information, see Chapter 4, "Using the JSF Lifecycle with ADF Faces."
Example 30-14 shows the overwritten broadcast
method for the tagPane
component.
Example 30-14 The broadcast Method in the tagPane Component
/** * @param facesEvent faces event * @throws AbortProcessingException exception during processing */ @Override public void broadcast(FacesEvent facesEvent) throws AbortProcessingException { // notify the bound TagSelectListener if (facesEvent instanceof TagSelectEvent) { TagSelectEvent event = (TagSelectEvent) facesEvent; // utility method found in UIXComponentBase for invoking method event // expressions broadcastToMethodExpression(event, getTagSelectListener()); } super.broadcast(facesEvent); }
After creating the component class, register the component by adding it to the /META-INF/faces-config.xml
file. By defining the component in the faces configuration file packaged with the JAR project, you ensure that component is automatically recognized by the JSF runtime during web application startup.
To register the component, enter the component type, which is a logical name used by the applications factory to instantiate an instance of the component. For example, the tagPane
component's type is oracle.adfdemo.acme.TagPane
. You also need to add the fully qualified class path for the component, for example oracle.adfdemo.acme.faces.component.TagPane
.
To register a custom component:
In the Application Navigator, double-click the faces-config.xml
file.
Click the Overview tab and click the Components navigation tab.
Click the Add icon and enter the type and class for the component.
Optionally, add any attributes, properties, or facets.
Example 30-15 shows the tagPane
component defined within a faces-config.xml
file.
Example 30-15 tagPane Component Added to the faces-config.xml File
<?xml version="1.0" encoding="UTF-8" ?> <faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee"> <application> </application> <component> <component-type>oracle.adfdemo.acme.TagPane</component-type> <component-class>oracle.adfdemo.acme.faces.component.TagPane </component-class> </component>
Resource bundles are used to store information for the component, such as text for labels and messages, as well as translated text used if the application allows locale switching. Skins also use resource bundles to hold text for components. Because your custom component must use at least the simple skin, you must create at least a resource bundle for that skin. For a custom component, create a Java file for the resource bundle. For more information about resource bundle classes, see Section 20.3, "Defining Skin Style Properties."
Tip: You can also use a properties file for your resources. |
To create the resource bundle class:
In the Application Navigator, right-click the project and select New.
In the New Gallery, expand General and select Java.
Select Java Class and click OK.
In the Create Java Class File dialog, do the following:
Name: Enter a resource bundle name. The name should reflect the skin with which it will be used. For example, for the sample component, you might enter AcmeSimpleDesktopBundle
.
Package: Enter a name for the package. For example, for the sample component, you might enter oracle.adfdemo.acme.faces.resource
.
Extends: For resource bundles, you must enter java.util.ListResourceBundle
.
In the Optional Attributes section, select the following:.
In the Access Modifiers section, select public.
At the bottom, select Constructors from Superclass and Implement Abstract Methods.
Add any keys and define the text as needed. For more information about creating resource bundles for skins, see Section 20.3.1, "How to Apply Skins to Text."
Example 30-16 shows the resource bundle code for the tagPane
component.
Example 30-16 tagPane Resource Bundle Java Code
package oracle.adfdemo.acme.faces.resource; import java.util.ListResourceBundle; /** * <p>Holds properties used by the components bundled in the jar project. * This bundle is part of the trinidad component skin that is configured * in the "/META-INF/trinidad-skins.xml" file. Component Renderers * will use the <code>RenderingContext</code> to lookup a key by calling * the <code>getTranslatedString(key)</code> method.</p> */ public class AcmeSimpleDesktopBundle extends ListResourceBundle { /** * <p>Returns a two dimensional object array that represents a resource bundle . * The first * element of each pair is the key and the second the value.</p> * * @return an array of value pairs */ protected Object[][] getContents() { return new Object[][] { {"AcmeTagPane_tag_title","Tag Weight: {0}"} }; } }
To register the resource bundle for the simple desktop skin and any other desired skins, double-click the /META-INF/trinidad-skins.xml file to open it and do the following:
In the Structure window, select skin-addition.
In the Property Inspector, enter a skin ID. For the simple skin ID, enter simple.desktop
.
In the Structure window, right-click skin-addition and choose Insert inside skin-addition > bundle-name.
In the Property Inspector, enter the fully qualified name of the resource bundle just created.
Note: JDeveloper addstranslation-source and bundle-name elements as comments. Instead of declaratively creating another bundle-name element, you can manually enter the bundle-name value in the generated element, and then remove the comment tag. |
Example 30-17 shows the code for registering the tagPane
resource bundle with the simple skin (you will add the style-sheet-name
element value in a later step).
Example 30-17 Registering a Resource Bundle with a Skin
<skins xmlns="http://myfaces.apache.org/trinidad/skin"> <skin-addition> <skin-id>simple.desktop</skin-id> <style-sheet-name></style-sheet-name> <bundle-name> oracle.adfdemo.acme.faces.resource.AcmeSimpleDesktopBundle </bundle-name> </skin-addition> </skins>
ADF Faces components delegate the functionality of the component to a component class, and when the consuming application uses JSPs, the display of the component to a renderer. By default, all tags for ADF Faces combine the associated component class with an HTML renderer, and are part of the HTML render kit. HTML render kits are included with ADF Faces for display on both desktop and PDA devices.
Renderers are qualified in a render kit by family and renderer type. The family is a general categorization for a component, and should be the same as the family defined in the superclass. You do not have to override the getFamily()
method in the component because the component will have the method through inheritance.
To create the renderer class:
In the Application Navigator, right-click the project and select New.
In the New Gallery, expand General then select Java.
Select Java Class and click OK.
In the Create Java Class File dialog, do the following:
Name: Enter a renderer name. For example, for the tagPane
component, you might enter TagPaneRenderer
.
Package: Enter a name for the package. For example, for the tagPane
component, you might enter oracle.adfdemo.acme.faces.render.
Extends: Enter oracle.adf.view.rich.render.RichRenderer
.
In the Optional Attributes section, select the following:.
In the Access Modifiers section, select public.
At the bottom, select Constructors from Superclass and Implement Abstract Methods.
Add any needed functionality. For example, the skinning functionality provides an API you can use to get the CSS style properties for a given CSS selector during rendering of the component. This API is useful if you need to do conditional rendering based on what styling is set. For more information, see RenderingContext#getStyles
and Styles#getSelectorStyleMap
in the MyFaces Trinidad Javadoc at http://myfaces.apache.org/trinidad/trinidad-1_2/trinidad-api/apidocs/index.html
.
After you create the renderer, register it using the faces-config.xml
configuration file. If you want the custom component to work with the other ADF Faces components, you must use the same render kit ID that ADF Faces components use.
Tip: The most granular level that JSF allows for defining a render kit is at the view root. |
To register the render kit and renderer:
In the Application Navigator, double-click the faces-config.xml
file to open it in the editor.
Select the Overview tab and then select the Render Kits navigation tab.
Click the Add icon for the Render Kits and enter oracle.adf.rich
for the render kit ID.
Register your renderer by clicking the Add icon for Renderers and doing the following:
Family: Enter the class that the component extends. For example, for the tagPane
component, you would enter org.apache.myfaces.trinidad.Object.
Type: Enter the type for the component. For example, for the tagPane
component, you would enter oracle.adfdemo.acme.TagPane
. This must match the renderer type.
Class: Enter the fully qualified class path to the renderer created in Section 30.4.7, "How to Create a Class for a Renderer." For example, for the tagPane
component, you would enter oracle.adfdemo.acme.faces.render.TagPaneRenderer
.
Example 30-18 shows the registration of the tagPane
component render kit and renderer.
Example 30-18 tagPane Renderer Added to the faces-config.xml File
<render-kit> <render-kit-id>oracle.adf.rich</render-kit-id> <renderer> <component-family>org.apache.myfaces.trinidad.Object</component-family> <renderer-type>oracle.adfdemo.acme.TagPane</renderer-type> <renderer-class>oracle.adfdemo.acme.faces.render.TagPaneRenderer </renderer-class> </renderer> </render-kit>
To use the component on a JSP page, you create a custom tag that will instantiate the custom component. The JSP tag has nothing to do with rendering because the component's renderer will actually perform that task. In JSF 1.1, the JSP tag would invoke rendering on the component after creating and adding it to the component tree. This caused problems because the non-JSF/JSP tags were writing to the same response writer. The timing of the interleaving did not work out for components that rendered their own child components.
Note: (An application that uses Facelets uses a handler to instantiate the component. For more information, see Section 30.2.8, "How to Add a Facelets Tag Library Configuration File") |
In JSF 1.2, the target for Java EE 5 (Servlet 2.5, JSP 2.1), most of the JSP problems were fixed. The JSF/JSP component acts as a component factory that is responsible only for creating components. This means that the rendering response phase is divided into two steps. First the component tree is created, and then the tree is rendered, instead of rendering the components as the component tree was being built. This functionality was made possible by insisting that the entire view be represented by JSF components. The non-JSF/JSP generates markup that implicitly becomes a JSF verbatim component.
As a result of changing these mechanics, in JSF 1.2, custom JSP tags extend the javax.faces.webapp.UIComponentELTag
class. The encodeBegin
, encodeChildren,
and encodeEnd
methods in the JSP tag have been deprecated. These methods once made corresponding calls to the component. Because the view root in JSF 1.2 does the rendering, all the work can be done in the doStartTag
and doEndTag
methods. MyFaces Trinidad has its own version of this base class that you will use. The org.apache.myfaces.Trinidad.webapp.UIComponentELTag
hooks into the components property bag and makes coding JSPs simpler.
The tag class includes the creation of the component's properties. You must choose tag properties carefully. There are some properties that you can ignore for tag implementation, but they may be required as TLD attributes.
The following three attributes are implemented by superclasses and shared by many components through Java inheritance:
id
binding
rendered
Do not implement the id
attribute because the id
attribute is implemented by the superclass javax.faces.webapp.UIComponentTagBase
. The superclass javax.faces.webapp.UIComponentELTag
implements the other two attributes, binding
and rendered
. Therefore, you do not need to add these to your tag class.
To add a JSP tag:
In the Application Navigator, right-click the project and select New.
In the New Gallery, expand General then select Java.
Select Java Class and click OK.
In the Create Java Class File dialog, do the following:
Name: Enter a tag name. For example, for the tagPane
component, you might enter TagPaneTag
.
Package: Enter a name for the package. For example, for the tagPane
component, you might enter oracle.adfdemo.acme.faces.taglib
.
Class: Enter org.apache.myfaces.trinidad.webapp.UIXComponentELTag
.
In the Optional Attributes section, select the following:.
In the Access Modifiers section, select public.
At the bottom, select Constructors from Superclass and Implement Abstract Methods.
In the source editor, add all the attributes to the file.
Example 30-19 shows the code for the attributes for the TagPaneTag
class.
Example 30-19 Attributes in the TagPaneTag Class
public class TagPaneTag extends UIXComponentELTag { private ValueExpression _partialTriggers = null; private ValueExpression _visible = null; private ValueExpression _inlineStyle = null; private ValueExpression _styleClass = null; private ValueExpression _tags = null; private ValueExpression _orderBy = null; private MethodExpression _tagSelectListener = null;
To declaratively generate the accessor methods for the attributes, right-click the file in the source editor and choose Generate Accessors.
In the Generate Accessors dialog, click Select All, set the Scope to public
and click OK.
Add the render type and component type to the class. The component type will be used by the superclass to instantiate the component using the application's factory method, createComponent(componentType)
.
Example 30-20 shows the code for the TagPane
Tag
class, where both the component type and render type are oracle.adfdemo.acme.TagPane
.
Example 30-20 Component Type and Render Type for the TagPaneTag Class
public String getComponentType() { return COMPONENT_TYPE; } public String getRendererType() { return RENDERER_TYPE; } /** * <p>This component's type, <code>oracle.adfdemo.acme.TagPane</code></p> */ static public final String COMPONENT_TYPE = "oracle.adfdemo.acme.TagPane"; /** * <p>Logical name given to the registered renderer for this component.</p> */ static public final String RENDERER_TYPE = "oracle.adfdemo.acme.TagPane";
Override the setProperties
method from the superclass that has a single formal parameter of type FacesBean
. This is a MyFaces Trinidad version on the base UIComponentELTag
, but it is passed the components state holder instead of the component reference. The job of the setProperties
method is to push the JSP tag attribute values to the component.
Example 30-21 shows the overridden method for the tagPane
Tag
class.
Example 30-21 Overridden setProperties Method in the TagPaneTag Class
@Override protected void setProperties(FacesBean facesBean) { super.setProperties(facesBean); setStringArrayProperty(facesBean, TagPane.PARTIAL_TRIGGERS_KEY, _partialTriggers); setProperty(facesBean, TagPane.VISIBLE_KEY, _visible); setProperty(facesBean, TagPane.INLINE_STYLE_KEY, _inlineStyle); setProperty(facesBean, TagPane.STYLE_CLASS_KEY, _styleClass); setProperty(facesBean, TagPane.TAGS_KEY, _tags); setProperty(facesBean, TagPane.ORDER_BY_KEY, _orderBy); facesBean.setProperty(TagPane.TAG_SELECT_LISTENER_KEY, _tagSelectListener); }
A tag library descriptor (TLD) provides more information on the Java Class to the JSP compilation engine and IDE tools (TLDs are not used in applications that use Facelets).
Before you begin:
Associate the tag library with a URI, assign a version, and give it a name. You should have already performed this step when you created the tag library stub file in Section 30.2.6, "How to Add a JavaServer Pages Tag Library Descriptor File."
To configure the TLD:
Open the skeleton TLD file.
In the Component Palette, drag and drop a tag element.
In the Insert tag dialog, do the following:
name: Enter the name of the component. For example, for the tagPane
component, you might enter tagPane
.
body-content: Enter JSP
.
tag-class: Click the ellipses button and navigate to the components tag class file.
Define each of the attributes as follows. For each attribute:
In the Structure window, right-click the tag element and choose Insert inside tag > attribute.
In the Insert Attribute dialog, enter a value for the name. This should be the same as the name given in the tag class.
In the Structure window, select the attribute and in the Property Inspector, set any attribute values.
There are three types of elements to define for each attribute. The <id>
element is a simple string. Additionally attributes can be either deferred-value or deferred-method attributes. These allow late (deferred) evaluation of the expression. Now that JSP and JSF share the same EL engine, the compiled EL can be passed directly to the component.
Example 30-22 shows the TLD for the tagPane
component.
Example 30-22 tagPane acme.tld Tag Library Descriptor Code
<?xml version = '1.0' encoding = 'windows-1252'?> <taglib xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" version="2.1" xmlns="http://java.sun.com/xml/ns/javaee"> <description>Acme Corporation JSF components</description> <display-name>acme</display-name> <tlib-version>1.0</tlib-version> <short-name>acme</short-name> <uri>http://oracle.adfdemo.acme</uri> <tag> <description> </description> <name>tagPane</name> <tag-class>oracle.adfdemo.acme.faces.taglib.TagPaneTag</tag-class> <body-content>JSP</body-content> <attribute> <name>id</name> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>rendered</name> <deferred-value> <type>boolean</type> </deferred-value> </attribute> <attribute> <name>tagSelectListener</name> <deferred-method> <method-signature>void </method-signature> myMethod(oracle.adfdemo.acme.faces.event.TagSelectEvent) </deferred-method> </attribute> <attribute> <name>visible</name> <deferred-value> <type>boolean</type> </deferred-value> </attribute> <attribute> <name>partialTriggers</name> <deferred-value> </deferred-value> </attribute> <attribute> <name>inlineStyle</name> <deferred-value/> </attribute> <attribute> <name>inlineClass</name> <deferred-value/> </attribute> <attribute> <name>tags</name> <deferred-value/> </attribute> <attribute> <name>binding</name> <deferred-value/> </attribute> <attribute> <name>orderBy</name> <deferred-value/> </attribute> </tag> </taglib>
A resource loader is required only if the custom component has image files needed for the component's skinning. The images files are packaged into the JAR project so that the consumer of the component library will need to include the JAR into the class path of their web project and add a few entries into their web deployment descriptor file (web.xml
). The rich client framework uses a resource servlet to deliver images. You need to register this servlet in the web.xml
file and then create the resource loader class. A component library requires a resource loader that is auto-loaded by the resource servlet. You create a URL pattern folder mapping for the servlet, which will be used to locate and identify resources within your custom component library.
To create a resource loader class:
In the Application Navigator, right-click the project and select New.
In the New Gallery, expand General and select Java.
Select Java Class and click OK.
In the Create Java Class File dialog, do the following:
Name: Enter a resource loader name. For example, for the tagPane
component, you might enter AcmeResourceLoader
.
Package: Enter a name for the package. For example, for the tagPane
component, you might enter oracle.adfdemo.acme.faces.resources
.
Extends: Enter a name for the class that the tag extends. For example, for the tagPane
component, you would enter org.apache.myfaces.trinidad.resource.RegexResourceLoader
.
In the Optional Attributes section, select the following:.
In the Access Modifiers section, select public.
At the bottom, select Constructors from Superclass and Implement Abstract Methods.
In the source editor, register regular expressions that map to more specific resource loaders. For example, you might create an expression that maps image resources located under an images directory.
Example 30-23 shows the expression for the tagPane
component that maps the /acme/images/
directory located relative to the /META-INF
folder of the custom component JAR. As a result of the registration, the custom component images should be located under /META-INF/acme/images
.
Example 30-23 Resource Loader for the tagPane Component
public class AcmeResourceLoader extends RegexResourceLoader { public AcmeResourceLoader() { // any resource in "/acme/" with the following suffixes will be // loaded from the base folder of "META-INF". // The servlet pattern match "/acme/*" should exist under "META-INF". // For example URL : context-root/acme/images/type1.gif // map to: META-INF/acme/images/type1.gif register("(/.*\\.(jpg|gif|png|jpeg))", new ClassLoaderResourceLoader("META-INF"));
Register the Libraries Resource Loader by opening the /META-INF/servlet/resources/
name
.resources
file and adding the fully qualified name of the resource loader class bound to the URI pattern.
The MyFaces Trinidad ResourceServlet
uses the servlet context to scan across all JAR files within the class path of the web application. The servlet looks at its own URI mappings in the web deployment descriptor to formulate the location of this resource file. This file must contain the fully qualified name of the Java class bound to the URI pattern. During startup, the ResourceServlet
will locate and use this file in a manner similar to how FacesServlet
locates and uses the faces-config.xml
files.
For the tagPane
component, the acme.resources
file would contain this entry for the composite resource loader:
oracle.adfdemo.acme.faces.resource.AcmeResourceLoader
A skin is a style sheet based on the CSS 3.0 syntax specified in one place for an entire application. Instead of inserting a style sheet on each page, you use one or more skins for the entire application. Every component automatically uses the styles as described by the skin. No design time code changes are required.
Oracle ADF Faces provides three skins for use in your applications:
blafplus-rich
: Defines the default styles for ADF Faces components. This skin extends the blafplus-medium
skin.
blafplus-medium
: Provides a modest amount of styling. This style extends the simple
skin.
simple
: Contains only minimal formatting.
Skins provide more options than setting standard CSS styles and layouts. The skin's CSS file is processed by the skin framework to extract skin properties and icons and register them with the Skin
object. Style sheet rules include a style selector, which identifies an element, and a set of style properties, which describes the appearance of the components.
All ADF Faces components use skins. The default skin is the simple skin. Because your custom components will be used in conjunction with other ADF Faces components, you add style selectors to an existing ADF Faces skin. Because the rich and medium skins inherit styles from the simple skin, you can simply add your selectors to the simple skin, and it will be available in all skins. However, you may want to style the selector differently for each skin. You set these styles in the CSS file you created. This file will be merged with other CSS styles in the application in which the component is used.
The text used in a skin is defined in a resource bundle. Create the text by creating a custom resource bundle and declaring the text you want to display. After you create your custom resource bundle, you register it with the skin. Coupling resource bundles with your CSS provides a method to make your components support multiple locales.
The /META-INF/trinidad-skins.xml
file you created is used to register your CSS file and your resource bundle with an ADF Faces skin.
To create styles for your component:
Open the CSS file you created in Section 30.2.4, "How to Add a Cascading Style Sheet."
Define a root style selector for the component. This style will be associated with the <DIV>
element that establishes the component.
Add other style selectors as needed. Example 30-24 shows the CSS file for the tagPane
component.
Example 30-24 CSS File for the tagPane component
acme|tagPane - root element acme|tagPane::content - container for the links acme|tagPane::tag - tag hyperlink
For more information about creating CSS for components to be used by skins, see Section 20.3, "Defining Skin Style Properties."
Create any needed resource bundle for your component.
To register your CSS with an ADF Faces skin, open the /META-INF/trinidad-skins.xm
l file.
In the Structure window, select the skin-addition element, and in the Property Inspector, do the following:
skin-id: Enter the ADF Faces skin to which you want to add the custom component selectors. You must register the selectors at least to the simple.desktop
skin in order for them to be compatible with ADF Faces components.
Note: If there is a possibility that the component will be used in an Oracle WebCenter application, then you must also register the selectors with thesimple.portlet skin. Skins are also available for PDAs (for example, simple.pda ). For more information, see Chapter 20, "Customizing the Appearance Using Styles and Skins." |
style-sheet-name: Use the dropdown menu to choose Edit, and navigate to the CSS file you created.
If you created a resource bundle, add the fully qualified path to the bundle as the value for the <bundle-name>
element.
Example 30-25 show the code for the tagPane
component.
Example 30-25 tagPane trinidad-skins.xml Code
<?xml version="1.0" encoding="UTF-8" ?> <skins xmlns="http://myfaces.apache.org/trinidad/skin"> <skin-addition> <skin-id>simple.desktop</skin-id> <style-sheet-name>acme/styles/acme-simple-desktop.css</style-sheet-name> <bundle-name>oracle.adfdemo.acme.faces.resource.AcmeSimpleDesktopBundle </bundle-name> </skin-addition> </skins>
Add an image folder for the images used for the custom component. This folder should be under the META-INF
directory. Place any images used by the custom component into this folder.
For tagPane
, the image folder is /META-INF/acme/images
.
After creating the custom component library, you must create a deployable artifact that can be used by a web application. Before you can build a Java archive (JAR) file, update the project's deployment profile by adding the many resources you created.
To create the JAR file for deployment:
In the Application Navigator, double-click the project to open the Project Properties dialog.
In the left pane, select Compiler.
On the right, ensure that all file types to be deployed are listed in the Copy File Types to Output Directory text field.
Note: Some file types, such as.css and .js are not included by default. You will need to add these. |
In the left pane, select Deployment.
On the right, under Deployment Profiles, select the ADF Library JAR file, and click Edit.
In the left pane, select JAR Options.
Verify the default directory path or enter a new path to store your ADF Library JAR file. Ensure that Include Manifest File is selected, and click OK.
To deploy, right-click the project and select Deploy >Project_name from the context menu. By default, the JAR file will be deployed to a deployment directory within the project directory.
After the component has been created and you have created an ADF Library, you can proceed to import it and use it in another application. However, before using it in an application under development, you should use it in a test application to ensure it works as expected. To do so, import the custom library into your test application. For procedures, see the "Adding ADF Library Components into Projects" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
After you add the library, you configure the web deployment descriptor to add a resource servlet mapping. When you use the component and run your test application, you may find you need to debug the component. Therefore, it helps to have logging and assertions enabled for the project.
Tip: Importing a library into an application allows the custom component to appear in JDeveloper's Component Palette. |
You configured the component resource loader to assume a servlet resource mapping (for example, for the tagPane
component, the mapping was acme)
. Therefore, you must add the expected resource servlet mappings to the consuming application's web.xml
file.
By default, MyFaces Trinidad skinning compresses the CSS classes when it normalizes CSS 3 into CSS 2. Turn off this compression while you are debugging the component. For a production deployment, toggle off this setting.
To configure the web.xml file:
In the Application Navigator, double-click the web.xml file to open it.
In the overview editor, select the Servlets navigation tab, and click the Add icon to add a new servlet.
In the Servlets table, do the following:
Name: Enter resources
.
Servlet Class: Enter org.apache.myfaces.trinidad.webapp.ResourceServlet
.
Below the table, click the Servlet Mappings tab, then click the Add icon.
Enter a URI prefix. Resources beginning with this prefix will be handled by the servlet. For example, for the tagPane
component, you might enter the prefix /acme/*
.
To disable compression of the style sheet:
Select Application.
Click the Add icon for Context Initialization Parameters.
For Name, enter org.apache.myfaces.trinidad.DISABLE_CONTENT_COMPRESSION
and for Value enter true
.
JavaScript debugging can be a difficult task. To help debug this dynamic language with no type checking, the rich client JavaScript libraries provide a logging mechanism similar to Java logging. There is also an assertion strategy to make the client scripts more type safe. Both of these features are turned on using configuration parameters in the web.xml
file. The logging and assertion routines are browser specific. The client JavaScript libraries will support Gecko, Internet Explorer, Opera, and Safari versions of browser agents. For more information, see Section A.2.3.4, "Resource Debug Mode."
To turn on logging and assertion:
In the Application Navigator, double-click the web.xml file.
In the overview editor, click the Application navigation tab.
On the Application page, click the Add icon for the Context Initialization Parameters.
Add the following parameter to turn on debugging:
Name: org.apache.myfaces.trinidad.resource.DEBUG
Value: true
This setting prevents MyFaces Trinidad from setting the cache headers for resources like JavaScript. It prevents the browser from caching resources.
Add the following parameter to set the debug level for client side JavaScript.
Name: oracle.adf.view.rich.LOGGER_LEVEL
Value: ALL
The valid values are OFF
, SEVERE
, WARNING
, INFO
, CONFIG
, FINE
, FINER
, FINEST
and ALL
. The default is OFF
.
Add the following parameter to turn on client-side script assertions:
Name: oracle.adf.view.rich.ASSERT_ENABLED
Value: true
This setting works together with logging. Toggling this switch to on will make debug information available to the browser. The assertions and logging are displayed differently, depending on the browser. For Internet Explorer, a child browser window will appear beside the active window. For FireFox with the Fire Bug plugin, the debug information will be available through the Fire Bug console.
To add the custom component to a JSF page:
Open the jspx page in the source editor.
Add the TLD namespace to the root tag.
For example, for the tagPane
component, because the tag library's URI is: http://adf-richclient-demo-acme
, you would add:
xmlns:acme="http://oracle.adfdemo.acme"
Use the Component Palette to add the component to the page. Use the Property Inspector to set any attributes.
Tip: If you are developing the application outside of JDeveloper, then on the page, use TLD short name and the component name. Also, add any values for attributes. For example, for thetagPane , you might add:
<acme:tagPane> <visible="true"> <orderBy="alpha"> <tagSelectionListener=#(tagBean.onTagSelect) </tagPane> |
If you wish to create the tagPane
component as described in this chapter, and use it in an application, you will need to use backing beans to bind the custom component to the application components.
Example 30-26 shows the backing bean code that is used to bind the tagPane
component to the File Explorer application.
Example 30-26 Backing Bean Logic for the tagPane Custom Component
public Map<String, Number> getTags() { if (_tags == null) { _tags = new TreeMap<String, Number>(); List<FileItem> nameToFileItems = feBean.getDataFactory().getFileItemList(); _doDeepTagCollection(_tags, nameToFileItems); } return _tags; } public void onTagSelect(TagSelectEvent event) { _selectedTag = event.getTag(); CriteriaFileItemFilter criteria = new CriteriaFileItemFilter(_selectedTag); List<FileItem> nameToFileItems = _feBean.getDataFactory().getFileItemList(); if (_selectedTagFileItemList == null) { _selectedTagFileItemList = new ArrayList<FileItem>(); else { _selectedTagFileItemList.clear(); } _doDeepTagSearch(criteria, _selectedTagFileItemList, nameToFileItems); _selectedTagResultsTableModel = new SortableModel(_selectedTagFileItemList); }