001package com.box.sdk.internal.pool; 002 003import java.security.NoSuchAlgorithmException; 004import java.util.Map; 005import java.util.Queue; 006import java.util.concurrent.ConcurrentHashMap; 007import java.util.concurrent.LinkedBlockingQueue; 008import javax.crypto.Mac; 009 010/** 011 * Reusable thread-safe pool for {@link Mac} instances. 012 * <p> 013 * Example: 014 * 015 * <pre> 016 * {@code 017 * Mac mac = macPool.acquire(); 018 * try { 019 * ... 020 * } finally { 021 * macPool.release(mac); 022 * } 023 * } 024 * </pre> 025 */ 026public class MacPool { 027 028 /** 029 * Pool of {@link Mac}-s by algorithm. 030 */ 031 private final Map<String, Queue<Mac>> macPoolByAlgorithm = new ConcurrentHashMap<String, Queue<Mac>>(); 032 033 /** 034 * Constructor. 035 */ 036 public MacPool() { 037 } 038 039 /** 040 * Acquires reusable {@link Mac}, has to be also released! 041 * 042 * @param algorithm {@link Mac#getAlgorithm()} 043 * @return shared {@link Mac} 044 * @see #release(Mac) 045 */ 046 public Mac acquire(String algorithm) { 047 Mac result = null; 048 049 Queue<Mac> pool = this.macPoolByAlgorithm.get(algorithm); 050 if (pool != null) { 051 result = pool.poll(); 052 } 053 054 if (result != null) { 055 // it has to be synchronized, for the case that some memory parts of Mac provider are changed, 056 // but not yet visible for this thread 057 synchronized (result) { 058 result.reset(); 059 } 060 return result; 061 } 062 063 try { 064 return Mac.getInstance(algorithm); 065 } catch (NoSuchAlgorithmException e) { 066 throw new IllegalArgumentException(String.format("NoSuchAlgorithm '%s':", algorithm), e); 067 } 068 } 069 070 /** 071 * Releases a previously acquired {@link Mac}. 072 * 073 * @param mac for release 074 * @see #acquire(String) 075 */ 076 public void release(Mac mac) { 077 Queue<Mac> pool = this.macPoolByAlgorithm.get(mac.getAlgorithm()); 078 if (pool == null) { 079 pool = new LinkedBlockingQueue<Mac>(); 080 this.macPoolByAlgorithm.put(mac.getAlgorithm(), pool); 081 } 082 pool.offer(mac); 083 } 084 085}