/**
*
*/
package org.eclipse.papyrus.infra.core.services;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.eclipse.papyrus.infra.core.Activator;
import org.eclipse.papyrus.infra.core.services.ServiceDescriptor.ServiceTypeKind;
import org.eclipse.papyrus.infra.core.services.internal.LazyStartupEntry;
import org.eclipse.papyrus.infra.core.services.internal.PojoServiceEntry;
import org.eclipse.papyrus.infra.core.services.internal.ServiceEntry;
import org.eclipse.papyrus.infra.core.services.internal.ServiceFactoryEntry;
import org.eclipse.papyrus.infra.core.services.internal.ServiceStartupEntry;
import org.eclipse.papyrus.infra.core.services.internal.ServiceTypeEntry;
import org.eclipse.papyrus.infra.core.services.internal.StartStartupEntry;
/**
* A registry of services. This registry allows to get a service by its
* identifier. The identifier is generally the classname of the service.
* Services can be added using the Eclipse extension mechanism (if you use {@link ExtensionServicesRegistry}). <br>
* A Service is a class providing operations. The ServiceRegistry is used to
* share objects (i.e. services) between nested editors and also the core main
* editor.
*
* <br>
* In this implementation, services should be added to the registry before the
* call to createServices(). If a service is added after the call, it will not
* be started (except if it is a lazy service). <br>
* A typical usage is:
*
* <pre>
* <code>
* ServicesRegistry serviceRegistry = new ServiceRegistry();
* // Add your services
* serviceRegistry.add( ...);
* serviceRegistry.add( ...);
*
* // start the services
* serviceRegistry.startRegistry();
*
* // Retrieve a service
* myService = serviceRegistry.getService( serviceKey );
* </code>
* </pre>
*
* It is possible to register new services after the serviceRegistry has been
* started. In this case, you need to start them explicitly if they are of type
* ServiceStartKind.STARTUP.
*
* <pre>
* <code>
* // Add your new services
* serviceRegistry.add( key1, ...);
* serviceRegistry.add( key2, ...);
*
* // start the new services
* serviceRegistry.startRegistry(key1, key2);
* </code>
* </pre>
*
* <ul>
* <li></li>
* <li></li>
* </ul>
*
* @author cedric dumoulin
*
*
*/
public class ServicesRegistry {
/** Log object */
protected Logger log = Logger.getLogger(getClass().getName());
/**
* Map of existing services.
*/
// private Map<Object, AbstractServiceEntry> services;
/**
* A Map of services added to the register (thow the addXxx() methods), but
* not yet registered. They will be registered after a call to startXxx().
*/
private Map<String, ServiceStartupEntry> addedServices = new HashMap<String, ServiceStartupEntry>();
/**
* Map of services registered with a name.
*/
private Map<String, ServiceStartupEntry> namedServices = new HashMap<String, ServiceStartupEntry>();
/**
* Map of services registered without a name (anonymous). Such services
* can't be retrieved.
*/
private List<ServiceStartupEntry> anonymousServices = new ArrayList<ServiceStartupEntry>();
/**
* Constructor.
*/
public ServicesRegistry() {
}
/**
* Add a service by its ServiceDescriptor.
*
* @param serviceDescriptor
* Descriptor describing the service.
* @throws ServiceException
* If an error occurs while initializing service.
*/
public void add(ServiceDescriptor serviceDescriptor) {
// Check if the service already exist.
ServiceStartupEntry service = addedServices.get(serviceDescriptor.getKey());
if(service != null) {
if(service.getDescriptor().getPriority() > serviceDescriptor.getPriority())
return;
else if(service.getDescriptor().getPriority() == serviceDescriptor.getPriority()) {
log.warning("Two services with same priority (" + serviceDescriptor.getPriority() + ") are declared under key '" + service.getDescriptor().getKey() + "'. Keep the first encountered only. (bundles: " + service.getDescriptor().getClassBundleID() + ", " + serviceDescriptor.getClassBundleID() + ")");
}
}
// Compute the service type entry
ServiceTypeEntry serviceTypeEntry;
ServiceTypeKind typeKind = serviceDescriptor.getServiceTypeKind();
if(typeKind == ServiceTypeKind.service)
serviceTypeEntry = new ServiceEntry(serviceDescriptor);
else if(typeKind == ServiceTypeKind.serviceFactory)
serviceTypeEntry = new ServiceFactoryEntry(serviceDescriptor);
else
serviceTypeEntry = new PojoServiceEntry(serviceDescriptor);
// Create the entry
ServiceStartupEntry serviceEntry;
if(serviceDescriptor.isStartAtStartup()) {
serviceEntry = new StartStartupEntry(serviceTypeEntry);
} else {
serviceEntry = new LazyStartupEntry(serviceTypeEntry, this);
}
// Add the entry
addedServices.put(serviceDescriptor.getKey(), serviceEntry);
}
/**
* Add a service. The descriptor will be created.
*
* @param key
* Service key
* @param priority
* service priority
* @param serviceInstance
* The instance of the service
*/
public void add(String key, int priority, IService serviceInstance) {
add(key, priority, serviceInstance, ServiceStartKind.STARTUP);
}
/**
* Add a service. The descriptor will be created.
*
* @param key
* Service key
* @param priority
* service priority
* @param serviceInstance
* The instance of the service
*/
public void add(Class<?> key, int priority, IService serviceInstance) {
add(key.getName(), priority, serviceInstance, ServiceStartKind.STARTUP);
}
/**
* Add a service. The descriptor will be created.
*
* @param key
* Service key
* @param priority
* service priority
* @param serviceInstance
* The instance of the service
*/
public void add(String key, int priority, IService serviceInstance, ServiceStartKind startKind) {
// Check if the service already exist.
ServiceStartupEntry service = addedServices.get(key);
if(service != null) {
if(service.getDescriptor().getPriority() > priority)
return;
else if(service.getDescriptor().getPriority() == priority)
log.warning("Two services with same priority (" + priority + ") are declared under key '" + service.getDescriptor().getKey() + "'. Keep the first encountered only.");
}
// Create descriptor and add service.
ServiceDescriptor descriptor = new ServiceDescriptor(key, serviceInstance.getClass().getName(), startKind, priority);
if(startKind == ServiceStartKind.STARTUP)
addedServices.put(key, new StartStartupEntry(new ServiceEntry(descriptor, serviceInstance)));
else
addedServices.put(key, new LazyStartupEntry(new ServiceEntry(descriptor, serviceInstance), this));
}
/**
* Add a service. The descriptor will be created.
*
* @param key
* Service key Class used as key. The classname is used as key.
* @param priority
* service priority
* @param serviceInstance
* The instance of the service
*/
public void add(Class<?> key, int priority, IService serviceInstance, ServiceStartKind startKind) {
add(key.getName(), priority, serviceInstance, startKind);
}
/**
* Add an already instanciated pojo (Plain Old Java Object) as Service. The
* descriptor will be created. No life cycle methods are called on the
* service.
*
* @param key
* Service key
* @param priority
* service priority
* @param serviceInstance
* The instance of the service
*/
public void add(Class<?> key, int priority, Object serviceInstance) {
add(key, priority, serviceInstance, ServiceStartKind.STARTUP);
}
/**
* Add an already instanciated pojo (Plain Old Java Object) as Service. The
* descriptor will be created. No life cycle methods are called on the
* service.
*
* @param key
* Service key
* @param priority
* service priority
* @param serviceInstance
* The instance of the service
* @param startKind
*
*/
public void add(String key, int priority, Object serviceInstance, ServiceStartKind startKind) {
// Check if the service already exist.
ServiceStartupEntry service = addedServices.get(key);
if(service != null) {
if(service.getDescriptor().getPriority() > priority)
return;
else if(service.getDescriptor().getPriority() == priority)
log.warning("Two services with same priority (" + priority + ") are declared under key '" + service.getDescriptor().getKey() + "'. Keep the first encountered only.");
}
// Create descriptor and add service.
ServiceDescriptor descriptor = new ServiceDescriptor(key, serviceInstance.getClass().getName(), startKind, priority);
if(startKind == ServiceStartKind.STARTUP)
addedServices.put(key, new StartStartupEntry(new PojoServiceEntry(descriptor, serviceInstance)));
else
addedServices.put(key, new LazyStartupEntry(new PojoServiceEntry(descriptor, serviceInstance), this));
}
/**
* Add an already instanciated pojo (Plain Old Java Object) as Service. The
* descriptor will be created. No life cycle methods are called on the
* service.
*
* @param key
* Service key Class used as key. The classname is used as key.
* @param priority
* service priority
* @param serviceInstance
* The instance of the service
* @param startKind
*
*/
public void add(Class<?> key, int priority, Object serviceInstance, ServiceStartKind startKind) {
add(key.getName(), priority, serviceInstance, startKind);
}
/**
* Remove the specified service from the registry.
*
* @param key
*/
public void remove(ServiceDescriptor serviceDescriptor) throws ServiceException {
remove(serviceDescriptor.getKey());
}
/**
* Remove the specified service from the registry.
*
* @param key
*/
public void remove(Object key) throws ServiceException {
ServiceStartupEntry service = namedServices.remove(key);
if(service == null) {
return;
}
// Stop the service
service.disposeService();
}
/**
* Get the requested service by its key. The key is usually the classname of
* the service.
*
* @param serviceClass
* @return
* @throws ServiceException
* If servive can't be started
*/
public Object getService(Object key) throws ServiceException {
ServiceStartupEntry service = namedServices.get(key);
if(service == null) {
// throw an exception.
// If added, say it.
service = addedServices.get(key);
if(service != null)
throw new BadStateException("Registry should be started before.", service.getState(), service.getDescriptor());
else
throw new ServiceNotFoundException("No service registered under '" + key + "'");
}
return service.getServiceInstance();
}
/**
* apex updated
*
* 에디터를 닫았다가 다시 열 때 등 namedServices가 null 인 경우 NullPointerException 발생 예방
*
* Get the requested service by its class (the service has to be registered
* by its class object).
*
* @param key
* The service class.
* @return The service.
* @throws ServiceException
* If service can't be started
*/
@SuppressWarnings("unchecked")
public <S> S getService(Class<S> key) throws ServiceException {
/* apex improved start */
if ( namedServices != null ) {
String realKey = key.getName();
ServiceStartupEntry service = namedServices.get(realKey);
if(service == null) {
// throw an exception.
// If added, say it.
service = addedServices.get(realKey);
if(service != null)
throw new BadStateException("Registry should be started before.", service.getState(), service.getDescriptor());
else
throw new ServiceNotFoundException("No service registered under '" + key + "'");
}
return (S)service.getServiceInstance();
} else {
return null;
}
/* apex improved end */
/* apex replaced
String realKey = key.getName();
ServiceStartupEntry service = namedServices.get(realKey);
if(service == null) {
// throw an exception.
// If added, say it.
service = addedServices.get(realKey);
if(service != null)
throw new BadStateException("Registry should be started before.", service.getState(), service.getDescriptor());
else
throw new ServiceNotFoundException("No service registered under '" + key + "'");
}
return (S)service.getServiceInstance();
*/
}
/**
* Return true if the service is instantiated. Return false otherwise.
*
* @return
*/
public boolean isStarted(Object key) throws ServiceNotFoundException {
ServiceStartupEntry service = namedServices.get(key);
if(service == null) {
throw new ServiceNotFoundException("No service registered under '" + key + "'");
}
return service.isStarted();
}
/**
* Return the state of the specified service.
*
* @return
*/
public ServiceState serviceState(Object key) throws ServiceNotFoundException {
ServiceStartupEntry service = namedServices.get(key);
if(service == null) {
throw new ServiceNotFoundException("No service registered under '" + key + "'");
}
return service.getState();
}
/**
* Start the registry. Start all services marked as start = STARTUP are
* started. All services are first created, then initialized and finally
* started. If an error occur on a service during one of this step, the
* service is removed from the registry and and the error is logged.
*
* @throws ServiceMultiException
*
* @throws ServiceException
* If a service can't be started.
*/
public void startRegistry() throws ServiceMultiException {
// Build the lookup maps
LookupMap map = new LookupMap(addedServices, namedServices);
// Check if all dependencies exist.
checkDependencies(addedServices.values(), map);
// Get all roots : LAZY and START
Collection<ServiceStartupEntry> roots = getServiceRoots(addedServices.values(), map);
// showServices(" Roots:", roots);
// Detect cycles
checkCycle(roots, map);
// Retain only services with startupkind = START
roots = retainsToStartServices(roots);
//
List<ServiceStartupEntry> toStart = buildTopologicalListOfServicesToStart(roots, map);
if(Activator.log.isDebugEnabled()) {
showServices(" Services to start:", toStart);
}
// Create an object to collect errors if any.
ServiceMultiException errors = new ServiceMultiException();
createServices(toStart, errors);
// Register all new services : lazy and start
registerServices(addedServices.values());
initServices(toStart, errors);
startServices(toStart, errors);
// Report errors if any
if(errors.getExceptions().size() > 0)
throw errors;
}
/**
* Start the specified services, and their required services. The specifies
* services should be in the addServices or already registered. Start all
* services marked as start = STARTUP . All eligible services are first
* created, then initialized and finally started. If an error occur on a
* service during one of this step, the service is removed from the registry
* and and the error is logged.
*
* @param serviceKeys
* Keys of services to start.
* @throws ServiceMultiException
* @throws ServiceNotFoundException
* If a service can't be retrieved by its key.
*
* @throws ServiceException
* If a service can't be started.
*/
public void startServices(List<String> serviceKeys) throws ServiceMultiException, ServiceNotFoundException {
// Build the lookup maps
LookupMap map = new LookupMap(addedServices, namedServices);
// Get the services
List<ServiceStartupEntry> services = keysToServices(serviceKeys, map);
// Start them
startServices(services, map);
}
/**
* Same as {@link #startServices(List)}, but with an array as input.
*
* @see #startServices(List)
*
* @param serviceKeys
* Keys of services to start.
* @throws ServiceMultiException
* @throws ServiceNotFoundException
* If a service can't be retrieved by its key.
*
* @throws ServiceException
* If a service can't be started.
*/
public void startServices(String... serviceKeys) throws ServiceMultiException, ServiceNotFoundException {
List<String> serviceKeysList = Arrays.asList(serviceKeys);
startServices(serviceKeysList);
}
/**
* Start the specified services, and their required services. The specifies
* services should be in the addServices or already registered. Start all
* services marked as start = STARTUP . All eligible services are first
* created, then initialized and finally started. If an error occur on a
* service during one of this step, the service is removed from the registry
* and and the error is logged.
*
* @param serviceKeys
* Keys of services to start. Keys will be translated to the
* classname.
* @throws ServiceMultiException
* @throws ServiceNotFoundException
* If a service can't be retrieved by its key.
*
* @throws ServiceException
* If a service can't be started.
*/
public void startServicesByClassKeys(List<Class<?>> serviceKeys) throws ServiceMultiException, ServiceNotFoundException {
// Build the lookup maps
LookupMap map = new LookupMap(addedServices, namedServices);
// Get the services
List<ServiceStartupEntry> services = classKeysToServices(serviceKeys, map);
// Start them
startServices(services, map);
}
/**
* Same as {@link #startServicesByClassKeys(List)}, but with an array as
* input.
*
* @see #startServices(List)
*
* @param serviceKeys
* Keys of services to start.
* @throws ServiceMultiException
* @throws ServiceNotFoundException
* If a service can't be retrieved by its key.
*
* @throws ServiceException
* If a service can't be started.
*/
public void startServicesByClassKeys(Class<?>... serviceKeys) throws ServiceMultiException, ServiceNotFoundException {
List<Class<?>> serviceKeysList = Arrays.asList(serviceKeys);
startServicesByClassKeys(serviceKeysList);
}
/**
* Start the specified services, and their required services. The specifies
* services should be in the specified map. The map is also used to resolves
* dependencies. Start all services marked as start = STARTUP . All eligible
* services are first created, then initialized and finally started. If an
* error occur on a service during one of this step, the service is removed
* from the registry and and the error is logged.
*
* @param services
* Services to start
* @param map
* a table of (key, service) used to get a service by its key.
* @throws ServiceMultiException
* If a service can't be started.
*/
private void startServices(List<ServiceStartupEntry> services, LookupMap map) throws ServiceMultiException {
// Check if all dependencies exist.
checkDependencies(services, map);
// Get all roots : LAZY and START
Collection<ServiceStartupEntry> roots = getServiceRoots(services, map);
if(Activator.log.isDebugEnabled()) {
showServices(" Roots:", roots);
}
// Detect cycles
checkCycle(roots, map);
// Retain only services with startupkind == START and state ==
// REGISTERED
roots = retainsToStartServices(roots);
//
List<ServiceStartupEntry> toStart = buildTopologicalListOfServicesToStart(roots, map);
// Remove already started services
toStart = retainsToStartServices(toStart);
// if( log.isLoggable(Level.FINE))
// {
showServices(" Services to start:", toStart);
// }
// Create an object to collect errors if any.
ServiceMultiException errors = new ServiceMultiException();
createServices(toStart, errors);
// Register all started services
registerServices(toStart);
initServices(toStart, errors);
startServices(toStart, errors);
// Report errors if any
if(errors.getExceptions().size() > 0)
throw errors;
}
/**
* Return a list of services from a list of services keys.
*
* @param serviceKeys
* @param map
* @return
* @throws ServiceNotFoundException
* If a service can't be retrieved by its key.
*/
private List<ServiceStartupEntry> keysToServices(List<String> serviceKeys, LookupMap map) throws ServiceNotFoundException {
List<ServiceStartupEntry> result = new ArrayList<ServiceStartupEntry>(serviceKeys.size());
for(String key : serviceKeys) {
result.add(map.getChecked(key));
}
return result;
}
/**
* Return a list of services from a list of services keys.
*
* @param serviceKeys
* @param map
* @return
* @throws ServiceNotFoundException
* If a service can't be retrieved by its key.
*/
private List<ServiceStartupEntry> classKeysToServices(List<Class<?>> serviceKeys, LookupMap map) throws ServiceNotFoundException {
List<ServiceStartupEntry> result = new ArrayList<ServiceStartupEntry>(serviceKeys.size());
for(Class<?> key : serviceKeys) {
result.add(map.getChecked(key.getName()));
}
return result;
}
/**
* Print the services. For debug purpose
*
* @param roots
*/
private void showServices(String message, Collection<ServiceStartupEntry> roots) {
StringBuffer buffer = new StringBuffer();
buffer.append("--------------------------\n");
buffer.append(message);
buffer.append("\n");
for(ServiceStartupEntry service : roots) {
buffer.append(" ");
buffer.append(service.getDescriptor().toString());
buffer.append("\n");
}
buffer.append("--------- done -----------\n");
Activator.log.debug(buffer.toString());
}
/**
* Check if all dependencies exist. Throw an error if a declared dependency
* has no corresponding service.
*
* @param services
* Services to check
* @param map
* Map of services by keys.
* @throws ServiceMultiException
*/
private void checkDependencies(Collection<ServiceStartupEntry> services, LookupMap map) throws ServiceMultiException {
ServiceMultiException errors = new ServiceMultiException();
// Walk each service and check if its required services exist.
for(ServiceStartupEntry service : services) {
ServiceDescriptor desc = service.getDescriptor();
// Check each required service
for(String key : desc.getRequiredServiceKeys()) {
// Check if service can be found
try {
map.getChecked(key);
} catch (ServiceNotFoundException e) {
System.out
.println("ServicesRegistry.checkDependencies, line "
+ Thread.currentThread().getStackTrace()[1]
.getLineNumber());
System.out.println("RequiringService : " + service);
System.out.println("RequiredService : " + key);
errors.addException(desc.getKey(), e);
}
}
}
// Throw errors if any
if(errors.getExceptions().size() > 0)
throw errors;
}
/**
* Retains only the services that should be started. Retains only services
* with startupkind = START and state == REGISTERED
*
* @param services
* Collection to filter
* @return a new Collection containing the services to start.
*/
private List<ServiceStartupEntry> retainsToStartServices(Collection<ServiceStartupEntry> services) {
List<ServiceStartupEntry> result = new ArrayList<ServiceStartupEntry>();
for(ServiceStartupEntry service : services) {
ServiceDescriptor desc = service.getDescriptor();
if(service.getState() == ServiceState.registered && desc.isStartAtStartup()) {
result.add(service);
}
}
return result;
}
/**
* Check for cycles. Throws an exception if a cycle is discovered. Each root
* is checked to see if it contains a cycle.
*
* @param roots
* @param map
*/
private void checkCycle(Collection<ServiceStartupEntry> roots, LookupMap map) {
// TODO Auto-generated method stub
}
/**
* Build a list of services to start, in the topological order (right
* order). The required services are placed before the dependent services in
* the list. Services already started are disguarded.
*
* @param roots
* @param map
* Map used to resolve the entry by their key.
* @return
*/
private List<ServiceStartupEntry> buildTopologicalListOfServicesToStart(Collection<ServiceStartupEntry> roots, LookupMap map) {
List<ServiceStartupEntry> result = new ArrayList<ServiceStartupEntry>();
// Each root represent a graph. Walk the root and its child in the list,
// in the right order.
for(ServiceStartupEntry root : roots) {
walkGraphDepthFirst(result, root, map);
}
return result;
}
/**
* Add recursively the provided node, and then its direct children.
*
* @param result
* The list where the node are added
* @param node
* The node to add
* @param map
*/
private void walkGraphDepthFirst(List<ServiceStartupEntry> result, ServiceStartupEntry node, LookupMap map) {
// Do not add already added or started node.
if(result.contains(node) || node.isStarted())
return;
// add direct child
for(String serviceKey : node.getDescriptor().getRequiredServiceKeys()) {
try {
ServiceStartupEntry child = map.getChecked(serviceKey);
walkGraphDepthFirst(result, child, map);
} catch (ServiceNotFoundException e) {
// Do nothing, we have already reported the problems with
// checkServices;
}
}
// Now add the node
result.add(node);
}
/**
* Create a List of the root services. The roots are services that are not
* required by any service.
*
* @param addedServices
* A collection from which roots are required. The collection is
* unmodified.
* @param map
* @return
*/
private Collection<ServiceStartupEntry> getServiceRoots(Collection<ServiceStartupEntry> addedServices, LookupMap keyServiceMap) {
// Create a copy of the list of services
Collection<ServiceStartupEntry> services = new ArrayList<ServiceStartupEntry>(addedServices);
List<ServiceStartupEntry> allRequired = new ArrayList<ServiceStartupEntry>();
// The roots are services that are not required by any service.
// Build a list of the services required by all other services.
for(ServiceStartupEntry service : services) {
// Add each child to the list of required
for(String serviceKey : service.getDescriptor().getRequiredServiceKeys()) {
try {
ServiceStartupEntry child = keyServiceMap.getChecked(serviceKey);
allRequired.add(child);
} catch (ServiceNotFoundException e) {
// Do nothing, we have already reported the problems with
// checkServices;
}
}
}
// Roots are those that are not required.
// So it is the original list minus the required.
services.removeAll(allRequired);
return services;
}
/**
* Dispose all services.
*
* @throws ServiceMultiException
*/
public void disposeRegistry() throws ServiceMultiException {
// List of keys of service in error.
ServiceMultiException errors = new ServiceMultiException();
disposeServices(namedServices.values(), errors);
disposeServices(anonymousServices, errors);
// Clean up properties to help GC
addedServices.clear();
addedServices = null;
anonymousServices.clear();
anonymousServices = null;
namedServices.clear();
namedServices = null;
// Report errors if any
if(errors.getExceptions().size() > 0)
throw errors;
}
/**
* Create all services provided in the list
*
* @param toStart
* List of services to create.
* @param errors
* Exception to collect errors.
*
* @throws ServiceMultiException
* If an error occure during the creation
*
* @throws ServiceException
* If a service can't be started.
*/
private void createServices(List<ServiceStartupEntry> toStart, ServiceMultiException errors) throws ServiceMultiException {
// Loop on all services
for(ServiceStartupEntry serviceEntry : toStart) {
try {
serviceEntry.createService();
} catch (ServiceException e) {
log.log(Level.SEVERE, "Can't create service '" + serviceEntry + "'", e);
errors.addException(serviceEntry.getDescriptor().getKey(), e);
}
}
}
/**
* Register all services provided in the list. After this operation,
* services are available thru {@link #getService(Class)}.
*
* @param toStart
* List of services to register.
*
* @throws ServiceException
* If a service can't be started.
*/
private void registerServices(Collection<ServiceStartupEntry> toStart) {
// Loop on all services
for(ServiceStartupEntry serviceEntry : toStart) {
ServiceDescriptor desc = serviceEntry.getDescriptor();
if(desc.isAnonymous()) {
anonymousServices.add(serviceEntry);
} else {
namedServices.put(desc.getKey(), serviceEntry);
}
}
}
/**
* Init all services provided in the list
*
* @param toStart
* List of services to init.
* @param errors
*
* @throws ServiceMultiException
* If an error occure during the process
*
* @throws ServiceException
* If a service can't be started.
*/
private void initServices(List<ServiceStartupEntry> toStart, ServiceMultiException errors) throws ServiceMultiException {
// Loop on all services
for(ServiceStartupEntry serviceEntry : toStart) {
try {
serviceEntry.initService(this);
} catch (ServiceException e) {
log.log(Level.SEVERE, "Can't initialize service '" + serviceEntry + "'", e);
errors.addException(serviceEntry.getDescriptor().getKey(), e);
}
}
}
/**
* Init all services provided in the list
*
* @param toStart
* List of services to init.
* @param errors
*
* @throws ServiceMultiException
* If an error occure during the process
*
* @throws ServiceException
* If a service can't be started.
*/
private void startServices(List<ServiceStartupEntry> toStart, ServiceMultiException errors) throws ServiceMultiException {
// Loop on all services
for(ServiceStartupEntry serviceEntry : toStart) {
try {
serviceEntry.startService();
} catch (ServiceException e) {
log.log(Level.SEVERE, "Can't start service '" + serviceEntry + "'", e);
errors.addException(serviceEntry.getDescriptor().getKey(), e);
}
}
}
/**
* Dispose all started services.
* Services are disposed in creation reverse order
*
* @throws ServiceMultiException
*
* @throws ServiceException
* If a service can't be started.
*/
private void disposeServices(Collection<ServiceStartupEntry> services, ServiceMultiException errors) {
// Dispose services
for(ServiceStartupEntry serviceEntry : services) {
try {
serviceEntry.disposeService();
} catch (ServiceException e) {
log.log(Level.SEVERE, "Can't dispose service '" + serviceEntry.getDescriptor().getKey() + "'", e);
errors.addException(serviceEntry.getDescriptor(), e);
}
}
}
/**
* This class represents a union of two maps of <String,
* ServiceStartupEntry>. It provide specific methods to retrieve a {@link ServiceStartupEntry} by its key.
*
* @author cedric dumoulin
*
*/
private class LookupMap {
Map<String, ServiceStartupEntry> map1;
Map<String, ServiceStartupEntry> map2;
/**
*
* Constructor. Build a union of two maps.
*
* @param map1
* @param map2
*/
public LookupMap(Map<String, ServiceStartupEntry> map1, Map<String, ServiceStartupEntry> map2) {
this.map1 = map1;
this.map2 = map2;
}
/**
*
* Constructor. Build a union of one map (sic).
*
* @param map
*/
@SuppressWarnings("unused")
public LookupMap(Map<String, ServiceStartupEntry> map) {
this(map, null);
}
/**
* Get a service by its key.
*
* @param key
* @return the service or null if not found.
*/
@SuppressWarnings("unused")
public ServiceStartupEntry get(String key) {
ServiceStartupEntry res = map1.get(key);
if(res != null)
return res;
if(map2 != null)
res = map2.get(key);
return res;
}
/**
* Get a service by its key.
*
* @param key
* @return The requested service.
* @throws ServiceNotFoundException
* if the service can't be found.
*/
public ServiceStartupEntry getChecked(String key) throws ServiceNotFoundException {
ServiceStartupEntry res = map1.get(key);
if(res != null)
return res;
if(map2 != null)
res = map2.get(key);
if(res != null)
return res;
throw new ServiceNotFoundException("No service found under key '" + key.toString() + "'");
}
}
}