package org.atomnuke.service; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.Queue; import java.util.Stack; import org.atomnuke.plugin.InstanceContext; import org.atomnuke.plugin.operation.ComplexOperation; import org.atomnuke.plugin.operation.OperationFailureException; import org.atomnuke.plugin.proxy.InstanceEnvProxyFactory; import org.atomnuke.service.gc.ReclamationHandler; import org.atomnuke.util.lifecycle.operation.ReclaimOperation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author zinic */ public abstract class AbstractServiceManager implements ServiceManager { private static final ComplexOperation<Service, ProvidesOperationArgument> PROVIDES_OPERATION = new ComplexOperation<Service, ProvidesOperationArgument>() { @Override public void perform(Service instance, ProvidesOperationArgument argument) throws OperationFailureException { if (instance.provides(argument.getServiceInterface())) { argument.setProvides(true); } } }; private static final Logger LOG = LoggerFactory.getLogger(AbstractServiceManager.class); private final Map<String, ManagedService> registeredServicesByName; private final Queue<InstanceContext<Service>> pendingServices; private final Stack<ManagedService> registeredServices; private final InstanceEnvProxyFactory proxyFactory; public AbstractServiceManager(InstanceEnvProxyFactory proxyFactory) { this.proxyFactory = proxyFactory; registeredServicesByName = new HashMap<String, ManagedService>(); pendingServices = new LinkedList<InstanceContext<Service>>(); registeredServices = new Stack<ManagedService>(); } protected synchronized int servicesPending() { return pendingServices.size(); } protected synchronized InstanceContext<Service> nextPendingService() { return !pendingServices.isEmpty() ? pendingServices.poll() : null; } protected synchronized void queuePendingService(InstanceContext<Service> service) { pendingServices.add(service); } protected Stack<ManagedService> registeredServices() { return registeredServices; } protected synchronized void register(String serviceName, ManagedService service) { registeredServicesByName.put(serviceName, service); registeredServices.push(service); } @Override public synchronized boolean serviceRegistered(Class serviceInterface) { final ProvidesOperationArgument argument = new ProvidesOperationArgument(serviceInterface); for (ManagedService managedService : registeredServices) { try { argument.reset(); managedService.serviceContext().perform(PROVIDES_OPERATION, argument); } catch (OperationFailureException ofe) { LOG.error("Failed to identify if the given service: " + managedService + " provides the interface: " + serviceInterface.getName() + " - Reason: " + ofe.getMessage(), ofe); } if (argument.provides()) { return true; } } return false; } @Override public synchronized boolean serviceRegistered(String serviceName) { return registeredServicesByName.containsKey(serviceName); } @Override public synchronized <T> T get(String name, Class<T> serviceInterface) { final ManagedService managedService = registeredServicesByName.get(name); if (managedService == null) { return null; } if (!managedService.serviceContext().instance().provides(serviceInterface)) { throw new IllegalArgumentException("Service: " + name + " does not provide interface: " + serviceInterface.getName()); } return proxyFactory.newServiceProxy(serviceInterface, managedService.serviceContext()); } @Override public synchronized void destroy() { final ProvidesOperationArgument argument = new ProvidesOperationArgument(ReclamationHandler.class); while (!registeredServices.empty()) { final ManagedService managedService = registeredServices.pop(); argument.reset(); try { managedService.serviceContext().perform(PROVIDES_OPERATION, argument); if (argument.provides()) { managedService.serviceContext().perform(ReclaimOperation.<Service>instance()); } } catch (OperationFailureException ofe) { LOG.error("Failed to reclaim service: " + managedService + " - Reason: " + ofe.getMessage()); } } } @Override public synchronized void submit(InstanceContext<Service> service) throws ServiceAlreadyRegisteredException { final String serviceName = service.instance().name(); if (registeredServicesByName.containsKey(serviceName)) { throw new ServiceAlreadyRegisteredException(serviceName); } pendingServices.add(service); } @Override public synchronized Collection<String> servicesAdvertising(Class serviceInterface) { final Collection<String> servicesMatchingInterface = new LinkedList<String>(); final ProvidesOperationArgument argument = new ProvidesOperationArgument(serviceInterface); for (ManagedService managedService : registeredServices) { final InstanceContext<Service> serviceContext = managedService.serviceContext(); argument.reset(); try { serviceContext.perform(PROVIDES_OPERATION, argument); if (argument.provides()) { servicesMatchingInterface.add(serviceContext.instance().name()); } } catch (OperationFailureException ofe) { LOG.error("Failed to identify if the given service: " + managedService + " provides the interface: " + serviceInterface.getName() + " - Reason: " + ofe.getMessage(), ofe); } } return servicesMatchingInterface; } }