Title: Deathmatch: Ruby on Rails vs' J2EE
1Deathmatch Ruby on Rails vs. J2EE
2Spring and Hibernate Extreme Makeover -
Architecture Edition
3Overview
- Re-factored application
- Spring concepts
- Loose coupling
- Spring EJB architecture
- Spring POJO architecture
- Lessons learned
- Hibernate concepts
- Hibernate DAO layer
- Spring Hibernate The dynamic duo
- Lessons learned
- Project lessons learned
- End results
- QA
4Personal Info - Qualifications
- Counterstrike screen name HoneycombB.I.G.
- Ran a BBS on Commodore 64
- Subscription to Java Developers Journal
- Frequent visitor to www.theserverside.com
5Find a new careerNow!
Java Web Developer Needed
- Java Web Developer Needed
- Reply to job-64857317_at_craigslist.orgDate
2005-03-22, 1042AM MSTJava developer needed to
assist with database-driven web applications.
Must be in Boulder area and provide references. - Dependibility and strong work ethic required.
Experience required - Java
- HTML
- Java Server Pages Servlets
- JDBC
- MySQL database design
- SQL (including complex table joining)
- Excellent code documentation
- CSS Experience preferred
- Apache Tomcat
- XML
- LOG4J
- JavaScript
- Job location is BoulderCompensation 15 per
hour, depending on experience This is a
part-time job.Principals only. Recruiters,
please don't contact this job poster.Please, no
phone calls about this job!Please do not contact
job poster about other services, products or
commercial interests.Reposting this message
elsewhere is NOT OK.
6Re-factoring with Spring and Hibernate
- Project Statistics
- 1600 Java files
- 50 entity Beans no relational mappings
- 20 Session Beans Entry Points, Nested
Transactions, WebServices - All tests written with Cactus. 0 out-of-container
tests - Build and deployment would take about 15 minutes
- Flagship Application Major Voice over IP
application - Application Requirements
- Scalable
- Reliable primarily an issue of code quality for
this analysis - Flexible resilient to support product changes
- Code Transpareny
- During development developer progress code
quality - Easy to integrate and test
- Enabling of high developer productivity
- End-state Solution
- Simplified, layered code
7VOIP App Problems and Challenges
8Spring Framework
- Spring is a layered Java/J2EE application
framework - Swiss army knife
- AOP cross cutting concerns
- MVC Framework
- JMS
- DAO Abstraction Layer
- Integration with Hibernate, iBATIS, etc.
- Inversion of control (bean wiring)
- Much more
- Our re-factor project used
- AOP auditing our entire web service layer
- Bean wiring injection
- EJB proxying transparent use of EJBs
- Hibernate integration no brainer
9Importance of Loose Coupling with Spring
- Adopting Spring is easier when architecture is
loosely coupled - Consistent transaction boundaries/entry points
- Spring adds more value with testing. Control
injection - No boundaries makes things a lot harder
10High Level of Coupling
Products
Application Framework
External Providers
Data Access
- Very tight coupling across the entire application
- Interaction complexity is extremely high.
- Unit testing is hard to do, if not impossible.
Impossible out of the container. - One code change could potentially affect multiple
areas of the code. - The application is very brittle, and development
takes much longer than in a layered architecture.
- More than a few developers and they will start
stepping on each other.
11Very Loose Coupling layers talk only to those
directly above and below them
Spring Interceptors (AOP)/Interface
Biz Services
Interface
Products
Application Framework
Spring Interceptors (AOP)/Interface
Interface
External Providers
Workflow
Spring Interceptors (AOP)/Interface
Data Access
- Structuring a system into layers has a number of
important benefits - Understand a single layer as a coherent whole
without knowing about the other layers - Substitute layers with alternative implementation
of the same basic services - Significantly reduce complexity of code
interactions - Simplify unit testing test each layer
separately - Much more rapid development
12Looking at a Layer Façade Pattern
After Refactor
Before Refactor
VOIP App
Spring Audit Interceptors
VOIP App
External Provider Layer
Service1
Service2
Service3
Service4
Service4
Service3
Service2
Service1
Refactor Enabled
VOIP App
Mock
Mock
Mock
Mock
Mock External Provider Layer
13Loose Coupling w/ Business Interface Pattern
- Having code in EJBs makes unit testing extremely
difficult since everything has to be run in an
application server. - Moved all business logic out of Stateless and
Message Driven EJBs into plain old java objects
(POJO). EJB is solely used for transaction and
thread management. This makes testing the
business logic much easier since we can write all
of our tests out of the container.
14ltbean id"orderService" lazy-init"true"
class"org.spring...SimpleRemoteStatelessSessionPr
oxyFactoryBean"gt ltproperty name"jndiName"gt
ltvaluegtOrderServicelt/valuegt lt/propertygt
ltproperty name"businessInterface"gt
ltvaluegtcom.voip.OrderServiceBizIFlt/valuegt
lt/propertygt lt/beangt
15Business Service Arch. Pattern with EJB
DAO 1 (POJO)
Hibernate Interceptor (Spring) Audit Interceptor
EJB CMT
Biz Service (POJO)
DAO 2 (POJO)
Biz Service 2 (POJO)
Hibernate Session
JTA Transaction (Hibernate has built-in JTA
auto-detect)
DAO 2 (POJO)
Injection
Biz Service 2 (POJO)
Biz Service (POJO)
DAO 1 (POJO)
16Business Service Arch. Pattern with Req. New Tx
EJB
17Business Service Arch. Pattern without EJB
18Interceptors Configuration
- ltbean id"hibernateInterceptor"
class"org.springframework.orm.hibernate.Hibernate
Interceptor"gt - ltproperty name"sessionFactory"gt
- ltref bean"sessionFactory"/gt
- lt/propertygt
- lt/beangt
- ltbean id"auditInterceptor" class"com.voip.AuditI
nterceptor"gt - ltproperty name"daoAudit"gt
- ltref bean"daoAudit"/gt
- lt/propertygt
- lt/beangt
19Biz Services Configuration
Interceptors
- ltbean id"_serviceAutoProxyCreator1"
class"org.spring.aop.framework.autoproxy.BeanName
AutoProxyCreator"gt - ltproperty name"interceptorNames"gt
- ltlistgt
- ltidref bean"hibernateInterceptor"/gt
- ltidref bean"auditInterceptor"/gt
- lt/listgt
- lt/propertygt
- ltproperty name"beanNames"gt
- ltlistgt
- ltidref local"OrderServiceBizIF"/gt
- lt/listgt
- lt/propertygt
- lt/beangt
- ltbean id"OrderServiceBizIF" class"com.voip.Order
ServiceBiz"gt - ltproperty name"daoOrder"gtltref
bean"daoOrder"/gtlt/propertygt - ltproperty nameservice2"gtltref
beanservice2"/gtlt/propertygt - lt/beangt
Beans
Service Class
Injection
20Typical Biz Service Class
- public class OrderServiceBiz implements
OrderServiceBizIF - private DAOOrderIF daoOrder // injected
- /
- _at_xdocletpublic-method
- /
- public OrderDTO placeOrder(String name) throws
MyAppException - OrderDTO order new OrderDTO()
- order.setCreateDate(new Date())
- order.setName(name)
- // do biz logic here
- getDaoOrder().storeOrder(order)
-
- public DAOOrderIF getDaoOrder()
- return daoOrder
-
21Spring Lessons Learned
- Start with bean wiring (Inversion of Control)
- Beans that are Spring wired are very easy to
apply AOP - The more injection, the more you can mock
- Spring can be used for test data retrieval
- One of Springs goal is to make existing
technologies easier. Spring is not Hibernate,
Hibernate is not Spring. - Ability to change behavior without changing code
is an important point and benefit of Spring (i.e.
datasource configuration, transaction manager,
our entire web service layer) - Re-factor into layers first, then add Spring and
Hibernate - Layering also creates boundaries
- Tradeoff between run-time flexibility and
run-time configuration validation - Changing one property in the database allows us
to change entire layers
22Hibernate
- Hibernate is a powerful, ultra-high performance
object/relational persistence and query service
for Java
23Data Access Object Layer
- Implementation details of DAO layer left up to
developer (i.e you can use JDBC, Hibernate,
iBATIS, JDO, Entity Beans, etc.) - Entity beans are hard to test and are not very
scalable since they are application server
managed objects. - Every Entity Bean was removed and replaced with a
Spring/Hibernate true object relational layer, or
Data Access Object Layer (DAO). This layer is
fully testable out of the container. - This layer was implemented with interfaces in
front which allows for the layer to be stubbed or
mocked for application testing - A DAO layer enables you to adopt new persistence
mechanisms
24Hibernate DAO Layer
- Many things are generated
- Middlegen Hibernate Mapping Files
- Hbm2java Data Transfer Objects (DTOs)
- XDoclet - Interfaces
- Spring makes Hibernate session management
transparent with Hibernate Interceptors and the
HibernateDAOSupport class - DAO Layer only took about a week to create.
Largely depends on underlying data model and
referential integrity - Hibernate allows for Hibernate Query Language or
pure SQL - This DAO layer provides all the benefits that
Hibernate brings to the table (caching, lazy
loading, etc.).
25DAO UML Diagram
26Typical DAO Class
- DAO represents an aggregate or functional area
- public class DAOAudit extends HibernateDaoSupport
implements DAOAuditIF - /
- _at_xdocletpublic-method
- /
- public AuditEventDTO loadAuditEvent(Long id)
- return (AuditEventDTO) getHibernateTemplate().load
(AuditEventDTO.class, id)
27Typical DAO Class (cont.)
- /
- _at_xdocletpublic-method
- /
- public Object findUniqueByDynamicQuery(final
Object dto, final Class dtoType) - HibernateCallback callback new
HibernateCallback() - public Object doInHibernate(Session
session) throws HibernateException - Example exampleDto Example.create(dto).i
gnoreCase().enableLike(MatchMode.ANYWHERE) - return session.createCriteria(dtoType).add
(exampleDto).uniqueResult() -
-
- return getHibernateTemplate().execute(callback
)
28Typical DAO Class (cont.)
- /
- _at_xdocletpublic-method
- /
- public Collection findSpringOrdersByName(String
name) - return getHibernateTemplate().find(
- "from AuditEventDTO event where event.name
?", name,Hibernate.STRING) -
29Hibernate/Spring ConfigSession Factory
- ltbean id"sessionFactory class"org.spring.orm.hi
bernate.LocalSessionFactoryBeangt - ltproperty name"dataSource"gtltref
bean"dataSource"/gtlt/propertygt - ltproperty name"mappingResources"gt
- ltlistgt
- ltvaluegtcom/voip/OrderDTO.hbm.xmllt/valuegt
- More DTOs
- lt/listgt
- lt/propertygt
- ltproperty name"hibernateProperties"gt
- ltpropsgt
- ltprop key"hibernate.dialect"gtnet.sf.hiberna
te.dialect.Oracle9Dialectlt/propgt - ltprop key"hibernate.trans.manager_lookup_cl
ass"gttransaction.lookup.classlt/propgt - lt/propsgt
- lt/propertygt
- lt/beangt
- ltbean id"nonTxSessionFactory class"org.spring.o
rm.hibernate.LocalSessionFactoryBean"gt - ltproperty name"dataSource"gtltref
bean"nonTxDataSource"/gtlt/propertygt - ltproperty name"mappingResources"gt
Hibernate Mapping Files
Auto JTA Detection
30Hibernate/Spring Configuration DAO
- lt!--
--gt - lt!-- Hibernate DAO --gt
- lt!--
--gt - ltbean id"daoOrder" class"com.voip.DAOOrder"gt
- ltproperty name"sessionFactory"gtltref
local"sessionFactory"/gtlt/propertygt - lt/beangt
- ltbean id"daoAudit" class"com.voip.DAOAudit"gt
- ltproperty name"sessionFactory"gtltref
local"nonTxSessionFactory"/gtlt/propertygt - lt/beangt
- Spring Property Files
- Production
- transaction.lookup.classnet.sf.hibernate.trans.We
blogicTransactionManagerLookup - Test
Inject with Tx Session Factory
Inject with NonTx Session Factory
31Hibernate/Spring Configuration Datasource
- lt!--
--gt - lt!-- Data Sources (Production) --gt Spring
Production Bean Factory - lt!--
--gt - ltbean id"dataSource" class"org.spring.jndi.JndiO
bjectFactoryBean"gt - ltproperty name"jndiName"gtltvaluegtspring_datasourc
elt/valuegtlt/propertygt - lt/beangt
- ltbean id"nonTxDataSource" class"org.spring.jndi.
JndiObjectFactoryBean"gt - ltproperty name"jndiName"gtltvaluegtnontx_datasource
lt/valuegtlt/propertygt - lt/beangt
- lt!--
--gt - lt!-- Data Sources (Testing) --gt Test Bean Factory
- lt!--
--gt - ltbean id"dataSource" class"springframework...Sin
gleConnectionDataSource"gt - ltproperty name"url"gtltvaluegtjdbc.urllt/valuegtlt/p
ropertygt - ltproperty name"username"gtltvaluegtjdbc.userna
melt/valuegtlt/propertygt - ltproperty name"password"gtltvaluegtjdbc.passwo
rdlt/valuegtlt/propertygt - lt/beangt
32DAO Lessons Learned
- Lazy loading a must have (session per
transaction) - Collections
- Class Level
- Left outer joins slow
- Checked Exceptions
- Remember the first level cache
- If re-factoring, create DAO layer first and get
code coverage to 100 - Automatic dirty-checking is a must have
(session per transaction) - Write generic finder methods instead of one
finder method for each possible combination - Bi-directional relationship problems
- Consistent patterns are very important for a DAO
layer exception handling, transaction mgmt,
finder methods, etc - Hiberate 3.0.1 SessionFactory.getCurrentSession()
method. It allows application developers to
delegate tracking of current sessions to
Hibernate itself. Currently, the
getCurrentSession() method is only available if
you are using Hibernate within a JTA environment.
33Replicating the container transactional unit
testing
34Replicating the container transactional unit
testing
- ltbean id"transactionManager" class"org.springfra
mework.orm.hibernate.HibernateTransactionManager"gt
- ltproperty name"sessionFactory"gt
- ltref bean"sessionFactory"/gt
- lt/propertygt
- lt/beangt
35Replicating the container transactional unit
testing
- protected void setUp() throws Exception
- setTransactionManager((PlatformTransactionManage
r) getClassFactory().getObjectById("transactionMan
ager")) - // Start a transaction
- transactionManager.getTransaction(new
DefaultTransactionDefinition()) -
- protected void tearDown() throws Exception
- try
- onTearDownInTransaction()
- finally
- getTransactionManager().rollback(getTransact
ionStatus()) -
-
36Summary of Patterns/Design Principles
- DAO
- separates a data resource's client interface from
its data access mechanisms. Adapts a specific
data resource's access API to a generic client
interface - Interface
- Keep a class that uses data and services provided
by instances of other classes independent of
those classes by having it access those instances
through an interface - AOP
- Aspect-oriented programming (AOP) is a new
programming technique that allows programmers to
modularize crosscutting concerns (behavior that
cuts across the typical divisions of
responsibility, such as logging) - IOC
- Inversion of Control (IOC) is a means to inject
components into other components thus allowing
for very loose coupling
37Project Lessons Learned
- Steel Thread/Prototype/Reference Architecture
- Do your homework (0 infrastructure bugs).
Replacing the engines in-flight on an airplane
analogy - Iterations
- Scapegoat central
- Need someone with crosscutting knowledge
- Correct or dispel bad press quickly
- Set realistic expectations there will be bugs
- Not a silver bullet must use all the parts
- Be pragmatic dont use because its cool
- Existing unit tests make life a lot easier
38Re-factor Results
- Entire code base can be tested out of container
except for EJB ? EJB calls - Code is much more maintainable
- Re-factoring is much easier with baseline of unit
tests in place - Inversion of control helps immensely in mocking
out external service layer calls - Testing becomes much easier meaning more likely
to happen - Teams able to scale with less code contention
39Questions?
fgarsombke_at_yahoo.com
http//dozer.sourceforge.net
Shameless Plug
Dozer is a powerful, yet simple Java Bean to Java
Bean mapper that recursively copies data from one
object to another. Typically, these Java Beans
will be of different complex types.
Dozer supports simple property mapping, complex
type mapping, bi-directional mapping,
implicit-explicit mapping, as well as recursive
mapping. This includes mapping collection
attributes that also need mapping at the element
level.