Title: MultiParadigm Design in Java
1Multi-Paradigm Design in Java
- Frode Standal,
- Chief Consultant
- frode.standal_at_kantega.no
- 47 92418571
- www.kantega.no
2Introduction
- Java offers many programming paradigms
- Object-Oriented Programming
- Meta-Programming
- Generic Programming (JDK 1.5)
- Aspect-Oriented Programming
- Avoid the Hammer-and-nail syndrome
- Combine the different paradigms
- Using Multi-Paradigm Design Principles
- Examples from application development in the
context of J2EE and EJB
3Roadmap
- Paradigms
- Design Principles
- Multi-Paradigm Design
4Paradigms
- Object-Oriented Programming
- Meta-Programming
- Generic Programming
- Aspect-Oriented Programming
5Object-Oriented Programming
- Interface Inheritance
- For subtyping (supporting polymorphism and
dynamic binding) - Implementation Inheritance
- For code reuse
- Often combined
- Known uses
- Everywhere
6Meta-Programming
- An object usually represents a part of the
application domain (e.g. Order, Customer) or the
solution domain (e.g. Cache, AuthenticationFilter)
- A meta-object represents a part of the program
(e.g. Class, Method)
7Meta-Programming Continued
- Basic reflection
- Get info on an objects methods (with arguments
and return types) represented as an object
(meta-object) - Invoke a method using the method meta-object
- Dynamic proxy
- Create an implementation of one or more
interfaces on the fly - The implementation delegates to an invocation
handler providing meta-information - Some known uses
- In web application frameworks (e.g. Struts and
WebWork) for mapping HTTP request parameters to
java beans and for accessing java beans from JSP
tags - In the Spring framework for mapping configuration
files to java beans
8Generic Programming
- Generic class
- A class that serves as a template for a group of
classes which share implementation - Is parameterized by one or more other classes
- Example public class Buffer ltTgt ...
- We must provide actual parameters when creating
an instance of the class BufferltMessagegt buffer
new BufferltMessagegt() - Generic method
- A method that serves as a template for a group of
methods which share implementation - Is parameterized by one or more other classes
- Some known uses
- The Collections API
9Aspect-Oriented Programming
- An aspect is a modularization of the
implementation of a requirement which affects
many classes/methods/modules (often a
non-functional requirement) - Advice
- Piece of code to be executed before/after/around
a set of points of execution (join points) of a
program - A set of join points are specified using a
wildcard syntax - Method introduction
- Adding methods or fields to existing
classes/interfaces - Mixin inheritance
- Modifying the inheritance hierarchy of existing
classes/interfaces
10Aspect-Oriented Programming Continued
- Alternative AOP technolgies
- AspectJ, JBoss AOP, Spring AOP, AspectWerkz,
Nanning - Aspects are weaved into the program
- AspectJ uses a special compiler to do this
- Some known uses of AOP
- JBoss 4 (transactions, security, caching, etc)
- Spring (transactions, security, etc)
- Logging
11Design Principles
- Modularity
- Grouping logically related code
- Minimizing the dependencies among modules
- The Open-Closed Principle
- It should be possible to extend the behaviour of
an module without having to modify existing code - Refactor common code
- Avoid code duplication
12Refactoring
- Choose refactoring strategy depending on the
commonalities and variabilities in your code - Interface Inheritance
- Commonality Types and method signatures
- Variability Algorithm implementation
- Implementation Inheritance
- Commonality Behaviour and data structure
- Variability Behaviour and data structure
13Refactoring
- Generic classes and methods
- Commonality Behaviour and data structure
- Variability Detailed type(s)
- Basic reflection
- Commonality Read/modify properties of an object
- Variability The types, names, and number of
properties - AOP Advice
- Commonality Code to be executed
before/after/around the execution of methods - Variability The methods/classes/packages where
the common code is needed
14Multi-Paradigm Design
- Requirements
- Architectural Context
- Iterative Analysis and Solution Design
15Requirements
- Use-Case View Orders
- Basic Flow
- Actor Customer
- The user selects the View Orders operation
- The system reads all the customers orders from
the database, and displays the order information
for each order - The user selects one of the displayed orders
- The system reads all the order details (line
items) from the database and displays them
16Requirements Continued
- Alternative flow
- Actor Administrator
- The administrator selects a customer
- Same as basic flow, steps 1-4
17Architectural Context
- J2EE
- EJB (Stateless session beans)
- JDBC
- DAO (Data Access Object)
- DTO (Data Transfer Object)
18Iteration 0 - Solution Design
- Stateless session bean OrderService
- Collection getOrders(String customer)
- Collection getOrderDetails(Integer orderId)
- The methods return collection of Order and
OrderDetail respectively (DTOs) - The methods delegate to DAO which encapsulates
database access
19public Collection getOrders(String customer)
Connection conn null PreparedStatement ps
null ResultSet rs null try conn
dataSource.getConnection() String stmt
"select id, customer, order_date from
orders where customer ?" ps
conn.prepareStatement(stmt) ps.setString(1,
customer) rs ps.executeQuery()
Collection result new ArrayList() while
(rs.next()) Order o new Order()
o.setId(new Integer(rs.getInt("id")))
o.setCustomer(rs.getString("customer"))
o.setOrderDate(rs.getTimestamp("order_date"))
result.add(o) return result
catch (SQLException e) log.error("", e)
throw new DBException(e) finally
try if (rs ! null) rs.close()
catch (SQLException e) try if (ps
! null) ps.close() catch
(SQLException e) try if (conn !
null) conn.close() catch (SQLException
e)
public Collection getOrderDetails(Integer
orderId) Connection conn null
PreparedStatement ps null ResultSet rs
null try conn dataSource.getConnection
() String stmt "select id, name, order_id,
unit_price, count from order_details where
order_id ?" ps conn.prepareStatement(stmt
) ps.setObject(1, orderId) rs
ps.executeQuery() Collection result new
ArrayList() while (rs.next())
OrderDetail o new OrderDetail()
o.setId(new Integer(rs.getInt("id")))
o.setName(rs.getString("name"))
o.setOrderId(new Integer(rs.getInt("order_id")))
o.setUnitPrice(rs.getFloat("unit_price"))
o.setCount(rs.getInt("count"))
result.add(o) return result
catch (SQLException e) log.error("", e)
throw new DBException(e) finally
try if (rs ! null) rs.close()
catch (SQLException e) try if (ps
! null) ps.close() catch
(SQLException e) try if (conn !
null) conn.close() catch (SQLException
e)
20Iteration 1 - Analysis
- Commonalities Overall algorithm
- Get database connection
- Create SQL statement
- Execute statement
- Process result set
- Close connection
- Variabilities
- Query
- Result set
- Type of DTO
21Iteration 1 - Solution Design
- Refactor using object orientation
- Capture overall algorithm in a base class
(DBQuery) - Implement query, result set handling and DTO
initialization in subclasses
22public abstract class DBQuery public
Collection select(String query, Object arg
Connection conn null PreparedStatement ps
null ResultSet rs null try
conn dataSource.getConnection() ps
conn.prepareStatement(query)
fillStatement(ps, args) rs
ps.executeQuery() Collection result new
ArrayList() while (rs.next())
Object o processRow(rs)
result.add(o) return result
catch (SQLException e)
log.error("", e) throw new
DBException(e) finally try
if (rs ! null) rs.close()
catch (SQLException e) try if
(ps ! null) ps.close() catch
(SQLException e) try if (conn
! null) conn.close() catch
(SQLException e) protected
abstract Object processRow(ResultSet rs)
throws SQLException
public Collection getOrders(String customer)
DBQuery query new DBQuery(dataSource)
protected Object processRow(ResultSet rs)
throws SQLException Order o new
Order() o.setId(new Integer(rs.getInt("id")
)) o.setCustomer(rs.getString("customer"))
o.setOrderDate(rs.getTimestamp("order_date"
)) return o String stmt
"select id, customer, order_date from orders
where customer ?" return query.select(stmt,
new Object customer ) public Collection
getOrderDetails(Integer orderId) DBQuery
query new DBQuery(dataSource) protected
Object processRow(ResultSet rs) throws
SQLException OrderDetail o new
OrderDetail() o.setId(new
Integer(rs.getInt("id")))
o.setName(rs.getString("name"))
o.setOrderId(new Integer(rs.getInt("order_id")))
o.setUnitPrice(rs.getFloat("unit_price"))
o.setCount(rs.getInt("count")) return
o String stmt "select id, name,
order_id, unit_price, count from order_details
where order_id ?" return query.select(stmt,
new Object orderId )
23 Iteration 1 - Solution Design Continued
- Base class is abstract
- Subclasses are anonymous (optional)
- Template Method design pattern (GoF)
- We have achieved
- Less code to write
- Enforced cleanup code (avoiding potential
resource leak) - Only one place to maintain cleanup code
- Avoided the cutpaste programming antipattern
24Iteration 2 - Analysis
public Collection getOrders(String customer)
DBQuery query new DBQuery(dataSource)
protected Object processRow(ResultSet rs)
throws SQLException Order o new
Order() o.setId(new Integer(rs.getInt("id")
)) o.setCustomer(rs.getString("customer"))
o.setOrderDate(rs.getTimestamp("order_date"
)) return o String stmt
"select id, customer, order_date from orders
where customer ?" return query.select(stmt,
new Object customer )
public Collection getOrderDetails(Integer
orderId) DBQuery query new
DBQuery(dataSource) protected Object
processRow(ResultSet rs) throws
SQLException OrderDetail o new
OrderDetail() o.setId(new
Integer(rs.getInt("id")))
o.setName(rs.getString("name"))
o.setOrderId(new Integer(rs.getInt("order_id")))
o.setUnitPrice(rs.getFloat("unit_price"))
o.setCount(rs.getInt("count")) return
o String stmt "select id, name,
order_id, unit_price, count from order_details
where order_id ?" return query.select(stmt,
new Object orderId )
25Iteration 2 - Analysis Continued
- Commonalities
- Create DTO
- For each column get value from result set and
call setter in DTO - Variabilities
- Different type of DTO
- Column values have different names and types
- DTO properties have different names and types
- Variable number of columns/properties
26Iteration 2 - Solution Design
- Refactor using meta-programming in DBQuery to
- Create DTO instances
- Find names of columns from result set
- Find names of setters in DTO
- Call setters with values extracted from result
set - Assume a naming convention between column name
and property name (e.g. order_id and orderId) - No need for subclasses of DBQuery anymore
27public class DBQuery public Collection
select(Class cls,
String query,
Object args) Connection conn null
PreparedStatement ps null ResultSet rs
null try conn dataSource.getConnec
tion() ps conn.prepareStatement(query)
fillStatement(ps, args) rs
ps.executeQuery() Collection result
buildResult(cls, rs) return result
catch (SQLException e) log.error("",
e) throw new DBException(e)
finally try if (rs ! null)
rs.close() catch (SQLException e)
try if (ps ! null)
ps.close() catch (SQLException e)
try if (conn ! null)
conn.close() catch (SQLException
e)
protected Collection buildResult(Class cls,
ResultSet rs) throws SQLException
ResultSetMetaData md rs.getMetaData() try
ArrayList list new ArrayList() while
(rs.next()) Object o cls.newInstance()
for (int i 0 i lt md.getColumnCount()
i) String columnName
md.getColumnName(i1) String
propertyName toPropertyName(columnName)
PropertyDescriptor pd new
PropertyDescriptor(propertyName, o.getClass())
Method method pd.getWriteMethod()
Class propertyClass pd.getPropertyType()
Object arg null arg getValue(rs,
i1, propertyClass) Object args
arg method.invoke(o, args)
list.add(o) return list
catch (Exception e) throw new
DBException(e)
28Iteration 2 - Solution Design Continued
public Collection getOrders(String customer)
String stmt "select id, customer,
order_date from orders where customer ?"
return query.select(Order.class, stmt, new
Object customer ) public Collection
getOrderDetails(Integer orderId) String
stmt "select id, name, order_id,
unit_price, count from order_details where
order_id ?" return query.select(OrderDetail.c
lass, stmt, new Object orderId )
29Iteration 3 - Analysis
public Collection getOrders(String customer)
public Collection getOrderDetails(Integer
orderId)
-
- Both methods return a Collection, but element
type is not specified in the method signature,
needing documentation to tell the client
programmer what to expect - No compile-time type checking
30Iteration 3 - Solution Design
- Use generic programming
- Provides self-documenting code and compile-time
type checking on client - What about server side?
public CollectionltOrdergt getOrders(String
customer) public CollectionltOrderDetailgt
getOrderDetails(Integer orderId)
31Iteration 3 - Solution Design Continued
- Make DBQuery.select a generic method
- java.lang.Class is generic
- The type of Order.class is ClassltOrdergt
- The type of Order.class.newInstance() is Order
public ltEgt CollectionltEgt select(ClassltEgt cls,
String query,
Object args)
32public class DBQuery public ltEgt
CollectionltEgt select(ClassltEgt cls,
String query,
Object args) Connection conn
null PreparedStatement ps null
ResultSet rs null try conn
dataSource.getConnection() ps
conn.prepareStatement(query)
fillStatement(ps, args) rs
ps.executeQuery() CollectionltEgt result
buildResult(cls, rs) return result
catch (SQLException e) log.error("",
e) throw new DBException(e)
finally try if (rs ! null)
rs.close() catch (SQLException e)
try if (ps ! null)
ps.close() catch (SQLException e)
try if (conn ! null)
conn.close() catch (SQLException
e)
protected ltEgt CollectionltEgt buildResult(ClassltEgt
cls,
ResultSet rs) throws SQLException
ResultSetMetaData md rs.getMetaData() try
ArrayListltEgt list new ArrayListltEgt()
while (rs.next()) E o
cls.newInstance() for (int i 0 i lt
md.getColumnCount() i) String
columnName md.getColumnName(i1)
String propertyName toPropertyName(columnName)
PropertyDescriptor pd new
PropertyDescriptor(propertyName, o.getClass())
Method method pd.getWriteMethod()
Class propertyClass pd.getPropertyType()
Object arg null arg getValue(rs,
i1, propertyClass) Object args
arg method.invoke(o, args)
list.add(o) return list
catch (Exception e) throw new
DBException(e)
33Iteration 3 - Solution Design Continued
CollectionltOrdergt getOrders(String customer)
String stmt "select id, customer,
order_date from orders where customer ?"
return query.select(Order.class, stmt, new
Object customer ) CollectionltOrderDe
tailgt getOrderDetails(Integer orderId)
String stmt "select id, name, order_id,
unit_price, count from order_details where
order_id ?" return query.select(OrderDetail.c
lass, stmt, new Object orderId )
- Now we have compile-time type checking on server
as well
34New requirements Access control
- A customer may only see own orders and order
details - An administrator may se all customers orders and
order details
35Iteration 4 Analysis
- We do not want mix access control logic with
business logic/persistence logic (the modularity
principle) - We do not want to change existing code (the
open-closed principle) - EJB does not support declarative data-based
access control (only pure role-based) - No portable way to intercept calls to EJB using
the proxy-, decorator- or interceptor design
patterns
36Iteration 4 Solution Design
- Use aspect-oriented programming
- Create an aspect which handles the access control
requirement - Define before-advice for the methods in
OrderService
37public aspect OrderAccessControl
before(OrderServiceEJB bean, String customer)
execution( OrderServiceEJB.getOrders(String))
this(bean) args(customer)
checkAccess(bean.getSessionContext(),
customer) before(OrderServiceEJB bean,
Integer orderId) execution(
OrderServiceEJB.getOrderDetails(Integer))
this(bean) args(orderId) String
customer bean.getOrderDAO().getCustomerByOrder(o
rderId) checkAccess(bean.getSessionContext(),
customer) public void
checkAccess(SessionContext ctx, String customer)
if (!ctx.isCallerInRole("administrator"))
String caller ctx.getCallerPrincipal().g
etName() if (!caller.equals(customer))
throw new java.security.AccessControlException
("Access denied. " caller " tried
to access data belonging to " customer)
38Summary
- We have combined the programming paradigms to
achieve a better design - Multi-paradigm design supplements
- Design patterns
- Java coding idioms
- Frameworks
39Bibliography
- Multi-Paradigm Design for C (J. Coplien)
- Design Patterns (E. Gamma et al.)
- Java Reflection in Action (I. and N. Forman)
- The Art of the Metaobject Protocol (G. Kiczales
et al.) - Generics in the Java Programming Language (G.
Bracha) - AspectJ in Action (R. Laddad)