Search in sources :

Example 1 with NodeID

use of org.jivesoftware.openfire.cluster.NodeID in project Openfire by igniterealtime.

the class IQDiscoInfoHandler method restoreCacheContent.

private void restoreCacheContent() {
    for (String feature : localServerFeatures) {
        Lock lock = CacheFactory.getLock(feature, serverFeatures);
        try {
            lock.lock();
            Set<NodeID> nodeIDs = serverFeatures.get(feature);
            if (nodeIDs == null) {
                nodeIDs = new HashSet<>();
            }
            nodeIDs.add(XMPPServer.getInstance().getNodeID());
            serverFeatures.put(feature, nodeIDs);
        } finally {
            lock.unlock();
        }
    }
}
Also used : NodeID(org.jivesoftware.openfire.cluster.NodeID) Lock(java.util.concurrent.locks.Lock)

Example 2 with NodeID

use of org.jivesoftware.openfire.cluster.NodeID in project Openfire by igniterealtime.

the class ClusterListener method memberLeft.

public void memberLeft(MemberEvent memberEvent) {
    byte[] nodeID = memberEvent.getMember().getUid().toByteArray();
    if (memberEvent.isLocal()) {
        Log.info("Leaving cluster");
        // This node may have realized that it got kicked out of the cluster
        seniorClusterMember = false;
        // Clean up all traces. This will set all remote sessions as unavailable
        List<NodeID> nodeIDs = new ArrayList<NodeID>(nodeSessions.keySet());
        // Trigger event. Wait until the listeners have processed the event. Caches will be populated
        // again with local content.
        ClusterManager.fireLeftCluster();
        if (!XMPPServer.getInstance().isShuttingDown()) {
            for (NodeID key : nodeIDs) {
                // Clean up directed presences sent from entites hosted in the leaving node to local entities
                // Clean up directed presences sent to entites hosted in the leaving node from local entities
                cleanupDirectedPresences(key);
                // Clean up no longer valid sessions
                cleanupPresences(key);
            }
            // Remove traces of directed presences sent from local entities to handlers that no longer exist
            // At this point c2s sessions are gone from the routing table so we can identify expired sessions
            XMPPServer.getInstance().getPresenceUpdateHandler().removedExpiredPresences();
        }
        // Mark that we are done with the clean up
        done = true;
    } else {
        // Trigger event that a node left the cluster
        ClusterManager.fireLeftCluster(nodeID);
        // Clean up directed presences sent from entites hosted in the leaving node to local entities
        // Clean up directed presences sent to entites hosted in the leaving node from local entities
        cleanupDirectedPresences(NodeID.getInstance(nodeID));
        if (!seniorClusterMember && CacheFactory.isSeniorClusterMember()) {
            seniorClusterMember = true;
            ClusterManager.fireMarkedAsSeniorClusterMember();
        }
        if (CacheFactory.isSeniorClusterMember()) {
            cleanupNode(NodeID.getInstance(nodeID));
        }
        // Remove traces of directed presences sent from local entities to handlers that no longer exist.
        // At this point c2s sessions are gone from the routing table so we can identify expired sessions
        XMPPServer.getInstance().getPresenceUpdateHandler().removedExpiredPresences();
    }
    // Delete nodeID instance (release from memory)
    NodeID.deleteInstance(nodeID);
}
Also used : NodeID(org.jivesoftware.openfire.cluster.NodeID)

Example 3 with NodeID

use of org.jivesoftware.openfire.cluster.NodeID in project Openfire by igniterealtime.

the class ClusterListener method cleanupNode.

/**
     * Executes close logic for each session hosted in the remote node that is
     * no longer available. This logic is similar to the close listeners used by
     * the {@link SessionManager}.<p>
     *
     * If the node that went down performed its own clean up logic then the other
     * cluster nodes will have the correct state. That means that this method
     * will not find any sessions to remove.<p>
     *
     * If this operation is too big and we are still in a cluster then we can
     * distribute the work in the cluster to go faster.
     *
     * @param key the key that identifies the node that is no longer available.
     */
private void cleanupNode(NodeID key) {
    // TODO Fork in another process and even ask other nodes to process work
    RoutingTable routingTable = XMPPServer.getInstance().getRoutingTable();
    RemoteSessionLocator sessionLocator = XMPPServer.getInstance().getRemoteSessionLocator();
    SessionManager manager = XMPPServer.getInstance().getSessionManager();
    // TODO Consider removing each cached entry once processed instead of all at the end. Could be more error-prove.
    Set<String> registeredUsers = lookupJIDList(key, C2SCache.getName());
    if (!registeredUsers.isEmpty()) {
        for (String fullJID : new ArrayList<String>(registeredUsers)) {
            JID offlineJID = new JID(fullJID);
            manager.removeSession(null, offlineJID, false, true);
        }
    }
    Set<String> anonymousUsers = lookupJIDList(key, anonymousC2SCache.getName());
    if (!anonymousUsers.isEmpty()) {
        for (String fullJID : new ArrayList<String>(anonymousUsers)) {
            JID offlineJID = new JID(fullJID);
            manager.removeSession(null, offlineJID, true, true);
        }
    }
    // Remove outgoing server sessions hosted in node that left the cluster
    Set<String> remoteServers = lookupJIDList(key, S2SCache.getName());
    if (!remoteServers.isEmpty()) {
        for (String fullJID : new ArrayList<String>(remoteServers)) {
            JID serverJID = new JID(fullJID);
            routingTable.removeServerRoute(serverJID);
        }
    }
    Set<String> components = lookupJIDList(key, componentsCache.getName());
    if (!components.isEmpty()) {
        for (String address : new ArrayList<String>(components)) {
            Lock lock = CacheFactory.getLock(address, componentsCache);
            try {
                lock.lock();
                Set<NodeID> nodes = (Set<NodeID>) componentsCache.get(address);
                if (nodes != null) {
                    nodes.remove(key);
                    if (nodes.isEmpty()) {
                        componentsCache.remove(address);
                    } else {
                        componentsCache.put(address, nodes);
                    }
                }
            } finally {
                lock.unlock();
            }
        }
    }
    Set<String> componentSessions = lookupJIDList(key, componentSessionsCache.getName());
    if (!componentSessions.isEmpty()) {
        for (String domain : new ArrayList<String>(componentSessions)) {
            componentSessionsCache.remove(domain);
        // Registered subdomains of external component will be removed
        // by the clean up of the component cache
        }
    }
    Set<String> multiplexers = lookupJIDList(key, multiplexerSessionsCache.getName());
    if (!multiplexers.isEmpty()) {
        for (String fullJID : new ArrayList<String>(multiplexers)) {
            multiplexerSessionsCache.remove(fullJID);
        // c2s connections connected to node that went down will be cleaned up
        // by the c2s logic above. If the CM went down and the node is up then
        // connections will be cleaned up as usual
        }
    }
    Set<String> incomingSessions = lookupJIDList(key, incomingServerSessionsCache.getName());
    if (!incomingSessions.isEmpty()) {
        for (String streamIDValue : new ArrayList<>(incomingSessions)) {
            StreamID streamID = BasicStreamIDFactory.createStreamID(streamIDValue);
            IncomingServerSession session = sessionLocator.getIncomingServerSession(key.toByteArray(), streamID);
            // Remove all the hostnames that were registered for this server session
            for (String hostname : session.getValidatedDomains()) {
                manager.unregisterIncomingServerSession(hostname, session);
            }
        }
    }
    nodeSessions.remove(key);
// TODO Make sure that routing table has no entry referring to node that is gone
}
Also used : JID(org.xmpp.packet.JID) IncomingServerSession(org.jivesoftware.openfire.session.IncomingServerSession) Lock(java.util.concurrent.locks.Lock) RemoteSessionLocator(org.jivesoftware.openfire.session.RemoteSessionLocator) NodeID(org.jivesoftware.openfire.cluster.NodeID)

Example 4 with NodeID

use of org.jivesoftware.openfire.cluster.NodeID in project Openfire by igniterealtime.

the class RoutingTableImpl method removeComponentRoute.

@Override
public boolean removeComponentRoute(JID route) {
    String address = route.getDomain();
    boolean removed = false;
    Lock lock = CacheFactory.getLock(address, componentsCache);
    try {
        lock.lock();
        Set<NodeID> nodes = componentsCache.get(address);
        if (nodes != null) {
            removed = nodes.remove(server.getNodeID());
            if (nodes.isEmpty()) {
                componentsCache.remove(address);
            } else {
                componentsCache.put(address, nodes);
            }
        }
    } finally {
        lock.unlock();
    }
    localRoutingTable.removeRoute(address);
    return removed;
}
Also used : NodeID(org.jivesoftware.openfire.cluster.NodeID) Lock(java.util.concurrent.locks.Lock)

Example 5 with NodeID

use of org.jivesoftware.openfire.cluster.NodeID in project Openfire by igniterealtime.

the class RoutingTableImpl method routeToComponent.

/**
	 * Routes packets that are sent to components of the XMPP domain (which are
	 * subdomains of the XMPP domain)
	 * 
	 * @param jid
	 *            the recipient of the packet to route.
	 * @param packet
	 *            the packet to route.
	 * @throws PacketException
	 *             thrown if the packet is malformed (results in the sender's
	 *             session being shutdown).
	 * @return <tt>true</tt> if the packet was routed successfully,
	 *         <tt>false</tt> otherwise.
	 */
private boolean routeToComponent(JID jid, Packet packet, boolean routed) {
    if (!hasComponentRoute(jid) && !ExternalComponentManager.hasConfiguration(jid.getDomain())) {
        return false;
    }
    // First check if the component is being hosted in this JVM
    RoutableChannelHandler route = localRoutingTable.getRoute(jid.getDomain());
    if (route != null) {
        try {
            route.process(packet);
            routed = true;
        } catch (UnauthorizedException e) {
            Log.error("Unable to route packet " + packet.toXML(), e);
        }
    } else {
        // Check if other cluster nodes are hosting this component
        Set<NodeID> nodes = componentsCache.get(jid.getDomain());
        if (nodes != null) {
            for (NodeID nodeID : nodes) {
                if (server.getNodeID().equals(nodeID)) {
                    // could have been added after our previous check)
                    try {
                        RoutableChannelHandler localRoute = localRoutingTable.getRoute(jid.getDomain());
                        if (localRoute != null) {
                            localRoute.process(packet);
                            routed = true;
                            break;
                        }
                    } catch (UnauthorizedException e) {
                        Log.error("Unable to route packet " + packet.toXML(), e);
                    }
                } else {
                    // This is a route to a local component hosted in other node
                    if (remotePacketRouter != null) {
                        routed = remotePacketRouter.routePacket(nodeID.toByteArray(), jid, packet);
                        if (routed) {
                            break;
                        }
                    }
                }
            }
        }
    }
    return routed;
}
Also used : UnauthorizedException(org.jivesoftware.openfire.auth.UnauthorizedException) NodeID(org.jivesoftware.openfire.cluster.NodeID)

Aggregations

NodeID (org.jivesoftware.openfire.cluster.NodeID)41 JID (org.xmpp.packet.JID)18 Lock (java.util.concurrent.locks.Lock)15 java.util (java.util)12 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)12 ConcurrentMap (java.util.concurrent.ConcurrentMap)12 Collectors (java.util.stream.Collectors)11 Nonnull (javax.annotation.Nonnull)10 XMPPServer (org.jivesoftware.openfire.XMPPServer)10 UnauthorizedException (org.jivesoftware.openfire.auth.UnauthorizedException)9 MUCRole (org.jivesoftware.openfire.muc.MUCRole)8 MUCRoom (org.jivesoftware.openfire.muc.MUCRoom)8 Logger (org.slf4j.Logger)8 LoggerFactory (org.slf4j.LoggerFactory)8 Nullable (javax.annotation.Nullable)7 ClusterManager (org.jivesoftware.openfire.cluster.ClusterManager)7 CacheFactory (org.jivesoftware.util.cache.CacheFactory)7 Map (java.util.Map)6 PacketException (org.jivesoftware.openfire.PacketException)6 DomainPair (org.jivesoftware.openfire.session.DomainPair)6