Java tutorial
/** * $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); } }