searchplugin.java

来自「基于Jabber协议的即时消息服务器」· Java 代码 · 共 611 行 · 第 1/2 页

JAVA
611
字号
/**
 * Copyright (C) 2005 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.wildfire.plugin;

import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.PropertyEventDispatcher;
import org.jivesoftware.util.PropertyEventListener;
import org.jivesoftware.wildfire.XMPPServer;
import org.jivesoftware.wildfire.container.Plugin;
import org.jivesoftware.wildfire.container.PluginManager;
import org.jivesoftware.wildfire.forms.DataForm;
import org.jivesoftware.wildfire.forms.FormField;
import org.jivesoftware.wildfire.forms.spi.XDataFormImpl;
import org.jivesoftware.wildfire.forms.spi.XFormFieldImpl;
import org.jivesoftware.wildfire.user.User;
import org.jivesoftware.wildfire.user.UserManager;
import org.jivesoftware.wildfire.user.UserNotFoundException;
import org.xmpp.component.Component;
import org.xmpp.component.ComponentException;
import org.xmpp.component.ComponentManager;
import org.xmpp.component.ComponentManagerFactory;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
import org.xmpp.packet.PacketError;

import java.io.File;
import java.util.*;

/** 
 * Provides support for Jabber Search
 * (<a href="http://www.jabber.org/jeps/jep-0055.html">JEP-0055</a>).<p>
 *
 * The basic functionality is to query an information repository 
 * regarding the possible search fields, to send a search query, 
 * and to receive search results. This implementation was primarily designed to use
 * <a href="http://www.jabber.org/jeps/jep-0004.html">Data Forms</a>, but 
 * also supports non-dataform searches.
 * <p/>
 * 
 * @author Ryan Graham 
 */
public class SearchPlugin implements Component, Plugin, PropertyEventListener {
    public static final String PLUGIN_SEARCH_SERVICENAME = "plugin.search.serviceName";
    public static final String PLUGIN_SEARCH_SERVICEENABLED = "plugin.search.serviceEnabled";
   
    private UserManager userManager;
    private ComponentManager componentManager;
    private PluginManager pluginManager;

    private String serviceName;
    private boolean serviceEnabled;
    
    private static String serverName;

    private static String instructions = "The following fields are available for search. "
        + "Wildcard (*) characters are allowed as part of the query.";
    
    private static Element probeResult;

    private Collection<String> searchFields;
    private TreeMap<String, String> fieldLookup = new TreeMap<String, String>(new CaseInsensitiveComparator());
    private Map<String, String> reverseFieldLookup = new HashMap<String, String>();

    public SearchPlugin() {
        serviceName = JiveGlobals.getProperty("plugin.search.serviceName", "search");
        serviceEnabled = JiveGlobals.getBooleanProperty("plugin.search.serviceEnabled", true);
        
        serverName = XMPPServer.getInstance().getServerInfo().getName();
        // See if the installed provider supports searching. If not, workaround
        // by providing our own searching.
        UserManager manager = UserManager.getInstance();
        try {
            searchFields = manager.getSearchFields();
            userManager = UserManager.getInstance();
            searchFields = userManager.getSearchFields();
        }
        catch (UnsupportedOperationException uoe) {
            // Use a SearchPluginUserManager instead.
            searchFields = getSearchFields();
        }
        
        fieldLookup.put("jid", "Username");
        fieldLookup.put("username", "Username");
        fieldLookup.put("first", "Name");
        fieldLookup.put("last", "Name");
        fieldLookup.put("nick", "Name");
        fieldLookup.put("name", "Name");
        fieldLookup.put("email", "Email");
    }

    public String getName() {
        return pluginManager.getName(this);
    }

    public String getDescription() {
        return pluginManager.getDescription(this);
    }
    
    public void initializePlugin(PluginManager manager, File pluginDirectory) {        
        pluginManager = manager;
        
        componentManager = ComponentManagerFactory.getComponentManager();
        try {
            componentManager.addComponent(serviceName, this);
        }
        catch (Exception e) {
            componentManager.getLog().error(e);
        }
        PropertyEventDispatcher.addListener(this);

        if (probeResult == null) {
            probeResult = DocumentHelper.createElement(QName.get("query", "jabber:iq:search"));

            //non-data form
            probeResult.addElement("instructions").addText(instructions);
            
            XDataFormImpl searchForm = new XDataFormImpl(DataForm.TYPE_FORM);
            searchForm.setTitle("User Search");
            searchForm.addInstruction(instructions);
         
            XFormFieldImpl field = new XFormFieldImpl("FORM_TYPE");
            field.setType(FormField.TYPE_HIDDEN);
            field.addValue("jabber:iq:search");
            searchForm.addField(field);
            
            field = new XFormFieldImpl("search");
            field.setType(FormField.TYPE_TEXT_SINGLE);
            field.setLabel("Search");
            field.setRequired(true);
            searchForm.addField(field);
            
            for (String searchField : searchFields) {
                //non-data form
                probeResult.addElement(searchField);

                field = new XFormFieldImpl(searchField);
                field.setType(FormField.TYPE_BOOLEAN);
                field.addValue("1");
                field.setLabel(searchField);
                field.setRequired(false);
                searchForm.addField(field);
            }

            probeResult.add(searchForm.asXMLElement());
        }
    }
    
    public void initialize(JID jid, ComponentManager componentManager) {
    }

    public void start() {
    }

    public void destroyPlugin() {
        PropertyEventDispatcher.removeListener(this);
        pluginManager = null;
        try {
            componentManager.removeComponent(serviceName);
            componentManager = null;
        }
        catch (Exception e) {
            componentManager.getLog().error(e);
        }
        userManager = null;
        fieldLookup = null;
        reverseFieldLookup = null;
    }

    public void shutdown() {
    }
    
    public void processPacket(Packet p) {        
        if (p instanceof IQ) {
            IQ packet = (IQ) p;

            Element childElement = (packet).getChildElement();
            String namespace = null;
            if (childElement != null) {
                namespace = childElement.getNamespaceURI();
            }

            if ("jabber:iq:search".equals(namespace)) {
                try {
                    IQ replyPacket = handleIQ(packet);
                    if (replyPacket != null) {
                        componentManager.sendPacket(this, replyPacket);
                    }
                }
                catch (ComponentException e) {
                    componentManager.getLog().error(e);
                }
            }
            else if ("http://jabber.org/protocol/disco#info".equals(namespace)) {
                try {
                    IQ replyPacket = IQ.createResultIQ(packet);

                    Element responseElement = replyPacket
                            .setChildElement("query", "http://jabber.org/protocol/disco#info");
                    responseElement.addElement("identity").addAttribute("category", "search")
                                                          .addAttribute("type", "text")
                                                          .addAttribute("name", "User Search");
                    responseElement.addElement("feature").addAttribute("var", "jabber:iq:search");

                    componentManager.sendPacket(this, replyPacket);
                }
                catch (ComponentException e) {
                    componentManager.getLog().error(e);
                }
            }
            else if ("http://jabber.org/protocol/disco#items".equals(namespace)) {
                try {
                    IQ replyPacket = IQ.createResultIQ(packet);
                    replyPacket.setChildElement("query", "http://jabber.org/protocol/disco#items");
                    componentManager.sendPacket(this, replyPacket);
                }
                catch (ComponentException e) {
                    componentManager.getLog().error(e);
                }
            }
        }
    }

    private IQ handleIQ(IQ packet) {
        if (!serviceEnabled) {
            return replyDisabled(packet);
        }
        
        if (IQ.Type.get.equals(packet.getType())) {
            return processGetPacket(packet);
        }
        else if (IQ.Type.set.equals(packet.getType())) {
            return processSetPacket(packet);
        } else
        if (IQ.Type.result.equals(packet.getType()) || IQ.Type.error.equals(packet.getType())) {
            // Ignore
        }
        else {
            // Unknown type was sent so
            IQ reply = new IQ(IQ.Type.error, packet.getID());
            reply.setFrom(packet.getTo());
            reply.setTo(packet.getFrom());
            reply.setError(PacketError.Condition.bad_request);
            return reply;
        }

        return null;
    }
    
    private IQ replyDisabled(IQ packet) {
        IQ replyPacket = IQ.createResultIQ(packet);
        Element reply = replyPacket.setChildElement("query", "jabber:iq:search");
        XDataFormImpl unavailableForm = new XDataFormImpl(DataForm.TYPE_CANCEL);
        unavailableForm.setTitle("User Search");
        unavailableForm.addInstruction("This service is unavailable.");
        reply.add(unavailableForm.asXMLElement());

        return replyPacket;
    }

    private IQ processGetPacket(IQ packet) {
        IQ replyPacket = IQ.createResultIQ(packet);
        replyPacket.setChildElement(probeResult.createCopy());

        return replyPacket;
    }

    private IQ processSetPacket(IQ packet) {
        Set<User> users = new HashSet<User>();
        
        Element incomingForm = packet.getChildElement();
        boolean isDataFormQuery = (incomingForm.element(QName.get("x", "jabber:x:data")) != null);
        
        Hashtable<String, String> searchList = extractSearchQuery(incomingForm);
        Enumeration<String> searchIter = searchList.keys();
        while (searchIter.hasMoreElements()) {
            String field = searchIter.nextElement();
            String query = searchList.get(field);
            
            Collection<User> foundUsers = new ArrayList<User>();
            if (userManager != null) {
                if (query.length() > 0 && !query.equals("jabber:iq:search")) {
                    foundUsers.addAll(userManager.findUsers(new HashSet<String>(
                            Arrays.asList((field))), query));
                }
            }
            else {
                foundUsers.addAll(findUsers(field, query));
            }
            
            for (User user : foundUsers) {
                if (user != null) {
                    users.add(user);
                }
            }
        }
        

⌨️ 快捷键说明

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