Creating JSF applications with JRuby and ActiveRecord-JDBC (Part 1)
Is there any way to create JSF applications using scripting languages and its own persistence engines? The answer is: Yes! After some hours trying to integrate JSF + JRuby + ActiveRecord I finally could get a very simple application working, this application contains only one page where the user can add some costumer data, we have jsp as view, spring as IoC container and integration point with JRuby, ActiveRecord-JDBC as ORM.
The page has a managedbean defined as Ruby class, each Ruby bean must implement a Java interface to allow integration with Java/Spring, when the bean is requested by Spring a Java proxy class is instantiated based on its Java interface and then all Ruby code can be consumed properly.
If you wanna try by yourself you must create a webapplication and add the jars described on my previous post (except groovy-1.5.4.jar) plus these jars below on WEB/lib folder:
- hsqldb.jar
- jline-0.9.91.jar
- jruby-complete-1.0.3.jar
- jrubygems-0.3.jar
- backport-util-concurrent.jar
You also need add the following JRuby gems on WEB-INF/classes/gems folder:
- activerecord-2.0.2.gem
- activesupport-2.0.2.gem
- activerecord-jdbc-adapter-0.7.2.gem
- activerecord-jdbchsqldb-adapter-0.7.2.gem
- jdbc-hsqldb-1.8.0.7.gem
The web.xml and faces-config.xml remains the same as my previous post.
Now we must declare some of our JRuby beans in applicationContext.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:lang="http://www.springframework.org/schema/lang" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.5.xsd"> <lang:jruby id="costumerPage" scope="request" script-interfaces="br.eti.faces.jruby.beans.ICostumerPage" script-source="classpath:br/eti/faces/jruby/beans/CostumerPage.rb"> <lang:property name="dao" ref="costumerDao" /> </lang:jruby> <lang:jruby id="costumerDao" scope="singleton" script-interfaces="br.eti.faces.jruby.dao.ICostumerDao" script-source="classpath:br/eti/faces/jruby/dao/CostumerDao.rb"/> </beans> |
We are ready to create out JRuby classes, please open some basic text editor and add following lines then save on WEB-INF/classes/br/eti/faces/jruby/beans folder named as CostumerPage.rb:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | #The line bellow allow to use some special #statements for ruby -> java integration. require 'java' #Importing IMyCostumer java interface. include_class 'br.eti.faces.jruby.beans.ICostumerPage' #This class will act as jsf managedbean. class CostumerPage include ICostumerPage @name = '' @address = '' @country = '' @dao = nil def save #Calling dao method to save data @dao.add(@name, @address, @country) end def getCostumers #Calling dao method to retrieve costumers list @dao.getCostumers end def setName(name) @name = name end def getName @name end def setAddress(address) @address = address end def getAddress @address end def setCountry(country) @country = country end def getCountry @country end #Setter for dao injection def setDao(dao) @dao = dao end end CostumerPage.new |
The class above implements ICostumerPage, as I said at the begging of this post, each JRuby bean that will be consumed by JSF must implement a Java interface because a Java proxy class of CostumerPage JRuby class will be created allowing access to all JRuby class methods and properties.
Please create a file named ICostumerPage.java on WEB-INF/classes/br/eti/faces/jruby/beans folder and paste the following code into this file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | package br.eti.faces.jruby.beans; import java.util.ArrayList; import br.eti.faces.jruby.model.proxy.IMyCostumer; //This interface must be implemented //by CostumerPage Ruby class to allow //integration with Java/Spring. When //CostumberPage is requested by Spring //a Java proxy class will be created //based on this interface. public interface ICostumerPage { public void save(); public ArrayList<IMyCostumer> getCostumers(); public String getName(); public void setName(String name); public String getAddress(); public void setAddress(String address); public String getCountry(); public void setCountry(String country); } |
Wow! Great post again Rogerio!
Congratulations! Yours post about JSF and some dynamic languages ara excelents!
March 17th, 2008 | #
Hey, have you heard about attr_accessor in Ruby?
Your Ruby class is so verbose and Java-like that I don\\\’t see any reason at all in using Ruby if you program this Java way.
Your Ruby class could be three lines long
class CostumerPage
include ICostumerPage
attr_reader :name, :address, :country, :whatever
end
March 18th, 2008 | #
Ok, I’ll change it, thanks!
March 18th, 2008 | #
Good luck anyway
March 18th, 2008 | #
Thanks for that great article!
March 20th, 2008 | #
@Joeri: The accessors won’t conform to the ICostumerPage interface, which, sadly, is java-based, and mandated by Spring, IIRC.
March 25th, 2008 | #
To see ruby used in such an ugly way makes me sick
March 27th, 2008 | #
Me too Chris, this is just an experience giving some idea about how much work is necessary to use this combination and if it is viable.
March 27th, 2008 | #
JSF is actually in my opinion a more intuitive representation of a web page than Rails MVC which is stateless and request based. Spring also has its advantages over Rails (unless Rails has IoC features that I don\\\’t know about). Hibernate though is not as easy to use as ActiveRecord so JSF + Spring + ActiveRecord is a great combination. I have thought of tried doing this myself so this saves a lot of time, thanks!
May 22nd, 2008 | #