Creating JSF applications with JRuby and ActiveRecord-JDBC (Part 2)
My last article about this topic showed how can we start the development of an JSF webapp with JRuby and ActiveRecord-JDBC, we will discuss on this article how can we create the dao, domain class and the view used to show costumer data.
In this example, CostumerDao illustrate how can we perform some data persistence/retrieval using ActiveRecord domain classes, we defined MyCostumer JRuby class to act as a proxy of our domain class:
CostumerDao.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 | #The line bellow allow to use some special #statements for ruby -> java integration. require 'java' #Importing Costumer domain class require 'br/eti/faces/jruby/model/Costumer' #Importing MyCostumer proxy class of Costumer class require 'br/eti/faces/jruby/model/proxy/MyCostumer' #Importing ICostumerDao java interface. include_class 'br.eti.faces.jruby.dao.ICostumerDao' #This class will be instantiated by Spring and #injected as dependency on CostumerPage class. class CostumerDao include ICostumerDao def add(name, address, country) #We are instantiating a domain class #to save using ActiveRecord-JDBC costumer = Costumer.new costumer.name = name costumer.address = address costumer.country = country costumer.save end def getCostumers #This list will hold some proxy instances #of Costumer domain class. list = ArrayList.new Costumer.find(:all).each { | costumer | myCostumer = MyCostumer.new costumer list.add myCostumer } return list end end |
Click here download the Java interface of the class above.
Costumer is the domain class used by CostumerDao, this class will be handled by ActiveRecord-JDBC adding ORM capabilities to this application.
Costumer.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 | #Importing jrubygems, this class allow #to use/load gems that are on gems/ #directory of classpath. require 'jrubygems' #Loading ActiveRecord-JDBC gems. We #will use hsqldb adapter in this #example. gem 'jdbc-hsqldb' gem 'activesupport' gem 'activerecord' gem 'activerecord-jdbc-adapter' gem 'activerecord-jdbchsqldb-adapter' require 'jdbc_adapter' require 'active_record' #The method below configures a database #connection to be used by ActiveRecord-JDBC #classes. ActiveRecord::Base.establish_connection( :adapter => 'jdbchsqldb', :username => 'sa', :driver => 'org.hsqldb.jdbcDriver', :url => 'jdbc:hsqldb:file:c:/temp/db/data.db') #Each domain class must extend ActiveRecord::Base class Costumer < ActiveRecord::Base end |
Now we must create MyCostumer class, each MyCostumer instace holds one Costumer instance, we can’t access Costumer instances directly from JSF because ActiveRecord doesn’t allow Java interfaces on domain classes.
MyCostumer.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 | #The line bellow allow to use some special #statements for ruby -> java integration. require 'java' #Importing ArrayList class. include_class 'java.util.ArrayList' #Importing IMyCostumer java interface. include_class 'br.eti.faces.jruby.model.proxy.IMyCostumer' #This class implements IMyCostumer interface #to allow integration with Spring and Java. #Spring creates a proxy class of this Ruby #class at runtime based on Java interface #that this class implements. class MyCostumer include IMyCostumer @name = '' @address = '' @country = '' def initialize(costumer) @name = costumer.name @address = costumer.address @country = costumer.country end def getName @name end def getAddress @address end def getCountry @country end end |
You must click here to download the source code of IMyCostumer Java interface of MyCostumer JRuby class.
And now the view used to enter costumer data and display a list of costumers:
home.jsp:
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 | <%@ page session="false"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <html> <head> </head> <body> <f:view> <h:form> <center> <h:panelGrid columns="2"> <h:outputLabel for="enterName" value="Name:"/> <h:inputText id="enterName" value="#{costumerPage.name}"/> <h:outputLabel for="enterAddress" value="Address:"/> <h:inputText id="enterAddress" value="#{costumerPage.address}"/> <h:outputLabel for="enterCountry" value="Country:"/> <h:inputText id="enterCountry" value="#{costumerPage.country}"/> </h:panelGrid> <h:commandButton value="Save" action="#{costumerPage.save}"/> <br/> <h:dataTable value="#{costumerPage.costumers}" var="costumer"> <h:column> <f:facet name="header"> <h:outputText value="Name"/> </f:facet> <h:outputText value="#{costumer.name}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Address"/> </f:facet> <h:outputText value="#{costumer.address}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Country"/> </f:facet> <h:outputText value="#{costumer.country}"/> </h:column> </h:dataTable> </center> </h:form> </f:view> </body> </html> |
Wow! Excelent Rogerio!
However, i still am thinking too hard to work this way. Maybe the integration between JSF and dynamic languages might become best soon.
Finally, continue writting posts like this, i believe that soon you will get a best solution to integrate JSF and JRuby.
Do you know to say if it released the materials of the JSFDay about JSF e dynamic languages?
March 17th, 2008 | #
Hey,
I don\\\’t have any experience with jruby and using Java classes from within Ruby, I just do pure Rails development
but usually things like this:
def getCostumers
list = ArrayList.new
Costumer.find(:all).each { | costumer |
myCostumer = MyCostumer.new costumer
list.add myCostumer
}
return list
end
are much shorter. For example, if we needed just a Ruby array, we could do it this way:
def getCostumers
Costumer.find(:all).collect{ | costumer | MyCostumer.new(costumer) }
end
this method returns an instance of Ruby Array (which is closer to ArrayList than to Java arrays). Return is not necessary, and methods like select, collect, ad reject are cool
March 18th, 2008 | #
Hi Rogerio,
You might want to know that in your MyCostumer class @name from the class (@name = \\\’\\\’) is not the same as @name instance variable from the methods getName and setName. To see the difference add static method like this:
def MyCostumer.other_name
@name
end
then check the values:
costumer = MyCostumer.new()
costumer.setName(\\
March 19th, 2008 | #
Hm, it seems part of my post didn’t get through. Anyway, just set the name, than print it (puts costumer.getName) and than compare it with other_name (puts MyCostumer.other_name).
March 19th, 2008 | #
Rafael, the JSFDays presentation is available here: http://conference.irian.at/conference/main/schedule.jsf?conversationContext=1#sess_9. It doesn’t cover active record, though. Just some integration scenarios.
March 21st, 2008 | #
I checked the Kito presentation and it’s pretty similar to my approach but this article is only based on spring docs. In the end the Kito presentation and this article gives some ideas about the possibilities of web development using jsf.
March 23rd, 2008 | #