All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.javagimmicks.concurrent.BlockingSingletonRegistry Maven / Gradle / Ivy

The newest version!
package net.sf.javagimmicks.concurrent;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import net.sf.javagimmicks.util.WritableObjectContainer;

/**
 * This class serves as a registry that allows (de-)registration of objects
 * following the singleton pattern and provides blocking getter methods for
 * them. This means that getter calls will not return until the desired
 * singleton instance has been registered in this container (or a timeout or
 * interruption has occurred).
 * 

* This might be useful in server environments where the container (e.g. a CDI * container) takes care about instantiation (at some time) but clients want or * need to access the the instances from without the containers context (e.g. * via plain old static getter calls). *

* The class can be directly instantiated using the default constructor or a * static default instance can be used. *

* This class intensively uses {@link BlockingObjectContainer} internally * * @see BlockingObjectContainer */ public class BlockingSingletonRegistry { private static BlockingSingletonRegistry _defaultInstance; /** * Returns a static default (singleton) instance of the * {@link BlockingSingletonRegistry} * * @return the default instance */ public static BlockingSingletonRegistry getDefault() { if (_defaultInstance != null) { return _defaultInstance; } synchronized (BlockingSingletonRegistry.class) { if (_defaultInstance == null) { _defaultInstance = new BlockingSingletonRegistry(); } return _defaultInstance; } } private final Map, BlockingObjectContainer> _theContainers = Collections .synchronizedMap(new HashMap, BlockingObjectContainer>()); /** * Registers a new singleton instance in the registry * * @param instance * the singleton instance to register * @param * the type of the singleton object to register * @throws IllegalStateException * if there is already another instance of the given class * registered (it's not a singleton) */ public void set(final T instance) throws IllegalStateException { if (instance == null) { return; } // Get the class of the singleton instance @SuppressWarnings("unchecked") final Class clazz = (Class) instance.getClass(); // Get ore create a Container for the class and set the instance getOrCreateContainer(clazz).accept(instance); } /** * Removes the singleton of the given class from the registry * * @param * the type of the singleton object to remove * @param clazz * the singleton class whose instance should be removed */ public void remove(final Class clazz) { if (clazz == null) { return; } // Get the matching container ... @SuppressWarnings("unchecked") final WritableObjectContainer container = (WritableObjectContainer) _theContainers.remove(clazz); // ... and remove the singleton from there if there was one if (container != null) { container.remove(); } } /** * Remove the given singleton instance from the registry * * @param instance * the singleton instance that should be removed * @param * the type of the singleton object to remove * @throws IllegalArgumentException * if another one than the registered singleton instance should be * removed */ public void remove(final T instance) { if (instance == null) { return; } // Get the class of the singleton instance @SuppressWarnings("unchecked") final Class clazz = (Class) instance.getClass(); synchronized (_theContainers) { // Get the matching container ... @SuppressWarnings("unchecked") final BlockingObjectContainer container = (BlockingObjectContainer) _theContainers.get(clazz); // ... and abort if there is none if (container == null) { return; } // Check, if the object to remove is the same as the registered one final Object existingInstance = container.getNoWait(); if (existingInstance != null && existingInstance != instance) { throw new IllegalArgumentException("There is another instance of " + clazz.getName() + " registered! Are you sure it is a singleton?"); } // Checks were okay, so unregister the instance and remove the // container container.remove(); _theContainers.remove(clazz); } } /** * Retrieves the singleton instance of the given class waiting * uninterruptibly until it is registered (i.e. the waiting Thread will NOT * react to {@link Thread#interrupt()} calls) *

* Attention: this call blocks FOREVER - so you REALLY should take care that * the requested instance is finally registered * * @param clazz * the class whose singleton instance should be retrieved * @param * the type of the singleton object to retrieve * @return the resulting singleton instance of the given class */ public T get(final Class clazz) { return getOrCreateContainer(clazz).get(); } /** * Retrieves the singleton instance of the given class waiting interruptibly * until it is registered (i.e. the waiting Thread will react to * {@link Thread#interrupt()} calls) *

* Attention: this call block FOREVER (if not interrupted) - so you REALLY * should take care that the requested instance is finally registered * * @param clazz * the class whose singleton instance should be retrieved * @param * the type of the singleton object to retrieve * @return the resulting singleton instance of the given class * @throws InterruptedException * if the waiting Thread is interrupted while waiting */ public T getInterruptibly(final Class clazz) throws InterruptedException { return getOrCreateContainer(clazz).getInterruptibly(); } /** * Retrieves the singleton instance of the given class waiting interruptibly * (i.e. the waiting Thread will react to {@link Thread#interrupt()} calls) * until it is registered or the given timeout has elapsed * * @param clazz * the class whose singleton instance should be retrieved * @param time * the number of {@link TimeUnit}s to wait at until the call * returns * @param timeUnit * the {@link TimeUnit} of the given time amount to wait * @param * the type of the singleton object to retrieve * @return the resulting singleton instance of the given class * @throws InterruptedException * if the waiting Thread is interrupted while waiting */ public T get(final Class clazz, final long time, final TimeUnit timeUnit) throws InterruptedException { return getOrCreateContainer(clazz).get(time, timeUnit); } /** * Retrieves the singleton instance of the given class if currently * registered without potentially waiting for it (i.e. the call will always * return immediately) * * @param clazz * the class whose singleton instance should be retrieved * @param * the type of the singleton object to retrieve * @return the registered singleton instance or null if non is * registered */ public T getNoWait(final Class clazz) { return getOrCreateContainer(clazz).getNoWait(); } @SuppressWarnings("unchecked") protected BlockingObjectContainer getOrCreateContainer(final Class clazz) { // Get the potentially registered container BlockingObjectContainer result = (BlockingObjectContainer) _theContainers.get(clazz); // Return it immediately if one was registered if (result != null) { return result; } // Negative case: create a new one in the synchronized context synchronized (_theContainers) { // Re-check in the synchronized context result = (BlockingObjectContainer) _theContainers.get(clazz); if (result == null) { result = new BlockingObjectContainer(); _theContainers.put(clazz, result); } return result; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy