private void checkPresences() {
    for (JID prober : presenceMap.keySet()) {
      JID probee = presenceMap.get(prober);

      if (routingTable.hasComponentRoute(probee)) {
        Presence presence = new Presence();
        presence.setFrom(prober);
        presence.setTo(probee);
        routingTable.routePacket(probee, presence, false);

        // No reason to hold onto prober reference.
        presenceMap.remove(prober);
      }
    }
  }
 private void sendOfflineMessage(JID receipient, OfflineMessage offlineMessage) {
   Element offlineInfo = offlineMessage.addChildElement("offline", NAMESPACE);
   offlineInfo
       .addElement("item")
       .addAttribute("node", XMPPDateTimeFormat.format(offlineMessage.getCreationDate()));
   routingTable.routePacket(receipient, offlineMessage, true);
 }
 /**
  * Returns true if a component is associated to the specified address. Components registered with
  * this JVM or other cluster nodes are going to be considered.
  *
  * @param componentJID the address of the component. This is the complete domain.
  * @return true if a component is associated to the specified address.
  */
 public boolean hasComponent(JID componentJID) {
   synchronized (routables) {
     if (componentJID.getNode() != null || componentJID.getResource() != null) {
       return false;
     }
     //        if (componentJID.getDomain().lastIndexOf("." + serverDomain) == -1) {
     //            componentJID = new JID(componentJID.getDomain() + "." + serverDomain);
     //        }
     return routingTable.hasComponentRoute(componentJID);
   }
 }
 /**
  * Adds a new listener that will be notified of component events. Events being notified are: 1)
  * when a component is added to the component manager, 2) when a component is deleted and 3) when
  * disco#info is received from a component.
  *
  * @param listener the new listener to notify of component events.
  */
 public void addListener(ComponentEventListener listener) {
   listeners.add(listener);
   // Notify the new listener about existing components
   for (String domain : routingTable.getComponentsDomains()) {
     JID componentJID = new JID(domain);
     listener.componentRegistered(componentJID);
     // Check if there is disco#info stored for the component
     IQ disco = componentInfo.get(domain);
     if (disco != null) {
       listener.componentInfoReceived(disco);
     }
   }
 }
  /**
   * 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);
      }
    }
  }
  public void process(Presence presence) throws PacketException {
    try {
      JID senderJID = presence.getFrom();
      JID recipientJID = presence.getTo();
      Presence.Type type = presence.getType();

      // Reject presence subscription requests sent to the local server itself.
      if (recipientJID == null || recipientJID.toString().equals(serverName)) {
        if (type == Presence.Type.subscribe) {
          Presence reply = new Presence();
          reply.setTo(senderJID);
          reply.setFrom(recipientJID);
          reply.setType(Presence.Type.unsubscribed);
          deliverer.deliver(reply);
        }
        return;
      }

      try {
        Roster senderRoster = getRoster(senderJID);
        if (senderRoster != null) {
          manageSub(recipientJID, true, type, senderRoster);
        }
        Roster recipientRoster = getRoster(recipientJID);
        boolean recipientSubChanged = false;
        if (recipientRoster != null) {
          recipientSubChanged = manageSub(senderJID, false, type, recipientRoster);
        }

        // Do not forward the packet to the recipient if the presence is of type subscribed
        // and the recipient user has not changed its subscription state.
        if (!(type == Presence.Type.subscribed
            && recipientRoster != null
            && !recipientSubChanged)) {

          // If the user is already subscribed to the *local* user's presence then do not
          // forward the subscription request. Also, do not send an auto-reply on behalf
          // of the user. This presence stanza is the user's server know that it MUST no
          // longer send notification of the subscription state change to the user.
          // See http://tools.ietf.org/html/rfc3921#section-7 and/or OF-38
          if (type == Presence.Type.subscribe && recipientRoster != null && !recipientSubChanged) {
            try {
              RosterItem.SubType subType = recipientRoster.getRosterItem(senderJID).getSubStatus();
              if (subType == RosterItem.SUB_FROM || subType == RosterItem.SUB_BOTH) {
                return;
              }
            } catch (UserNotFoundException e) {
              // Weird case: Roster item does not exist. Should never happen
              Log.error(
                  "User does not exist while trying to update roster item. "
                      + "This should never happen (this indicates a programming "
                      + "logic error). Processing stanza: "
                      + presence.toString(),
                  e);
            }
          }

          // Try to obtain a handler for the packet based on the routes. If the handler is
          // a module, the module will be able to handle the packet. If the handler is a
          // Session the packet will be routed to the client. If a route cannot be found
          // then the packet will be delivered based on its recipient and sender.
          List<JID> jids = routingTable.getRoutes(recipientJID, null);
          if (!jids.isEmpty()) {
            for (JID jid : jids) {
              Presence presenteToSend = presence.createCopy();
              // Stamp the presence with the user's bare JID as the 'from' address,
              // as required by section 8.2.5 of RFC 3921
              presenteToSend.setFrom(senderJID.toBareJID());
              routingTable.routePacket(jid, presenteToSend, false);
            }
          } else {
            deliverer.deliver(presence.createCopy());
          }

          if (type == Presence.Type.subscribed) {
            // Send the presence of the local user to the remote user. The remote user
            // subscribed to the presence of the local user and the local user accepted
            JID prober =
                localServer.isLocal(recipientJID)
                    ? new JID(recipientJID.toBareJID())
                    : recipientJID;
            presenceManager.probePresence(prober, senderJID);
            PresenceEventDispatcher.subscribedToPresence(recipientJID, senderJID);
          }
        }

        if (type == Presence.Type.unsubscribed) {
          // Send unavailable presence from all of the local user's available resources
          // to the remote user
          presenceManager.sendUnavailableFromSessions(recipientJID, senderJID);
          PresenceEventDispatcher.unsubscribedToPresence(senderJID, recipientJID);
        }
      } catch (SharedGroupException e) {
        Presence result = presence.createCopy();
        JID sender = result.getFrom();
        result.setFrom(presence.getTo());
        result.setTo(sender);
        result.setError(PacketError.Condition.not_acceptable);
        deliverer.deliver(result);
      }
    } catch (Exception e) {
      Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
    }
  }
  @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);
        }
      }
    }
  }