/* * Copyright (c) 2008-2010 by Christian Lorenz, * Zuse Institute Berlin * * Licensed under the BSD License, see LICENSE file for details. * */ package de.mxro.thrd.xstreemfs.foundation.checksums; import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.concurrent.ConcurrentLinkedQueue; /** * A Factory for getting checksum algorithms from checksum provider. Implemented * as a Singleton. * * 19.08.2008 * * @author clorenz */ public class ChecksumFactory { /** * amount of cached instances/algorithm */ private static int MAX_CACHE_SIZE = 20; private static ChecksumFactory self; /** * Contains all available checksum algorithms (only one instance). */ private HashMap<String, ChecksumAlgorithm> algorithms; /** * Contains all known checksum provider */ private HashMap<String, ChecksumProvider> knownProvider; /** * Contains cached instances for all available checksum algorithms. */ private HashMap<String, ConcurrentLinkedQueue<ChecksumAlgorithm>> pool; /** * creates a new ChecksumFactory */ private ChecksumFactory() { super(); this.algorithms = new HashMap<String, ChecksumAlgorithm>(); this.pool = new HashMap<String, ConcurrentLinkedQueue<ChecksumAlgorithm>>(); this.knownProvider = new HashMap<String, ChecksumProvider>(); } /** * Get the instance of ChecksumFactory. * * @return the instance */ public static ChecksumFactory getInstance() { if (self == null) { self = new ChecksumFactory(); } return self; } /** * Get an instance of a specific checksum algorithm, if supported. * * @param name * of the algorithm * @return algorithm object or null, if algorithm is not supported */ public ChecksumAlgorithm getAlgorithm(String name) throws NoSuchAlgorithmException { ConcurrentLinkedQueue<ChecksumAlgorithm> cache = pool.get(name); if (cache == null) throw new NoSuchAlgorithmException("algorithm " + name + " not supported"); ChecksumAlgorithm algorithm = cache.poll(); if (algorithm == null) { // cache is empty return algorithms.get(name).clone(); // create new instance } else { return algorithm; // return caches instance } } /** * Returns an instance of a specific checksum algorithm for caching. * * @param instance * of the algorithm */ public void returnAlgorithm(ChecksumAlgorithm algorithm) { ConcurrentLinkedQueue<ChecksumAlgorithm> cache = pool.get(algorithm .getName()); if (cache.size() < MAX_CACHE_SIZE) { algorithm.reset(); cache.add(algorithm); } } /** * Adds a new provider to factory and adds all supported algorithms from the * provider to the algorithms-list. NOTE: Existing algorithms will be * overridden when the new provider contains the same algorithm (maybe * another implementation). * * @param provider */ public void addProvider(ChecksumProvider provider) { knownProvider.put(provider.getName(), provider); for (ChecksumAlgorithm algorithm : provider.getSupportedAlgorithms()) { addAlgorithm(algorithm); } } /** * Adds a new Algorithm to factory. NOTE: The same existing algorithm will * be overridden. * * @param algorithm */ public void addAlgorithm(ChecksumAlgorithm algorithm) { algorithms.put(algorithm.getName(), algorithm); pool.put(algorithm.getName(), new ConcurrentLinkedQueue<ChecksumAlgorithm>()); } /** * Removes a provider, but not the added algorithms. * * @param provider */ public void removeProvider(ChecksumProvider provider) { knownProvider.remove(provider.getName()); } /** * Removes an algorithm. * * @param algorithm */ public void removeAlgorithm(String algorithm) { algorithms.remove(algorithm); pool.remove(algorithm); } }