Proxy classes ( poor's man AOP ) in conjunction with iBatis framework do the trick:
Lets compare implementations of the same class xflow.server.controller.WorkflowP in Xflow2 and in original Xflow (API and functionality are exactly the same)
XFlow 2 |
Xflow |
| ~200 lines of code | ~620 lines of code |
| Typical code looks like this | Typical code looks like this |
149 public void abortWorkflow (final Integer workflowId)
throws SQLException {
150 Map params = new Hashtable();
151 params.put("workflowId",workflowId );
152 params.put("timeEnded", new Date() );
153 Persistence.getThreadSqlMapSession()
.update( "abortWorkflow",params );
154 }
|
284 public static void abortWorkflow (WorkflowId workflowId)
throws XflowException {
285
286 int wfId = workflowId.getValue();
287 Connection con = null;
288 Statement s = null;
289 try {
290 con = Persistence.getConnection();
291 s = con.createStatement();
292
293 String timeEnded = DateUtil.getTimestamp();
294 String sql =
"update workflow set isActive = false, timeEnded = '"
+ timeEnded +
295 "', status = 'ABORTED' where workflowid = " + wfId;
296 log.info (sql);
297 s.execute (sql);
298 } catch (Exception e) {
299 e.printStackTrace();
300 throw new XflowException ("Failed to abort workflow in database");
301 } finally {
302 if (s!=null) {
303 try {
304 s.close();
305 } catch (Exception e) {
306 e.printStackTrace();
307 }
308 }
309 if (con != null) {
310 try {
311 con.close();
312 } catch (Exception e) {
313 }
314 }
315 }
316 }
|
As we can see Xflow2 code is much smaller and does not have all that plumbing code to get a connection and handle possible exceptions. All that is possible because all those aspects are handled by proxy class that gets created at runtime. That is it: at runtime callers of the class above in reality deal with WorkflowP Proxy class. It is achived by using Factory pattern. Persistence class has methods to enhance DAO classes.
261 public static WorkflowP getWorkflowP() {
262 synchronized( guard ){
263 if( workflowP == null ){
264 workflowP = (WorkflowP) enhanceInstanceOfClass( WorkflowP.class );
265 }
266 return workflowP;
267 }
268
269 }
Enhancer creates Proxy class that looks exactly as given, but every method is wrapped by interceptor, that handles all the plumbing: