/**********************************************************************
* Copyright (c) 2005-2009 ant4eclipse project team.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Nils Hartmann, Daniel Kasmeroglu, Gerd Wuetherich
**********************************************************************/
package org.ant4eclipse.lib.core.service;
import org.ant4eclipse.lib.core.Assure;
import org.ant4eclipse.lib.core.CoreExceptionCode;
import org.ant4eclipse.lib.core.Lifecycle;
import org.ant4eclipse.lib.core.exception.Ant4EclipseException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* <p>
* The {@link ServiceRegistry} implements a singleton that can be used to register and retrieve services. A service is
* an instance of any kind of class.
* </p>
* <p>
* The service registry must be configured before it can be used. To configure the registry a
* {@link ServiceRegistryConfiguration} must be implemented: <code><pre>
* final ServiceRegistryConfiguration configuration = new ServiceRegistryConfiguration() {
* public void configure(final ConfigurationContext context) {
* // register service
* context.registerService(new MyServiceImpl(), MyService.class);
* }
* }; </pre></code>
* <p>
* An instance of type {@link ServiceRegistryConfiguration} must be set through the configure() method: <code><pre>
* ServiceRegistry.configure(configuration);</pre></code>
* </p>
* <p>
* After configuring the registry, services can be requested.
* </p>
*
* @author Gerd Wütherich (gerd@gerd-wuetherich.de)
*
* @todo [10-Dec-2009:KASI] The static reference should be removed so that classloading won't cleanup existing data
* (happens within a taskdef if ant).
*/
public class ServiceRegistry {
/** the service map **/
private Map<String, Object> _serviceMap;
/** list that contains the ordering of the services **/
private List<Object> _serviceOrdering;
/** indicates whether the registry instance is initialized **/
private boolean _isInitialized = false;
/**
* <p>
* Returns <code>true</code> if a service with the identifier <code>serviceType.getName()</code> is registered.
* </p>
*
* @param <T>
* The type of the service class.
* @param serviceType
* The service class itself.
*
* @return <code>true</code> <=> A service is registered using the supplied type.
*/
public <T> boolean hasService(Class<T> serviceType) {
return hasService(serviceType.getName());
}
/**
* <p>
* Returns <code>true</code> if a service with the supplied identifier could be found.
* </p>
*
* @param serviceIdentifier
* The identifier of the service class used to look for.
*
* @return <code>true</code> <=> A service is registered using the supplied identifier.
*/
public final boolean hasService(String serviceIdentifier) {
return this._serviceMap.containsKey(serviceIdentifier);
}
/**
* <p>
* Returns the service with the identifier <code>serviceType.getName()</code>.
* </p>
*
* @param <T>
* The type of the service class.
* @param serviceType
* The service class itself.
*
* @return The instance of the service class.
*/
@SuppressWarnings("unchecked")
public <T> T getService(Class<T> serviceType) {
Object result = this._serviceMap.get(serviceType.getName());
if (result == null) {
throw new Ant4EclipseException(CoreExceptionCode.SERVICE_NOT_AVAILABLE, serviceType.getName());
}
return (T) result;
}
/**
* Returns a list of all currently registered services.
*
* @return A list of all currently registered services. Not <code>null</code>.
*/
public Object[] getAllServices() {
Object[] result = new Object[this._serviceMap.size()];
this._serviceMap.values().toArray(result);
return result;
}
/**
* <p>
* </p>
*
* @return
*/
private final boolean isInitialized() {
return this._isInitialized;
}
/**
* <p>
* </p>
*/
void initialize() {
Assure.assertTrue(!isInitialized(), "Service registry already has been initialized!");
Iterator<Object> iterator = this._serviceOrdering.iterator();
while (iterator.hasNext()) {
Object service = iterator.next();
if (service instanceof Lifecycle) {
try {
((Lifecycle) service).initialize();
} catch (Exception e) {
throw new Ant4EclipseException(e, CoreExceptionCode.SERVICE_COULD_NOT_BE_INITIALIZED, service.getClass()
.getName());
}
}
}
setInitialized(true);
}
/**
* <p>
* </p>
*/
void dispose() {
Assure.assertTrue(isInitialized(), "Service registry is not initialized.");
Iterator<Object> iterator = this._serviceOrdering.iterator();
while (iterator.hasNext()) {
Object service = iterator.next();
if (service instanceof Lifecycle) {
try {
((Lifecycle) service).dispose();
} catch (Exception e) {
// no need to do anything here...
System.err.printf(CoreExceptionCode.SERVICE_COULD_NOT_BE_DISPOSED.getMessage(), service);
}
}
}
setInitialized(false);
}
/**
* @param b
*/
private void setInitialized(boolean b) {
this._isInitialized = b;
}
/**
* <p>
* Creates an instance of type {@link ServiceRegistry}.
* </p>
*
* @param configuration
* the service registry configuration
*/
ServiceRegistry(ServiceRegistryConfiguration configuration) {
this._serviceMap = new HashMap<String, Object>();
this._serviceOrdering = new LinkedList<Object>();
configuration.configure(new ConfigurationContextImpl());
}
/**
* ConfigurationContextImpl --
*
* @author Gerd Wütherich (gerd@gerd-wuetherich.de)
*/
private class ConfigurationContextImpl implements ConfigurationContext {
/**
* {@inheritDoc}
*/
public void registerService(Object service, String serviceIdentifier) {
Assure.assertTrue(!ServiceRegistry.this._isInitialized, "ServiceRegistry.this._isInitialized!");
Assure.notNull("service", service);
Assure.notNull("serviceIdentifier", serviceIdentifier);
if (!ServiceRegistry.this._serviceMap.containsKey(serviceIdentifier)) {
ServiceRegistry.this._serviceMap.put(serviceIdentifier, service);
ServiceRegistry.this._serviceOrdering.add(service);
} else {
throw new Ant4EclipseException(CoreExceptionCode.SERVICE_IDENTIFIER_IS_NOT_UNIQUE, serviceIdentifier);
}
}
/**
* {@inheritDoc}
*/
public void registerService(Object service, String[] serviceIdentifier) {
Assure.assertTrue(!ServiceRegistry.this._isInitialized, "ServiceRegistry.this._isInitialized!");
Assure.notNull("service", service);
Assure.notNull("serviceIdentifier", serviceIdentifier);
Assure.assertTrue(serviceIdentifier.length > 0, "serviceIdentifier.length = 0!");
for (int i = 0; i < serviceIdentifier.length; i++) {
Assure.assertTrue(serviceIdentifier[i] != null, "Parameter serviceIdentifier[" + i + "] has to be set!");
}
for (String object : serviceIdentifier) {
if (ServiceRegistry.this._serviceMap.containsKey(object)) {
throw new Ant4EclipseException(CoreExceptionCode.SERVICE_IDENTIFIER_IS_NOT_UNIQUE, (Object) serviceIdentifier);
}
}
for (String object : serviceIdentifier) {
ServiceRegistry.this._serviceMap.put(object, service);
ServiceRegistry.this._serviceOrdering.add(service);
}
}
} /* ENDCLASS */
} /* ENDCLASS */