コード例 #1
0
/**
 * Creates the service that acts as the {@link org.jboss.as.controller.ModelController} for a Host
 * Controller process.
 *
 * @author Brian Stansberry (c) 2011 Red Hat Inc.
 */
public class DomainModelControllerService extends AbstractControllerService
    implements DomainController, HostModelUtil.HostModelRegistrar {

  public static final ServiceName SERVICE_NAME =
      HostControllerService.HC_SERVICE_NAME.append("model", "controller");

  private static final int PINGER_POOL_SIZE;

  static {
    int poolSize = -1;
    try {
      poolSize =
          Integer.parseInt(
              SecurityActions.getSystemProperty("jboss.as.domain.ping.pool.size", "5"));
    } catch (Exception e) {
      // TODO log
    } finally {
      PINGER_POOL_SIZE = poolSize > 0 ? poolSize : 5;
    }
  }

  private volatile HostControllerConfigurationPersister hostControllerConfigurationPersister;
  private final HostControllerEnvironment environment;
  private final HostRunningModeControl runningModeControl;
  private final LocalHostControllerInfoImpl hostControllerInfo;
  private final HostFileRepository localFileRepository;
  private final RemoteFileRepository remoteFileRepository;
  private final InjectedValue<ProcessControllerConnectionService>
      injectedProcessControllerConnection = new InjectedValue<ProcessControllerConnectionService>();
  private final ConcurrentMap<String, ProxyController> hostProxies;
  private final ConcurrentMap<String, HostRegistration> hostRegistrationMap =
      new ConcurrentHashMap<String, HostRegistration>();
  private final Map<String, ProxyController> serverProxies;
  private final PrepareStepHandler prepareStepHandler;
  private final BootstrapListener bootstrapListener;
  private ManagementResourceRegistration modelNodeRegistration;
  private final AbstractVaultReader vaultReader;
  private final ContentRepository contentRepository;
  private final ExtensionRegistry extensionRegistry;
  private final ControlledProcessState processState;
  private final IgnoredDomainResourceRegistry ignoredRegistry;
  private final PathManagerService pathManager;
  private final ExpressionResolver expressionResolver;
  private final DelegatingResourceDefinition rootResourceDefinition;
  private final DomainControllerRuntimeIgnoreTransformationRegistry
      runtimeIgnoreTransformationRegistry;

  private volatile ServerInventory serverInventory;

  // TODO look into using the controller executor
  private volatile ExecutorService proxyExecutor;
  private volatile ScheduledExecutorService pingScheduler;

  static ServiceController<ModelController> addService(
      final ServiceTarget serviceTarget,
      final HostControllerEnvironment environment,
      final HostRunningModeControl runningModeControl,
      final ControlledProcessState processState,
      final BootstrapListener bootstrapListener,
      final PathManagerService pathManager) {
    final ConcurrentMap<String, ProxyController> hostProxies =
        new ConcurrentHashMap<String, ProxyController>();
    final Map<String, ProxyController> serverProxies =
        new ConcurrentHashMap<String, ProxyController>();
    final LocalHostControllerInfoImpl hostControllerInfo =
        new LocalHostControllerInfoImpl(processState, environment);
    final AbstractVaultReader vaultReader = service(AbstractVaultReader.class);
    ROOT_LOGGER.debugf("Using VaultReader %s", vaultReader);
    final ContentRepository contentRepository =
        ContentRepository.Factory.create(environment.getDomainContentDir());
    final IgnoredDomainResourceRegistry ignoredRegistry =
        new IgnoredDomainResourceRegistry(hostControllerInfo);
    final ExtensionRegistry extensionRegistry =
        new ExtensionRegistry(ProcessType.HOST_CONTROLLER, runningModeControl);
    final DomainControllerRuntimeIgnoreTransformationRegistry runtimeIgnoreTransformationRegistry =
        new DomainControllerRuntimeIgnoreTransformationRegistry();
    final PrepareStepHandler prepareStepHandler =
        new PrepareStepHandler(
            hostControllerInfo,
            contentRepository,
            hostProxies,
            serverProxies,
            ignoredRegistry,
            extensionRegistry,
            runtimeIgnoreTransformationRegistry);
    final ExpressionResolver expressionResolver = new RuntimeExpressionResolver(vaultReader);
    DomainModelControllerService service =
        new DomainModelControllerService(
            environment,
            runningModeControl,
            processState,
            hostControllerInfo,
            contentRepository,
            hostProxies,
            serverProxies,
            prepareStepHandler,
            vaultReader,
            ignoredRegistry,
            bootstrapListener,
            pathManager,
            expressionResolver,
            new DelegatingResourceDefinition(),
            extensionRegistry,
            runtimeIgnoreTransformationRegistry);

    ApplyMissingDomainModelResourcesHandler applyMissingDomainModelResourcesHandler =
        new ApplyMissingDomainModelResourcesHandler(
            service, environment, hostControllerInfo, ignoredRegistry);
    prepareStepHandler.initialize(applyMissingDomainModelResourcesHandler);

    return serviceTarget
        .addService(SERVICE_NAME, service)
        .addDependency(
            HostControllerService.HC_EXECUTOR_SERVICE_NAME,
            ExecutorService.class,
            service.getExecutorServiceInjector())
        .addDependency(
            ProcessControllerConnectionService.SERVICE_NAME,
            ProcessControllerConnectionService.class,
            service.injectedProcessControllerConnection)
        .addDependency(PathManagerService.SERVICE_NAME) // ensure this is up
        .setInitialMode(ServiceController.Mode.ACTIVE)
        .install();
  }

  private DomainModelControllerService(
      final HostControllerEnvironment environment,
      final HostRunningModeControl runningModeControl,
      final ControlledProcessState processState,
      final LocalHostControllerInfoImpl hostControllerInfo,
      final ContentRepository contentRepository,
      final ConcurrentMap<String, ProxyController> hostProxies,
      final Map<String, ProxyController> serverProxies,
      final PrepareStepHandler prepareStepHandler,
      final AbstractVaultReader vaultReader,
      final IgnoredDomainResourceRegistry ignoredRegistry,
      final BootstrapListener bootstrapListener,
      final PathManagerService pathManager,
      final ExpressionResolver expressionResolver,
      final DelegatingResourceDefinition rootResourceDefinition,
      final ExtensionRegistry extensionRegistry,
      final DomainControllerRuntimeIgnoreTransformationRegistry
          runtimeIgnoreTransformationRegistry) {
    super(
        ProcessType.HOST_CONTROLLER,
        runningModeControl,
        null,
        processState,
        rootResourceDefinition,
        prepareStepHandler,
        new RuntimeExpressionResolver(vaultReader));
    this.environment = environment;
    this.runningModeControl = runningModeControl;
    this.processState = processState;
    this.hostControllerInfo = hostControllerInfo;
    this.localFileRepository =
        new LocalFileRepository(
            environment.getDomainBaseDir(),
            environment.getDomainContentDir(),
            environment.getDomainConfigurationDir());

    this.remoteFileRepository = new RemoteFileRepository(localFileRepository);
    this.contentRepository = contentRepository;
    this.hostProxies = hostProxies;
    this.serverProxies = serverProxies;
    this.prepareStepHandler = prepareStepHandler;
    this.vaultReader = vaultReader;
    this.ignoredRegistry = ignoredRegistry;
    this.bootstrapListener = bootstrapListener;
    this.extensionRegistry = extensionRegistry;
    this.pathManager = pathManager;
    this.expressionResolver = expressionResolver;
    this.rootResourceDefinition = rootResourceDefinition;
    this.runtimeIgnoreTransformationRegistry = runtimeIgnoreTransformationRegistry;
  }

  @Override
  public RunningMode getCurrentRunningMode() {
    return runningModeControl.getRunningMode();
  }

  @Override
  public LocalHostControllerInfo getLocalHostInfo() {
    return hostControllerInfo;
  }

  @Override
  public void registerRemoteHost(
      final String hostName,
      final ManagementChannelHandler handler,
      final Transformers transformers,
      Long remoteConnectionId,
      DomainControllerRuntimeIgnoreTransformationEntry runtimeIgnoreTransformation)
      throws SlaveRegistrationException {
    if (!hostControllerInfo.isMasterDomainController()) {
      throw SlaveRegistrationException.forHostIsNotMaster();
    }

    if (runningModeControl.getRunningMode() == RunningMode.ADMIN_ONLY) {
      throw SlaveRegistrationException.forMasterInAdminOnlyMode(
          runningModeControl.getRunningMode());
    }

    final PathElement pe = PathElement.pathElement(ModelDescriptionConstants.HOST, hostName);
    final PathAddress addr = PathAddress.pathAddress(pe);
    ProxyController existingController = modelNodeRegistration.getProxyController(addr);

    if (existingController != null || hostControllerInfo.getLocalHostName().equals(pe.getValue())) {
      throw SlaveRegistrationException.forHostAlreadyExists(pe.getValue());
    }

    SlaveHostPinger pinger =
        remoteConnectionId == null
            ? null
            : new SlaveHostPinger(hostName, handler, pingScheduler, remoteConnectionId);
    hostRegistrationMap.put(hostName, new HostRegistration(remoteConnectionId, handler, pinger));

    // Create the proxy controller
    final TransformingProxyController hostControllerClient =
        TransformingProxyController.Factory.create(
            handler, transformers, addr, ProxyOperationAddressTranslator.HOST);

    modelNodeRegistration.registerProxyController(pe, hostControllerClient);
    runtimeIgnoreTransformationRegistry.registerHost(hostName, runtimeIgnoreTransformation);
    hostProxies.put(hostName, hostControllerClient);
    //        if (pinger != null) {
    //            pinger.schedulePing(SlaveHostPinger.STD_TIMEOUT, SlaveHostPinger.STD_INTERVAL);
    //        }
  }

  @Override
  public boolean isHostRegistered(String id) {
    return hostControllerInfo.getLocalHostName().equals(id) || hostRegistrationMap.containsKey(id);
  }

  @Override
  public void unregisterRemoteHost(String id, Long remoteConnectionId) {
    HostRegistration hostRegistration = hostRegistrationMap.get(id);
    if (hostRegistration != null) {
      if ((remoteConnectionId == null
              || remoteConnectionId.equals(hostRegistration.remoteConnectionId))
          && hostRegistrationMap.remove(id, hostRegistration)) {
        if (hostRegistration.pinger != null) {
          hostRegistration.pinger.cancel();
        }
        hostProxies.remove(id);
        runtimeIgnoreTransformationRegistry.unregisterHost(id);
        modelNodeRegistration.unregisterProxyController(PathElement.pathElement(HOST, id));
        DOMAIN_LOGGER.unregisteredRemoteSlaveHost(id);
      }
    }
  }

  @Override
  public void pingRemoteHost(String id) {
    HostRegistration reg = hostRegistrationMap.get(id);
    if (reg != null && reg.pinger != null && !reg.pinger.isCancelled()) {
      reg.pinger.schedulePing(SlaveHostPinger.SHORT_TIMEOUT, 0);
    }
  }

  @Override
  public void registerRunningServer(final ProxyController serverControllerClient) {
    PathAddress pa = serverControllerClient.getProxyNodeAddress();
    PathElement pe = pa.getElement(1);
    if (modelNodeRegistration.getProxyController(pa) != null) {
      throw MESSAGES.serverNameAlreadyRegistered(pe.getValue());
    }
    ROOT_LOGGER.registeringServer(pe.getValue());
    // Register the proxy
    final ManagementResourceRegistration hostRegistration =
        modelNodeRegistration.getSubModel(
            PathAddress.pathAddress(
                PathElement.pathElement(HOST, hostControllerInfo.getLocalHostName())));
    hostRegistration.registerProxyController(pe, serverControllerClient);
    // Register local operation overrides
    final ManagementResourceRegistration serverRegistration =
        hostRegistration.getSubModel(PathAddress.EMPTY_ADDRESS.append(pe));
    ServerConfigResourceDefinition.registerServerLifecycleOperations(
        serverRegistration, serverInventory);
    serverProxies.put(pe.getValue(), serverControllerClient);
  }

  @Override
  public void unregisterRunningServer(String serverName) {
    PathAddress pa =
        PathAddress.pathAddress(
            PathElement.pathElement(HOST, hostControllerInfo.getLocalHostName()));
    PathElement pe = PathElement.pathElement(RUNNING_SERVER, serverName);
    ROOT_LOGGER.unregisteringServer(serverName);
    ManagementResourceRegistration hostRegistration = modelNodeRegistration.getSubModel(pa);
    hostRegistration.unregisterProxyController(pe);
    serverProxies.remove(serverName);
  }

  @Override
  public ModelNode getProfileOperations(String profileName) {
    ModelNode operation = new ModelNode();

    operation.get(OP).set(DESCRIBE);
    operation
        .get(OP_ADDR)
        .set(PathAddress.pathAddress(PathElement.pathElement(PROFILE, profileName)).toModelNode());

    ModelNode rsp = getValue().execute(operation, null, null, null);
    if (!rsp.hasDefined(OUTCOME) || !SUCCESS.equals(rsp.get(OUTCOME).asString())) {
      ModelNode msgNode = rsp.get(FAILURE_DESCRIPTION);
      String msg =
          msgNode.isDefined() ? msgNode.toString() : MESSAGES.failedProfileOperationsRetrieval();
      throw new RuntimeException(msg);
    }
    return rsp.require(RESULT);
  }

  @Override
  public HostFileRepository getLocalFileRepository() {
    return localFileRepository;
  }

  @Override
  public HostFileRepository getRemoteFileRepository() {
    if (hostControllerInfo.isMasterDomainController()) {
      throw MESSAGES.cannotAccessRemoteFileRepository();
    }
    return remoteFileRepository;
  }

  @Override
  public void start(StartContext context) throws StartException {
    final ExecutorService executorService = getExecutorServiceInjector().getValue();
    this.hostControllerConfigurationPersister =
        new HostControllerConfigurationPersister(
            environment, hostControllerInfo, executorService, extensionRegistry);
    setConfigurationPersister(hostControllerConfigurationPersister);
    prepareStepHandler.setExecutorService(executorService);
    ThreadFactory threadFactory =
        new JBossThreadFactory(
            new ThreadGroup("proxy-threads"),
            Boolean.FALSE,
            null,
            "%G - %t",
            null,
            null,
            doPrivileged(GetAccessControlContextAction.getInstance()));
    proxyExecutor = Executors.newCachedThreadPool(threadFactory);
    ThreadFactory pingerThreadFactory =
        new JBossThreadFactory(
            new ThreadGroup("proxy-pinger-threads"),
            Boolean.TRUE,
            null,
            "%G - %t",
            null,
            null,
            doPrivileged(GetAccessControlContextAction.getInstance()));
    pingScheduler = Executors.newScheduledThreadPool(PINGER_POOL_SIZE, pingerThreadFactory);

    super.start(context);
  }

  @Override
  protected void initModel(Resource rootResource, ManagementResourceRegistration rootRegistration) {
    HostModelUtil.createRootRegistry(
        rootRegistration, environment, ignoredRegistry, this, processType);
    VersionModelInitializer.registerRootResource(
        rootResource, environment != null ? environment.getProductConfig() : null);
    this.modelNodeRegistration = rootRegistration;
  }

  // See superclass start. This method is invoked from a separate non-MSC thread after start. So we
  // can do a fair
  // bit of stuff
  @Override
  protected void boot(final BootContext context) throws ConfigurationPersistenceException {

    final ServiceTarget serviceTarget = context.getServiceTarget();
    boolean ok = false;
    boolean reachedServers = false;
    try {
      // Install server inventory callback
      ServerInventoryCallbackService.install(serviceTarget);

      // Parse the host.xml and invoke all the ops. The ops should rollback on any Stage.RUNTIME
      // failure
      // We run the first op ("add-host") separately to let it set up the host
      // ManagementResourceRegistration
      List<ModelNode> hostBootOps = hostControllerConfigurationPersister.load();
      ModelNode addHostOp = hostBootOps.remove(0);
      ok = boot(Collections.singletonList(addHostOp), true);
      ok = ok && boot(hostBootOps, true);

      final RunningMode currentRunningMode = runningModeControl.getRunningMode();

      if (ok) {

        // Now we know our discovery configuration.
        List<DiscoveryOption> discoveryOptions =
            hostControllerInfo.getRemoteDomainControllerDiscoveryOptions();
        if (hostControllerInfo.isMasterDomainController() && (discoveryOptions != null)) {
          // Install the discovery service
          DiscoveryService.install(
              serviceTarget,
              discoveryOptions,
              hostControllerInfo.getNativeManagementInterface(),
              hostControllerInfo.getNativeManagementPort(),
              hostControllerInfo.isMasterDomainController());
        }

        // Now we know our management interface configuration. Install the server inventory
        Future<ServerInventory> inventoryFuture =
            ServerInventoryService.install(
                serviceTarget,
                this,
                runningModeControl,
                environment,
                extensionRegistry,
                hostControllerInfo.getNativeManagementInterface(),
                hostControllerInfo.getNativeManagementPort());

        if (!hostControllerInfo.isMasterDomainController() && !environment.isUseCachedDc()) {
          serverInventory = getFuture(inventoryFuture);

          if ((discoveryOptions != null) && !discoveryOptions.isEmpty()) {
            Future<MasterDomainControllerClient> clientFuture =
                RemoteDomainConnectionService.install(
                    serviceTarget,
                    getValue(),
                    extensionRegistry,
                    hostControllerInfo,
                    environment.getProductConfig(),
                    hostControllerInfo.getRemoteDomainControllerSecurityRealm(),
                    remoteFileRepository,
                    ignoredRegistry,
                    new InternalExecutor(),
                    this,
                    environment);
            MasterDomainControllerClient masterDomainControllerClient = getFuture(clientFuture);
            // Registers us with the master and gets down the master copy of the domain model to our
            // DC
            // TODO make sure that the RDCS checks env.isUseCachedDC, and if true falls through to
            // that
            // BES 2012/02/04 Comment ^^^ implies the semantic is to use isUseCachedDC as a fallback
            // to
            // a failure to connect as opposed to being an instruction to not connect at all. I
            // believe
            // the current impl is the latter. Don't change this without a discussion first, as the
            // current semantic is a reasonable one.
            try {
              masterDomainControllerClient.register();
            } catch (Exception e) {
              // We could not connect to the host
              ROOT_LOGGER.cannotConnectToMaster(e);
              System.exit(ExitCodes.HOST_CONTROLLER_ABORT_EXIT_CODE);
            }
          } else if (currentRunningMode != RunningMode.ADMIN_ONLY) {
            // Invalid configuration; no way to get the domain config
            ROOT_LOGGER.noDomainControllerConfigurationProvided(
                currentRunningMode, CommandLineConstants.ADMIN_ONLY, RunningMode.ADMIN_ONLY);
            System.exit(ExitCodes.HOST_CONTROLLER_ABORT_EXIT_CODE);
          }

        } else {

          if (environment.isUseCachedDc()) {
            remoteFileRepository.setRemoteFileRepositoryExecutor(
                new RemoteDomainConnectionService.RemoteFileRepositoryExecutor() {
                  @Override
                  public File getFile(
                      String relativePath, byte repoId, HostFileRepository localFileRepository) {
                    return localFileRepository.getFile(relativePath);
                  }
                });
          }

          // parse the domain.xml and load the steps
          // TODO look at having LocalDomainControllerAdd do this, using Stage.IMMEDIATE for the
          // steps
          ConfigurationPersister domainPersister =
              hostControllerConfigurationPersister.getDomainPersister();
          ok = boot(domainPersister.load(), false);

          if (!ok && runningModeControl.getRunningMode().equals(RunningMode.ADMIN_ONLY)) {
            ROOT_LOGGER.reportAdminOnlyDomainXmlFailure();
            ok = true;
          }

          if (ok) {
            InternalExecutor executor = new InternalExecutor();
            ManagementRemotingServices.installManagementChannelServices(
                serviceTarget,
                ManagementRemotingServices.MANAGEMENT_ENDPOINT,
                new MasterDomainControllerOperationHandlerService(
                    this, executor, executor, runtimeIgnoreTransformationRegistry),
                DomainModelControllerService.SERVICE_NAME,
                ManagementRemotingServices.DOMAIN_CHANNEL,
                null,
                null);
            serverInventory = getFuture(inventoryFuture);
          }
        }
      }

      if (ok) {
        // Install the server > host operation handler
        ServerToHostOperationHandlerFactoryService.install(
            serviceTarget,
            ServerInventoryService.SERVICE_NAME,
            proxyExecutor,
            new InternalExecutor(),
            this,
            expressionResolver);

        // demand native mgmt services
        serviceTarget
            .addService(ServiceName.JBOSS.append("native-mgmt-startup"), Service.NULL)
            .addDependency(
                ManagementRemotingServices.channelServiceName(
                    ManagementRemotingServices.MANAGEMENT_ENDPOINT,
                    ManagementRemotingServices.SERVER_CHANNEL))
            .setInitialMode(ServiceController.Mode.ACTIVE)
            .install();

        // demand http mgmt services
        serviceTarget
            .addService(ServiceName.JBOSS.append("http-mgmt-startup"), Service.NULL)
            .addDependency(
                ServiceBuilder.DependencyType.OPTIONAL, _UndertowHttpManagementService.SERVICE_NAME)
            .setInitialMode(ServiceController.Mode.ACTIVE)
            .install();

        reachedServers = true;
        if (currentRunningMode == RunningMode.NORMAL) {
          startServers();
        }
      }

    } catch (Exception e) {
      ROOT_LOGGER.caughtExceptionDuringBoot(e);
      if (!reachedServers) {
        ok = false;
      }
    } finally {
      if (ok) {
        try {
          finishBoot();
        } finally {
          // Trigger the started message
          bootstrapListener.printBootStatistics();
        }
      } else {
        // Die!
        ROOT_LOGGER.unsuccessfulBoot();
        System.exit(ExitCodes.HOST_CONTROLLER_ABORT_EXIT_CODE);
      }
    }
  }

  private <T> T getFuture(Future<T> future) {
    try {
      return future.get();
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      throw new RuntimeException(e);
    } catch (ExecutionException e) {
      throw new RuntimeException(e);
    }
  }

  private void startServers() {
    ModelNode addr = new ModelNode();
    addr.add(HOST, hostControllerInfo.getLocalHostName());
    ModelNode op = Util.getEmptyOperation(StartServersHandler.OPERATION_NAME, addr);

    getValue().execute(op, null, null, null);
  }

  @Override
  public void stop(final StopContext context) {
    serverInventory = null;
    extensionRegistry.clear();
    super.stop(context);

    context.asynchronous();
    Thread executorShutdown =
        new Thread(
            new Runnable() {
              @Override
              public void run() {
                try {
                  pingScheduler.shutdownNow();
                } finally {
                  try {
                    proxyExecutor.shutdown();
                  } finally {
                    context.complete();
                  }
                }
              }
            },
            DomainModelControllerService.class.getSimpleName()
                + " ExecutorService Shutdown Thread");
    executorShutdown.start();
  }

  @Override
  public void stopLocalHost() {
    stopLocalHost(0);
  }

  @Override
  public void stopLocalHost(int exitCode) {
    final ProcessControllerClient client =
        injectedProcessControllerConnection.getValue().getClient();
    processState.setStopping();
    try {
      client.shutdown(exitCode);
    } catch (IOException e) {
      throw MESSAGES.errorClosingDownHost(e);
    }
  }

  @Override
  public void registerHostModel(String hostName, ManagementResourceRegistration root) {
    HostModelUtil.createHostRegistry(
        hostName,
        root,
        hostControllerConfigurationPersister,
        environment,
        runningModeControl,
        localFileRepository,
        hostControllerInfo,
        new DelegatingServerInventory(),
        remoteFileRepository,
        contentRepository,
        this,
        extensionRegistry,
        vaultReader,
        ignoredRegistry,
        processState,
        pathManager);
  }

  public void initializeMasterDomainRegistry(
      final ManagementResourceRegistration root,
      final ExtensibleConfigurationPersister configurationPersister,
      final ContentRepository contentRepository,
      final HostFileRepository fileRepository,
      final ExtensionRegistry extensionRegistry,
      final PathManagerService pathManager) {
    initializeDomainResource(
        root,
        configurationPersister,
        contentRepository,
        fileRepository,
        true,
        hostControllerInfo,
        extensionRegistry,
        null,
        pathManager);
  }

  public void initializeSlaveDomainRegistry(
      final ManagementResourceRegistration root,
      final ExtensibleConfigurationPersister configurationPersister,
      final ContentRepository contentRepository,
      final HostFileRepository fileRepository,
      final LocalHostControllerInfo hostControllerInfo,
      final ExtensionRegistry extensionRegistry,
      final IgnoredDomainResourceRegistry ignoredDomainResourceRegistry,
      final PathManagerService pathManagery) {
    initializeDomainResource(
        root,
        configurationPersister,
        contentRepository,
        fileRepository,
        false,
        hostControllerInfo,
        extensionRegistry,
        ignoredDomainResourceRegistry,
        pathManager);
  }

  private void initializeDomainResource(
      final ManagementResourceRegistration root,
      final ExtensibleConfigurationPersister configurationPersister,
      final ContentRepository contentRepo,
      final HostFileRepository fileRepository,
      final boolean isMaster,
      final LocalHostControllerInfo hostControllerInfo,
      final ExtensionRegistry extensionRegistry,
      final IgnoredDomainResourceRegistry ignoredDomainResourceRegistry,
      final PathManagerService pathManager) {

    DomainRootDefinition domainRootDefinition =
        new DomainRootDefinition(
            this,
            environment,
            configurationPersister,
            contentRepo,
            fileRepository,
            isMaster,
            hostControllerInfo,
            extensionRegistry,
            ignoredDomainResourceRegistry,
            pathManager,
            isMaster ? runtimeIgnoreTransformationRegistry : null);
    rootResourceDefinition.setDelegate(domainRootDefinition, root);
  }

  private static class HostRegistration {
    private final Long remoteConnectionId;
    private final ManagementChannelHandler channelHandler;
    private final SlaveHostPinger pinger;

    private HostRegistration(
        Long remoteConnectionId, ManagementChannelHandler channelHandler, SlaveHostPinger pinger) {
      this.remoteConnectionId = remoteConnectionId;
      this.channelHandler = channelHandler;
      this.pinger = pinger;
    }

    @Override
    public int hashCode() {
      return remoteConnectionId == null ? Integer.MIN_VALUE : channelHandler.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
      return obj instanceof HostRegistration
          && safeEquals(remoteConnectionId, ((HostRegistration) obj).remoteConnectionId);
    }

    private static boolean safeEquals(Object a, Object b) {
      return a == b || (a != null && a.equals(b));
    }
  }

  private class DelegatingServerInventory implements ServerInventory {
    public ProxyController serverCommunicationRegistered(
        String serverProcessName, ManagementChannelHandler channelHandler) {
      return serverInventory.serverCommunicationRegistered(serverProcessName, channelHandler);
    }

    public boolean serverReconnected(
        String serverProcessName, ManagementChannelHandler channelHandler) {
      return serverInventory.serverReconnected(serverProcessName, channelHandler);
    }

    public void serverProcessAdded(String serverProcessName) {
      serverInventory.serverProcessAdded(serverProcessName);
    }

    public void serverStartFailed(String serverProcessName) {
      serverInventory.serverStartFailed(serverProcessName);
    }

    @Override
    public void serverStarted(String serverProcessName) {
      serverInventory.serverStarted(serverProcessName);
    }

    public void serverProcessStopped(String serverProcessName) {
      serverInventory.serverProcessStopped(serverProcessName);
    }

    public String getServerProcessName(String serverName) {
      return serverInventory.getServerProcessName(serverName);
    }

    public String getProcessServerName(String processName) {
      return serverInventory.getProcessServerName(processName);
    }

    @Override
    public ServerStatus reloadServer(String serverName, boolean blocking) {
      return serverInventory.reloadServer(serverName, blocking);
    }

    public void processInventory(Map<String, ProcessInfo> processInfos) {
      serverInventory.processInventory(processInfos);
    }

    public Map<String, ProcessInfo> determineRunningProcesses() {
      return serverInventory.determineRunningProcesses();
    }

    public Map<String, ProcessInfo> determineRunningProcesses(boolean serversOnly) {
      return serverInventory.determineRunningProcesses(serversOnly);
    }

    public ServerStatus determineServerStatus(String serverName) {
      return serverInventory.determineServerStatus(serverName);
    }

    public ServerStatus startServer(String serverName, ModelNode domainModel) {
      return serverInventory.startServer(serverName, domainModel);
    }

    @Override
    public ServerStatus startServer(String serverName, ModelNode domainModel, boolean blocking) {
      return serverInventory.startServer(serverName, domainModel, blocking);
    }

    public void reconnectServer(
        String serverName,
        ModelNode domainModel,
        byte[] authKey,
        boolean running,
        boolean stopping) {
      serverInventory.reconnectServer(serverName, domainModel, authKey, running, stopping);
    }

    public ServerStatus restartServer(
        String serverName, int gracefulTimeout, ModelNode domainModel) {
      return serverInventory.restartServer(serverName, gracefulTimeout, domainModel);
    }

    @Override
    public ServerStatus restartServer(
        String serverName, int gracefulTimeout, ModelNode domainModel, boolean blocking) {
      return serverInventory.restartServer(serverName, gracefulTimeout, domainModel, blocking);
    }

    public ServerStatus stopServer(String serverName, int gracefulTimeout) {
      return serverInventory.stopServer(serverName, gracefulTimeout);
    }

    @Override
    public ServerStatus stopServer(String serverName, int gracefulTimeout, boolean blocking) {
      return serverInventory.stopServer(serverName, gracefulTimeout, blocking);
    }

    public CallbackHandler getServerCallbackHandler() {
      return serverInventory.getServerCallbackHandler();
    }

    @Override
    public void stopServers(int gracefulTimeout) {
      serverInventory.stopServers(gracefulTimeout);
    }

    @Override
    public void stopServers(int gracefulTimeout, boolean blockUntilStopped) {
      serverInventory.stopServers(gracefulTimeout, blockUntilStopped);
    }

    @Override
    public void connectionFinished() {
      serverInventory.connectionFinished();
    }

    @Override
    public void serverProcessStarted(String processName) {
      serverInventory.serverProcessStarted(processName);
    }

    @Override
    public void serverProcessRemoved(String processName) {
      serverInventory.serverProcessRemoved(processName);
    }

    @Override
    public void operationFailed(String processName, ProcessMessageHandler.OperationType type) {
      serverInventory.operationFailed(processName, type);
    }

    @Override
    public void destroyServer(String serverName) {
      serverInventory.destroyServer(serverName);
    }

    @Override
    public void killServer(String serverName) {
      serverInventory.killServer(serverName);
    }

    @Override
    public void awaitServersState(Collection<String> serverNames, boolean started) {
      serverInventory.awaitServersState(serverNames, started);
    }
  }

  private static <S> S service(final Class<S> service) {
    final ServiceLoader<S> serviceLoader = ServiceLoader.load(service);
    final Iterator<S> it = serviceLoader.iterator();
    if (it.hasNext()) return it.next();
    return null;
  }

  @Override
  public ExtensionRegistry getExtensionRegistry() {
    return extensionRegistry;
  }

  @Override
  public ExpressionResolver getExpressionResolver() {
    return expressionResolver;
  }

  private static class DelegatingResourceDefinition implements ResourceDefinition {
    private volatile ResourceDefinition delegate;

    void setDelegate(DomainRootDefinition delegate, ManagementResourceRegistration root) {
      this.delegate = delegate;
      delegate.initialize(root);
    }

    @Override
    public void registerOperations(ManagementResourceRegistration resourceRegistration) {
      // These will be registered later
    }

    @Override
    public void registerChildren(ManagementResourceRegistration resourceRegistration) {
      // These will be registered later
    }

    @Override
    public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
      // These will be registered later
    }

    @Override
    public PathElement getPathElement() {
      return delegate.getPathElement();
    }

    @Override
    public DescriptionProvider getDescriptionProvider(
        ImmutableManagementResourceRegistration resourceRegistration) {
      return delegate.getDescriptionProvider(resourceRegistration);
    }
  }

  final class InternalExecutor
      implements HostControllerRegistrationHandler.OperationExecutor,
          ServerToHostProtocolHandler.OperationExecutor,
          MasterDomainControllerOperationHandlerService.TransactionalOperationExecutor {

    @Override
    public ModelNode execute(
        final ModelNode operation,
        final OperationMessageHandler handler,
        final ModelController.OperationTransactionControl control,
        final OperationAttachments attachments,
        final OperationStepHandler step) {
      return internalExecute(operation, handler, control, attachments, step);
    }

    @Override
    @SuppressWarnings("deprecation")
    public ModelNode joinActiveOperation(
        ModelNode operation,
        OperationMessageHandler handler,
        ModelController.OperationTransactionControl control,
        OperationAttachments attachments,
        OperationStepHandler step,
        int permit) {
      return executeReadOnlyOperation(operation, handler, control, attachments, step, permit);
    }

    @Override
    public ModelNode executeAndAttemptLock(
        final ModelNode operation,
        final OperationMessageHandler handler,
        final ModelController.OperationTransactionControl control,
        final OperationAttachments attachments,
        final OperationStepHandler step) {
      return internalExecute(operation, handler, control, attachments, step, true);
    }
  };
}
コード例 #2
0
/**
 * Creates the service that acts as the {@link org.jboss.as.controller.ModelController} for a Host
 * Controller process.
 *
 * @author Brian Stansberry (c) 2011 Red Hat Inc.
 */
public class DomainModelControllerService extends AbstractControllerService
    implements DomainController, UnregisteredHostChannelRegistry {

  private static final Logger log = Logger.getLogger("org.jboss.as.host.controller");

  public static final ServiceName SERVICE_NAME =
      HostControllerService.HC_SERVICE_NAME.append("model", "controller");

  private HostControllerConfigurationPersister hostControllerConfigurationPersister;
  private final HostControllerEnvironment environment;
  private final RunningModeControl runningModeControl;
  private final LocalHostControllerInfoImpl hostControllerInfo;
  private final FileRepository localFileRepository;
  private final RemoteFileRepository remoteFileRepository;
  private final InjectedValue<ProcessControllerConnectionService>
      injectedProcessControllerConnection = new InjectedValue<ProcessControllerConnectionService>();
  private final Map<String, ProxyController> hostProxies;
  private final Map<String, ProxyController> serverProxies;
  private final PrepareStepHandler prepareStepHandler;
  private final BootstrapListener bootstrapListener;
  private ManagementResourceRegistration modelNodeRegistration;

  private final Map<String, Channel> unregisteredHostChannels = new HashMap<String, Channel>();
  private final Map<String, ProxyCreatedCallback> proxyCreatedCallbacks =
      new HashMap<String, ProxyCreatedCallback>();
  // TODO look into using the controller executor
  private final ExecutorService proxyExecutor = Executors.newCachedThreadPool();
  private final AbstractVaultReader vaultReader;

  private volatile ServerInventory serverInventory;

  public static ServiceController<ModelController> addService(
      final ServiceTarget serviceTarget,
      final HostControllerEnvironment environment,
      final RunningModeControl runningModeControl,
      final ControlledProcessState processState,
      final BootstrapListener bootstrapListener) {
    final Map<String, ProxyController> hostProxies =
        new ConcurrentHashMap<String, ProxyController>();
    final Map<String, ProxyController> serverProxies =
        new ConcurrentHashMap<String, ProxyController>();
    final LocalHostControllerInfoImpl hostControllerInfo =
        new LocalHostControllerInfoImpl(processState);
    final AbstractVaultReader vaultReader = service(AbstractVaultReader.class);
    log.debugf("Using VaultReader %s", vaultReader);
    final PrepareStepHandler prepareStepHandler =
        new PrepareStepHandler(hostControllerInfo, hostProxies, serverProxies);
    DomainModelControllerService service =
        new DomainModelControllerService(
            environment,
            runningModeControl,
            processState,
            hostControllerInfo,
            hostProxies,
            serverProxies,
            prepareStepHandler,
            vaultReader,
            bootstrapListener);
    return serviceTarget
        .addService(SERVICE_NAME, service)
        .addDependency(
            HostControllerService.HC_EXECUTOR_SERVICE_NAME,
            ExecutorService.class,
            service.getExecutorServiceInjector())
        .addDependency(
            ProcessControllerConnectionService.SERVICE_NAME,
            ProcessControllerConnectionService.class,
            service.injectedProcessControllerConnection)
        .setInitialMode(ServiceController.Mode.ACTIVE)
        .install();
  }

  private DomainModelControllerService(
      final HostControllerEnvironment environment,
      final RunningModeControl runningModeControl,
      final ControlledProcessState processState,
      final LocalHostControllerInfoImpl hostControllerInfo,
      final Map<String, ProxyController> hostProxies,
      final Map<String, ProxyController> serverProxies,
      final PrepareStepHandler prepareStepHandler,
      final AbstractVaultReader vaultReader,
      final BootstrapListener bootstrapListener) {
    super(
        ProcessType.HOST_CONTROLLER,
        runningModeControl,
        null,
        processState,
        DomainDescriptionProviders.ROOT_PROVIDER,
        prepareStepHandler,
        new RuntimeExpressionResolver(vaultReader));
    this.environment = environment;
    this.runningModeControl = runningModeControl;
    this.hostControllerInfo = hostControllerInfo;
    this.localFileRepository = new LocalFileRepository(environment);
    this.remoteFileRepository = new RemoteFileRepository(localFileRepository);
    this.hostProxies = hostProxies;
    this.serverProxies = serverProxies;
    this.prepareStepHandler = prepareStepHandler;
    this.vaultReader = vaultReader;
    this.bootstrapListener = bootstrapListener;
  }

  @Override
  public LocalHostControllerInfo getLocalHostInfo() {
    return hostControllerInfo;
  }

  @Override
  public void registerRemoteHost(ProxyController hostControllerClient)
      throws SlaveRegistrationException {
    if (!hostControllerInfo.isMasterDomainController()) {
      throw SlaveRegistrationException.forHostIsNotMaster();
    }

    if (runningModeControl.getRunningMode() == RunningMode.ADMIN_ONLY) {
      throw SlaveRegistrationException.forMasterInAdminOnlyMode(
          runningModeControl.getRunningMode());
    }
    PathAddress pa = hostControllerClient.getProxyNodeAddress();
    PathElement pe = pa.getElement(0);
    ProxyController existingController = modelNodeRegistration.getProxyController(pa);

    if (existingController != null || hostControllerInfo.getLocalHostName().equals(pe.getValue())) {
      throw SlaveRegistrationException.forHostAlreadyExists(pe.getValue());
    }
    modelNodeRegistration.registerProxyController(pe, hostControllerClient);
    hostProxies.put(pe.getValue(), hostControllerClient);

    Logger.getLogger("org.jboss.domain").info("Registered remote slave host " + pe.getValue());
  }

  @Override
  public void unregisterRemoteHost(String id) {
    unregisteredHostChannels.remove(id);
    if (hostProxies.remove(id) != null) {
      Logger.getLogger("org.jboss.domain").info("Unregistered remote slave host " + id);
    }
    modelNodeRegistration.unregisterProxyController(PathElement.pathElement(HOST, id));
  }

  @Override
  public void registerRunningServer(ProxyController serverControllerClient) {
    PathAddress pa = serverControllerClient.getProxyNodeAddress();
    PathElement pe = pa.getElement(1);
    if (modelNodeRegistration.getProxyController(pa) != null) {
      throw new IllegalArgumentException(
          "There is already a registered server named '" + pe.getValue() + "'");
    }
    Logger.getLogger("org.jboss.host.controller").info("Registering server " + pe.getValue());
    ManagementResourceRegistration hostRegistration =
        modelNodeRegistration.getSubModel(PathAddress.pathAddress(PathElement.pathElement(HOST)));
    hostRegistration.registerProxyController(pe, serverControllerClient);
    serverProxies.put(pe.getValue(), serverControllerClient);
  }

  @Override
  public void unregisterRunningServer(String serverName) {
    PathAddress pa =
        PathAddress.pathAddress(
            PathElement.pathElement(HOST, hostControllerInfo.getLocalHostName()));
    PathElement pe = PathElement.pathElement(RUNNING_SERVER, serverName);
    Logger.getLogger("org.jboss.host.controller").info("Unregistering server " + serverName);
    ManagementResourceRegistration hostRegistration = modelNodeRegistration.getSubModel(pa);
    hostRegistration.unregisterProxyController(pe);
    serverProxies.remove(serverName);
  }

  @Override
  public ModelNode getProfileOperations(String profileName) {
    ModelNode operation = new ModelNode();

    operation.get(OP).set(DESCRIBE);
    operation
        .get(OP_ADDR)
        .set(PathAddress.pathAddress(PathElement.pathElement(PROFILE, profileName)).toModelNode());

    ModelNode rsp = getValue().execute(operation, null, null, null);
    if (!rsp.hasDefined(OUTCOME) || !SUCCESS.equals(rsp.get(OUTCOME).asString())) {
      ModelNode msgNode = rsp.get(FAILURE_DESCRIPTION);
      String msg =
          msgNode.isDefined()
              ? msgNode.toString()
              : "Failed to retrieve profile operations from domain controller";
      throw new RuntimeException(msg);
    }
    return rsp.require(RESULT);
  }

  @Override
  public FileRepository getLocalFileRepository() {
    return localFileRepository;
  }

  @Override
  public FileRepository getRemoteFileRepository() {
    if (hostControllerInfo.isMasterDomainController()) {
      throw new IllegalStateException(
          "Cannot access a remote file repository from the master domain controller");
    }
    return remoteFileRepository;
  }

  @Override
  public void start(StartContext context) throws StartException {
    final ExecutorService executorService = getExecutorServiceInjector().getValue();
    this.hostControllerConfigurationPersister =
        new HostControllerConfigurationPersister(environment, hostControllerInfo, executorService);
    setConfigurationPersister(hostControllerConfigurationPersister);
    prepareStepHandler.setExecutorService(executorService);
    super.start(context);
  }

  @Override
  protected void initModel(Resource rootResource, ManagementResourceRegistration rootRegistration) {
    DomainModelUtil.updateCoreModel(rootResource.getModel());
    HostModelUtil.createHostRegistry(
        rootRegistration,
        hostControllerConfigurationPersister,
        environment,
        runningModeControl,
        localFileRepository,
        hostControllerInfo,
        new DelegatingServerInventory(),
        remoteFileRepository,
        this,
        this,
        vaultReader);
    this.modelNodeRegistration = rootRegistration;
  }

  // See superclass start. This method is invoked from a separate non-MSC thread after start. So we
  // can do a fair
  // bit of stuff
  @Override
  protected void boot(final BootContext context) throws ConfigurationPersistenceException {

    final ServiceTarget serviceTarget = context.getServiceTarget();
    try {
      super.boot(
          hostControllerConfigurationPersister
              .load()); // This parses the host.xml and invokes all ops

      final RunningMode currentRunningMode = runningModeControl.getRunningMode();

      // Now we know our management interface configuration. Install the server inventory
      Future<ServerInventory> inventoryFuture =
          ServerInventoryService.install(
              serviceTarget,
              this,
              environment,
              hostControllerInfo.getNativeManagementInterface(),
              hostControllerInfo.getNativeManagementPort());

      // Install the core remoting endpoint and listener
      ManagementRemotingServices.installRemotingEndpoint(
          serviceTarget,
          ManagementRemotingServices.MANAGEMENT_ENDPOINT,
          hostControllerInfo.getLocalHostName(),
          EndpointService.EndpointType.MANAGEMENT,
          null,
          null);

      if (!hostControllerInfo.isMasterDomainController() && !environment.isUseCachedDc()) {
        serverInventory = getFuture(inventoryFuture);

        if (hostControllerInfo.getRemoteDomainControllerHost() != null) {
          Future<MasterDomainControllerClient> clientFuture =
              RemoteDomainConnectionService.install(
                  serviceTarget,
                  getValue(),
                  hostControllerInfo.getLocalHostName(),
                  hostControllerInfo.getRemoteDomainControllerHost(),
                  hostControllerInfo.getRemoteDomainControllertPort(),
                  hostControllerInfo.getRemoteDomainControllerSecurityRealm(),
                  remoteFileRepository);
          MasterDomainControllerClient masterDomainControllerClient = getFuture(clientFuture);
          // Registers us with the master and gets down the master copy of the domain model to our
          // DC
          // TODO make sure that the RDCS checks env.isUseCachedDC, and if true falls through to
          // that
          try {
            masterDomainControllerClient.register();
          } catch (IllegalStateException e) {
            // We could not connect to the host
            log.error(HostControllerMessages.MESSAGES.cannotConnectToMaster(e));
            System.exit(ExitCodes.HOST_CONTROLLER_ABORT_EXIT_CODE);
          }
        } else if (currentRunningMode != RunningMode.ADMIN_ONLY) {
          // We could not connect to the host
          log.error(
              HostControllerMessages.MESSAGES.noDomainControllerConfigurationProvided(
                  currentRunningMode, CommandLineConstants.ADMIN_ONLY, RunningMode.ADMIN_ONLY));
          System.exit(ExitCodes.HOST_CONTROLLER_ABORT_EXIT_CODE);
        }

      } else {
        // TODO look at having LocalDomainControllerAdd do this, using Stage.IMMEDIATE for the steps
        // parse the domain.xml and load the steps
        ConfigurationPersister domainPersister =
            hostControllerConfigurationPersister.getDomainPersister();
        super.boot(domainPersister.load());

        ManagementRemotingServices.installManagementChannelServices(
            serviceTarget,
            ManagementRemotingServices.MANAGEMENT_ENDPOINT,
            new MasterDomainControllerOperationHandlerService(this, this),
            DomainModelControllerService.SERVICE_NAME,
            ManagementRemotingServices.DOMAIN_CHANNEL,
            null,
            null);
        serverInventory = getFuture(inventoryFuture);
      }

      // TODO look into adding some of these services in the handlers, but ON-DEMAND.
      // Then here just add some simple service that demands them

      ServerToHostOperationHandlerFactoryService.install(
          serviceTarget, ServerInventoryService.SERVICE_NAME, proxyExecutor);

      NativeManagementAddHandler.installNativeManagementServices(
          serviceTarget, hostControllerInfo, null, null);

      if (hostControllerInfo.getHttpManagementInterface() != null) {
        HttpManagementAddHandler.installHttpManagementServices(
            serviceTarget, hostControllerInfo, environment, null);
      }

      if (currentRunningMode == RunningMode.NORMAL) {
        startServers();
      }

      // TODO when to call hostControllerConfigurationPersister.successful boot? Look into this for
      // standalone as well; may be broken now
    } finally {
      try {
        finishBoot();
      } finally {
        bootstrapListener.tick();
      }
    }
  }

  private <T> T getFuture(Future<T> future) {
    try {
      return future.get();
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      throw new RuntimeException(e);
    } catch (ExecutionException e) {
      throw new RuntimeException(e);
    }
  }

  private void startServers() {
    ModelNode addr = new ModelNode();
    addr.add(HOST, hostControllerInfo.getLocalHostName());
    ModelNode op = Util.getEmptyOperation(StartServersHandler.OPERATION_NAME, addr);

    getValue().execute(op, null, null, null);
  }

  @Override
  public void stop(StopContext context) {
    serverInventory = null;
    super.stop(context);
  }

  @Override
  public void stopLocalHost() {
    final ProcessControllerClient client =
        injectedProcessControllerConnection.getValue().getClient();
    try {
      client.shutdown();
    } catch (IOException e) {
      throw new RuntimeException("Error closing down host", e);
    }
  }

  @Override
  public synchronized void registerChannel(
      final String hostName, final Channel channel, final ProxyCreatedCallback callback) {

    /* Disable this as part of the REM3-121 workarounds
    PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(HOST, hostName));
    if (modelNodeRegistration.getProxyController(addr) != null) {
        throw new IllegalArgumentException("There is already a registered slave named '" + hostName + "'");
    }
    */
    if (unregisteredHostChannels.containsKey(hostName)) {
      throw new IllegalArgumentException("Already have a connection for host " + hostName);
    }
    unregisteredHostChannels.put(hostName, channel);
    proxyCreatedCallbacks.put(hostName, callback);
    channel.addCloseHandler(
        new CloseHandler<Channel>() {
          public void handleClose(final Channel closed, final IOException exception) {
            unregisteredHostChannels.remove(hostName);
            proxyCreatedCallbacks.remove(hostName);
          }
        });
  }

  @Override
  public synchronized ProxyController popChannelAndCreateProxy(final String hostName) {
    final Channel channel = unregisteredHostChannels.remove(hostName);
    if (channel == null) {
      throw new IllegalArgumentException("No channel for host " + hostName);
    }
    channel.addCloseHandler(
        new CloseHandler<Channel>() {
          public void handleClose(final Channel closed, final IOException exception) {
            unregisterRemoteHost(hostName);
          }
        });
    final PathAddress addr =
        PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.HOST, hostName));
    RemoteProxyController proxy =
        RemoteProxyController.create(
            proxyExecutor, addr, ProxyOperationAddressTranslator.HOST, channel);
    ProxyCreatedCallback callback = proxyCreatedCallbacks.remove(hostName);
    if (callback != null) {
      callback.proxyCreated(proxy);
    }
    return proxy;
  }

  private class DelegatingServerInventory implements ServerInventory {
    public void serverRegistered(
        String serverProcessName, Channel channel, ProxyCreatedCallback callback) {
      serverInventory.serverRegistered(serverProcessName, channel, callback);
    }

    public void serverStartFailed(String serverProcessName) {
      serverInventory.serverStartFailed(serverProcessName);
    }

    public void serverStopped(String serverProcessName) {
      serverInventory.serverStopped(serverProcessName);
    }

    public String getServerProcessName(String serverName) {
      return serverInventory.getServerProcessName(serverName);
    }

    public String getProcessServerName(String processName) {
      return serverInventory.getProcessServerName(processName);
    }

    public void processInventory(Map<String, ProcessInfo> processInfos) {
      serverInventory.processInventory(processInfos);
    }

    public Map<String, ProcessInfo> determineRunningProcesses() {
      return serverInventory.determineRunningProcesses();
    }

    public Map<String, ProcessInfo> determineRunningProcesses(boolean serversOnly) {
      return serverInventory.determineRunningProcesses(serversOnly);
    }

    public ServerStatus determineServerStatus(String serverName) {
      return serverInventory.determineServerStatus(serverName);
    }

    public int hashCode() {
      return serverInventory.hashCode();
    }

    public ServerStatus startServer(String serverName, ModelNode domainModel) {
      return serverInventory.startServer(serverName, domainModel);
    }

    public void reconnectServer(String serverName, ModelNode domainModel, boolean running) {
      serverInventory.reconnectServer(serverName, domainModel, running);
    }

    public ServerStatus restartServer(
        String serverName, int gracefulTimeout, ModelNode domainModel) {
      return serverInventory.restartServer(serverName, gracefulTimeout, domainModel);
    }

    public ServerStatus stopServer(String serverName, int gracefulTimeout) {
      return serverInventory.stopServer(serverName, gracefulTimeout);
    }

    public CallbackHandler getServerCallbackHandler() {
      return serverInventory.getServerCallbackHandler();
    }

    public boolean equals(Object obj) {
      return serverInventory.equals(obj);
    }

    public String toString() {
      return serverInventory.toString();
    }

    @Override
    public void stopServers(int gracefulTimeout) {
      serverInventory.stopServers(gracefulTimeout);
    }
  }

  private static <S> S service(final Class<S> service) {
    final ServiceLoader<S> serviceLoader = ServiceLoader.load(service);
    final Iterator<S> it = serviceLoader.iterator();
    if (it.hasNext()) return it.next();
    return null;
  }
}