JSF Flex

Java Development News:

JSF Flex

By Ji Hoon Kim

01 Sep 2008 | TheServerSide.com

JavaServer Faces Flex goal is to provide users capability in creating standard Flex components, part of flexSDK which is open sourced through MPL license, as normal JSF components [note that other dynamic components such as chart are not part of flexSDK]. So users would create the components as normal JSF components and the project will create the necessary SWC, SWF, and etcetera and link the values of the components back to the managed beans using JSON+JavaScript and ActionScript. This article, which is mainly targeted for JSF developers, will provide an overview of creating a simple multilingual JSF page consisting of JSF Flex tags. Please note that the project is in its beta state and any input regarding the project is most appreciated!


[View Larger]

JSF Flex Overall Example

Setting up JSF Flex project

Retrieval of artifacts

First retrieve the JSF Flex artifacts [note that the project currently supports MyFaces 1.2 + Mojarra 1.2 implementations].

  • If one is using Maven as their project management tool, one can add the dependencies by adding the following repository info and the artifact info to pom.xml:
 <repositories> <repository> <id>jsf-flex-repository</id> <name>JSF Flex Repository</name> <url>http://jsf-flex.googlecode.com/svn/repository/release/</url> </repository> </repositories> <dependencies> <!-- Below artifact contains components, phaseListener, filter, and etcetera for JSF Flex project --> <dependency> <groupId>com.googlecode.jsf-flex.jsf-flex-project</groupId> <artifactId>jsf-flex</artifactId> <version>${jsf.flex.version}</version> <scope>runtime</scope> </dependency> <!-- Below artifact contains renderers and _AnnotationDocletParser implementation for JSF Flex project --> <dependency> <groupId>com.googlecode.jsf-flex.jsf-flex-project</groupId> <artifactId>jsf-flex-project-renderKit14</artifactId> <version>${jsf.flex.version}</version> <scope>runtime</scope> </dependency> <!-- Below three dependencies are implementations that provide creation of preMxml, Mxml, SWC, SWF, and etcetera. --> <dependency> <groupId> com.googlecode.jsf-flex.runner-impl-project.common-runner-project </groupId> <artifactId>sdk-standard-common-impl</artifactId> <version>${jsf.flex.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId> com.googlecode.jsf-flex.runner-impl-project.file-manipulator-runner-project </groupId> <artifactId>velocity-file-manipulator-impl</artifactId> <version>${jsf.flex.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId> com.googlecode.jsf-flex.runner-impl-project.flex-runner-project </groupId> <artifactId>ant-flex-impl</artifactId> <version>${jsf.flex.version}</version> <scope>runtime</scope> </dependency> <!-- Below dependency provides MXMLRenderKit* java files and etcetera that are specific to MyFaces Impl --> <dependency> <groupId>com.googlecode.jsf-flex.jsf-flex-project</groupId> <artifactId>jsf-flex-myFaces-impl</artifactId> <version>${jsf.flex.version}</version> <scope>runtime</scope> </dependency> <!-- Below dependency provides MXMLRenderKit* java files and etcetera that are specific to Mojarra Impl --> <dependency> <groupId>com.googlecode.jsf-flex.jsf-flex-project</groupId> <artifactId>jsf-flex-mojarra-impl</artifactId> <version>${jsf.flex.version}</version> <scope>runtime</scope> </dependency> </dependencies> <properties> <jsf.flex.version>1.0b</jsf.flex.version> </properties>

JSF Flex Maven info

Note that one needs one dependency of either jsf-flex-myFaces-impl artifact or jsf-flex-mojarra-impl artifact. The reason that there exists separate maven projects for the two implementation is to provide capability in using other renderKits such as HTML_BASIC when user is using MXML_BASIC renderKit. However, since there exists a difference in MyFaces + Mojarra implementation where, if I remember correctly, the latter implementation adds the HTML_BASIC renderKit within the constructor, the class needed to be extended to intercept the call to addRenderer [there are other methods, but chose this option as it is clear].

  • If one is not using Maven as their project management tool :
    • Retrieve the JSF Flex artifacts by downloading the latest Zip file for the specific implementation from http://code.google.com/p/jsf-flex/downloads/list .
    • Then extract the content of the artifacts to the web project’s WEB-INF/lib directory.

Running a JSF page consisting of JSF Flex tag

Modify web.xml

In order to make the process simple, merge the following content to web.xml.

 <?xml version="1.0" encoding="UTF-8"?> <!-- * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. --> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <!-- Below is for Facelet support with the example pages ending in standard .xhtml extension --> <context-param> <param-name>facelets.VIEW_MAPPINGS</param-name> <param-value>*.xhtml</param-value> </context-param> <context-param> <param-name>facelets.DEVELOPMENT</param-name> <param-value>true</param-value> </context-param> <context-param> <description>Comma separated list of URIs of (additional) faces config files. (e.g. /WEB-INF/my-config.xml) See JSF 1.0 PRD2, 10.3.2 Attention: You may not put /WEB-INF/faces-config.xml in here. </description> <param-name>javax.faces.CONFIG_FILES</param-name> <param-value>/WEB-INF/examples-config.xml</param-value> </context-param> <context-param> <description>State saving method: "client" or "server" (= default) See JSF Specification 2.5.3</description> <param-name>javax.faces.STATE_SAVING_METHOD</param-name> <param-value>server</param-value> </context-param> <context-param> <description> The relative web context path for the locale resources, if being used for multilingual application </description> <param-name>com.googlecode.jsfFlex.LocaleWebContextRelativePath</param-name> <param-value>locale</param-value> </context-param> <context-param> <description> The default locale </description> <param-name>com.googlecode.jsfFlex.DefaultLocale</param-name> <param-value>en_US</param-value> </context-param> <context-param> <description> For JSF Flex Flash To JavaScript Log Level, possible values are (Log, Debug, Info, Warn, Error) If the field is not provided, it will make a decision based on com.googlecode.jsfFlex.MODE with production being Error and non-production being Log. Specifically it is only allowed for Firebug unless the user uses Firebug Lite or has Dojo with debug set to true. </description> <param-name>com.googlecode.jsfFlex.FlashToJavaScriptLogLevel</param-name> <param-value>Debug</param-value> </context-param> <context-param> <description>For JSF Flex build mode, possible values are (debugMode, simplySwfMode, productionMode [default]) </description> <param-name>com.googlecode.jsfFlex.MODE</param-name> <param-value>debugMode</param-value> </context-param> <filter> <filter-name>jsfFlexResourceFilter</filter-name> <filter-class>com.googlecode.jsfFlex.filter.JsfFlexResourceFilter</filter-class> </filter> <!-- The below filter-mapping is to generate a standard <script> html elements within the html head, so to have /jsfFlexResourceRequest/* filter-mapping generate those resources --> <filter-mapping> <filter-name>jsfFlexResourceFilter</filter-name> <url-pattern>*.jsf</url-pattern> </filter-mapping> <!-- The below filter-mapping is used to respond to script requests from *.jsf filter-mapping --> <filter-mapping> <filter-name>jsfFlexResourceFilter</filter-name> <url-pattern>/jsfFlexResourceRequest/*</url-pattern> </filter-mapping> <!-- The below filter-mapping is used for Facelet support --> <filter-mapping> <filter-name>jsfFlexResourceFilter</filter-name> <url-pattern>/faces/*</url-pattern> </filter-mapping> <!-- Faces Servlet --> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <!-- Faces Servlet Mapping --> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping> <!-- Below mapping is for JsfFlexHttpServicePhaseListener which will handle asynchronous requests from the client --> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/jsfFlexHttpServiceRequestListener/*</url-pattern> </servlet-mapping> <!-- Below mapping is for Facelet support --> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> </web-app>

JSF Flex web.xml content

Create a locale directory

Within the previous step, there exists two parameters that define the application of being a multilingual application. These two parameters are com.googlecode.jsfFlex.LocaleWebContextRelativePath and com.googlecode.jsfFlex.DefaultLocale where the first defines the relative web context path for the locale resources and where the second defines the default locale to be used if the requested locale does not exist [i.e. if the application supports english + korean and the user’s browser setting is set for german, the application will return the default value of en_US]. Now create the directory locale, value of com.googlecode.jsfFlex.LocaleWebContextRelativePath, under WebContent and directory en_US, value of com.googlecode.jsfFlex.DefaultLocale, underneath locale. Then you can create an another directory ko_KR to demonstrate the usage of locale and copy the following two files to their respective directory, first one to en_US and the latter to ko_KR. There are couple of things to note regarding the locale support within JSF Flex :

  • if the application needs to support only one language, one can omit these parameters from web.xml.
  • at the current time Flex does not provide runtime access of Locale messages, meaning whenever there exists change within the .properties file one has to recreate the associated SWF files by changing com.googlecode.jsfFlex.MODE field to debugMode within web.xml.

greeting=Hello

greeting=uC548uB155

Create examples-config.xml under WEB-INF directory

Copy the below examples-config.xml file, which contains reference to a managed bean for the to be created JSF page and Facelet View Handler info under WEB-INF directory, since we will be using Facelet View Handler rather than the default JSP View Handler:

 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN" "http://java.sun.com/dtd/web-facesconfig_1_1.dtd"> <!-- =========== FULL CONFIGURATION FILE ================================== --> <faces-config> <application> <locale-config> <default-locale>en</default-locale> </locale-config> <view-handler>com.sun.facelets.FaceletViewHandler</view-handler> </application> <managed-bean> <managed-bean-name>mxmlLocaleBean</managed-bean-name> <managed-bean-class>com.googlecode.jsfFlex.examples.mxml.MXMLLocaleExampleBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> </faces-config>

JSF Flex examples-config.xml content

Create a managed bean to be used for the JSF page

Copy the below file under comgooglecodejsfFlexexamplesmxml

 /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package com.googlecode.jsfFlex.examples.mxml; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * @author Ji Hoon Kim */ public final class MXMLLocaleExampleBean implements Serializable { private static final long serialVersionUID = -3006842391681193512L; private static final String LARGE_DATA_STRING_DISPLAY_MESSAGE = "Displaying column data for "; private List<LargeDataEntry> _largeDataEntries; private List<LargeDataEntry> _largeSecondDataEntries; private List<WisePeopleEntry> _wisePeopleEntries; public MXMLLocaleExampleBean(){ super(); _largeDataEntries = new ArrayList<LargeDataEntry>(); _largeSecondDataEntries = new ArrayList<LargeDataEntry>(); for(int i=0; i < 500; i++){ _largeDataEntries.add(new LargeDataEntry(LARGE_DATA_STRING_DISPLAY_MESSAGE + i, Long.valueOf(i))); } _wisePeopleEntries = new ArrayList<WisePeopleEntry>(); _wisePeopleEntries.add(new WisePeopleEntry("Issac Newton", "This most beautiful system [The Universe] could only proceed from the dominion of an intelligent and powerful Being.")); _wisePeopleEntries.add(new WisePeopleEntry("James Clark Maxwell", "At quite uncertain times and places. The atoms left their heavenly path, And by fortuitous embraces, Engendered all that being hath.")); _wisePeopleEntries.add(new WisePeopleEntry("Blaise Pascal", "Belief is a wise wager. Granted that faith cannot be proved, what harm will come to you if you gamble on its truth and it proves false? If you gain, you gain all; if you lose, you lose nothing. Wager, then, without hesitation, that He exists.")); _wisePeopleEntries.add(new WisePeopleEntry("Socrates", "It is not living that matters, but living rightly. I know that I am intelligent, because I know that I know nothing. The end of life is to be like God, and the soul following God will be like Him.")); _wisePeopleEntries.add(new WisePeopleEntry("Marcus Tullius Cicero", "A man of courage is also full of faith. Knowledge which is divorced from justice, may be called cunning rather than wisdom.")); } public List<LargeDataEntry> getLargeDataEntries() { return _largeDataEntries; } public void setLargeDataEntries(List<LargeDataEntry> largeDataEntries) { _largeDataEntries = largeDataEntries; } public List<LargeDataEntry> getLargeSecondDataEntries() { return _largeSecondDataEntries; } public void setLargeSecondDataEntries(List<LargeDataEntry> largeSecondDataEntries) { _largeSecondDataEntries = largeSecondDataEntries; } public List<WisePeopleEntry> getWisePeopleEntries() { return _wisePeopleEntries; } public void setWisePeopleEntries(List<WisePeopleEntry> wisePeopleEntries) { _wisePeopleEntries = wisePeopleEntries; } public final static class LargeDataEntry implements Serializable { private static final long serialVersionUID = 8426305474249836025L; private static final int HASH_CODE_INIT_VALUE = 3; private static final int HASH_CODE_MULTIPLY_VALUE = 31; private String _firstColumnEntry; private Long _secondColumnEntry; /** * Need to have public modifier, so that it can be instantiated by * AbstractMXMLUIDataGrid when data from one DataGrid component is * added to an another. */ public LargeDataEntry(){ super(); } private LargeDataEntry(String firstColumnEntry, Long secondColumnEntry){ super(); _firstColumnEntry = firstColumnEntry; _secondColumnEntry = secondColumnEntry; } public String getFirstColumnEntry() { return _firstColumnEntry; } public void setFirstColumnEntry(String firstColumnEntry) { _firstColumnEntry = firstColumnEntry; } public Long getSecondColumnEntry() { return _secondColumnEntry; } public void setSecondColumnEntry(Long secondColumnEntry) { _secondColumnEntry = secondColumnEntry; } public boolean equals(Object instance) { if(!(instance instanceof LargeDataEntry)){ return false; } LargeDataEntry largeDataEntryInstance = (LargeDataEntry) instance; return _firstColumnEntry.equals(largeDataEntryInstance._firstColumnEntry) && _secondColumnEntry.equals(largeDataEntryInstance._secondColumnEntry); } public int hashCode() { int hashCodeVal = HASH_CODE_INIT_VALUE; hashCodeVal = HASH_CODE_MULTIPLY_VALUE * hashCodeVal + _firstColumnEntry.hashCode(); hashCodeVal = HASH_CODE_MULTIPLY_VALUE * hashCodeVal + _secondColumnEntry.hashCode(); return hashCodeVal; } } public final static class WisePeopleEntry implements Serializable { private static final long serialVersionUID = -4974974584395025727L; private static final int HASH_CODE_INIT_VALUE = 3; private static final int HASH_CODE_MULTIPLY_VALUE = 31; private String _name; private String _quote; private WisePeopleEntry(String name, String quote){ super(); _name = name; _quote = quote; } public String getName() { return _name; } public void setName(String name) { _name = name; } public String getQuote() { return _quote; } public void setQuote(String quote) { _quote = quote; } public boolean equals(Object instance) { if(!(instance instanceof WisePeopleEntry)){ return false; } WisePeopleEntry wisePeopleEntryInstance = (WisePeopleEntry) instance; return _name.equals(wisePeopleEntryInstance._name) && _quote.equals(wisePeopleEntryInstance._quote); } public int hashCode() { int hashCodeVal = HASH_CODE_INIT_VALUE; hashCodeVal = HASH_CODE_MULTIPLY_VALUE * hashCodeVal + _name.hashCode(); hashCodeVal = HASH_CODE_MULTIPLY_VALUE * hashCodeVal + _quote.hashCode(); return hashCodeVal; } } }

JSF Flex MXMLLocaleExampleBean.java

Create a JSF page consisting of JSF Flex tag

Copy the below mxmlLocale.xhtml JSF example page consisting of Label component for locale example and a DataGrid component as an addition to the same directory that WEB-INF is within of dynamic web project.

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:jf="http://jsf-flex.googlecode.com"> <!-- /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ //--> <body> <f:view renderKitId="MXML_BASIC"> <h:form> <jf:mxmlApplication mxmlPackageName="mxmlLocale" height="500" width="1200"> <jf:mxmlDividedBox direction="horizontal" width="100%" height="100%"> <jf:mxmlBox width="55%" height="100%"> <jf:mxmlLabel text="Following label contains text to demonstrate locale" color="#FFFFFF" fontWeight="bold"/> <jf:mxmlLabel text="@Resource(bundle='LocaleExample', key='greeting')" color="#FFFFFF" fontWeight="bold" fontSize="14"/> <jf:mxmlDataGrid bindingBeanList="#{mxmlLocaleBean.wisePeopleEntries}" width="100%" rowCount="4" resizableColumns="true" editable="true" height="100%"> <jf:mxmlColumns> <jf:mxmlDataGridColumn dataField="name" headerText="Name" /> <jf:mxmlDataGridColumn wordWrap="true" dataField="quote" headerText="Quote" minWidth="170" /> </jf:mxmlColumns> </jf:mxmlDataGrid> </jf:mxmlBox> <jf:mxmlBox width="45%" height="100%"> <jf:mxmlDataGrid bindingBeanList="#{mxmlLocaleBean.largeDataEntries}" width="100%" rowCount="10" resizableColumns="true" editable="true" dragEnabled="true" allowMultipleSelection="true" dragMoveEnabled="true"> <jf:mxmlColumns> <jf:mxmlDataGridColumn dataField="firstColumnEntry" headerText="First Column Entry" /> <jf:mxmlDataGridColumn dataField="secondColumnEntry" headerText="Second Column Entry"> <f:convertNumber /> </jf:mxmlDataGridColumn> </jf:mxmlColumns> </jf:mxmlDataGrid> <jf:mxmlDataGrid bindingBeanList="#{mxmlLocaleBean.largeSecondDataEntries}" width="100%" rowCount="10" resizableColumns="true" editable="true" dropEnabled="true" allowMultipleSelection="true" bindingBeanClassName="com.googlecode.jsfFlex.examples.mxml.MXMLLocaleExampleBean$LargeDataEntry"> <jf:mxmlColumns> <jf:mxmlDataGridColumn dataField="firstColumnEntry" headerText="First Column Entry" /> <jf:mxmlDataGridColumn dataField="secondColumnEntry" headerText="Second Column Entry"> <f:convertNumber /> </jf:mxmlDataGridColumn> </jf:mxmlColumns> </jf:mxmlDataGrid> </jf:mxmlBox> </jf:mxmlDividedBox> </jf:mxmlApplication> </h:form> </f:view> </body> </html>

JSF Flex mxmlLocale.xhtml

There are couple of things to note within the JSF example page :

  1. JSF Flex does contain a renderKit with id MXML_BASIC which allows users to intermix other renderKits [i.e. HTML_BASIC] tags along with JSF Flex tags. This is due to MXMLRenderKitFactoryImplWrapper handing off additional renderKits to MXMLRenderKitImplWrapper which checks for the components initially within MXMLRenderKitImpl and if not found will search for the component in other renderKits by traversing through them.
  2. All JSF Flex tags such as mxmlAccordion, mxmlRichTextEditor, and etcetera must be nested under mxmlApplication tag.
  3. Update of the binding bean entries for DataGrid is done asynchronously through ActionScript whereas the update of the binding bean entries for other components [i.e. textInput] are done during the JSF processUpdates.
  4. Flex’s DataGrid component has been augmented with features :
  • To allow partitioning of data when the data size is large [additional data will be fetched asynchronously using ActionScript when the user scrolls for more info].
  • To allow server’s managed beans to be updated if modification of DataGrid’s entry is performed or if drag + drop action is performed from one DataGrid to an another DataGrid. Note the need to specify bindingBeanClassName attribute within the DataGrid component that will accept the drop, since the binding bean list is empty for that component. However, if bindingBeanClassName attribute is not provided, it is assumed that the binding bean list is not empty and the project will use the first entry’s className to create new instances of the object.
  • To allow sorting of the server’s managed beans if the data is partitioned, else it will be sorted only on the client side. In order to allow sorting, the bean’s dataField, an attribute of mxmlDataGridColumn which is a child component of mxmlDataGrid component, must implement the Comparable interface [i.e. String, Long].

Here is an image showing the example mxmlLocale.xhtml


[View Larger]

JSF Flex mxmlLocale.xhtml screen shot

That is it. When ran under debugMode, respective SWF files will be created under its respective directory and depending on the user’s browser setting the correct locale SWF file will be fetched:

  • en_US : mxmlLocale-en_US.swf
  • ko_KR : mxmlLocale-ko_KR.swf

Note that once the user is finished tweaking the JSF page, one should change the com.googlecode.jsfFlex.MODE to productionMode to see the actual performance of the page. An additional, crucial note to remember for the user is to copy the system generated WebContent/swf directory to the actual WorkSpace when packaging for WAR or EAR, since the project uses servletContext.getRealPath("") as the root directory of preMxml, MXML, SWC, and SWF directory and

  • Tomcat on default flushes it out to their cache directory under metadata i.e. C:OpenSource.metadata.pluginsorg.eclipse.wst.server.coretmp0wtpwebappsjsf-flex-examples
  • JBoss on default flushes it out to their temp directory i.e. C:Program Filesjboss-4.2.3.GAserverdefaulttmpdeploytmp46689jsf-flex-examples.war

Conclusion

With the Web 2.0 technology flourishing within the web world, JSF Flex allows bridging of these two technologies which excel in their own area :

  • Flex in creating a Rich Internet Application
  • JSF in componentizing the data on the server side and binding it to managed beans.

In the future JSF Flex will have tighter bound with JSF/Java and ActionScript in similar manner as DataGrid component, will provide MethodExpression to provide better control of resources [i.e. memory], beans, and action, and support Flex 3 [currently supporting Flex 2].

Resources

Further details and the source code : http://code.google.com/p/jsf-flex/

Project member’s main discussion list : http://groups.google.com/group/jsf-flex/

About the Author

Ji Hoon Kim is a Software Engineer within IBM and the founder of JSF Flex project.

Related Content

Related Resources