Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Below is the code snippet that I developed for ConnectionPool. Kindly let me know if there are any problems or shortcomings with the below code. I've deployed it to our test environment and was able to see that its not creating more the allowed MAX_CONN_CAPACITY and the objects are being re-used (I checked this by logging the ODServerHolder's hashcode into the log file). I would just like to know what other developers think.

getOndemandConnection() and releaseOndemandConnection() are the methods that will be called by other classes using this pool.

public final class ServerConnPool {


private ServerConnPool(){
    //making sure no one else initializes this class. though all field are defined static, just to make sure 
    //its not instantiated ... 
}
private static WSLogger logger =
        new WSLogger(ServerConnPool.class);

private static String strContextRoot = "EAFService";
private static int MAX_CONN_CAPACITY = 5; 
private static LinkedBlockingDeque<ODServerHolder> odServerConnectionPool ;
static ScheduledThreadPoolExecutor threadPool = new ScheduledThreadPoolExecutor(1); 
// FOR PERFORMANCE CAN CHANGE LATER TO NUMBER OF AVAILABLE CPUS..

private static AtomicInteger ATOMIC_POOL_COUNTER = new AtomicInteger(0); 

static {
    try {
        MAX_CONN_CAPACITY = 5;
        odServerConnectionPool = new LinkedBlockingDeque<ODServerHolder>(MAX_CONN_CAPACITY);
    } catch (Exception e) {
        logger.error(e.getMessage());
        throw new RuntimeException(e.getLocalizedMessage());
    }
    for (int i = 0; i < MAX_CONN_CAPACITY; i++) {
        ODServerHolder OdServerHolder =null;
        try {
            OdServerHolder = initServerHolder();
        } catch (ODException e) {
            logger.error(e.getMessage());           }
        odServerConnectionPool.add(OdServerHolder);

    }
}

public static ODServerHolder  getOnDemandConnection(String credential,String credentialType) throws Exception
{
    return getConnection(credential, credentialType);
}

/**
 * 
 * @param credential
 * @param credentialType
 * @return
 * @throws Exception
 */
private static ODServerHolder getConnection(String credential,String credentialType) throws Exception{
    try {
//          String strFullPath = ODUtils.iniFile.getFullFileName().substring(0,ODUtils.iniFile.getFullFileName().lastIndexOf(File.separator)+ 1);
        ODServerHolder odHolder = odServerConnectionPool.take();
        ODServer odServerConn= odHolder.getODServer();
        if(odServerConn == null){
            odServerConn = initializeODServer();
            odHolder.setODServer(odServerConn);
        }
        if(!odServerConn.isInitialized()) {  //  || odServerConn.isServerTimedOut()){   
            odServerConn.initialize(strContextRoot);
            odHolder.setODServer(odServerConn);
        }
        return odHolder;
    } catch (Exception ex) {
        logger.error("Error during OD connection: " + ex.getMessage());
        throw ex;
    }
}

/**
 * release back ODServerConnection to the Pool.
 * @param odHolder
 */
public static void releaseODServerConnection(ODServerHolder odHolder){
    try {
        odHolder.getODServer().keepServerAlive();
        odServerConnectionPool.put(odHolder);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

/**
 * method to initialize ODServer connection.
 * @param odServerConn
 * @throws ODException
 */
private static ODServer initializeODServer() throws ODException{

    ODServer odServerConn = new ODServer();
    odServerConn.initialize(strContextRoot);
    odServerConn.keepServerAlive();
    return odServerConn;
}

private static ODServerHolder initServerHolder() throws ODException {
    ODServer server = null;
    int id = ATOMIC_POOL_COUNTER.incrementAndGet();
    ODServerHolder sHolder = new ODServerHolder(server,id);
    return sHolder;
}

private static class ODServerConnectionCleanerThread implements Runnable {

    private ODServerConnectionCleanerThread(){
    }
    @Override
    public void run() {
        try {
            logger.info("current ODServer Connection pool capacity is : "+ odServerConnectionPool.size());

            for (ODServerHolder odHolder : odServerConnectionPool) {
                ODServer odConn = odHolder.odServerConn;
                int id = odHolder.getId();
                if(odConn!= null)
                    logger.info("Server Number : "+id+" odServer hashCode:  " +
                            ""+odConn.hashCode() + " is Server Timed out : "+ 
                            odConn.isServerTimedOut()+" is it Initialized? : "+ odConn.isInitialized());
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("ODServerConnectionCleanerThread : Problem in running " +
                    "the schduler this time.. will continue again.. ");
        }
    }
}

}
share|improve this question

migrated from stackoverflow.com Oct 6 '14 at 14:10

This question came from our site for professional and enthusiast programmers.

1 Answer 1

If I were to code review this, I would make the following comments.

I would recommend using a singleton instead of a static block to initialize. The static block will trigger when the classloader first loads your class, which is much harder to control/debug/fix. creating a static synchronized getInstance() method, or avoid the synchronized by using the enum notation for singletons. (http://en.wikipedia.org/wiki/Singleton_pattern, look for 'the enum way')

private static String strContextRoot = "EAFService";

This is never assigned to. if it is a constant, make it final and the name should be in uppercase.

private static int MAX_CONN_CAPACITY = 5; 

This is assigned to again in a static block (but assigned the same value). the second assignment can be removed and this property can be made final. if you intend to have this property actually be configurable then it will probably need a setter or similar.

try {
    MAX_CONN_CAPACITY = 5;
    odServerConnectionPool = new LinkedBlockingDeque<ODServerHolder>(MAX_CONN_CAPACITY);
} catch (Exception e) {
    logger.error(e.getMessage());
    throw new RuntimeException(e.getLocalizedMessage());
}

catching generic Exception is a bad. Try to avoid it. in this case the only situation you could get an exception is if your MAX_CONN_CAPACITY is < 1 As you know the capacity, the illegalargumentexception will not be thrown so the try/catch can be removed.

additionally, throwing a runtimeexception with just the message, means you lose your stacktrace. better to wrap the whole exception which will preserve the stacktrace.

If it is your intention to let capacity be configured from outside (by a setMaxConnCapacity method), then make sure it never is < 1 (throw an illegal argument exception when someone tries to set the wrong value) that way, again, the exception never happens and you avoid uncertainty in your code.

for (int i = 0; i < MAX_CONN_CAPACITY; i++) {
    ODServerHolder OdServerHolder =null;
    try {
        OdServerHolder = initServerHolder();
    } catch (ODException e) {
        logger.error(e.getMessage());           
    }
    odServerConnectionPool.add(OdServerHolder);

}

1: if initServerHolder throws an ODException then you end up doing odServerConnectionPool.add(null). I don't think this is intentional. if you intend only to add odserverholder if it was initialised, then pull the declaration inside the try. (for small methods it's no big deal but it creates uncertainty where there needs be none.

like so:

for (int i = 0; i < MAX_CONN_CAPACITY; i++) {
    try {
        ODServerHolder OdServerHolder = initServerHolder();
        odServerConnectionPool.add(OdServerHolder);
    } catch (ODException e) {
        logger.error(e.getMessage());           
    }
}

2: variableNamesAlwaysLowerCaseFirst :) OdServerHolder should be odServerHolder or oDServerHolder

3: I cannot find the constructor/class definition for ODServerHolder, but constructors throwing business exceptions is a bad situation in my opinion. I'm expecting the ODException is never actually thrown in the constructor but am missing code.

4: By the way in initServerHolder ODServer is always null, so this variable could be removed. I'm not sure if this is the behaviour you want. I can only hazard a guess.

Moving on:

private static ODServerHolder getConnection(String credential,String credentialType) throws Exception{

and

public static ODServerHolder  getOnDemandConnection(String credential,String credentialType) throws Exception

1: unfinished javadoc comment.

2: do not catch exception. Catch the specific exceptions that are thrown. You are adding uncertainty to your code, which then bubbles upwards. Note that your getOnDemandConnection also throws Exception. this sort of stuff is infectious :)

3: do not print ex.getMessage(). print ex.getStackTrace() (logger("message", ex) works pretty well for this)

4: commented out code should be removed.

5: initializeODServer already calls initialize(strContextRoot). is this needed a second time during getCOnnection?

6: as initializeODServer already calls initialize(...) , will the test

if(!odServerConn.isInitialized())

ever trigger? I suspect this code can be removed, though ofcourse check it.

7: Either releaseconnection should set server = null, or during initializeODServer you can already set the ODServer. At least to me it makes no sense to set the server during getConnection if you then keep it set forever after. May as well set it from the start. Though note, I can't see what the initialize does so it may depend on this logic.

Moving on..

1: releaseODServerConnection: use logger to log the exception. printStackTrace will probably use system.err see: http://stackoverflow.com/questions/7469316/why-is-exception-printstacktrace-considered-bad-practice

2: the inner class ODServerConnectionCleanerThread doesn't clean ODServerConnection. it is a monitor / logger thread and should be renamed, if you actually use it during operation

3: ODServer odConn = odHolder.odServerConn; should probably use an accessor. (getOdServerConn())

4: change error message tologger.error("the message", e) to log the exception. remove printStackTrace. (and dont' catch exception, etc, etc)

I'm running out of steam but overall, the implementation isn't bad at all. However you need to work on making your exception handling clearer and to avoid propagating uncertainty upwards. (and avoid throwing exceptions that are never thrown). I would take a good look at the ODExceptions and see if you can eliminate some of those. You'll always have interruptedExceptions but I don't see you handling them. I think getConnection can specify it throws an INterruptedException so the outer layer can deal with not receiving a connection. It does bleed a little of your internal representation (blocking call on queue) but that's acceptable as long as this is a low level call and you specifically note this in your interface. (so throws InterruptedException, not Exception)

hope you didn't think I was too harsh, as I said in the beginning i'm listing what I would list when I review this at work. Hope it's helpeful.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.