com.adspore.splat.xep0030.DiscoItemsHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.adspore.splat.xep0030.DiscoItemsHandler.java

Source

/**
 * $RCSfile$
 * $Revision: 1701 $
 * $Date: 2005-07-26 02:23:45 -0300 (Tue, 26 Jul 2005) $
 *
 * Copyright (C) 2005-2008 Jive Software. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.adspore.splat.xep0030;

import java.util.Collection;
import java.util.Iterator;

import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.PacketError;

import com.adspore.contracts.IContext;
import com.adspore.splat.SplatComponent;
import com.adspore.util.JIDUtils;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;

/**
 * Originally supplied as part of Openfire, refactored to work with AbstractComponent plug-ins to
 * Openfire. <p/>
 * 
 * IQDiscoItemsHandler is responsible for handling disco#items requests. This class holds a map with
 * the main entities and the associated DiscoItemsProvider. We are considering the host of the
 * recipient JIDs as main entities. It's the DiscoItemsProvider responsibility to provide the items
 * associated with the JID's name together with any possible requested node.<p>
 * <p/>
 * For example, let's have in the entities map the following entries: "localhost" and
 * "conference.localhost". Associated with each entry we have different DiscoItemsProvider. Now we
 * receive a disco#items request for the following JID: "room@conference.localhost" which is a disco
 * request for a MUC room. So IQDiscoItemsHandler will look for the DiscoItemsProvider associated
 * with the JID's host which in this case is "conference.localhost". Once we have located the
 * provider we will delegate to the provider the responsibility to provide the items specific to
 * the JID's name which in this case is "room". Depending on the implementation, the items could be
 * the list of existing occupants if that information is publicly available. Finally, after we have
 * collected all the items provided by the provider we will add them to the reply. On the other
 * hand, if no provider was found or the provider has no information for the requested name/node
 * then a not-found error will be returned.<p>
 * <p/>
 * Publishing of client items is still not supported.
 *
 * @author Gaston Dombiak
 */
public class DiscoItemsHandler {
    private static final Logger mLogger = LoggerFactory.getLogger(DiscoItemsHandler.class);

    protected final IContext mContext;
    protected final SplatComponent mComponent;
    protected final Multimap<String, DiscoItemsProvider> mEntities;

    @SuppressWarnings("unused")
    private DiscoItemsHandler() {
        mContext = null;
        mComponent = null;
        mEntities = null;
    }

    public DiscoItemsHandler(IContext context, SplatComponent component) {
        mContext = context;
        mComponent = component;
        mEntities = HashMultimap.create();
    }

    public void initialize() {
    }

    public IQ handleDiscoItemsIQ(IQ packet) {
        /*
         * We'll stuff the 'query' element into the reply, then add identity and feature elements
         * to that if they exist.  
         */
        Element queryElement = packet.getChildElement().createCopy();
        IQ reply = IQ.createResultIQ(packet);
        reply.setChildElement(queryElement);

        /*
         *  Look for a DiscoInfoProvider associated with the requested entity, there may be more than one.
         *  We consider the host of the recipient JID of the packet as the entity. It's the
         *  DiscoInfoProvider responsibility to provide information about the JID's name together
         *  with any possible requested node.
         *  
         *  As part of the refactoring, I moved this to a MultiMap implementation because there
         *  may be multiple DiscoInfoProviders that can speak regarding a particular node, as a node
         *  may host multiple identities.  For instance, a JID+Node may support PubSub as well
         *  as ping and time. Every node supports info and item.
         *  
         *  One of the things that makes this so problematic, is the confusion between the JID's
         *  concept of 'Node' and the Entity's concept of 'Node'.  When referring to PubSub, the
         *  node is really placed in a JID's 'resource', and the JID uses the 'Node' to identify
         *  the User's name.  See example:
         *  
         *   nodeId@domainFoo.domainBar/resource
         *
         *   When using the JID+Node approach, this goes very wrong....
         *  
         */
        final Element iq = packet.getChildElement(); //   Assumption: it's a 'query' object...
        final String node = queryElement.attributeValue("node");

        final JID targetJID = (null != node) ? JIDUtils.setNodeIDAsResource(packet.getTo(), node) : packet.getTo();
        final JID senderJID = packet.getFrom();
        /*
          * Lookup all possible DiscoInfoProviders that service the target.  Base this on the
          * 'domain' field of the JID, patch up with username later if required.
          */
        Collection<DiscoItemsProvider> itemProviders = getProviders(targetJID.toBareJID());
        if (!itemProviders.isEmpty()) {
            /*
             *    Begin looping through the providers, checking with each to provide them with the
             * opportunity to add information on their behalf if they have any to add.
             */
            Iterator<DiscoItemsProvider> providerItor = itemProviders.iterator();
            while (providerItor.hasNext()) {
                //   Add the items that this provider says it has...
                DiscoItemsProvider provider = providerItor.next();

                if (true == provider.hasItems(targetJID, senderJID)) {
                    Iterator<DiscoItem> itemItor = provider.getItems(targetJID, senderJID);
                    while (itemItor.hasNext()) {
                        queryElement.add(itemItor.next().getElement().createCopy());
                    }
                }
            }
        } else {
            // If we didn't find a DiscoItemsProvider then answer a not found error
            reply.setError(PacketError.Condition.item_not_found);
        }
        return reply;
    }

    /**
     * Returns the DiscoItemsProvider responsible for providing the items related to a given entity
     * or null if none was found.
     *
     * @param name the name of the identity.
     * @return the DiscoItemsProvider responsible for providing the items related to a given entity
     *         or null if none was found.
     */
    public Collection<DiscoItemsProvider> getProviders(String name) {
        return mEntities.get(name);
    }

    /**
     * Sets that a given DiscoItemsProvider will provide the items related to a given entity. This
     * message must be used when new modules (e.g. MUC) are implemented and need to provide
     * the items related to them.
     *
     * @param name     the name of the entity.
     * @param provider the DiscoItemsProvider that will provide the entity's items.
     */
    public boolean setProvider(String name, DiscoItemsProvider provider) {
        return mEntities.put(name, provider);
    }

    /**
     * Removes the DiscoItemsProvider related to a given entity.
     *
     * @param name the name of the entity.
     */
    public boolean removeProvider(String name, DiscoItemsProvider provider) {
        return mEntities.remove(name, provider);
    }
}