StartServiceInfo(String service, String value, String[] serverArgs) {
      name = service;

      //
      // Separate the entry point from the arguments.
      //
      int pos = IceUtilInternal.StringUtil.findFirstOf(value, " \t\n");
      if (pos == -1) {
        className = value;
        args = new String[0];
      } else {
        className = value.substring(0, pos);
        try {
          args = IceUtilInternal.Options.split(value.substring(pos));
        } catch (IceUtilInternal.Options.BadQuote ex) {
          FailureException e = new FailureException();
          e.reason =
              "ServiceManager: invalid arguments for service `" + name + "':\n" + ex.toString();
          throw e;
        }
      }

      if (serverArgs.length > 0) {
        java.util.List<String> l = new java.util.ArrayList<String>(java.util.Arrays.asList(args));
        for (String arg : serverArgs) {
          if (arg.startsWith("--" + service + ".")) {
            l.add(arg);
          }
        }
        args = l.toArray(args);
      }
    }
  private synchronized void start(String service, String className, String[] args)
      throws FailureException {
    //
    // Instantiate the class.
    //
    ServiceInfo info = new ServiceInfo();
    info.name = service;
    info.status = StatusStopped;
    info.args = args;
    try {
      Class<?> c = IceInternal.Util.findClass(className, null);
      if (c == null) {
        FailureException e = new FailureException();
        e.reason = "ServiceManager: class " + className + " not found";
        throw e;
      }
      java.lang.Object obj = c.newInstance();
      try {
        info.service = (Service) obj;
      } catch (ClassCastException ex) {
        FailureException e = new FailureException();
        e.reason = "ServiceManager: class " + className + " does not implement IceBox.Service";
        throw e;
      }
    } catch (IllegalAccessException ex) {
      FailureException e = new FailureException();
      e.reason = "ServiceManager: unable to access default constructor in class " + className;
      e.initCause(ex);
      throw e;
    } catch (InstantiationException ex) {
      FailureException e = new FailureException();
      e.reason = "ServiceManager: unable to instantiate class " + className;
      e.initCause(ex);
      throw e;
    }

    //
    // Invoke Service::start().
    //
    try {
      //
      // If Ice.UseSharedCommunicator.<name> is defined, create a
      // communicator for the service. The communicator inherits
      // from the shared communicator properties. If it's not
      // defined, add the service properties to the shared
      // commnunicator property set.
      //
      Ice.Communicator communicator;
      if (_communicator.getProperties().getPropertyAsInt("IceBox.UseSharedCommunicator." + service)
          > 0) {
        assert (_sharedCommunicator != null);
        communicator = _sharedCommunicator;
      } else {
        //
        // Create the service properties. We use the communicator properties as the default
        // properties if IceBox.InheritProperties is set.
        //
        Ice.InitializationData initData = new Ice.InitializationData();
        initData.properties = createServiceProperties(service);
        Ice.StringSeqHolder serviceArgs = new Ice.StringSeqHolder(info.args);
        if (serviceArgs.value.length > 0) {
          //
          // Create the service properties with the given service arguments. This should
          // read the service config file if it's specified with --Ice.Config.
          //
          initData.properties = Ice.Util.createProperties(serviceArgs, initData.properties);

          //
          // Next, parse the service "<service>.*" command line options (the Ice command
          // line options were parsed by the createProperties above)
          //
          serviceArgs.value =
              initData.properties.parseCommandLineOptions(service, serviceArgs.value);
        }

        //
        // Clone the logger to assign a new prefix.
        //
        initData.logger =
            _logger.cloneWithPrefix(initData.properties.getProperty("Ice.ProgramName"));

        //
        // Remaining command line options are passed to the communicator. This is
        // necessary for Ice plug-in properties (e.g.: IceSSL).
        //
        info.communicator = Ice.Util.initialize(serviceArgs, initData);
        info.args = serviceArgs.value;
        communicator = info.communicator;
      }

      try {
        info.service.start(service, communicator, info.args);
        info.status = StatusStarted;

        //
        // There is no need to notify the observers since the 'start all'
        // (that indirectly calls this method) occurs before the creation of
        // the Server Admin object, and before the activation of the main
        // object adapter (so before any observer can be registered)
        //
      } catch (Throwable ex) {
        if (info.communicator != null) {
          try {
            info.communicator.shutdown();
            info.communicator.waitForShutdown();
          } catch (Ice.CommunicatorDestroyedException e) {
            //
            // Ignore, the service might have already destroyed
            // the communicator for its own reasons.
            //
          } catch (java.lang.Exception e) {
            java.io.StringWriter sw = new java.io.StringWriter();
            java.io.PrintWriter pw = new java.io.PrintWriter(sw);
            e.printStackTrace(pw);
            pw.flush();
            _logger.warning(
                "ServiceManager: exception in shutting down communicator for service "
                    + service
                    + "\n"
                    + sw.toString());
          }

          try {
            info.communicator.destroy();
          } catch (java.lang.Exception e) {
            java.io.StringWriter sw = new java.io.StringWriter();
            java.io.PrintWriter pw = new java.io.PrintWriter(sw);
            e.printStackTrace(pw);
            pw.flush();
            _logger.warning(
                "ServiceManager: exception in destroying communciator for service"
                    + service
                    + "\n"
                    + sw.toString());
          }
        }
        throw ex;
      }

      _services.add(info);
    } catch (FailureException ex) {
      throw ex;
    } catch (Throwable ex) {
      FailureException e = new FailureException();
      e.reason = "ServiceManager: exception while starting service " + service + ": " + ex;
      e.initCause(ex);
      throw e;
    }
  }
  public int run() {
    try {
      Ice.Properties properties = _communicator.getProperties();

      //
      // Create an object adapter. Services probably should NOT share
      // this object adapter, as the endpoint(s) for this object adapter
      // will most likely need to be firewalled for security reasons.
      //
      Ice.ObjectAdapter adapter = null;
      if (!properties.getProperty("IceBox.ServiceManager.Endpoints").equals("")) {
        adapter = _communicator.createObjectAdapter("IceBox.ServiceManager");

        Ice.Identity identity = new Ice.Identity();
        identity.category = properties.getPropertyWithDefault("IceBox.InstanceName", "IceBox");
        identity.name = "ServiceManager";
        adapter.add(this, identity);
      }

      //
      // Parse the property set with the prefix "IceBox.Service.". These
      // properties should have the following format:
      //
      // IceBox.Service.Foo=Package.Foo [args]
      //
      // We parse the service properties specified in IceBox.LoadOrder
      // first, then the ones from remaining services.
      //
      final String prefix = "IceBox.Service.";
      java.util.Map<String, String> services = properties.getPropertiesForPrefix(prefix);
      String[] loadOrder = properties.getPropertyAsList("IceBox.LoadOrder");
      java.util.List<StartServiceInfo> servicesInfo = new java.util.ArrayList<StartServiceInfo>();
      for (String name : loadOrder) {
        if (name.length() > 0) {
          String key = prefix + name;
          String value = services.get(key);
          if (value == null) {
            FailureException ex = new FailureException();
            ex.reason = "ServiceManager: no service definition for `" + name + "'";
            throw ex;
          }
          servicesInfo.add(new StartServiceInfo(name, value, _argv));
          services.remove(key);
        }
      }
      for (java.util.Map.Entry<String, String> p : services.entrySet()) {
        String name = p.getKey().substring(prefix.length());
        String value = p.getValue();
        servicesInfo.add(new StartServiceInfo(name, value, _argv));
      }

      //
      // Check if some services are using the shared communicator in which
      // case we create the shared communicator now with a property set which
      // is the union of all the service properties (services which are using
      // the shared communicator).
      //
      if (properties.getPropertiesForPrefix("IceBox.UseSharedCommunicator.").size() > 0) {
        Ice.InitializationData initData = new Ice.InitializationData();
        initData.properties = createServiceProperties("SharedCommunicator");
        for (StartServiceInfo service : servicesInfo) {
          if (properties.getPropertyAsInt("IceBox.UseSharedCommunicator." + service.name) <= 0) {
            continue;
          }

          //
          // Load the service properties using the shared communicator properties as
          // the default properties.
          //
          Ice.StringSeqHolder serviceArgs = new Ice.StringSeqHolder(service.args);
          Ice.Properties svcProperties =
              Ice.Util.createProperties(serviceArgs, initData.properties);
          service.args = serviceArgs.value;

          //
          // Erase properties from the shared communicator which don't exist in the
          // service properties (which include the shared communicator properties
          // overriden by the service properties).
          //
          java.util.Map<String, String> allProps = initData.properties.getPropertiesForPrefix("");
          for (String key : allProps.keySet()) {
            if (svcProperties.getProperty(key).length() == 0) {
              initData.properties.setProperty(key, "");
            }
          }

          //
          // Add the service properties to the shared communicator properties.
          //
          for (java.util.Map.Entry<String, String> p :
              svcProperties.getPropertiesForPrefix("").entrySet()) {
            initData.properties.setProperty(p.getKey(), p.getValue());
          }

          //
          // Parse <service>.* command line options (the Ice command line options
          // were parsed by the createProperties above)
          //
          service.args = initData.properties.parseCommandLineOptions(service.name, service.args);
        }
        _sharedCommunicator = Ice.Util.initialize(initData);
      }

      for (StartServiceInfo s : servicesInfo) {
        start(s.name, s.className, s.args);
      }

      //
      // We may want to notify external scripts that the services
      // have started. This is done by defining the property:
      //
      // IceBox.PrintServicesReady=bundleName
      //
      // Where bundleName is whatever you choose to call this set of
      // services. It will be echoed back as "bundleName ready".
      //
      // This must be done after start() has been invoked on the
      // services.
      //
      String bundleName = properties.getProperty("IceBox.PrintServicesReady");
      if (bundleName.length() > 0) {
        System.out.println(bundleName + " ready");
      }

      //
      // Don't move after the adapter activation. This allows
      // applications to wait for the service manager to be
      // reachable before sending a signal to shutdown the
      // IceBox.
      //
      Ice.Application.shutdownOnInterrupt();

      //
      // Register "this" as a facet to the Admin object and
      // create Admin object
      //
      try {
        _communicator.addAdminFacet(this, "IceBox.ServiceManager");

        //
        // Add a Properties facet for each service
        //
        for (ServiceInfo info : _services) {
          Ice.Communicator communicator =
              info.communicator != null ? info.communicator : _sharedCommunicator;
          _communicator.addAdminFacet(
              new PropertiesAdminI(communicator.getProperties()),
              "IceBox.Service." + info.name + ".Properties");
        }

        _communicator.getAdmin();
      } catch (Ice.ObjectAdapterDeactivatedException ex) {
        //
        // Expected if the communicator has been shutdown.
        //
      }

      //
      // Start request dispatching after we've started the services.
      //
      if (adapter != null) {
        try {
          adapter.activate();
        } catch (Ice.ObjectAdapterDeactivatedException ex) {
          //
          // Expected if the communicator has been shutdown.
          //
        }
      }

      _communicator.waitForShutdown();
      Ice.Application.defaultInterrupt();

      //
      // Invoke stop() on the services.
      //
      stopAll();
    } catch (FailureException ex) {
      java.io.StringWriter sw = new java.io.StringWriter();
      java.io.PrintWriter pw = new java.io.PrintWriter(sw);
      pw.println(ex.reason);
      ex.printStackTrace(pw);
      pw.flush();
      _logger.error(sw.toString());
      stopAll();
      return 1;
    } catch (Ice.LocalException ex) {
      java.io.StringWriter sw = new java.io.StringWriter();
      java.io.PrintWriter pw = new java.io.PrintWriter(sw);
      ex.printStackTrace(pw);
      pw.flush();
      _logger.error("ServiceManager: " + ex + "\n" + sw.toString());
      stopAll();
      return 1;
    } catch (java.lang.Exception ex) {
      java.io.StringWriter sw = new java.io.StringWriter();
      java.io.PrintWriter pw = new java.io.PrintWriter(sw);
      ex.printStackTrace(pw);
      pw.flush();
      _logger.error("ServiceManager: unknown exception\n" + sw.toString());
      stopAll();
      return 1;
    }

    return 0;
  }