package org.atomnuke.service; import java.util.Collections; import org.atomnuke.NukeEnvironment; import org.atomnuke.plugin.InstanceContext; import org.atomnuke.plugin.operation.OperationFailureException; import org.atomnuke.plugin.proxy.InstanceEnvProxyFactory; import org.atomnuke.service.context.ServiceContextImpl; import org.atomnuke.service.operation.ServiceInitOperation; import org.atomnuke.lifecycle.resolution.ResolutionAction; import org.atomnuke.lifecycle.resolution.ResolutionActionType; import org.atomnuke.service.introspection.ServicesInterrogatorImpl; import org.atomnuke.util.remote.AtomicCancellationRemote; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author zinic */ public class RuntimeServiceManager extends AbstractServiceManager { private static final Logger LOG = LoggerFactory.getLogger(RuntimeServiceManager.class); private final ResolutionHandlerImpl resolutionHandler; private final NukeEnvironment environment; public RuntimeServiceManager(NukeEnvironment environment, InstanceEnvProxyFactory proxyFactory) { super(proxyFactory); this.environment = environment; this.resolutionHandler = new ResolutionHandlerImpl(this); } @Override public void resolve() { /** * We can sweep the service registry equal to the number of services that * are pending. While we may miss a few services, calls to this method * should stack and flush everything out correctly. */ boolean continueResolving; do { final int totalResolutionAttemptsAllowed = servicesPending(); continueResolving = false; for (int resolutionAttempt = 0; servicesPending() > 0 && resolutionAttempt < totalResolutionAttemptsAllowed; resolutionAttempt++) { final InstanceContext<Service> pendingService = nextPendingService(); // There's a possibility that we're trying to resove and the number of pending services has changed drastically if (pendingService == null) { break; } // Attempt to resolve the service and decide what to do based on that final ResolutionAction action = resolutionHandler.resolve(pendingService); final ResolutionActionType actionType = action.type(); if (actionType == ResolutionActionType.INIT) { initService(pendingService); continueResolving = true; break; } else if (actionType == ResolutionActionType.DEFER) { LOG.debug("Service: " + pendingService.instance().name() + " deferred startup."); queuePendingService(pendingService); } else { LOG.error("Service: " + pendingService.instance().name() + " failed to start. Fallout will cease attempting to initialize it."); } } } while (continueResolving); } private void initService(InstanceContext<Service> pendingService) { LOG.info("Service: " + pendingService.instance().name() + " initializing."); // TODO: Fix parameter passing - this is just terrible :p final ServiceContext serviceContext = new ServiceContextImpl(new ServicesInterrogatorImpl(this), Collections.EMPTY_MAP, environment, this); try { pendingService.perform(ServiceInitOperation.<Service>instance(), serviceContext); final ManagedService managedService = new ManagedService(pendingService, new AtomicCancellationRemote()); register(pendingService.instance().name(), managedService); } catch (OperationFailureException ofe) { LOG.error("Unable to initialize service: " + pendingService + " - Reason: " + ofe.getMessage(), ofe); } } }