LocalRoutingTable.java 6.22 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
/**
 * $RCSfile: $
 * $Revision: $
 * $Date: $
 *
 * Copyright (C) 2007 Jive Software. All rights reserved.
 *
 * This software is published under the terms of the GNU Public License (GPL),
 * a copy of which is included in this distribution.
 */

package org.jivesoftware.openfire.spi;

import org.jivesoftware.openfire.RoutableChannelHandler;
import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.session.*;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.TaskEngine;
import org.xmpp.packet.JID;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Internal component used by the RoutingTable to keep references to routes hosted by this JVM. When
 * running in a cluster each cluster member will have its own RoutingTable containing an instance of
 * this class. Each LocalRoutingTable is responsible for storing routes to components, client sessions
 * and outgoing server sessions hosted by local cluster node.
 *
 * @author Gaston Dombiak
 */
class LocalRoutingTable {
    Map<String, RoutableChannelHandler> routes = new ConcurrentHashMap<String, RoutableChannelHandler>();

    /**
     * Adds a route of a local {@link RoutableChannelHandler}
     *
     * @param address the string representation of the JID associated to the route.
     * @param route the route hosted by this node.
     * @return true if the element was added or false if was already present.
     */
    boolean addRoute(String address, RoutableChannelHandler route) {
        return routes.put(address, route) != route;
    }

    /**
     * Returns the route hosted by this node that is associated to the specified address.
     *
     * @param address the string representation of the JID associated to the route.
     * @return the route hosted by this node that is associated to the specified address.
     */
    RoutableChannelHandler getRoute(String address) {
        return routes.get(address);
    }

    /**
     * Returns the client sessions that are connected to this JVM.
     *
     * @return the client sessions that are connected to this JVM.
     */
    Collection<LocalClientSession> getClientRoutes() {
        List<LocalClientSession> sessions = new ArrayList<LocalClientSession>();
        for (RoutableChannelHandler route : routes.values()) {
            if (route instanceof LocalClientSession) {
                sessions.add((LocalClientSession) route);
            }
        }
        return sessions;
    }

    /**
     * Returns the outgoing server sessions that are connected to this JVM.
     *
     * @return the outgoing server sessions that are connected to this JVM.
     */
    Collection<LocalOutgoingServerSession> getServerRoutes() {
        List<LocalOutgoingServerSession> sessions = new ArrayList<LocalOutgoingServerSession>();
        for (RoutableChannelHandler route : routes.values()) {
            if (route instanceof LocalOutgoingServerSession) {
                sessions.add((LocalOutgoingServerSession) route);
            }
        }
        return sessions;
    }

    /**
     * Returns the external component sessions that are connected to this JVM.
     *
     * @return the external component sessions that are connected to this JVM.
     */
    Collection<RoutableChannelHandler> getComponentRoute() {
        List<RoutableChannelHandler> sessions = new ArrayList<RoutableChannelHandler>();
        for (RoutableChannelHandler route : routes.values()) {
            if (!(route instanceof LocalOutgoingServerSession || route instanceof LocalClientSession)) {
                sessions.add(route);
            }
        }
        return sessions;
    }

    /**
     * Removes a route of a local {@link RoutableChannelHandler}
     *
     * @param address the string representation of the JID associated to the route.
     */
    void removeRoute(String address) {
        routes.remove(address);
    }

    public void start() {
        // Run through the server sessions every 3 minutes after a 3 minutes server startup delay (default values)
        int period = 3 * 60 * 1000;
        TaskEngine.getInstance().scheduleAtFixedRate(new ServerCleanupTask(), period, period);
    }

    public void stop() {
        try {
            // Send the close stream header to all connected connections
            for (RoutableChannelHandler route : routes.values()) {
                if (route instanceof LocalSession) {
                    LocalSession session = (LocalSession) route;
                    try {
                        // Notify connected client that the server is being shut down
                        session.getConnection().systemShutdown();
                    }
                    catch (Throwable t) {
                        // Ignore.
                    }
                }
            }
        }
        catch (Exception e) {
            // Ignore.
        }
    }

    public boolean isLocalRoute(JID jid) {
        return routes.containsKey(jid.toString());
    }

    /**
     * Task that closes idle server sessions.
     */
    private class ServerCleanupTask extends TimerTask {
        /**
         * Close outgoing server sessions that have been idle for a long time.
         */
        public void run() {
            // Do nothing if this feature is disabled
            int idleTime = SessionManager.getInstance().getServerSessionIdleTime();
            if (idleTime == -1) {
                return;
            }
            final long deadline = System.currentTimeMillis() - idleTime;
            for (RoutableChannelHandler route : routes.values()) {
                // Check outgoing server sessions
                if (route instanceof OutgoingServerSession) {
                    Session session = (Session) route;
                    try {
                        if (session.getLastActiveDate().getTime() < deadline) {
                            session.close();
                        }
                    }
                    catch (Throwable e) {
                        Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
                    }
                }
            }
        }
    }
}