Creating a JSF component using RichFaces CDK
Hi,
this time I will explain how to create a simple output component using the Ajax4Jsf/Richfaces CDK framework.
CDK is a framework that simplifies the JSF component creation process so you can concentrate on developing the component functionalities instead of thinking to all the boiler code that this kind of work need.
There isn't an official manual on how to use it (it's still on development) so you have to look on richfaces forum and wiki, and some article you can find on net (see the links at the end of this post).
Before starting I want to point that I'm learning this stuff too and I'm not an expert on jsf component making and I'm still learning. Every suggestion is welcome.
Also you have to assure to have maven installed and working on your system, you have also to configure it for Ajax4Jsf/RichFaces CDK as it is written here.
We are going to make a skypecall component: it insert a link that permit to call a person from the web page via skype.
Let's start!
First of all create a new directory to start from (use a short and without space path);
After that create a file named pom.xml and put this content (modify values with your data if you want):
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>it.novaware</groupId>
<artifactId>ui</artifactId>
<url>http://www.novaware.it</url>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Novaware JSF components library</name>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<modules>
</modules>
</project>
Now open a shell, go in the root directory and execute this command:
mvn archetype:create -DarchetypeGroupId=org.richfaces.cdk -DarchetypeArtifactId=maven-archetype-jsf-component -DarchetypeVersion=3.1.5-GA -DgroupId=it.novaware -DartifactId=skypecallwith skypecall as the name of your component.
In the new generated directory there is a pom.xml file. Open it and add this code after the </build> tag:
<dependencies>
<dependency>
<groupid>junit</groupid>
<artifactid>junit</artifactid>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupid>org.richfaces.framework</groupid>
<artifactid>richfaces-impl</artifactid>
<version>3.1.1-GA</version>
</dependency>
</dependencies>
Using the shell, enter in the new directory (cd skypecall).
Execute this command to create the new component structure:
mvn cdk:create -Dname=skypecallNow you can try it compiling it and making the jar:
mvn install
(To clean the build you can execute: mvn clean)
Mvn install must say BUILD SUCCESSFUL.
Now we are ready to personalize the new component!
Go in the generated src/main directory of skypecall directory: you will find 4 new subfolders with generated files.
Let's start from the config: edit the skypecall/src/main/config/component/skypecall.xml file to insert the component attributes. We are going to insert 5 attributes:
- img: the kind of image to insert. You can use the "default" value to show the default image (see color and size attributes),
the "none" value to show no image, or directly put the URL to show the image you like. So possible value are: default, none, url_of_image. Default is "default". - color: the color of the default image. It works if "image" attribute is "default". It can be "green" or "blue". Default is "blue".
- size: the size of the default image. It works if "image" attribute is "default". Possible values are: small, medium, big. Default is "medium".
- number: skype number to call. Default is null.
- type: the type of skype link to create. Possible values are: call, chat, voicemail, add, userinfo, sendfile. Default is call.
So the final code of skypecall.xml is:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//AJAX4JSF//CDK Generator config/EN" "https://ajax4jsf.dev.java.net/nonav/dtds/component-config.dtd" >
<components>
<component>
<name>org.richfaces.Skypecall</name>
<family>org.richfaces.Skypecall</family>
<classname>org.richfaces.component.html.HtmlSkypecall</classname>
<superclass>org.richfaces.component.UISkypecall</superclass>
<description>
<![CDATA[
A component that insert a link that permit to call a person from the web via skype.
]]>
</description>
<renderer generate="true" override="true">
<name>org.richfaces.SkypecallRenderer</name>
<template>org/richfaces/htmlSkypecall.jspx</template>
</renderer>
<tag>
<name>skypecall</name>
<classname>org.richfaces.taglib.SkypecallTag</classname>
<superclass>
org.ajax4jsf.webapp.taglib.HtmlComponentTagBase
</superclass>
</tag>
<!--
<taghandler>
<classname>org.ajax4jsf.tag.TestHandler</classname>
</taghandler>
-->
&ui_component_attributes;
&html_events;
&html_style_attributes;
<property>
<name>img</name>
<classname>java.lang.String</classname>
<description>The kind of image to insert. You can use the "default" value to show the default image (see color and size attributes),
the "none" value to show no image, or directly put the URL to show the image you like. So possible value are: default, none, url_of_image. Default is "default".
</description>
<defaultvalue>"default"</defaultvalue>
</property>
<property>
<name>color</name>
<classname>java.lang.String</classname>
<description>The color of the default image. It works if "image" attribute is "default". It can be "green" or "blue". Default is "blue".
</description>
<defaultvalue>"blue"</defaultvalue>
</property>
<property>
<name>size</name>
<classname>java.lang.String</classname>
<description>The size of the default image. It works if "image" attribute is "default". Possible values are: small, medium, big. Default is "medium".
</description>
<defaultvalue>"medium"</defaultvalue>
</property>
<property>
<name>number</name>
<classname>java.lang.String</classname>
<description>Skype number to call. Default is null.
</description>
<defaultvalue>""</defaultvalue>
</property>
<property>
<name>type</name>
<classname>java.lang.String</classname>
<description>The type of skype link to create. Possible values are: call, chat, voicemail, add, userinfo, sendfile. Default is call.
</description>
<defaultvalue>"call"</defaultvalue>
</property>
<!--
<property>
<name>param</name>
<classname>java.lang.String</classname>
<description>
</description>
<defaultvalue>"default"</defaultvalue>
</property>
-->
</component>
</components>
Now we have to modify the jspx template that will generate the renderer, edit src/main/templates/it/novaware/htmlSkypecall.jspx, it might look like that:
<?xml version="1.0" encoding="UTF-8"?>
<f:root
xmlns:f="http://ajax4jsf.org/cdk/template"
xmlns:c=" http://java.sun.com/jsf/core"
xmlns:ui=" http://ajax4jsf.org/cdk/ui"
xmlns:u=" http://ajax4jsf.org/cdk/u"
xmlns:x=" http://ajax4jsf.org/cdk/x"
class="it.novaware.renderkit.html.SkypecallRenderer"
baseclass="org.ajax4jsf.renderkit.AjaxComponentRendererBase"
component="it.novaware.component.UISkypecall"
>
<f:clientid var="clientId"/>
<!--
I can't use this because I can't use parameter inside the name attribute
<f:resource var="skypeImage2" name="/images/green-medium.png" />-->
<jsp:scriptlet>
<![CDATA[
/* See what I have to do with internal image */
String skypeImage = null;
String image=(String) component.getAttributes().get("img");
if (image.compareToIgnoreCase("default")==0) {
/* dynamically compose the default image name */
skypeImage = getResource( "images/"+(String)component.getAttributes().get("color")+"-"+(String)component.getAttributes().get("size")+".png" ).getUri(context, component);
} else if (image.compareToIgnoreCase("none")==0) {
/* skypeImage stays null */
} else {
/* put the url of the image */
skypeImage=image;
}
variables.setVariable("skypeImage",skypeImage);
]]>
</jsp:scriptlet>
<a id="#{clientId}"
name="#{clientId}"
x:passThruWithExclusions="value,name,type,id,number,size,color"
href="skype:#{component.attributes['number']}?#{component.attributes['type']}"
>
<jsp:scriptlet>
<![CDATA[
if (variables.getVariable("skypeImage")!=null) {
]]>
</jsp:scriptlet>
<img src="#{skypeImage}" border="0"/>
<jsp:scriptlet>
<![CDATA[
}
]]>
</jsp:scriptlet>
<vcp:body>
<f:call name="renderChildren" />
</vcp:body>
</a>
</f:root>
Notice that I have to point a dynamic named image (it is composed by the color and the size, look at the code) so I can't use the f:resource tag and I have to use a scriptlet.
I also called renderChilder using the f:call tag to be able to put other components inside the skypecall anchor tag.I think that it is clear what the code do: if the img attribute of the component is none it doesn't put the img tag; if it is default or omitted it uses the color and size attribute to find a default image (that we'll copy in the resource directory in the next final step); if not it uses the passed value as URL for the src attribute of the img tag.
As I said, the final step is to copy the resources images in the appropriate directory so go to skypecall/src/main/resources and insert the it/novaware/renderkit/html/images directories: go inside and copy the default image files that you can find here.
You have finished!
After that you can come back to your shell at skypecallskypecall directory and launch mvn install.
Let's try it!
If you look inside the generatedskypecall/target directory you will find a jar library called skypecall-1.0-SNAPSHOT.jar: you have to copy it in the WEB-INF/libdirectory of your project.
To use it in an xhtml page just use the following namespace:
http://www.novaware.it/skypecallSo if you are using Facelets add:
<xmlns:nw="http://www.novaware.it/skypecall">If you are using JSP add:
<%@ taglib uri="http://www.novaware.it/skypecall" prefix="nw"%>to each page that uses the component.
Here some example of use:
<nw:skypecall img="default" color="blue" number="echo123" type="call" size="small" ></nw:skypecall>
<nw:skypecall size="big" color="green" number="echo123" ></nw:skypecall>
<nw:skypecall size="medium" color="green" number="echo123" ></nw:skypecall>
<nw:skypecall img="default" color="green" number="echo123" type="call" size="small" ></nw:skypecall>
<nw:skypecall img="none" number="echo123" type="call" >call me!</nw:skypecall>
That would produce the following:

Use can also download the source files from here and the compiled library from here.
Here some links you can start from:
As I said, every suggestion is welcome!!
Demetrio

11 Comments:
What was the purpose to put all attributes to the UI class?
By
Sergey, At
October 18, 2007 12:41 AM
Hi, I saw the spacer example: there are some (not all) attributes in UI class but I can't see where they are used so I thought to put all...
Can you explain better this point so I can correct the article?
Thanks
Demetrio
By
demetrio.it, At
October 18, 2007 12:58 AM
Just for information, the discussion continued here.
Demetrio
By
demetrio.it, At
October 21, 2007 4:59 PM
Hello demetrio.it! I get the error stack below when trying to follow your instructions. Could you please update them, to reflect the current repositories?
Thanks!
-----------
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] Ignoring available plugin update: 2.0-alpha-1 as it requires Maven version 2.0.7
Downloading: http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-archetype-plugin/1.0-alpha-7/maven-archetype-plugin-1.0-alpha-7.pom
4K downloaded
Downloading: http://repo1.maven.org/maven2/org/apache/maven/archetype/maven-archetype/1.0-alpha-7/maven-archetype-1.0-alpha-7.pom
3K downloaded
Downloading: http://repo1.maven.org/maven2/org/apache/maven/archetype/maven-archetype-parent/2/maven-archetype-parent-2.pom
2K downloaded
Downloading: http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-archetype-plugin/1.0-alpha-7/maven-archetype-plugin-1.0-alpha-7.jar
12K downloaded
[INFO] ----------------------------------------------------------------------------
[INFO] Building Novaware JSF components library
[INFO] task-segment: [archetype:create] (aggregator-style)
[INFO] ----------------------------------------------------------------------------
Downloading: http://repo1.maven.org/maven2/org/apache/maven/archetype/maven-archetype-core/1.0-alpha-7/maven-archetype-core-1.0-alpha-7.pom
1K downloaded
Downloading: http://repo1.maven.org/maven2/org/apache/maven/shared/maven-downloader/1.0/maven-downloader-1.0.pom
1K downloaded
Downloading: http://repo1.maven.org/maven2/org/apache/maven/archetype/maven-archetype-creator/1.0-alpha-7/maven-archetype-creator-1.0-alpha-7.pom
1K downloaded
Downloading: http://repo1.maven.org/maven2/org/apache/maven/archetype/maven-archetype-model/1.0-alpha-7/maven-archetype-model-1.0-alpha-7.pom
1K downloaded
Downloading: http://repo1.maven.org/maven2/org/codehaus/plexus/plexus-archiver/1.0-alpha-5/plexus-archiver-1.0-alpha-5.pom
439b downloaded
Downloading: http://repo1.maven.org/maven2/org/apache/maven/archetype/maven-archetype-creator/1.0-alpha-7/maven-archetype-creator-1.0-alpha-7.jar
23K downloaded
Downloading: http://repo1.maven.org/maven2/org/codehaus/plexus/plexus-archiver/1.0-alpha-5/plexus-archiver-1.0-alpha-5.jar
129K downloaded
Downloading: http://repo1.maven.org/maven2/org/apache/maven/archetype/maven-archetype-model/1.0-alpha-7/maven-archetype-model-1.0-alpha-7.jar
18K downloaded
Downloading: http://repo1.maven.org/maven2/org/apache/maven/archetype/maven-archetype-core/1.0-alpha-7/maven-archetype-core-1.0-alpha-7.jar
24K downloaded
Downloading: http://repo1.maven.org/maven2/org/apache/maven/shared/maven-downloader/1.0/maven-downloader-1.0.jar
6K downloaded
[INFO] Setting property: classpath.resource.loader.class => 'org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader'.
[INFO] Setting property: velocimacro.messages.on => 'false'.
[INFO] Setting property: resource.loader => 'classpath'.
[INFO] Setting property: resource.manager.logwhenfound => 'false'.
[INFO] **************************************************************
[INFO] Starting Jakarta Velocity v1.4
[INFO] RuntimeInstance initializing.
[INFO] Default Properties File: org\apache\velocity\runtime\defaults\velocity.properties
[INFO] Default ResourceManager initializing. (class org.apache.velocity.runtime.resource.ResourceManagerImpl)
[INFO] Resource Loader Instantiated: org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader
[INFO] ClasspathResourceLoader : initialization starting.
[INFO] ClasspathResourceLoader : initialization complete.
[INFO] ResourceCache : initialized. (class org.apache.velocity.runtime.resource.ResourceCacheImpl)
[INFO] Default ResourceManager initialization complete.
[INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Literal
[INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Macro
[INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Parse
[INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Include
[INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Foreach
[INFO] Created: 20 parsers.
[INFO] Velocimacro : initialization starting.
[INFO] Velocimacro : adding VMs from VM library template : VM_global_library.vm
[ERROR] ResourceManager : unable to find resource 'VM_global_library.vm' in any resource loader.
[INFO] Velocimacro : error using VM library template VM_global_library.vm : org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource 'VM_glo
bal_library.vm'
[INFO] Velocimacro : VM library template macro registration complete.
[INFO] Velocimacro : allowInline = true : VMs can be defined inline in templates
[INFO] Velocimacro : allowInlineToOverride = false : VMs defined inline may NOT replace previous VM definitions
[INFO] Velocimacro : allowInlineLocal = false : VMs defined inline will be global in scope if allowed.
[INFO] Velocimacro : initialization complete.
[INFO] Velocity successfully started.
[INFO] [archetype:create]
[INFO] Defaulting package to group ID: it.novaware
Downloading: http://repo1.maven.org/maven2/org/richfaces/cdk/maven-archetype-jsf-component/3.1.1-GA/maven-archetype-jsf-component-3.1.1-GA.jar
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Failed to resolve artifact.
GroupId: org.richfaces.cdk
ArtifactId: maven-archetype-jsf-component
Version: 3.1.1-GA
Reason: Unable to download the artifact from any repository
Try downloading the file manually from the project website.
Then, install it using the command:
mvn install:install-file -DgroupId=org.richfaces.cdk -DartifactId=maven-archetype-jsf-component \
-Dversion=3.1.1-GA -Dpackaging=jar -Dfile=/path/to/file
org.richfaces.cdk:maven-archetype-jsf-component:jar:3.1.1-GA
from the specified remote repositories:
central (http://repo1.maven.org/maven2)
[INFO] ------------------------------------------------------------------------
[INFO] For more information, run Maven with the -e switch
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6 seconds
[INFO] Finished at: Sat Feb 23 23:17:50 EST 2008
[INFO] Final Memory: 5M/9M
[INFO] ------------------------------------------------------------------------
By
boba, At
February 24, 2008 5:28 AM
Very good article. Can I use CDK to extend existing RichFaces components? I want to extend tree component and add folder/document details. Details like Date Modified, Author and Size in the same row. Something like a MAC finder view.
Is this easy to extend tree component with CDK? Or is CDK used only to create new components?
By
BinnyG, At
March 5, 2008 12:18 AM
Excellant article...Thank you very much demetrio..
Please refer the following link in caseanybody faces issues while trying out this article. RichFaces artifact version naming convention has been slightly changed between builds.
http://www.jboss.com/index.html?module=bb&op=viewtopic&t=135836
By
Jobinesh, At
May 31, 2008 6:44 AM
Thanks to all...and sorry for being absent but I had a lot of work during those months...
I updated the post (thanks jobinesh)...
I did a lot of other works, have to find the time to write articles and maybe start a set of open source extra components!
Is there someone want to help me? :)
demetrio
By
demetrio.it, At
July 6, 2008 3:54 PM
Thanks demetrio, Very well written article... it got me started almost instantaneously.
I am trying to create a custom component and want to collate components (both richfaces components and my other custom components). Is there a sample/reference that I can look at?
By
Anonymous, At
July 20, 2008 3:17 PM
Terrible instructions, bitch.
By
Anonymous, At
November 6, 2008 9:57 PM
I guess I'm the bitch. It was a problem with my maven path variable.
By
Anonymous, At
November 6, 2008 10:06 PM
Negative and evil thoughts make the mind weak. The weak and uncontrolled mind always succumbs to calling those who are trying to help names.
I thought it was a great tutorial. Thanks Demetrio.
By
iroh, At
November 6, 2008 11:15 PM
Post a Comment
Subscribe to Post Comments [Atom]
<< Home