Dan Walmsley
Dan Walmsley

Reputation: 2821

How to run methods inside a standard try catch

It's been a while since I have done any Java programming. And I find my self a bit stuck.

My problem is that I have a pooled db connection in tomcat. That is working nicely. But there is a lot of boiler plate required.

    public void init() {
    Connection conn = null;
    ResultSet rst = null;
    Statement stmt = null;
    try {

        //SETUP 
        Context initContext = new InitialContext();
        Context envContext = (Context) initContext.lookup("java:/comp/env/jdbc");
        OracleDataSource ds = (OracleDataSource) envContext.lookup("tclsms");

        if (envContext == null) throw new Exception("Error: No Context");
        if (ds == null) throw new Exception("Error: No DataSource");
        if (ds != null) conn = ds.getConnection();
        if (conn == null) throw new Exception("Error: No Connection")

        message = "Got Connection " + conn.toString() + ", ";

        //BODY 
        stmt = conn.createStatement();
        rst = stmt.executeQuery("SELECT 'Success obtaining connection' FROM DUAL");

        if (rst.next()) message = rst.getString(1);



        //TEAR DOWN 
        rst.close();
        rst = null;
        stmt.close();
        stmt = null;
        conn.close(); // Return to connection pool
        conn = null; // Make sure we don't close it twice
    } catch (Exception e) {
        e.printStackTrace();
        //TODO proper error handling 
    } finally {
        // Always make sure result sets and statements are closed,
        // and the connection is returned to the pool
        if (rst != null) {
            try {
                rst.close();
            } catch (SQLException e) {;}
            rst = null;
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {;}
            stmt = null;
        }

        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {;}
            conn = null;
        }
    } //END FINALLY
} //END INIT

So I want to do the equivalent of passing a method into init that will run in the body of the function. I know I can't do this in Java. But I'm sure there must be a nice way to do this. Or at least a best practice for this sort of thing.

Any help much appreciated.

Upvotes: 2

Views: 1563

Answers (4)

Christian Bongiorno
Christian Bongiorno

Reputation: 5648

You should prefer delegation to inheritance. The above can/will work but isn't well thought out.

Implementing Runnable on the primary class exposes it for abuse because the 'run()' method is public.

A second improvement is to use to delegate your activity to an interface (and this CAN be passed around like a function pointer whereas extending the class cannot). In addition, it makes it Spring friendly

This allows the action implementer to decide if they want multi-threaded behavior or not. You can inject composites, caching delegates, etc and the primary class is none-the-wiser. This conforms with good design practice of separation of concerns

public class MyClass {

    private Action action;

    public MyClass (Action action) {
        this.action = action;
    }

    public void connection() {

        try{
            action.perform()
        } catch (Exception e){
            // handle
        } finally {
            tearDown();
        }
    }

    Connection getConnection(){
        return conn;
    }

    private void setUp(){
        // SETUP here
        // set the conn field
    }

    private void tearDown(){
        // TEAR DOWN here
    }

}

Upvotes: 1

aj.esler
aj.esler

Reputation: 931

abstract class UseDBConnectionTask extends Runnable {

    private Connection conn;

    public UseDBConnectionTask(){
        setUp();
    }

    // should probably refine this to specific exceptions
    public abstract void process() throws Exception; 

    public void run(){

        try{
            process()
            // this should catch specific exceptions
        } catch (Exception e){
            // handle
        } finally {
            tearDown();
        }
    }

    Connection getConnection(){
        return conn;
    }

    public void setUp(){
        // SETUP here
        // set the conn field
    }

    public void tearDown(){
        // TEAR DOWN here
    }
}

use like:

UseDBConnectionTask dbTransaction = new UseDBConnectionTask(){

    public void process(){
        // do processing 
        // use conn via getConnection()
        // eg
        Statement stmt = conn.createStatement();
        ResultSet rst = stmt.executeQuery("SELECT 'Success obtaining connection' FROM DUAL");

        String message = null;
        if (rst.next()) message = rst.getString(1);
    }

}

new Thread(dbTransaction).start();

The advantage of extending Runnable is that you can then pass this instance into a thread pool or similar. Just have to be careful of threading issues. It also assumes that the tear down is always the same.

Upvotes: 1

aj.esler
aj.esler

Reputation: 931

interface IDbAction {
    public DbActionResult runAction(Connection conn);
}

class DbActionResult {

    Statement statement;
    ResultSet resultSet;

    public DbActionResult(Statement statement, ResultSet resultSet){
        this.statement = statement;
        this.resultSet = resultSet;
    }

    public void getStatement(){ return this.statement; }
    public void getResultSet(){ return this.resultSet; }
}

public void runAgainstDB(IDbAction action) {

    Connection conn = null;
    ResultSet rst = null;
    Statement stmt = null;

    try {

        //SETUP 
        Context initContext = new InitialContext();
        Context envContext = (Context) initContext.lookup("java:/comp/env/jdbc");
        OracleDataSource ds = (OracleDataSource) envContext.lookup("tclsms");

        if (envContext == null) throw new Exception("Error: No Context");
        if (ds == null) throw new Exception("Error: No DataSource");
        if (ds != null) conn = ds.getConnection();
        if (conn == null) throw new Exception("Error: No Connection")

        message = "Got Connection " + conn.toString() + ", ";

        //BODY 
        DbActionResult actionResult = action.runAction(conn);

        //TEAR DOWN 

        if((rst = actionResult.getResultSet()) != null){
            rst.close();
            rst = null;
        }

        if((stmt = actionResult.getStatement()) != null){
            stmt.close();
            stmt = null;
        }

        actionResult = null;

        conn.close(); // Return to connection pool
        conn = null; // Make sure we don't close it twice
    } catch (Exception e) {
        e.printStackTrace();
        //TODO proper error handling 
    } finally {
        // Always make sure result sets and statements are closed,
        // and the connection is returned to the pool
        if (rst != null) {
            try {
                rst.close();
            } catch (SQLException e) {;}
            rst = null;
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {;}
            stmt = null;
        }

        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {;}
            conn = null;
        }
    } //END FINALLY
} //END 

Use like:

IDbAction action = new IDbAction(){

    public DbActionResult prcoessAction(Connection conn){
        Statement stmt = conn.createStatement();
        ResultSet rst = stmt.executeQuery("SELECT 'Success obtaining connection' FROM DUAL");

        if (rst.next()) message = rst.getString(1);

        return new DbActionResult(stmt, rst);
    }

}

runAgainstDB(action);

Upvotes: 0

user2251760
user2251760

Reputation:

private void Todo(Context initContext, Context envContext, OracleDataSource ds){

            if (envContext == null) throw new Exception("Error: No Context");
            if (ds == null) throw new Exception("Error: No DataSource");
            if (ds != null) conn = ds.getConnection();
            if (conn == null) throw new Exception("Error: No Connection")

            message = "Got Connection " + conn.toString() + ", ";

            //BODY 
            stmt = conn.createStatement();
            rst = stmt.executeQuery("SELECT 'Success obtaining connection' FROM DUAL");

            if (rst.next()) message = rst.getString(1);



            //TEAR DOWN 
            rst.close();
            rst = null;
            stmt.close();
            stmt = null;
            conn.close(); // Return to connection pool
            conn = null; // Make sure we don't close it twice
        } catch (Exception e) {
            e.printStackTrace();
            //TODO proper error handling 
        } finally {
            // Always make sure result sets and statements are closed,
            // and the connection is returned to the pool
            if (rst != null) {
                try {
                    rst.close();
                } catch (SQLException e) {;}
                rst = null;
            }

            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {;}
                stmt = null;
            }

            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {;}
                conn = null;
            }
        } //END FINALLY
}

Then call it from your Init like this this. Todo(initContext,envContext , ds)

Upvotes: 0

Related Questions