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