@Override
  public void unregisterService(ServiceState serviceState) {
    List<ServiceName> serviceNames = serviceState.getServiceNames();
    log.debug("Unregister service: " + serviceNames);

    AbstractBundle serviceOwner = serviceState.getServiceOwner();

    // This event is synchronously delivered before the service has completed unregistering.
    eventsPlugin.fireServiceEvent(serviceOwner, ServiceEvent.UNREGISTERING, serviceState);

    // Remove from using bundles
    for (AbstractBundle bundleState : serviceState.getUsingBundlesInternal()) {
      while (ungetService(bundleState, serviceState)) ;
    }

    // Remove from owner bundle
    serviceOwner.removeRegisteredService(serviceState);

    // Unregister name associations
    for (ServiceName serviceName : serviceNames) {
      String[] clazzes = (String[]) serviceState.getProperty(Constants.OBJECTCLASS);
      for (String clazz : clazzes) unregisterNameAssociation(clazz, serviceName);
    }

    // Remove from controller
    ServiceName rootServiceName = serviceNames.get(0);
    try {
      ServiceController<?> controller = serviceContainer.getService(rootServiceName);
      controller.setMode(Mode.REMOVE);
    } catch (RuntimeException ex) {
      log.error("Cannot remove service: " + rootServiceName, ex);
    }
  }
  @Override
  @SuppressWarnings({"rawtypes", "unchecked"})
  public ServiceState registerService(
      AbstractBundle bundleState, String[] clazzes, Object serviceValue, Dictionary properties) {
    if (clazzes == null || clazzes.length == 0)
      throw new IllegalArgumentException("Null service classes");

    // Immediately after registration of a {@link ListenerHook}, the ListenerHook.added() method
    // will be called
    // to provide the current collection of service listeners which had been added prior to the hook
    // being registered.
    Collection<ListenerInfo> listenerInfos = null;
    if (serviceValue instanceof ListenerHook)
      listenerInfos = eventsPlugin.getServiceListenerInfos(null);

    // A temporary association of the clazz and name
    Map<ServiceName, String> associations = new HashMap<ServiceName, String>();

    // Generate the service names
    long serviceId = getNextServiceId();
    ServiceName[] serviceNames = new ServiceName[clazzes.length];
    for (int i = 0; i < clazzes.length; i++) {
      if (clazzes[i] == null)
        throw new IllegalArgumentException("Null service class at index: " + i);

      String shortName = clazzes[i].substring(clazzes[i].lastIndexOf(".") + 1);
      serviceNames[i] =
          ServiceName.of(
              "jbosgi", bundleState.getSymbolicName(), shortName, new Long(serviceId).toString());
    }

    final ServiceState serviceState =
        new ServiceState(bundleState, serviceId, serviceNames, clazzes, serviceValue, properties);
    BatchBuilder batchBuilder = serviceContainer.batchBuilder();
    Service service =
        new Service() {
          @Override
          public Object getValue() throws IllegalStateException {
            // [TODO] for injection to work this needs to be the Object value
            return serviceState;
          }

          @Override
          public void start(StartContext context) throws StartException {}

          @Override
          public void stop(StopContext context) {}
        };

    log.debug("Register service: " + Arrays.asList(serviceNames));

    ServiceName rootServiceName = serviceNames[0];
    BatchServiceBuilder serviceBuilder = batchBuilder.addService(rootServiceName, service);
    associations.put(rootServiceName, clazzes[0]);

    // Set the startup mode
    serviceBuilder.setInitialMode(Mode.AUTOMATIC);

    // Add the service aliases
    for (int i = 1; i < serviceNames.length; i++) {
      ServiceName alias = serviceNames[i];
      associations.put(alias, clazzes[1]);
      serviceBuilder.addAliases(alias);
    }

    try {
      batchBuilder.install();

      // Register the name association. We do this here
      // in case anything went wrong during the install
      for (Entry<ServiceName, String> aux : associations.entrySet()) {
        bundleState.addRegisteredService(serviceState);
        registerNameAssociation(aux.getValue(), aux.getKey());
      }
    } catch (ServiceRegistryException ex) {
      log.error("Cannot register services: " + serviceNames, ex);
    }

    // Call the newly added ListenerHook.added() method
    if (serviceValue instanceof ListenerHook) {
      ListenerHook listenerHook = (ListenerHook) serviceValue;
      listenerHook.added(listenerInfos);
    }

    // This event is synchronously delivered after the service has been registered with the
    // Framework.
    eventsPlugin.fireServiceEvent(bundleState, ServiceEvent.REGISTERED, serviceState);

    return serviceState;
  }