Oracle Blog

Arun Gupta's Weblog

Wednesday Oct 27, 2010

The Java Server Faces 2.0 uses Facelets instead of JSP as the view declaration language. This allows "view" part of MVC to be completely written using XHTML and CSS only and all the business logic resides in the backing bean. This enables a cleaner separation of views with model and controller and thus follows the MVC design pattern in a more intuitive way. JSF 2 also defines how resources can be packaged, located, and rendered by JSF runtime within a web application.

Using these two features of Facelets and Resource Handling, JSF2 defines a composite component as a component that consists of one or more JSF components defined in a Facelet markup file that resides inside of a resource library. The composite component is defined in the defining page and used in the using page. The "defining page" defines the metadata (or parameters) using <cc:interface> and implementation using <cc:implementation> where "cc" is the prefix for "http://java.sun.com/jsf/composite" namespace. Future versions of the JSF 2 specification may relax the requirement to specify metadata as it can be derived from the implementation itself.

A composite component can be defined using JSF 1.2 as well but it requires a much deeper understanding of JSF lifecycle and also authoring multiple files. JSF2 really simplifies the authoring of composite components using just an XHTML file.

Code is king! This Tip Of The Day (TOTD) will explain how to convert an existing code fragment into a JSF2 composite component using NetBeans IDE.

This fragment displays an HTML form with two text input boxes and a "submit" button. The two input boxes are bound to "user" bean and clicking on the button invokes "register" method of the "userService" bean.

Instead of repeating this code in multiple pages, its beneficial to convert this into a composite component and use the resulting tag instead of the complete fragment again. Why ?

Follows the DRY principle and allows to keep the code, that can be potentially be repeated at multiple places, in a single file.

It allows developers to author new components without any Java code or XML configuration.

How do you convert an existing code fragment to a composite component ? NetBeans makes it really easy.

<cc:interface> defines metadata that describe the characteristics of component, such as supported attributes, facets, and attach points for event listeners. <cc:implementation> contains the markup substituted for the composite component.

<cc:interface> is generated in the page but is empty and may be made optional in a subsequent release of the JSF specification.The "using page" will declare a new namespace as:

xmlns:ez="http://java.sun.com/jsf/composite/ezcomp"

and then replace the code fragment with:

<ez:loginPanel/>

The tag name for the new composite component is the same as the "defining page" file name. This enables "<ez:loginPanel/>" to be used instead of repeating that entire code fragment.

Now lets say that the code fragment need to pass different value expressions (instead of #{user.name}) and invoke a different method (instead of #{userService.register}) when submit button is clicked in different "using page"s. The "defining page" can then look like:

All the parameters are explicitly specified in <cc:interface> for clarity. The third parameter has a "targets" attribute referrring to "ccForm:loginButton".

In <cc:implementation>

The <h:form> in has "id" attribute. This is required such that the button within the form can be explicitly referenced.

<h:inputText> is now using #{cc.attrs.xxx} instead of #{user.xxx}. #{cc.attrs} is a default EL expression that is available for composite component authors and provide access to attributes of the current composite component. In this case #{cc.attrs} has "name" and "password" defined as attributes.

"actionListener" is an attach point for event listener, defined as a "method-signature" and describes the signature of a method pointed to by the expression.

<h:commandButton> has "id" attribute so that it can be clearly identified within the <h:form>.

The "user", "password", and "actionListener" are then passed as required attributes in the "using page" as:

The service component model uses a declarative model for publishing, finding and binding to OSGi services. This model simplifies the task of authoring OSGi services by performing the work of registering the service and handling service dependencies.

There are several advantages of OSGi declarative services and they are well defined in the specification.

This Tip Of The Day shows how to use Maven Bundle Plugin and Maven SCR Plugin to create an OSGi bundle with two declarative services. Then it shows how to create a Java EE client, inject the declared services, and invoke them.

Lets get started!

For those who want want to see the results first:

Download service project and build as "mvn clean install". Install the service as "cp target/helloservice-1.0-SNAPSHOT.jar" to "domains/domain1/autodeploy/bundles".

This class is an implementation of the service interface. Notice this class is in "impl" package, different from the "api" package where interface was defined.

The business method implementation appends the greeting "Hello " to name parameter and generates the response message. The @Component and @Service annotations help in generation of the component descriptors as defined by the Maven SCR Plugin. This plugin provides many other annotations to customize the generation of metadata in "OSGI-INF/servicesComponent.xml". The "name" attribute will be used later by the Java EE client to access this service.

Maven SCR Plugin generates the descriptor file using the metadata specified by the @Component and @Service annotation in service implementations. If this plugin is used with Maven Bundle Plugin then it also adds the generated descriptor (OSGI-INF/serviceComponents.xml) to the bundle and set the required "Service-Component" manifest header.

Giving "mvn clean install" generates "target/helloservice-1.0-SNAPSHOT.jar" and installs the bundle in the local repository. This JAR is used later in the client project for importing the service API definition. The generated JAR has the following manifest:

Notice that the "Service-Component" manifest header is pointing to this generated descriptor. And so the two declared services "hello-service" and "howdy-service" are available for consumption by other clients.

There are several ways to manage OSGi runtime bundle in GlassFish as described in TOTD #118. Simply copying the bundle to "glassfish/domains/domain1/autodeploy/bundles" is sufficient in this case, so lets do that.

The remote telnet shell (accessible using "telnet localhst 6666") shows status of the deployed bundle and associated service as:

This is a Java EE 6-style Servlet, using @WebServlet annotation, and will be accessible at "/HelloClient". The two OSGi services are injected using @Resource annotation and using the name specified in the "OSGI-INF/serviceComponents.xml" descriptor earlier.