0
\$\begingroup\$

I'm doing research on GenericObjectPool by putting Cipher in pool so it can be reused.

GenericObjectPool<Cipher> pool;

CipherFactory factory = new CipherFactory(); 
this.pool = new GenericObjectPool<Cipher>(factory);
pool.setMaxTotal(10);
pool.setBlockWhenExhausted(true);
pool.setMaxWaitMillis(30 * 1000);

CipherFactory

public class CipherFactory extends BasePooledObjectFactory<Cipher> {

    private boolean running = false;

    @Override
    public Cipher create() throws Exception {
        return Cipher.getInstance("DESede/CBC/NoPadding");
    }

    @Override
    public PooledObject<Cipher> wrap(Cipher arg0) {
        return new DefaultPooledObject<Cipher>(arg0);
    }

    @Override
    public boolean validateObject(PooledObject<Cipher> p) {
        //Ensures that the instance is safe to be returned by the pool
        return true;
    }

    @Override
    public void destroyObject(PooledObject<Cipher> p) {
        //Destroys an instance no longer needed by the pool. 
        System.out.println("destroying");
    }

    @Override
    public void activateObject(PooledObject<Cipher> p) throws Exception { //Reinitialize an instance to be returned by the pool

        setRunning(true);
    }

    @Override
    public void passivateObject(PooledObject<Cipher> p) throws Exception {   // reset the object after the object returns to the pool

        setRunning(false);
    }

    public void setRunning(boolean running) {

        this.running = running;
    }
//    
}

This is how I implement ObjectPool in my Example class

public Key aKey(byte[] tmkByte) throws Exception {

        Cipher cipher = null;
        cipher = pool.borrowObject(); //get the object from the pool
        try {
            System.out.println("****************** After borrow ****************");
            printPool();
            cipher.init(Cipher.DECRYPT_MODE, mkkey, algParamSpec);
            byte[] de = cipher.doFinal(tmkByte);
            SecretKey tmk = new SecretKeySpec(de, "DESede");
            return tmk;
        } catch (Exception e) {
            pool.invalidateObject(cipher);
            cipher = null;
        } finally {
            if (null != cipher) {
                pool.returnObject(cipher);
                System.out.println("****************** After return ****************");
                printPool();
            }
        }
        return (Key) cipher;
    }

printPool

public void printPool() {
        System.out.println("Pool for cipher with instances DESede/CBC/NoPadding");
        System.out.println("Active [" + pool.getNumActive() + "]"); //Return the number of instances currently borrowed from this pool
        System.out.println("Idle [" + pool.getNumIdle() + "]"); //The number of instances currently idle in this pool
        System.out.println("Total Created [" + pool.getCreatedCount() + "]");      
    }

Here comes the interesting part. When I run my application, I get this output:

****************** After borrow ****************
Pool for cipher with instances DESede/CBC/NoPadding
Active [1]
Idle [0]
Waiter [0]
Total Created [1]
****************** After return ****************
Pool for cipher with instances DESede/CBC/NoPadding
Active [0]
Idle [1]
Waiter [0]
Total Created [1]

If I run my application 3 times without returnObject to pool

****************** After borrow ****************
Pool for cipher with instances DESede/CBC/NoPadding
Active [1]
Idle [0]
Waiter [0]
Total Created [1]

****************** After return ****************
Pool for cipher with instances DESede/CBC/NoPadding
Active [1]
Idle [0]
Waiter [0]
Total Created [1]

****************** After borrow ****************
Pool for cipher with instances DESede/CBC/NoPadding
Active [2]
Idle [0]
Waiter [0]
Total Created [2]

****************** After return ****************
Pool for cipher with instances DESede/CBC/NoPadding
Active [2]
Idle [0]
Waiter [0]
Total Created [2]

****************** After borrow ****************
Pool for cipher with instances DESede/CBC/NoPadding
Active [3]
Idle [0]
Waiter [0]
Total Created [3]

****************** After return ****************
Pool for cipher with instances DESede/CBC/NoPadding
Active [3]
Idle [0]
Waiter [0]
Total Created [3]

If I run more than 10 times, I get this as expected:

java.util.NoSuchElementException: Timeout waiting for idle object

Based on the output and code, am I implemented correctly?

\$\endgroup\$
  • \$\begingroup\$ code not yet written ? lol \$\endgroup\$ – user138426 May 11 '17 at 2:49
0
\$\begingroup\$

Looks good, except: activateObject/passivateObject method: I don't see any usage of the running variable? Beside that, you don't need to do anything in that method anyway, that will be called, before the object will be returned, I don't think that is needed for a Cipher instance, isn't it?

But why I'm actually answering: I'm fairly certain you won't gain any benefit by using a pool for Cipher instances. The management of the pool, the synchronizing, the maintaining of the code and the additional library will use way more ressources.

A general rule is, "by definition": More code means less performance. Of course, that's not entirely true - what I want to say: If you want to improve performance, you have to measure, before and after your changes. And not only millis, but also cpu, memory, gc, io and so on. You have to be sure, you're changes actually did make an improvement and not the opposite.

Hope that helps,...

\$\endgroup\$
  • 1
    \$\begingroup\$ You need a profiler, a good one: visualvm.java.net/docindex.html \$\endgroup\$ – HSchmale May 10 '17 at 2:25
  • \$\begingroup\$ Okay, well, I never worked with those fancy modules directly. No, I don't think it will solve your problem, at least not entirely. Because, sessions are usually kept open by the user because of bad implementation or because of application crashes. The latter can't be avoided. \$\endgroup\$ – slowy May 10 '17 at 9:15