/**
  * Removes a component. The {@link Component#shutdown} method will be called on the component.
  * Note that if the component was an external component that was connected several times then all
  * its connections will be terminated.
  *
  * @param subdomain the subdomain of the component's address.
  */
 @Override
 public void removeComponent(String subdomain) {
   RoutableComponents components = null;
   if (routables == null || (components = routables.get(subdomain)) == null) {
     return;
   }
   List<Component> componentsToRemove = new ArrayList<>(components.getComponents());
   for (Component component : componentsToRemove) {
     removeComponent(subdomain, component);
   }
 }
  /**
   * Removes a given component. Unlike {@link #removeComponent(String)} this method will just remove
   * a single component instead of all components associated to the subdomain. External components
   * may connect several times and register for the same subdomain. This method just removes a
   * singled connection not all of them.
   *
   * @param subdomain the subdomain of the component's address.
   * @param component specific component to remove.
   */
  public void removeComponent(String subdomain, Component component) {
    if (component == null) {
      return;
    }
    synchronized (routables) {
      Log.debug("InternalComponentManager: Unregistering component for domain: " + subdomain);
      RoutableComponents routable = routables.get(subdomain);
      routable.removeComponent(component);
      if (routable.numberOfComponents() == 0) {
        routables.remove(subdomain);

        JID componentJID = new JID(subdomain + "." + serverDomain);

        // Remove the route for the service provided by the component
        routingTable.removeComponentRoute(componentJID);

        // Ask the component to shutdown
        component.shutdown();

        if (!routingTable.hasComponentRoute(componentJID)) {
          // Remove the disco item from the server for the component that is being removed
          IQDiscoItemsHandler iqDiscoItemsHandler =
              XMPPServer.getInstance().getIQDiscoItemsHandler();
          if (iqDiscoItemsHandler != null) {
            iqDiscoItemsHandler.removeComponentItem(componentJID.toBareJID());
          }
          removeComponentInfo(componentJID);
          // Notify listeners that an existing component has been unregistered
          notifyComponentUnregistered(componentJID);
          // Alert other nodes of component removed event
          CacheFactory.doClusterTask(new NotifyComponentUnregistered(componentJID));
        }
        Log.debug("InternalComponentManager: Component unregistered for domain: " + subdomain);
      } else {
        Log.debug("InternalComponentManager: Other components still tied to domain: " + subdomain);
      }
    }
  }
 /**
  * Retrieves the <code>Component</code> which is mapped to the specified JID. The look up will
  * only be done on components that were registered with this JVM. That means that components
  * registered in other cluster nodes are not going to be considered.
  *
  * @param componentJID the jid mapped to the component.
  * @return the list of components with the specified id.
  */
 private List<Component> getComponents(JID componentJID) {
   synchronized (routables) {
     if (componentJID.getNode() != null) {
       return Collections.emptyList();
     }
     RoutableComponents routable = routables.get(componentJID.getDomain());
     if (routable != null) {
       return routable.getComponents();
     } else {
       // Search again for those JIDs whose domain include the server name but this
       // time remove the server name from the JID's domain
       String serverName = componentJID.getDomain();
       int index = serverName.lastIndexOf("." + serverDomain);
       if (index > -1) {
         routable = routables.get(serverName.substring(0, index));
         if (routable != null) {
           return routable.getComponents();
         }
       }
     }
     return Collections.emptyList();
   }
 }
  @Override
  public void addComponent(String subdomain, Component component) throws ComponentException {
    synchronized (routables) {
      RoutableComponents routable = routables.get(subdomain);
      if (routable != null && routable.hasComponent(component)) {
        // This component has already registered with this subdomain.
        // TODO: Is this all we should do?  Should we return an error?
        return;
      }
      Log.debug("InternalComponentManager: Registering component for domain: " + subdomain);
      JID componentJID = new JID(subdomain + "." + serverDomain);
      boolean notifyListeners = false;
      if (routable != null) {
        routable.addComponent(component);
      } else {
        routable = new RoutableComponents(componentJID, component);
        routables.put(subdomain, routable);

        if (!routingTable.hasComponentRoute(componentJID)) {
          notifyListeners = true;
        }
        // Add the route to the new service provided by the component
        routingTable.addComponentRoute(componentJID, routable);
      }

      // Initialize the new component
      try {
        component.initialize(componentJID, this);
        component.start();

        if (notifyListeners) {
          // Notify listeners that a new component has been registered
          notifyComponentRegistered(componentJID);
          // Alert other nodes of new registered domain event
          CacheFactory.doClusterTask(new NotifyComponentRegistered(componentJID));
        }

        // Check for potential interested users.
        checkPresences();
        // Send a disco#info request to the new component. If the component provides information
        // then it will be added to the list of discoverable server items.
        checkDiscoSupport(component, componentJID);
        Log.debug("InternalComponentManager: Component registered for domain: " + subdomain);
      } catch (Exception e) {
        // Unregister the component's domain
        routable.removeComponent(component);
        if (e instanceof ComponentException) {
          // Rethrow the exception
          throw (ComponentException) e;
        }
        // Rethrow the exception
        throw new ComponentException(e);
      } finally {
        if (routable.numberOfComponents() == 0) {
          // If there are no more components associated with this subdomain, remove it.
          routables.remove(subdomain);
          // Remove the route
          XMPPServer.getInstance().getRoutingTable().removeComponentRoute(componentJID);
        }
      }
    }
  }