Boiler Plating Database Resource Cleanup
This presentation is the property of its rightful owner.
Sponsored Links
1 / 55

Boiler Plating Database Resource Cleanup With Execute Around Method ACCU London February 2009 PowerPoint PPT Presentation


  • 44 Views
  • Uploaded on
  • Presentation posted in: General

Boiler Plating Database Resource Cleanup With Execute Around Method ACCU London February 2009 ACCU Conference April 2009. Paul Grenyer Senior Software Engineer [email protected] http://paulgrenyer.blogspot.com. Validus 8 Thorpe Road Norwich NR1 1RY www.validus-ivc.co.uk.

Download Presentation

Boiler Plating Database Resource Cleanup With Execute Around Method ACCU London February 2009

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


Boiler plating database resource cleanup with execute around method accu london february 2009

Boiler Plating Database Resource Cleanup

With Execute Around Method

ACCU London February 2009

ACCU Conference April 2009

Paul GrenyerSenior Software Engineer

[email protected]

http://paulgrenyer.blogspot.com

Validus

8 Thorpe Road

Norwich

NR1 1RY

www.validus-ivc.co.uk


Boiler plating database resource cleanup with execute around method accu london february 2009

Agenda

All About Me

The Problem (audience participation)

Execute Around Method

A solution


Boiler plating database resource cleanup with execute around method accu london february 2009

Speaker biography

Who am I?

My career so far

Validus-IVC and what I do there


Boiler plating database resource cleanup with execute around method accu london february 2009

The Problem


Boiler plating database resource cleanup with execute around method accu london february 2009

Audience Participation 1

Write some JDBC code to execute the following update statement:

UPDATE SERVICES

SET URL="http://prodserv01/axis/services/email2"

WHERE NAME = 'EMAIL'

Key concept: Connection User


Boiler plating database resource cleanup with execute around method accu london february 2009

Creating a Connection

try

{

Class.forName(DRIVER);

final Connection con = DriverManager.getConnection( CONNECTION_STRING,

USERNAME,

PASSWORD);

con.setCatalog(DATABASE);

// Use connection

}

catch(ClassNotFoundException e)

{

// handle error

}

catch(SQLException e)

{

// handle error

}


Boiler plating database resource cleanup with execute around method accu london february 2009

Creating and using a Statement

...

final Statement stmt = con.createStatement();

try

{

stmt.execute(SQL);

}

finally

{

try

{

stmt.close();

}

catch(SQLException e)

{

// handle error

}

}

...


Boiler plating database resource cleanup with execute around method accu london february 2009

Wouldn't it be nicer if you could do this?

try

{

final ConnectionProvider cp =

new ConnectionProvider(new StringConnection(DRIVER, CONNECTION_STRING)

.setUser(USERNAME,PASSWORD)

.setDatabase(DATABASE));

Query.execute( cp, "UPDATE … WHERE NAME = 'Email'");

}

catch(Exception e)

{

// Report error

}


Boiler plating database resource cleanup with execute around method accu london february 2009

Audience Participation 2

Write some JDBC code to execute the following select statement:

SELECT URL FROM SERVICES

and write the result to the console

Key concept: Connection Value


Boiler plating database resource cleanup with execute around method accu london february 2009

Creating and using a Result Set

...

final Statement stmt = con.createStatement();

try

{

final ResultSet rs = stmt.executeQuery(SQL);

try

{

while(rs.next())

{

System.out.println(rs.getString("url"));

}

}

finally

{

try

{

rs.close();

}

catch(Exception e)

{

// Handle exception

}

}

}

...


Boiler plating database resource cleanup with execute around method accu london february 2009

Wouldn't it be nicer if you could do this?

try

{

final ConnectionProvider cp =

new ConnectionProvider(new StringConnection(DRIVER,CONNECTION_STRING)

.setUser(USERNAME, PASSWORD)

.setDatabase(DATABASE));

final List<String> urls

= Query.execute( cp,

"SELECT URL FROM SERVICES", new RSProcessor());

for(String url : urls)

{

System.out.println(url);

}

}

catch(Exception e)

{

e.printStackTrace();

}


Boiler plating database resource cleanup with execute around method accu london february 2009

Wouldn't it be nicer if you could do this?

class RSProcessor extends AbstractResultSetFunction<List<String>>

{

@Override

public List<String> read(ResultSet rs)

{

List<String> result = new ArrayList<String>();

try

{

while (rs.next())

{

result.add(rs.getString("url"));

}

}

catch(SQLException ex)

{

getErrorPolicy().handleError(ex);

}

return result;

}

}


Boiler plating database resource cleanup with execute around method accu london february 2009

Execute Around Method (EAM)

“Encapsulate pairs of actions in the object that requires them, not code that uses the object, and pass usage code to the object as another object.”

Kevlin Henney

?


Boiler plating database resource cleanup with execute around method accu london february 2009

File Writer


Boiler plating database resource cleanup with execute around method accu london february 2009

public interface WriterUser

{

void use(Writer writer) throws IOException ;

}

public class FileWriterProvider

{

private final String filename;

public FileWriterProvider(String filename)

{ this.filename = filename; }

public void provideTo(WriterUser user) throws IOException

{

final FileWriter writer = new FileWriter(filename);

try

{

user.use(writer);

}

finally

{

writer.close();

}

}

}


Boiler plating database resource cleanup with execute around method accu london february 2009

new FileWriterProvider("out.txt").provideTo(new WriterUser()

{

@Override

public void use(Writer writer) throws IOException

{

writer.write("Execute Around Method!");

}

});


Boiler plating database resource cleanup with execute around method accu london february 2009

Execute Around Method (EAM)

“Using an object to manage a resource and provide it to another object to use”


Boiler plating database resource cleanup with execute around method accu london february 2009

The Solution

Resource management

Providers (inc. connection factory) & Users

Error handling


Boiler plating database resource cleanup with execute around method accu london february 2009

Resource Management

Resources to manage:

Connection

Statement

ResultSet

Each must be:

Acquired

Used

Cleaned-up


Boiler plating database resource cleanup with execute around method accu london february 2009

Connection Provider

<<Connection User>>

<<Connection Value>>

Statement Provider

<<Statement User>>

<<Statement Value>>

ResultSet Provider

<<ResultSet Function>>


Boiler plating database resource cleanup with execute around method accu london february 2009

  • Connection Provider

  • The concept of a connection provider was suggested to me by Adrian Fagg. The idea is that:

    • A single class is responsible for acquiring a connection

    • Providing it to another class for use

    • Releasing it again

      Execute Around Method!


Boiler plating database resource cleanup with execute around method accu london february 2009

Connection Provider


Boiler plating database resource cleanup with execute around method accu london february 2009

Connection Factory Interface

public interface ConnectionFactory

{

Connection connect();

void disconnect(Connection con);

}

Why have a connection factory?

On demand connection

Connection pool

Existing connection

Custom connection


Boiler plating database resource cleanup with execute around method accu london february 2009

  • Connection Factory: disconnect

  • public abstract class AbstractConnectionFactory implements ConnectionFactory

  • {

  • @Override

  • public void disconnect(Connection con)

  • {

  • if (con != null)

  • {

  • try

  • {

  • con.close();

  • }

  • catch(final SQLException ex)

  • {

  • // To do

  • }

  • }

  • }

  • }

  • A Connection can be created any number of ways.

  • A Connection is usually closed in the same way.


Boiler plating database resource cleanup with execute around method accu london february 2009

Connection Factory: connect

public Connection connect()

{

Connection con = null;

try

{

Class.forName(driver);

con = DriverManager.getConnection( connectionString,

username,

password);

}

catch(ClassNotFoundException ex)

{

// To do

}

catch(SQLException ex)

{

// To do

}

return con;

}


Boiler plating database resource cleanup with execute around method accu london february 2009

Connection Provider: Construction

public final class ConnectionProvider

{

private final ConnectionFactory conFactory;

public ConnectionProvider(ConnectionFactory conFactory)

{

this.conFactory = conFactory;

}

}


Boiler plating database resource cleanup with execute around method accu london february 2009

Key Concepts

User:

An object that uses a JDBC resource, but doesn’t return a value.

public interface ConnectionUser

{

void use(Connection con);

}

Value User:

An object that uses a JDBC resource and returns a value.

public interface ConnectionValue<T>

{

T fetch(Connection con);

}


Boiler plating database resource cleanup with execute around method accu london february 2009

Connection User Interface

public interface ConnectionUser

{

void use(Connection con);

}

Uses the connection

Does not return a value!


Boiler plating database resource cleanup with execute around method accu london february 2009

Connection Provider: User

public void provideTo( ConnectionUser user )

{

final Connection con = conFactory.connect();

try

{

user.use(con);

}

finally

{

conFactory.disconnect(con);

}

}

Uses Finally for Each Release Pattern to:

Create a Connection from the factory

Passes the Connection to the user

Closes Connection


Boiler plating database resource cleanup with execute around method accu london february 2009

Connection Value User

public interface ConnectionValue<T>

{

T fetch(Connection con);

}

Like the ConnectionUser, but:

Fetch method has a return type

Return type is a generic parameter


Boiler plating database resource cleanup with execute around method accu london february 2009

Connection Provider: Value User

public <T> T provideTo( ConnectionValue<T> valueUser )

{

final Connection con = conFactory.connect();

T result = null;

try

{

result = valueUser.fetch(con);

}

finally

{

conFactory.disconnect(con);

}

return result;

}

Uses Finally for Each Release pattern to:

Create a Connection from the factory

Passes the Connection to the user and stores the result

Closes connection

Passes the result back.


Boiler plating database resource cleanup with execute around method accu london february 2009

Statement Provider


Boiler plating database resource cleanup with execute around method accu london february 2009

Statement User and Value User

public interface StatementUser

{

void use(Statement stmt);

}

public interface StatementValue<T>

{

T use(Statement stmt);

}


Boiler plating database resource cleanup with execute around method accu london february 2009

Statement Provider: Value User

public <T> T provideTo( StatementValue<T> valueUser )

{

T result = null;

try

{

final Statement stmt = con.createStatement();

try

{

result = valueUser.use(stmt);

}

finally

{

try

{

stmt.close();

}

catch(SQLException ex)

{

// To do

}

}

}

catch(SQLException ex)

{

// To do

}

return result;

}


Boiler plating database resource cleanup with execute around method accu london february 2009

Result Set Provider


Boiler plating database resource cleanup with execute around method accu london february 2009

ResultSetFunction

public interface ResultSetFunction<T>

{

T read(ResultSet rs);

}

Iterates through RecordSet.

Returns result.


Boiler plating database resource cleanup with execute around method accu london february 2009

ResultSet Provider

public <T> T provideTo(ResultSetFunction<T> fetcher)

{

T result = null;

try

{

final ResultSet rs = stmt.executeQuery(sql);

try

{

result = fetcher.read(rs);

}

finally

{

try

{

rs.close();

}

catch(Exception ex)

{

// To do

}

}

}

catch(SQLException ex)

{

// To do

}

return result;

}


Boiler plating database resource cleanup with execute around method accu london february 2009

Putting It All Together.

Connection Provider

<<Connection User>>

<<Connection Value>>

Statement Provider

<<Statement User>>

<<Statement Value>>

ResultSet Provider

<<ResultSet Function>>


Boiler plating database resource cleanup with execute around method accu london february 2009

  • Error Policy

  • A common error policy allows the client to decide how to handle errors:

    • public interface ErrorPolicy

    • {

    • void handleError(Exception ex)

    • void handleCleanupError(Exception ex)

    • }

  • Clean-up exceptions could be handled differently

  • May be logged, rather than re-thrown

  • Decision can be made by the client


Boiler plating database resource cleanup with execute around method accu london february 2009

public <T> T provideTo( StatementValue<T> valueUser )

{

T result = null;

try

{

final Statement stmt = con.createStatement();

try

{

result = valueUser.use(stmt);

}

finally

{

try

{

stmt.close();

}

catch(SQLException ex)

{

// handle clean-up exception

}

}

}

catch(SQLException ex)

{

// Handle exception

}

return result;

}


Boiler plating database resource cleanup with execute around method accu london february 2009

To Check or Not To Check

Checked Exceptions

Interface methods can throw Exception.

Interface methods can throw a custom exception that all checked exceptions must be translated into.

public interface ErrorPolicy

{

void handleError(Exception ex) throws Exception;

void handleCleanupError(Exception ex) throws Exception;

}

public interface ErrorPolicy

{

void handleError(Exception ex) throws CustomException;

void handleCleanupError(Exception ex) throws CustomException;

}


Boiler plating database resource cleanup with execute around method accu london february 2009

To Check or Not To Check

Runtime Exceptions

The implementer of the interface is forced to translate checked exceptions to runtime exceptions.

public interface ErrorPolicy

{

void handleError(Exception ex)

void handleCleanupError(Exception ex)

}


Boiler plating database resource cleanup with execute around method accu london february 2009

Default Error Policy

public class DefaultErrorPolicy implements ErrorPolicy

{

private Exception firstException = null;

@Override

public void handleCleanupError(Exception ex)

{

handleError(ex);

}

@Override

public void handleError(Exception ex)

{

if (firstException == null)

{

firstException = ex;

throw new RuntimeException(ex);

}

}

}


Boiler plating database resource cleanup with execute around method accu london february 2009

  • Error Policy User

    • public interface ErrorPolicyUser

    • {

    • void setErrorPolicy(ErrorPolicy errorPolicy);

    • }

  • All classes that use an ErrorPolicy must implement the ErrorPolicyUser interface.

  • The ErrorPolicyUser is used by providers to pass an ErrorPolicy to its Users and Values (dependency injection).

  • All Users and Values must therefore be an ErrorPolicyUser.


Boiler plating database resource cleanup with execute around method accu london february 2009

public interface ConnectionFactory extends ErrorPolicyUser

{

Connection connect();

void disconnect(Connection con);

}

public interface ConnectionUser extends ErrorPolicyUser

{

void use(Connection con);

}

public interface ConnectionValue<T> extends ErrorPolicyUser

{

T fetch(Connection con);

}

public interface StatementUserextends ErrorPolicyUser

{

void use(Statement stmt);

}

public interface StatementValue<T>extends ErrorPolicyUser

{

T use(Statement stmt);

}

public interface ResultSetFunction<T> extends ErrorPolicyUser

{

T read(ResultSet rs);

}


Boiler plating database resource cleanup with execute around method accu london february 2009

public final class StatementProvider

{

public void provideTo( StatementUser user )

{

user.setErrorPolicy(errorPolicy);

try

{

final Statement stmt = con.createStatement();

try

{

user.use(stmt);

}

finally

{

try

{

stmt.close();

}

catch(SQLException ex)

{

errorPolicy.handleCleanupError(ex);

}

}

}

catch(SQLException ex)

{

errorPolicy.handleError(ex);

}

}

}


Boiler plating database resource cleanup with execute around method accu london february 2009

  • Common Error Policy User

  • public abstract class AbstractErrorPolicyUser implements ErrorPolicyUser

  • {

  • private ErrorPolicy errorPolicy = new DefaultErrorPolicy();

  • protected ErrorPolicy getErrorPolicy()

  • {

  • return errorPolicy;

  • }

  • @Override

  • public void setErrorPolicy(ErrorPolicy errorPolicy)

  • {

  • this.errorPolicy = errorPolicy;

  • }

  • }

  • The CommonErrorPolicyUser provides a common:

    • ErrorPolicy set method

    • ErrorPolicy reference

    • ErrorPolicy accessor


Boiler plating database resource cleanup with execute around method accu london february 2009

Composition

  • Unnecessary ErrorPolicyUser reference.

  • Unnecessary set/get ErrorPolicy methods implemented in ConcreteUser.


Boiler plating database resource cleanup with execute around method accu london february 2009

Inheritance

  • ConcreteConnection inherits set/get methods for free.

  • ConecreteConnection IS-A ErrorPolicyUser


Boiler plating database resource cleanup with execute around method accu london february 2009

public class Execute extends AbstractErrorPolicyUser implements StatementUser

{

...

@Override

public void use(Statement stmt)

{

try

{

for(String s : sql)

{

stmt.execute(s);

}

}

catch(SQLException ex)

{

getErrorPolicy().handleError(ex);

}

}

}


Boiler plating database resource cleanup with execute around method accu london february 2009

Sorted!


Boiler plating database resource cleanup with execute around method accu london february 2009

Connection Provider

<<Connection User>>

<<Connection Value>>

Statement Provider

<<Statement User>>

<<Statement Value>>

ResultSet Provider

<<ResultSet Function>>


Boiler plating database resource cleanup with execute around method accu london february 2009

Reminder

try

{

final ConnectionProvider cp =

new ConnectionProvider(new StringConnection(DRIVER,CONNECTION_STRING)

.setUser(USERNAME, PASSWORD)

.setDatabase(DATABASE));

final List<String> urls

= Query.execute( cp,

"SELECT URL FROM SERVICES", new RSProcessor());

for(String url : urls)

{

System.out.println(url);

}

}

catch(Exception e)

{

e.printStackTrace();

}


Boiler plating database resource cleanup with execute around method accu london february 2009

Reminder

class RSProcessor extends AbstractResultSetFunction<List<String>>

{

@Override

public List<String> read(ResultSet rs)

{

List<String> result = new ArrayList<String>();

try

{

while (rs.next())

{

result.add(rs.getString("url"));

}

}

catch(SQLException ex)

{

getErrorPolicy().handleError(ex);

}

return result;

}

}


Anymore questions see you in the bar

Anymore questions?

See you in the bar…

Paul GrenyerSenior Software Engineer

[email protected]

http://paulgrenyer.blogspot.com

Validus

8 Thorpe Road

Norwich

NR1 1RY

www.validus-ivc.co.uk


  • Login