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); } } } }