/*
* Copyright Aduna (http://www.aduna-software.com/) (c) 2007.
*
* Licensed under the Aduna BSD-style license.
*/
package info.aduna.lang.service;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A registry that stores services by some key. Upon initialization, the
* registry searches for service description files at
* META-INF/services/<service class name> and initializes
* itself accordingly.
*
* @see javax.imageio.spi.ServiceRegistry
* @author Arjohn Kampman
*/
public abstract class ServiceRegistry {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
protected Map services = new HashMap();
protected ServiceRegistry(Class serviceClass) {
// Note: Using javax.imageio.spi.ServiceRegistry as it publicly exposes
// the sun.misc.Service functionality. Starting from Java 6, this
// functionality is also available java.util.ServiceLoader
Iterator services = javax.imageio.spi.ServiceRegistry.lookupProviders(serviceClass, serviceClass.getClassLoader());
while (true) {
try {
if (services.hasNext()) {
S service = services.next();
S oldService = add(service);
if (oldService != null) {
logger.warn("New service {} replaces existing service {}", service.getClass(),
oldService.getClass());
}
logger.debug("Registered service class {}", service.getClass().getName());
}
else {
break;
}
}
catch (Error e) {
logger.error("Failed to instantiate service", e);
}
}
}
/**
* Adds a service to the registry. Any service that is currently registered
* for the same key (as specified by {@link #getKey(Object)}) will be
* replaced with the new service.
*
* @param service
* The service that should be added to the registry.
* @return The previous service that was registered for the same key, or
* null if there was no such service.
*/
public S add(S service) {
return services.put(getKey(service), service);
}
/**
* Removes a service from the registry.
*
* @param service
* The service be removed from the registry.
*/
public void remove(S service) {
services.remove(getKey(service));
}
/**
* Gets the service for the specified key, if any.
*
* @param key
* The key identifying which service to get.
* @return The service for the specified key, or null if no such
* service is avaiable.
*/
public S get(K key) {
return services.get(key);
}
/**
* Checks whether a service for the specified key is available.
*
* @param key
* The key identifying which service to search for.
* @return true if a service for the specific key is available,
* false otherwise.
*/
public boolean has(K key) {
return services.containsKey(key);
}
/**
* Gets all registered services.
*
* @return An unmodifiable collection containing all registered servivces.
*/
public Collection getAll() {
return Collections.unmodifiableCollection(services.values());
}
/**
* Gets the set of registered keys.
*
* @return An unmodifiable set containing all registered keys.
*/
public Set getKeys() {
return Collections.unmodifiableSet(services.keySet());
}
/**
* Gets the key for the specified service.
*
* @param service
* The service to get the key for.
* @return The key for the specified service.
*/
protected abstract K getKey(S service);
}