Java tutorial
/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco * * Alfresco is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Alfresco is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see <http://www.gnu.org/licenses/>. */ package org.alfresco.util.registry; import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import org.alfresco.api.AlfrescoPublicApi; import org.alfresco.error.AlfrescoRuntimeException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.extensions.surf.util.ParameterCheck; /** * An generic registry of objects held by name. This is effectively a strongly-typed, * synchronized map. * * @author Derek Hulley * @since 3.2 */ @AlfrescoPublicApi public class NamedObjectRegistry<T> { private static final Log logger = LogFactory.getLog(NamedObjectRegistry.class); private final ReentrantReadWriteLock.ReadLock readLock; private final ReentrantReadWriteLock.WriteLock writeLock; private Class<T> storageType; private Pattern namePattern; private final Map<String, T> objects; /** * Default constructor. The {@link #setStorageType(Class)} method must be called. */ public NamedObjectRegistry() { ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); readLock = lock.readLock(); writeLock = lock.writeLock(); this.namePattern = null; // Deliberately null this.storageType = null; // Deliberately null this.objects = new HashMap<String, T>(13); } /** * Constructor that takes care of {@link #setStorageType(Class)}. * * @see #setStorageType(Class) */ public NamedObjectRegistry(Class<T> type) { this(); setStorageType(type); } /** * Set the type of class that the registry holds. Any attempt to register a * an instance of another type will be rejected. * * @param clazz the type to store */ public void setStorageType(Class<T> clazz) { writeLock.lock(); try { this.storageType = clazz; } finally { writeLock.unlock(); } } /** * Optionally set a pattern to which all object names must conform * @param namePattern a regular expression */ public void setNamePattern(String namePattern) { writeLock.lock(); try { this.namePattern = Pattern.compile(namePattern); } catch (PatternSyntaxException e) { throw new AlfrescoRuntimeException( "Regular expression compilation failed for property 'namePrefix': " + e.getMessage(), e); } finally { writeLock.unlock(); } } /** * Register a named object instance. * * @param name the name of the object * @param object the instance to register, which correspond to the type */ public void register(String name, T object) { ParameterCheck.mandatoryString("name", name); ParameterCheck.mandatory("object", object); if (!storageType.isAssignableFrom(object.getClass())) { throw new IllegalArgumentException( "This NameObjectRegistry only accepts objects of type " + storageType); } writeLock.lock(); try { if (storageType == null) { throw new IllegalStateException( "The registry has not been configured (setStorageType not yet called yet)"); } if (namePattern != null) { if (!namePattern.matcher(name).matches()) { throw new IllegalArgumentException( "Object name '" + name + "' does not match required pattern: " + namePattern); } } T prevObject = objects.put(name, object); if (prevObject != null && prevObject != object) { logger.warn("Overwriting name object in registry: \n" + " Previous: " + prevObject + "\n" + " New: " + object); } } finally { writeLock.unlock(); } } /** * Get a named object if it has been registered * * @param name the name of the object to retrieve * @return Returns the instance of the object, which will necessarily * be of the correct type, or <tt>null</tt> */ public T getNamedObject(String name) { readLock.lock(); try { // Get it return objects.get(name); } finally { readLock.unlock(); } } /** * @return Returns a copy of the map of instances */ public Map<String, T> getAllNamedObjects() { readLock.lock(); try { // Get it return new HashMap<String, T>(objects); } finally { readLock.unlock(); } } public void reset() { writeLock.lock(); try { if (storageType == null) objects.clear(); } finally { writeLock.unlock(); } } }