⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 internalcomponentmanager.java

📁 openfire 服务器源码下载
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/**
 * $RCSfile$
 * $Revision: 3126 $
 * $Date: 2005-11-30 15:20:53 -0300 (Wed, 30 Nov 2005) $
 *
 * Copyright (C) 2008 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, or a commercial license
 * agreement with Jive.
 */

package org.jivesoftware.openfire.component;

import org.dom4j.Element;
import org.jivesoftware.openfire.*;
import org.jivesoftware.openfire.container.BasicModule;
import org.jivesoftware.openfire.disco.IQDiscoItemsHandler;
import org.jivesoftware.openfire.session.ComponentSession;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.xmpp.component.Component;
import org.xmpp.component.ComponentException;
import org.xmpp.component.ComponentManager;
import org.xmpp.component.ComponentManagerFactory;
import org.xmpp.packet.*;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * Manages the registration and delegation of Components. The ComponentManager
 * is responsible for managing registration and delegation of {@link Component Components},
 * as well as offering a facade around basic server functionallity such as sending and
 * receiving of packets.<p>
 *
 * This component manager will be an internal service whose JID will be component.[domain]. So the
 * component manager will be able to send packets to other internal or external components and also
 * receive packets from other components or even from trusted clients (e.g. ad-hoc commands).
 *
 * @author Derek DeMoro
 */
public class InternalComponentManager extends BasicModule implements ComponentManager, RoutableChannelHandler {

    final private Map<String, RoutableComponents> routables = new ConcurrentHashMap<String, RoutableComponents>();
    private Map<String, IQ> componentInfo = new ConcurrentHashMap<String, IQ>();
    private Map<JID, JID> presenceMap = new ConcurrentHashMap<JID, JID>();
    /**
     * Holds the list of listeners that will be notified of component events.
     */
    private List<ComponentEventListener> listeners = new CopyOnWriteArrayList<ComponentEventListener>();

    private static InternalComponentManager instance;
    /**
     * XMPP address of this internal service. The address is of the form: component.[domain]
     */
    private JID serviceAddress;
    /**
     * Holds the domain of the server. We are using an iv since we use this value many times
     * in many methods.
     */
    private String serverDomain;
    private RoutingTable routingTable;

    public InternalComponentManager() {
        super("Internal Component Manager");
        instance = this;
    }

    public static InternalComponentManager getInstance() {
        return instance;
    }

    public void initialize(XMPPServer server) {
        super.initialize(server);
        routingTable = server.getRoutingTable();
    }

    public void start() {
        // Set this ComponentManager as the current component manager
        ComponentManagerFactory.setComponentManager(instance);

        XMPPServer server = XMPPServer.getInstance();
        serverDomain = server.getServerInfo().getXMPPDomain();
        // Set the address of this internal service. component.[domain]
        serviceAddress = new JID(null, "component." + serverDomain, null);
        if (!server.isSetupMode()) {
            // Add a route to this service
            server.getRoutingTable().addComponentRoute(getAddress(), this);
        }
    }

    public void stop() {
        super.stop();
        if (getAddress() != null) {
            // Remove the route to this service
            XMPPServer.getInstance().getRoutingTable().removeComponentRoute(getAddress());
        }
    }

    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);
            if (routable != null) {
                routable.addComponent(component);
            }
            else {
                routable = new RoutableComponents(componentJID, component);
                routables.put(subdomain, routable);

                // Add the route to the new service provided by the component
                XMPPServer.getInstance().getRoutingTable().addComponentRoute(componentJID, routable);
            }

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

                // Notify listeners that a new component has been registered
                for (ComponentEventListener listener : listeners) {
                    listener.componentRegistered(component, 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);
                }
            }
        }
    }

    /**
     * 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.
     */
    public void removeComponent(String subdomain) {
        List<Component> componentsToRemove = new ArrayList<Component>(routables.get(subdomain).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) {
        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);

                // Remove any info stored with the component being removed
                componentInfo.remove(subdomain);

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

                // Remove the route for the service provided by the component
                RoutingTable routingTable = XMPPServer.getInstance().getRoutingTable();
                if (routingTable != null) {
                    routingTable.removeComponentRoute(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());
                }

                // Ask the component to shutdown
                if (component != null) {
                    component.shutdown();
                }

                // Notify listeners that an existing component has been unregistered
                for (ComponentEventListener listener : listeners) {
                    listener.componentUnregistered(component, componentJID);
                }
                Log.debug("InternalComponentManager: Component unregistered for domain: " + subdomain);
            }
            else {
                Log.debug("InternalComponentManager: Other components still tied to domain: " + subdomain);
            }
        }
    }

    public void sendPacket(Component component, Packet packet) {
        if (packet != null && packet.getFrom() == null) {
            throw new IllegalArgumentException("Packet with no FROM address was received from component.");
        }
        
        PacketRouter router = XMPPServer.getInstance().getPacketRouter();
        if (router != null) {
            router.route(packet);
        }
    }

    public IQ query(Component component, IQ packet, int timeout) throws ComponentException {
        final LinkedBlockingQueue<IQ> answer = new LinkedBlockingQueue<IQ>(8);
        XMPPServer.getInstance().getIQRouter().addIQResultListener(packet.getID(), new IQResultListener() {
            public void receivedAnswer(IQ packet) {
                answer.offer(packet);
            }

            public void answerTimeout(String packetId) {
                Log.warn("An answer to a previously sent IQ stanza was never received. Packet id: " + packetId);
            }
        });
        sendPacket(component, packet);
        IQ reply = null;
        try {
            reply = answer.poll(timeout, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            // Ignore
        }
        if (reply == null) {
            reply = IQ.createResultIQ(packet);
            reply.setError(PacketError.Condition.item_not_found);
        }
        return reply;
    }

    public void query(Component component, IQ packet, IQResultListener listener) throws ComponentException {
        XMPPServer.getInstance().getIQRouter().addIQResultListener(packet.getID(), listener);
        sendPacket(component, packet);
    }

    /**
     * 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 (Map.Entry<String, RoutableComponents> entry : routables.entrySet()) {
            String subdomain = entry.getKey();
            RoutableComponents routable = entry.getValue();
            for (Component component : routable.getComponents()) {
                JID componentJID = new JID(subdomain + "." + serverDomain);
                listener.componentRegistered(component, componentJID);
                // Check if there is disco#info stored for the component
                IQ disco = componentInfo.get(subdomain);
                if (disco != null) {
                    listener.componentInfoReceived(component, disco);
                }
            }
        }
    }

    /**
     * Removes the specified listener from the listeners being notified of component

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -