Commit 8c78affa authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

Result set merge work. JM-1147

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@9293 b35dd754-fafc-0310-a699-88a17e54d16e
parent 87e7616f
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* $Revision: 3023 $ * $Revision: 3023 $
* $Date: 2005-11-02 18:00:15 -0300 (Wed, 02 Nov 2005) $ * $Date: 2005-11-02 18:00:15 -0300 (Wed, 02 Nov 2005) $
* *
* Copyright (C) 2006 Jive Software. All rights reserved. * Copyright (C) 2007 Jive Software. All rights reserved.
* *
* This software is published under the terms of the GNU Public License (GPL), * This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution. * a copy of which is included in this distribution.
...@@ -112,21 +112,17 @@ public class AdHocCommandHandler extends IQHandler ...@@ -112,21 +112,17 @@ public class AdHocCommandHandler extends IQHandler
} }
} }
public Iterator<Element> getItems(String name, String node, JID senderJID) { public Iterator<DiscoItem> getItems(String name, String node, JID senderJID) {
List<Element> answer = new ArrayList<Element>(); List<DiscoItem> answer = new ArrayList<DiscoItem>();
if (!NAMESPACE.equals(node)) { if (!NAMESPACE.equals(node)) {
answer = Collections.emptyList(); answer = Collections.emptyList();
} }
else { else {
Element item;
for (AdHocCommand command : manager.getCommands()) { for (AdHocCommand command : manager.getCommands()) {
// Only include commands that the sender can invoke (i.e. has enough permissions) // Only include commands that the sender can invoke (i.e. has enough permissions)
if (command.hasPermission(senderJID)) { if (command.hasPermission(senderJID)) {
item = DocumentHelper.createElement("item"); final DiscoItem item = new DiscoItem(new JID(serverName),
item.addAttribute("jid", serverName); command.getLabel(), command.getCode(), null);
item.addAttribute("node", command.getCode());
item.addAttribute("name", command.getLabel());
answer.add(item); answer.add(item);
} }
} }
......
/** /**
* $RCSfile$ * $RCSfile$
* $Revision: 128 $ * $Revision: $
* $Date: 2004-10-25 20:42:00 -0300 (Mon, 25 Oct 2004) $ * $Date: $
* *
* Copyright (C) 2004 Jive Software. All rights reserved. * Copyright (C) 2007 Jive Software. All rights reserved.
* *
* This software is published under the terms of the GNU Public License (GPL), * This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution. * a copy of which is included in this distribution.
...@@ -11,51 +11,165 @@ ...@@ -11,51 +11,165 @@
package org.jivesoftware.openfire.disco; package org.jivesoftware.openfire.disco;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jivesoftware.openfire.resultsetmanager.Result;
import org.xmpp.packet.JID;
/** /**
* An item is associated with an XMPP Entity, usually thought of a children of the parent * An item is associated with an XMPP Entity, usually thought of a children of
* entity and normally are addressable as a JID.<p> * the parent entity and normally are addressable as a JID.<p>
* <p/> *
* An item associated with an entity may not be addressable as a JID. In order to handle * An item associated with an entity may not be addressable as a JID. In order
* such items, Service Discovery uses an optional 'node' attribute that supplements the * to handle such items, Service Discovery uses an optional 'node' attribute
* 'jid' attribute. * that supplements the 'jid' attribute.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public interface DiscoItem { public class DiscoItem implements Result {
private final JID jid;
private final String name;
private final String node;
private final String action;
private final Element element;
public DiscoItem(Element element) {
this.element = element;
jid = new JID(element.attributeValue("jid"));
action = element.attributeValue("action");
name = element.attributeValue("name");
node = element.attributeValue("node");
}
/** /**
* Creates a new DiscoItem instance.
*
* @param jid
* specifies the Jabber ID of the item "owner" or location
* (required).
* @param name
* specifies a natural-language name for the item (can be null).
* @param node
* specifies the particular node associated with the JID of the
* item "owner" or location (can be null).
* @param action
* specifies the action to be taken for the item.
* @throws IllegalArgumentException
* If a required parameter was null, or if the supplied 'action'
* parameter has another value than 'null', "update" or
* "remove".
*/
public DiscoItem(JID jid, String name, String node, String action) {
if (jid == null) {
throw new IllegalArgumentException("Argument 'jid' cannot be null.");
}
if (action != null && !action.equals("update")
&& !action.equals("remove")) {
throw new IllegalArgumentException(
"Argument 'jid' cannot have any other value than null, \"update\" or \"remove\".");
}
this.jid = jid;
this.name = name;
this.node = node;
this.action = action;
element = DocumentHelper.createElement("item");
element.addAttribute("jid", jid.toString());
if (action != null) {
element.addAttribute("action", action);
}
if (name != null) {
element.addAttribute("name", name);
}
if (node != null) {
element.addAttribute("node", node);
}
}
/**
* <p>
* Returns the entity's ID. * Returns the entity's ID.
* </p>
* *
* @return the entity's ID. * @return the entity's ID.
*/ */
public abstract String getJID(); public JID getJID() {
return jid;
}
/** /**
* Returns the node attribute that supplements the 'jid' attribute. A node is merely * <p>
* something that is associated with a JID and for which the JID can provide information.<p> * Returns the node attribute that supplements the 'jid' attribute. A node
* <p/> * is merely something that is associated with a JID and for which the JID
* Node attributes SHOULD be used only when trying to provide or query information which * can provide information.
* is not directly addressable. * </p>
* <p>
* Node attributes SHOULD be used only when trying to provide or query
* information which is not directly addressable.
* </p>
* *
* @return the node attribute that supplements the 'jid' attribute * @return the node attribute that supplements the 'jid' attribute
*/ */
public abstract String getNode(); public String getNode() {
return node;
}
/** /**
* Returns the entity's name. The entity's name specifies in natural-language the name for the * <p>
* item. * Returns the entity's name. The entity's name specifies in
* natural-language the name for the item.
* </p>
* *
* @return the entity's name. * @return the entity's name.
*/ */
public abstract String getName(); public String getName() {
return name;
}
/**
* <p>
* Returns the action (i.e. update or remove) that indicates what must be
* done with this item or null if none. An "update" action requests the
* server to create or update the item. Whilst a "remove" action requests to
* remove the item.
* </p>
*
* @return the action (i.e. update or remove) that indicates what must be
* done with this item or null if none.
*/
public String getAction() {
return action;
}
/** /**
* Returns the action (i.e. update or remove) that indicates what must be done with this item or * Returns a dom4j element that represents this DiscoItem object.
* null if none. An "update" action requests the server to create or update the item. Whilst a
* "remove" action requests to remove the item.
* *
* @return the action (i.e. update or remove) that indicates what must be done with this item or * @return element representing this object.
* null if none.
*/ */
public abstract String getAction(); public Element getElement() {
return element;
}
/*
* (non-Javadoc)
*
* @see org.jivesoftware.util.resultsetmanager.Result#getUID()
*/
public String getUID() {
final StringBuilder sb = new StringBuilder(jid.toString());
if (name != null) {
sb.append(name);
}
if (node != null) {
sb.append(node);
}
if (action != null) {
sb.append(action);
}
return sb.toString();
}
} }
\ No newline at end of file
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
package org.jivesoftware.openfire.disco; package org.jivesoftware.openfire.disco;
import org.dom4j.Element;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import java.util.Iterator; import java.util.Iterator;
...@@ -30,7 +29,7 @@ import java.util.Iterator; ...@@ -30,7 +29,7 @@ import java.util.Iterator;
public interface DiscoItemsProvider { public interface DiscoItemsProvider {
/** /**
* Returns an Iterator (of Element) with the target entity's items or null if none. Each Element * Returns an Iterator (of DiscoItem) with the target entity's items or null if none. Each DiscoItem
* must include a JID attribute and may include the name and node attributes of the entity. In * must include a JID attribute and may include the name and node attributes of the entity. In
* case that the sender of the disco request is not authorized to discover items an * case that the sender of the disco request is not authorized to discover items an
* UnauthorizedException will be thrown. * UnauthorizedException will be thrown.
...@@ -38,8 +37,8 @@ public interface DiscoItemsProvider { ...@@ -38,8 +37,8 @@ public interface DiscoItemsProvider {
* @param name the recipient JID's name. * @param name the recipient JID's name.
* @param node the requested disco node. * @param node the requested disco node.
* @param senderJID the XMPPAddress of user that sent the disco items request. * @param senderJID the XMPPAddress of user that sent the disco items request.
* @return an Iterator (of Element) with the target entity's items or null if none. * @return an Iterator (of DiscoItem) with the target entity's items or null if none.
*/ */
public abstract Iterator<Element> getItems(String name, String node, JID senderJID); public abstract Iterator<DiscoItem> getItems(String name, String node, JID senderJID);
} }
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
package org.jivesoftware.openfire.disco; package org.jivesoftware.openfire.disco;
import org.xmpp.packet.JID;
/** /**
* Represent a DiscoItem provided by the server. Therefore, the DiscoServerItems are responsible * Represent a DiscoItem provided by the server. Therefore, the DiscoServerItems are responsible
* for providing the DiscoInfoProvider and DiscoItemsProvider that will provide the information and * for providing the DiscoInfoProvider and DiscoItemsProvider that will provide the information and
...@@ -26,7 +28,27 @@ package org.jivesoftware.openfire.disco; ...@@ -26,7 +28,27 @@ package org.jivesoftware.openfire.disco;
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public interface DiscoServerItem extends DiscoItem { public class DiscoServerItem extends DiscoItem {
private final DiscoInfoProvider infoProvider;
private final DiscoItemsProvider itemsProvider;
public DiscoServerItem(JID jid, String name, String node, String action, DiscoInfoProvider infoProvider, DiscoItemsProvider itemsProvider) {
super(jid, name, node, action);
if (infoProvider == null)
{
throw new IllegalArgumentException("Argument 'infoProvider' cannot be null.");
}
if (itemsProvider == null)
{
throw new IllegalArgumentException("Argument 'itemsProvider' cannot be null.");
}
this.infoProvider = infoProvider;
this.itemsProvider = itemsProvider;
}
/** /**
* Returns the DiscoInfoProvider responsible for providing the information related to this item. * Returns the DiscoInfoProvider responsible for providing the information related to this item.
...@@ -35,7 +57,10 @@ public interface DiscoServerItem extends DiscoItem { ...@@ -35,7 +57,10 @@ public interface DiscoServerItem extends DiscoItem {
* *
* @return the DiscoInfoProvider responsible for providing the information related to this item. * @return the DiscoInfoProvider responsible for providing the information related to this item.
*/ */
public abstract DiscoInfoProvider getDiscoInfoProvider(); public DiscoInfoProvider getDiscoInfoProvider()
{
return infoProvider;
}
/** /**
* Returns the DiscoItemsProvider responsible for providing the items related to this item. * Returns the DiscoItemsProvider responsible for providing the items related to this item.
...@@ -44,5 +69,8 @@ public interface DiscoServerItem extends DiscoItem { ...@@ -44,5 +69,8 @@ public interface DiscoServerItem extends DiscoItem {
* *
* @return the DiscoItemsProvider responsible for providing the items related to this item. * @return the DiscoItemsProvider responsible for providing the items related to this item.
*/ */
public abstract DiscoItemsProvider getDiscoItemsProvider(); public DiscoItemsProvider getDiscoItemsProvider()
{
return itemsProvider;
}
} }
...@@ -22,6 +22,7 @@ import org.jivesoftware.openfire.cluster.ClusterManager; ...@@ -22,6 +22,7 @@ import org.jivesoftware.openfire.cluster.ClusterManager;
import org.jivesoftware.openfire.cluster.NodeID; import org.jivesoftware.openfire.cluster.NodeID;
import org.jivesoftware.openfire.forms.spi.XDataFormImpl; import org.jivesoftware.openfire.forms.spi.XDataFormImpl;
import org.jivesoftware.openfire.handler.IQHandler; import org.jivesoftware.openfire.handler.IQHandler;
import org.jivesoftware.openfire.resultsetmanager.ResultSet;
import org.jivesoftware.openfire.user.UserManager; import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.UserNotFoundException; import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
...@@ -59,6 +60,7 @@ import java.util.concurrent.locks.Lock; ...@@ -59,6 +60,7 @@ import java.util.concurrent.locks.Lock;
*/ */
public class IQDiscoInfoHandler extends IQHandler implements ClusterEventListener { public class IQDiscoInfoHandler extends IQHandler implements ClusterEventListener {
public static final String NAMESPACE_DISCO_INFO = "http://jabber.org/protocol/disco#info";
private Map<String, DiscoInfoProvider> entities = new HashMap<String, DiscoInfoProvider>(); private Map<String, DiscoInfoProvider> entities = new HashMap<String, DiscoInfoProvider>();
private Set<String> localServerFeatures = new CopyOnWriteArraySet<String>(); private Set<String> localServerFeatures = new CopyOnWriteArraySet<String>();
private Cache<String, Set<NodeID>> serverFeatures; private Cache<String, Set<NodeID>> serverFeatures;
...@@ -72,7 +74,7 @@ public class IQDiscoInfoHandler extends IQHandler implements ClusterEventListene ...@@ -72,7 +74,7 @@ public class IQDiscoInfoHandler extends IQHandler implements ClusterEventListene
public IQDiscoInfoHandler() { public IQDiscoInfoHandler() {
super("XMPP Disco Info Handler"); super("XMPP Disco Info Handler");
info = new IQHandlerInfo("query", "http://jabber.org/protocol/disco#info"); info = new IQHandlerInfo("query", NAMESPACE_DISCO_INFO);
// Initialize the user identity and features collections (optimization to avoid creating // Initialize the user identity and features collections (optimization to avoid creating
// the same objects for each response) // the same objects for each response)
Element userIdentity = DocumentHelper.createElement("identity"); Element userIdentity = DocumentHelper.createElement("identity");
...@@ -83,7 +85,7 @@ public class IQDiscoInfoHandler extends IQHandler implements ClusterEventListene ...@@ -83,7 +85,7 @@ public class IQDiscoInfoHandler extends IQHandler implements ClusterEventListene
userIdentity.addAttribute("category", "account"); userIdentity.addAttribute("category", "account");
userIdentity.addAttribute("type", "registered"); userIdentity.addAttribute("type", "registered");
registeredUserIdentities.add(userIdentity); registeredUserIdentities.add(userIdentity);
userFeatures.add("http://jabber.org/protocol/disco#info"); userFeatures.add(NAMESPACE_DISCO_INFO);
} }
public IQHandlerInfo getInfo() { public IQHandlerInfo getInfo() {
...@@ -120,17 +122,42 @@ public class IQDiscoInfoHandler extends IQHandler implements ClusterEventListene ...@@ -120,17 +122,42 @@ public class IQDiscoInfoHandler extends IQHandler implements ClusterEventListene
// Add to the reply all the identities provided by the DiscoInfoProvider // Add to the reply all the identities provided by the DiscoInfoProvider
Element identity; Element identity;
Iterator identities = infoProvider.getIdentities(name, node, packet.getFrom()); Iterator<Element> identities = infoProvider.getIdentities(name, node, packet.getFrom());
while (identities.hasNext()) { while (identities.hasNext()) {
identity = (Element)identities.next(); identity = identities.next();
identity.setQName(new QName(identity.getName(), queryElement.getNamespace())); identity.setQName(new QName(identity.getName(), queryElement.getNamespace()));
queryElement.add((Element)identity.clone()); queryElement.add((Element)identity.clone());
} }
// Add to the reply all the features provided by the DiscoInfoProvider // Add to the reply all the features provided by the DiscoInfoProvider
Iterator features = infoProvider.getFeatures(name, node, packet.getFrom()); Iterator<String> features = infoProvider.getFeatures(name, node, packet.getFrom());
boolean hasDiscoInfoFeature = false;
boolean hasDiscoItemsFeature = false;
boolean hasResultSetManagementFeature = false;
while (features.hasNext()) { while (features.hasNext()) {
queryElement.addElement("feature").addAttribute("var", (String)features.next()); final String feature = features.next();
queryElement.addElement("feature").addAttribute("var", feature);
if (feature.equals(NAMESPACE_DISCO_INFO)) {
hasDiscoInfoFeature = true;
} else if (feature.equals("http://jabber.org/protocol/disco#items")) {
hasDiscoItemsFeature = true;
} else if (feature.equals(ResultSet.NAMESPACE_RESULT_SET_MANAGEMENT)) {
hasResultSetManagementFeature = true;
}
}
if (hasDiscoItemsFeature && !hasResultSetManagementFeature) {
// IQDiscoItemsHandler provides result set management
// support.
queryElement.addElement("feature").addAttribute("var",
ResultSet.NAMESPACE_RESULT_SET_MANAGEMENT);
}
if (!hasDiscoInfoFeature) {
// XEP-0030 requires that every entity that supports service
// discovery broadcasts the disco#info feature.
queryElement.addElement("feature").addAttribute("var", NAMESPACE_DISCO_INFO);
} }
// Add to the reply the extended info (XDataForm) provided by the DiscoInfoProvider // Add to the reply the extended info (XDataForm) provided by the DiscoInfoProvider
...@@ -280,7 +307,7 @@ public class IQDiscoInfoHandler extends IQHandler implements ClusterEventListene ...@@ -280,7 +307,7 @@ public class IQDiscoInfoHandler extends IQHandler implements ClusterEventListene
public void initialize(XMPPServer server) { public void initialize(XMPPServer server) {
super.initialize(server); super.initialize(server);
serverFeatures = CacheFactory.createCache("Disco Server Features"); serverFeatures = CacheFactory.createCache("Disco Server Features");
addServerFeature("http://jabber.org/protocol/disco#info"); addServerFeature(NAMESPACE_DISCO_INFO);
// Track the implementors of ServerFeaturesProvider so that we can collect the features // Track the implementors of ServerFeaturesProvider so that we can collect the features
// provided by the server // provided by the server
for (ServerFeaturesProvider provider : server.getServerFeaturesProviders()) { for (ServerFeaturesProvider provider : server.getServerFeaturesProviders()) {
......
...@@ -22,6 +22,8 @@ import org.jivesoftware.openfire.cluster.ClusterEventListener; ...@@ -22,6 +22,8 @@ import org.jivesoftware.openfire.cluster.ClusterEventListener;
import org.jivesoftware.openfire.cluster.ClusterManager; import org.jivesoftware.openfire.cluster.ClusterManager;
import org.jivesoftware.openfire.cluster.NodeID; import org.jivesoftware.openfire.cluster.NodeID;
import org.jivesoftware.openfire.handler.IQHandler; import org.jivesoftware.openfire.handler.IQHandler;
import org.jivesoftware.openfire.resultsetmanager.ResultSet;
import org.jivesoftware.openfire.resultsetmanager.ResultSetImpl;
import org.jivesoftware.openfire.roster.RosterItem; import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.session.Session; import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.openfire.user.User; import org.jivesoftware.openfire.user.User;
...@@ -68,6 +70,7 @@ import java.util.concurrent.locks.Lock; ...@@ -68,6 +70,7 @@ import java.util.concurrent.locks.Lock;
public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProvider, ClusterEventListener, public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProvider, ClusterEventListener,
UserItemsProvider { UserItemsProvider {
public static final String NAMESPACE_DISCO_ITEMS = "http://jabber.org/protocol/disco#items";
private Map<String,DiscoItemsProvider> entities = new HashMap<String,DiscoItemsProvider>(); private Map<String,DiscoItemsProvider> entities = new HashMap<String,DiscoItemsProvider>();
private Map<String, Element> localServerItems = new HashMap<String, Element>(); private Map<String, Element> localServerItems = new HashMap<String, Element>();
private Cache<String, ClusteredServerItem> serverItems; private Cache<String, ClusteredServerItem> serverItems;
...@@ -77,7 +80,7 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv ...@@ -77,7 +80,7 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv
public IQDiscoItemsHandler() { public IQDiscoItemsHandler() {
super("XMPP Disco Items Handler"); super("XMPP Disco Items Handler");
info = new IQHandlerInfo("query", "http://jabber.org/protocol/disco#items"); info = new IQHandlerInfo("query", NAMESPACE_DISCO_ITEMS);
} }
public IQHandlerInfo getInfo() { public IQHandlerInfo getInfo() {
...@@ -97,39 +100,6 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv ...@@ -97,39 +100,6 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv
return reply; return reply;
} }
// If addressed to user@domain, add items from UserItemsProviders to
// the reply.
if (packet.getTo() != null && packet.getTo().getNode() != null) {
String name = packet.getTo().getNode();
reply.setChildElement(packet.getChildElement().createCopy());
Element queryElement = reply.getChildElement();
List<UserItemsProvider> itemsProviders = XMPPServer.getInstance().getUserItemsProviders();
if (itemsProviders.isEmpty()) {
// If we didn't find any UserItemsProviders, then answer a not found error
reply.setChildElement(packet.getChildElement().createCopy());
reply.setError(PacketError.Condition.item_not_found);
}
else {
for (UserItemsProvider itemsProvider : itemsProviders) {
// Check if we have items associated with the requested name
Iterator<Element> itemsItr = itemsProvider.getUserItems(name, packet.getFrom());
if (itemsItr != null) {
// Add to the reply all the items provided by the UserItemsProvider
Element item;
while (itemsItr.hasNext()) {
item = itemsItr.next();
item.setQName(new QName(item.getName(), queryElement.getNamespace()));
queryElement.add(item.createCopy());
}
}
}
}
return reply;
}
// Look for a DiscoItemsProvider associated with the requested entity. // Look for a DiscoItemsProvider associated with the requested entity.
// We consider the host of the recipient JID of the packet as the entity. It's the // We consider the host of the recipient JID of the packet as the entity. It's the
// DiscoItemsProvider responsibility to provide the items associated with the JID's name // DiscoItemsProvider responsibility to provide the items associated with the JID's name
...@@ -147,19 +117,69 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv ...@@ -147,19 +117,69 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv
String node = iq.attributeValue("node"); String node = iq.attributeValue("node");
// Check if we have items associated with the requested name and node // Check if we have items associated with the requested name and node
Iterator<Element> itemsItr = itemsProvider.getItems(name, node, packet.getFrom()); Iterator<DiscoItem> itemsItr = itemsProvider.getItems(name, node, packet.getFrom());
if (itemsItr != null) { if (itemsItr != null) {
reply.setChildElement(iq.createCopy()); reply.setChildElement(iq.createCopy());
Element queryElement = reply.getChildElement(); Element queryElement = reply.getChildElement();
// See if the requesting entity would like to apply 'result set
// management'
final Element rsmElement = packet.getChildElement().element(
QName.get("set",
ResultSet.NAMESPACE_RESULT_SET_MANAGEMENT));
// apply RSM only if the element exists, and the (total) results
// set is not empty.
final boolean applyRSM = rsmElement != null
&& itemsItr.hasNext();
if (applyRSM) {
if (!ResultSet.isValidRSMRequest(rsmElement))
{
reply.setError(PacketError.Condition.bad_request);
return reply;
}
// Calculate which results to include.
final List<DiscoItem> rsmResults;
final List<DiscoItem> allItems = new ArrayList<DiscoItem>();
while (itemsItr.hasNext()) {
allItems.add(itemsItr.next());
}
final ResultSet<DiscoItem> rs = new ResultSetImpl<DiscoItem>(
allItems);
try {
rsmResults = rs.applyRSMDirectives(rsmElement);
} catch (NullPointerException e) {
final IQ itemNotFound = IQ.createResultIQ(packet);
itemNotFound.setError(PacketError.Condition.item_not_found);
return itemNotFound;
}
// add the applicable results to the IQ-result
for (DiscoItem item : rsmResults) {
final Element resultElement = item.getElement();
resultElement.setQName(new QName(resultElement
.getName(), queryElement.getNamespace()));
queryElement.add(resultElement.createCopy());
}
// overwrite the 'set' element.
queryElement.remove(queryElement.element(
QName.get("set",
ResultSet.NAMESPACE_RESULT_SET_MANAGEMENT)));
queryElement.add(rs.generateSetElementFromResults(rsmResults));
} else {
// don't apply RSM:
// Add to the reply all the items provided by the DiscoItemsProvider // Add to the reply all the items provided by the DiscoItemsProvider
Element item; Element item;
while (itemsItr.hasNext()) { while (itemsItr.hasNext()) {
item = itemsItr.next(); item = itemsItr.next().getElement();
item.setQName(new QName(item.getName(), queryElement.getNamespace())); item.setQName(new QName(item.getName(), queryElement.getNamespace()));
queryElement.add(item.createCopy()); queryElement.add(item.createCopy());
} }
} }
}
else { else {
// If the DiscoItemsProvider has no items for the requested name and node // If the DiscoItemsProvider has no items for the requested name and node
// then answer a not found error // then answer a not found error
...@@ -227,10 +247,10 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv ...@@ -227,10 +247,10 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv
while (items.hasNext()) { while (items.hasNext()) {
discoItem = items.next(); discoItem = items.next();
// Add the element to the list of items related to the server // Add the element to the list of items related to the server
addComponentItem(discoItem.getJID(), discoItem.getNode(), discoItem.getName()); addComponentItem(discoItem.getJID().toString(), discoItem.getNode(), discoItem.getName());
// Add the new item as a valid entity that could receive info and items disco requests // Add the new item as a valid entity that could receive info and items disco requests
String host = new JID(discoItem.getJID()).getDomain(); String host = discoItem.getJID().getDomain();
infoHandler.setProvider(host, discoItem.getDiscoInfoProvider()); infoHandler.setProvider(host, discoItem.getDiscoInfoProvider());
setProvider(host, discoItem.getDiscoItemsProvider()); setProvider(host, discoItem.getDiscoItemsProvider());
} }
...@@ -251,10 +271,10 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv ...@@ -251,10 +271,10 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv
while (items.hasNext()) { while (items.hasNext()) {
discoItem = items.next(); discoItem = items.next();
// Remove the item from the server items list // Remove the item from the server items list
removeComponentItem(discoItem.getJID()); removeComponentItem(discoItem.getJID().toString());
// Remove the item as a valid entity that could receive info and items disco requests // Remove the item as a valid entity that could receive info and items disco requests
String host = new JID(discoItem.getJID()).getDomain(); String host = discoItem.getJID().getDomain();
infoHandler.removeProvider(host); infoHandler.removeProvider(host);
removeProvider(host); removeProvider(host);
} }
...@@ -452,7 +472,7 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv ...@@ -452,7 +472,7 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv
private DiscoItemsProvider getServerItemsProvider() { private DiscoItemsProvider getServerItemsProvider() {
return new DiscoItemsProvider() { return new DiscoItemsProvider() {
public Iterator<Element> getItems(String name, String node, JID senderJID) { public Iterator<DiscoItem> getItems(String name, String node, JID senderJID) {
if (node != null) { if (node != null) {
// Check if there is a provider for the requested node // Check if there is a provider for the requested node
if (serverNodeProviders.get(node) != null) { if (serverNodeProviders.get(node) != null) {
...@@ -461,15 +481,39 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv ...@@ -461,15 +481,39 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv
return null; return null;
} }
if (name == null) { if (name == null) {
List<Element> answer = new ArrayList<Element>(); List<DiscoItem> answer = new ArrayList<DiscoItem>();
for (ClusteredServerItem item : serverItems.values()) { for (ClusteredServerItem item : serverItems.values()) {
answer.add(item.element); answer.add(new DiscoItem(item.element));
} }
return answer.iterator(); return answer.iterator();
} }
else { else {
// If addressed to user@domain, add items from UserItemsProviders to
// the reply.
List<UserItemsProvider> itemsProviders = XMPPServer.getInstance().getUserItemsProviders();
if (itemsProviders.isEmpty()) {
// If we didn't find any UserItemsProviders, then answer a not found error
return null; return null;
} }
List<DiscoItem> answer = new ArrayList<DiscoItem>();
for (UserItemsProvider itemsProvider : itemsProviders) {
// Check if we have items associated with the requested name
Iterator<Element> itemsItr = itemsProvider.getUserItems(name, senderJID);
if (itemsItr != null) {
// Add to the reply all the items provided by the UserItemsProvider
Element item;
while (itemsItr.hasNext()) {
item = itemsItr.next();
JID itemJid = new JID(item.attributeValue("jid"));
String itemName = item.attributeValue("name");
String itemNode = item.attributeValue("node");
String itemAction = item.attributeValue("action");
answer.add(new DiscoItem(itemJid, itemName, itemNode, itemAction));
}
}
}
return answer.iterator();
}
} }
}; };
} }
......
...@@ -16,10 +16,7 @@ import org.dom4j.Element; ...@@ -16,10 +16,7 @@ import org.dom4j.Element;
import org.jivesoftware.openfire.*; import org.jivesoftware.openfire.*;
import org.jivesoftware.openfire.auth.UnauthorizedException; import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.container.BasicModule; import org.jivesoftware.openfire.container.BasicModule;
import org.jivesoftware.openfire.disco.DiscoInfoProvider; import org.jivesoftware.openfire.disco.*;
import org.jivesoftware.openfire.disco.DiscoItemsProvider;
import org.jivesoftware.openfire.disco.DiscoServerItem;
import org.jivesoftware.openfire.disco.ServerItemsProvider;
import org.jivesoftware.openfire.filetransfer.FileTransferManager; import org.jivesoftware.openfire.filetransfer.FileTransferManager;
import org.jivesoftware.openfire.forms.spi.XDataFormImpl; import org.jivesoftware.openfire.forms.spi.XDataFormImpl;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
...@@ -284,31 +281,11 @@ public class FileTransferProxy extends BasicModule ...@@ -284,31 +281,11 @@ public class FileTransferProxy extends BasicModule
return items.iterator(); return items.iterator();
} }
items.add(new DiscoServerItem() { final DiscoServerItem item = new DiscoServerItem(new JID(
public String getJID() { getServiceDomain()), "Socks 5 Bytestreams Proxy", null, null, this,
return getServiceDomain(); this);
} items.add(item);
public String getName() {
return "Socks 5 Bytestreams Proxy";
}
public String getAction() {
return null;
}
public String getNode() {
return null;
}
public DiscoInfoProvider getDiscoInfoProvider() {
return FileTransferProxy.this;
}
public DiscoItemsProvider getDiscoItemsProvider() {
return FileTransferProxy.this;
}
});
return items.iterator(); return items.iterator();
} }
...@@ -338,9 +315,9 @@ public class FileTransferProxy extends BasicModule ...@@ -338,9 +315,9 @@ public class FileTransferProxy extends BasicModule
return true; return true;
} }
public Iterator<Element> getItems(String name, String node, JID senderJID) { public Iterator<DiscoItem> getItems(String name, String node, JID senderJID) {
// A proxy server has no items // A proxy server has no items
return new ArrayList<Element>().iterator(); return new ArrayList<DiscoItem>().iterator();
} }
public void process(Packet packet) throws UnauthorizedException, PacketException { public void process(Packet packet) throws UnauthorizedException, PacketException {
......
...@@ -159,20 +159,14 @@ public class IQOfflineMessagesHandler extends IQHandler implements ServerFeature ...@@ -159,20 +159,14 @@ public class IQOfflineMessagesHandler extends IQHandler implements ServerFeature
return NAMESPACE.equals(node) && userManager.isRegisteredUser(senderJID.getNode()); return NAMESPACE.equals(node) && userManager.isRegisteredUser(senderJID.getNode());
} }
public Iterator<Element> getItems(String name, String node, JID senderJID) { public Iterator<DiscoItem> getItems(String name, String node, JID senderJID) {
// Mark that offline messages shouldn't be sent when the user becomes available // Mark that offline messages shouldn't be sent when the user becomes available
stopOfflineFlooding(senderJID); stopOfflineFlooding(senderJID);
List<Element> answer = new ArrayList<Element>(); List<DiscoItem> answer = new ArrayList<DiscoItem>();
Element item;
for (OfflineMessage offlineMessage : messageStore.getMessages(senderJID.getNode(), false)) { for (OfflineMessage offlineMessage : messageStore.getMessages(senderJID.getNode(), false)) {
item = DocumentHelper.createElement("item");
item.addAttribute("jid", senderJID.toBareJID());
item.addAttribute("name", offlineMessage.getFrom().toString());
synchronized (dateFormat) { synchronized (dateFormat) {
item.addAttribute("node", dateFormat.format(offlineMessage.getCreationDate())); answer.add(new DiscoItem(new JID(senderJID.toBareJID()), offlineMessage.getFrom().toString(), dateFormat.format(offlineMessage.getCreationDate()), null));
} }
answer.add(item);
} }
return answer.iterator(); return answer.iterator();
......
...@@ -16,10 +16,7 @@ import org.dom4j.Element; ...@@ -16,10 +16,7 @@ import org.dom4j.Element;
import org.jivesoftware.openfire.*; import org.jivesoftware.openfire.*;
import org.jivesoftware.openfire.auth.UnauthorizedException; import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.container.BasicModule; import org.jivesoftware.openfire.container.BasicModule;
import org.jivesoftware.openfire.disco.DiscoInfoProvider; import org.jivesoftware.openfire.disco.*;
import org.jivesoftware.openfire.disco.DiscoItemsProvider;
import org.jivesoftware.openfire.disco.DiscoServerItem;
import org.jivesoftware.openfire.disco.ServerItemsProvider;
import org.jivesoftware.openfire.forms.spi.XDataFormImpl; import org.jivesoftware.openfire.forms.spi.XDataFormImpl;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
...@@ -91,7 +88,9 @@ public class MediaProxyService extends BasicModule ...@@ -91,7 +88,9 @@ public class MediaProxyService extends BasicModule
Thread t = new Thread(echo); Thread t = new Thread(echo);
t.start(); t.start();
} catch (UnknownHostException e) { } catch (UnknownHostException e) {
// Ignore
} catch (SocketException e) { } catch (SocketException e) {
// Ignore
} }
routingTable.addComponentRoute(getAddress(), this); routingTable.addComponentRoute(getAddress(), this);
...@@ -117,9 +116,9 @@ public class MediaProxyService extends BasicModule ...@@ -117,9 +116,9 @@ public class MediaProxyService extends BasicModule
return serviceName; return serviceName;
} }
public Iterator<Element> getItems(String name, String node, JID senderJID) { public Iterator<DiscoItem> getItems(String name, String node, JID senderJID) {
// A proxy server has no items // A proxy server has no items
return new ArrayList<Element>().iterator(); return new ArrayList<DiscoItem>().iterator();
} }
public void process(Packet packet) throws UnauthorizedException, PacketException { public void process(Packet packet) throws UnauthorizedException, PacketException {
...@@ -287,37 +286,17 @@ public class MediaProxyService extends BasicModule ...@@ -287,37 +286,17 @@ public class MediaProxyService extends BasicModule
return new JID(null, getServiceDomain(), null); return new JID(null, getServiceDomain(), null);
} }
public Iterator<DiscoServerItem> getItems() { public Iterator<DiscoServerItem> getItems()
{
List<DiscoServerItem> items = new ArrayList<DiscoServerItem>(); List<DiscoServerItem> items = new ArrayList<DiscoServerItem>();
if (!isEnabled()) { if (!isEnabled())
{
return items.iterator(); return items.iterator();
} }
items.add(new DiscoServerItem() { final DiscoServerItem item = new DiscoServerItem(new JID(
public String getJID() { getServiceDomain()), "Media Proxy Service", null, null, this, this);
return getServiceDomain(); items.add(item);
}
public String getName() {
return "Media Proxy Service";
}
public String getAction() {
return null;
}
public String getNode() {
return null;
}
public DiscoInfoProvider getDiscoInfoProvider() {
return MediaProxyService.this;
}
public DiscoItemsProvider getDiscoItemsProvider() {
return MediaProxyService.this;
}
});
return items.iterator(); return items.iterator();
} }
......
...@@ -18,6 +18,7 @@ import org.jivesoftware.openfire.muc.spi.IQAdminHandler; ...@@ -18,6 +18,7 @@ import org.jivesoftware.openfire.muc.spi.IQAdminHandler;
import org.jivesoftware.openfire.muc.spi.IQOwnerHandler; import org.jivesoftware.openfire.muc.spi.IQOwnerHandler;
import org.jivesoftware.openfire.muc.spi.LocalMUCRole; import org.jivesoftware.openfire.muc.spi.LocalMUCRole;
import org.jivesoftware.openfire.muc.spi.LocalMUCUser; import org.jivesoftware.openfire.muc.spi.LocalMUCUser;
import org.jivesoftware.openfire.resultsetmanager.Result;
import org.jivesoftware.openfire.user.UserAlreadyExistsException; import org.jivesoftware.openfire.user.UserAlreadyExistsException;
import org.jivesoftware.openfire.user.UserNotFoundException; import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.JiveConstants; import org.jivesoftware.util.JiveConstants;
...@@ -40,7 +41,7 @@ import java.util.List; ...@@ -40,7 +41,7 @@ import java.util.List;
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
@JiveID(JiveConstants.MUC_ROOM) @JiveID(JiveConstants.MUC_ROOM)
public interface MUCRoom extends Externalizable { public interface MUCRoom extends Externalizable, Result {
/** /**
* Get the name of this room. * Get the name of this room.
......
...@@ -2197,4 +2197,15 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -2197,4 +2197,15 @@ public class LocalMUCRoom implements MUCRoom {
emptyDate = otherRoom.emptyDate; emptyDate = otherRoom.emptyDate;
savedToDB = otherRoom.savedToDB; savedToDB = otherRoom.savedToDB;
} }
/*
* (non-Javadoc)
* @see org.jivesoftware.util.resultsetmanager.Result#getUID()
*/
@Override
public String getUID()
{
// name is unique for each one particular MUC service.
return name;
}
} }
\ No newline at end of file
...@@ -18,16 +18,14 @@ import org.jivesoftware.openfire.auth.UnauthorizedException; ...@@ -18,16 +18,14 @@ import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.cluster.ClusterEventListener; import org.jivesoftware.openfire.cluster.ClusterEventListener;
import org.jivesoftware.openfire.cluster.ClusterManager; import org.jivesoftware.openfire.cluster.ClusterManager;
import org.jivesoftware.openfire.container.BasicModule; import org.jivesoftware.openfire.container.BasicModule;
import org.jivesoftware.openfire.disco.DiscoInfoProvider; import org.jivesoftware.openfire.disco.*;
import org.jivesoftware.openfire.disco.DiscoItemsProvider;
import org.jivesoftware.openfire.disco.DiscoServerItem;
import org.jivesoftware.openfire.disco.ServerItemsProvider;
import org.jivesoftware.openfire.forms.DataForm; import org.jivesoftware.openfire.forms.DataForm;
import org.jivesoftware.openfire.forms.FormField; import org.jivesoftware.openfire.forms.FormField;
import org.jivesoftware.openfire.forms.spi.XDataFormImpl; import org.jivesoftware.openfire.forms.spi.XDataFormImpl;
import org.jivesoftware.openfire.forms.spi.XFormFieldImpl; import org.jivesoftware.openfire.forms.spi.XFormFieldImpl;
import org.jivesoftware.openfire.muc.*; import org.jivesoftware.openfire.muc.*;
import org.jivesoftware.openfire.muc.cluster.*; import org.jivesoftware.openfire.muc.cluster.*;
import org.jivesoftware.openfire.resultsetmanager.ResultSet;
import org.jivesoftware.openfire.stats.Statistic; import org.jivesoftware.openfire.stats.Statistic;
import org.jivesoftware.openfire.stats.StatisticsManager; import org.jivesoftware.openfire.stats.StatisticsManager;
import org.jivesoftware.util.*; import org.jivesoftware.util.*;
...@@ -52,8 +50,8 @@ import java.util.concurrent.atomic.AtomicLong; ...@@ -52,8 +50,8 @@ import java.util.concurrent.atomic.AtomicLong;
* *
* Temporary rooms are held in memory as long as they have occupants. They will be destroyed after * Temporary rooms are held in memory as long as they have occupants. They will be destroyed after
* the last occupant left the room. On the other hand, persistent rooms are always present in memory * the last occupant left the room. On the other hand, persistent rooms are always present in memory
* even after the last occupant left the room. In order to keep memory clean of peristent rooms that * even after the last occupant left the room. In order to keep memory clean of persistent rooms that
* have been forgotten or abandonded this class includes a clean up process. The clean up process * have been forgotten or abandoned this class includes a clean up process. The clean up process
* will remove from memory rooms that haven't had occupants for a while. Moreover, forgotten or * will remove from memory rooms that haven't had occupants for a while. Moreover, forgotten or
* abandoned rooms won't be loaded into memory when the Multi-User Chat service starts up. * abandoned rooms won't be loaded into memory when the Multi-User Chat service starts up.
* *
...@@ -129,6 +127,12 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -129,6 +127,12 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
* The handler of packets with namespace jabber:iq:register for the server. * The handler of packets with namespace jabber:iq:register for the server.
*/ */
private IQMUCRegisterHandler registerHandler = null; private IQMUCRegisterHandler registerHandler = null;
/**
* The handler of search requests ('jabber:iq:search' namespace).
*/
private IQMUCSearchHandler searchHandler = null;
/** /**
* The total time all agents took to chat * * The total time all agents took to chat *
*/ */
...@@ -186,7 +190,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -186,7 +190,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
/** /**
* The time to elapse between each rooms cleanup. Default frequency is 60 minutes. * The time to elapse between each rooms cleanup. Default frequency is 60 minutes.
*/ */
private final long cleanup_frequency = 60 * 60 * 1000; private static final long CLEANUP_FREQUENCY = 60 * 60 * 1000;
/** /**
* Total number of received messages in all rooms since the last reset. The counter * Total number of received messages in all rooms since the last reset. The counter
...@@ -272,6 +276,10 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -272,6 +276,10 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
IQ reply = registerHandler.handleIQ(iq); IQ reply = registerHandler.handleIQ(iq);
router.route(reply); router.route(reply);
} }
else if ("jabber:iq:search".equals(namespace)) {
IQ reply = searchHandler.handleIQ(iq);
router.route(reply);
}
else if ("http://jabber.org/protocol/disco#info".equals(namespace)) { else if ("http://jabber.org/protocol/disco#info".equals(namespace)) {
// TODO MUC should have an IQDiscoInfoHandler of its own when MUC becomes // TODO MUC should have an IQDiscoInfoHandler of its own when MUC becomes
// a component // a component
...@@ -616,9 +624,9 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -616,9 +624,9 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
} }
/** /**
* Returns the limit date after which rooms whithout activity will be removed from memory. * Returns the limit date after which rooms without activity will be removed from memory.
* *
* @return the limit date after which rooms whithout activity will be removed from memory. * @return the limit date after which rooms without activity will be removed from memory.
*/ */
private Date getCleanupDate() { private Date getCleanupDate() {
return new Date(System.currentTimeMillis() - (emptyLimit * 3600000)); return new Date(System.currentTimeMillis() - (emptyLimit * 3600000));
...@@ -862,12 +870,14 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -862,12 +870,14 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
timer.schedule(logConversationTask, log_timeout, log_timeout); timer.schedule(logConversationTask, log_timeout, log_timeout);
// Remove unused rooms from memory // Remove unused rooms from memory
cleanupTask = new CleanupTask(); cleanupTask = new CleanupTask();
timer.schedule(cleanupTask, cleanup_frequency, cleanup_frequency); timer.schedule(cleanupTask, CLEANUP_FREQUENCY, CLEANUP_FREQUENCY);
routingTable = server.getRoutingTable(); routingTable = server.getRoutingTable();
router = server.getPacketRouter(); router = server.getPacketRouter();
// Configure the handler of iq:register packets // Configure the handler of iq:register packets
registerHandler = new IQMUCRegisterHandler(this); registerHandler = new IQMUCRegisterHandler(this);
// Configure the handler of jabber:iq:search packets
searchHandler = new IQMUCSearchHandler(this);
// Listen to cluster events // Listen to cluster events
ClusterManager.addListener(this); ClusterManager.addListener(this);
} }
...@@ -1073,42 +1083,30 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -1073,42 +1083,30 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
} }
public Iterator<DiscoServerItem> getItems() { public Iterator<DiscoServerItem> getItems() {
// Check if the service is disabled. Info is not available when disabled. // Check if the service is disabled. Info is not available when
if (!isServiceEnabled()) { // disabled.
if (!isServiceEnabled())
{
return null; return null;
} }
ArrayList<DiscoServerItem> items = new ArrayList<DiscoServerItem>();
items.add(new DiscoServerItem() {
public String getJID() {
return getServiceDomain();
}
public String getName() { final ArrayList<DiscoServerItem> items = new ArrayList<DiscoServerItem>();
final String name;
// Check if there is a system property that overrides the default value // Check if there is a system property that overrides the default value
String serviceName = JiveGlobals.getProperty("muc.service-name"); String serviceName = JiveGlobals.getProperty("muc.service-name");
if (serviceName != null && serviceName.trim().length() > 0) { if (serviceName != null && serviceName.trim().length() > 0)
return serviceName; {
name = serviceName;
} }
else
{
// Return the default service name based on the current locale // Return the default service name based on the current locale
return LocaleUtils.getLocalizedString("muc.service-name"); name = LocaleUtils.getLocalizedString("muc.service-name");
}
public String getAction() {
return null;
}
public String getNode() {
return null;
}
public DiscoInfoProvider getDiscoInfoProvider() {
return MultiUserChatServerImpl.this;
} }
public DiscoItemsProvider getDiscoItemsProvider() { final DiscoServerItem item = new DiscoServerItem(new JID(
return MultiUserChatServerImpl.this; getServiceDomain()), name, null, null, this, this);
} items.add(item);
});
return items.iterator(); return items.iterator();
} }
...@@ -1122,6 +1120,12 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -1122,6 +1120,12 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
identity.addAttribute("type", "text"); identity.addAttribute("type", "text");
identities.add(identity); identities.add(identity);
Element searchId = DocumentHelper.createElement("identity");
searchId.addAttribute("category", "directory");
searchId.addAttribute("name", "Public Chatroom Search");
searchId.addAttribute("type", "chatroom");
identities.add(searchId);
} }
else if (name != null && node == null) { else if (name != null && node == null) {
// Answer the identity of a given room // Answer the identity of a given room
...@@ -1160,6 +1164,8 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -1160,6 +1164,8 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
features.add("http://jabber.org/protocol/muc"); features.add("http://jabber.org/protocol/muc");
features.add("http://jabber.org/protocol/disco#info"); features.add("http://jabber.org/protocol/disco#info");
features.add("http://jabber.org/protocol/disco#items"); features.add("http://jabber.org/protocol/disco#items");
features.add("jabber:iq:search");
features.add(ResultSet.NAMESPACE_RESULT_SET_MANAGEMENT);
} }
else if (name != null && node == null) { else if (name != null && node == null) {
// Answer the features of a given room // Answer the features of a given room
...@@ -1266,22 +1272,21 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -1266,22 +1272,21 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
return false; return false;
} }
public Iterator<Element> getItems(String name, String node, JID senderJID) { public Iterator<DiscoItem> getItems(String name, String node, JID senderJID) {
// Check if the service is disabled. Info is not available when disabled. // Check if the service is disabled. Info is not available when disabled.
if (!isServiceEnabled()) { if (!isServiceEnabled()) {
return null; return null;
} }
List<Element> answer = new ArrayList<Element>(); List<DiscoItem> answer = new ArrayList<DiscoItem>();
if (name == null && node == null) { if (name == null && node == null)
Element item; {
// Answer all the public rooms as items // Answer all the public rooms as items
for (MUCRoom room : rooms.values()) { for (MUCRoom room : rooms.values())
if (canDiscoverRoom(room)) { {
item = DocumentHelper.createElement("item"); if (canDiscoverRoom(room))
item.addAttribute("jid", room.getRole().getRoleAddress().toString()); {
item.addAttribute("name", room.getNaturalLanguageName()); answer.add(new DiscoItem(room.getRole().getRoleAddress(),
room.getNaturalLanguageName(), null, null));
answer.add(item);
} }
} }
} }
...@@ -1289,13 +1294,9 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -1289,13 +1294,9 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
// Answer the room occupants as items if that info is publicly available // Answer the room occupants as items if that info is publicly available
MUCRoom room = getChatRoom(name); MUCRoom room = getChatRoom(name);
if (room != null && canDiscoverRoom(room)) { if (room != null && canDiscoverRoom(room)) {
Element item;
for (MUCRole role : room.getOccupants()) { for (MUCRole role : room.getOccupants()) {
// TODO Should we filter occupants that are invisible (presence is not broadcasted)? // TODO Should we filter occupants that are invisible (presence is not broadcasted)?
item = DocumentHelper.createElement("item"); answer.add(new DiscoItem(role.getRoleAddress(), null, null, null));
item.addAttribute("jid", role.getRoleAddress().toString());
answer.add(item);
} }
} }
} }
......
...@@ -22,10 +22,7 @@ import org.jivesoftware.openfire.cluster.ClusterManager; ...@@ -22,10 +22,7 @@ import org.jivesoftware.openfire.cluster.ClusterManager;
import org.jivesoftware.openfire.commands.AdHocCommandManager; import org.jivesoftware.openfire.commands.AdHocCommandManager;
import org.jivesoftware.openfire.component.InternalComponentManager; import org.jivesoftware.openfire.component.InternalComponentManager;
import org.jivesoftware.openfire.container.BasicModule; import org.jivesoftware.openfire.container.BasicModule;
import org.jivesoftware.openfire.disco.DiscoInfoProvider; import org.jivesoftware.openfire.disco.*;
import org.jivesoftware.openfire.disco.DiscoItemsProvider;
import org.jivesoftware.openfire.disco.DiscoServerItem;
import org.jivesoftware.openfire.disco.ServerItemsProvider;
import org.jivesoftware.openfire.forms.DataForm; import org.jivesoftware.openfire.forms.DataForm;
import org.jivesoftware.openfire.forms.spi.XDataFormImpl; import org.jivesoftware.openfire.forms.spi.XDataFormImpl;
import org.jivesoftware.openfire.forms.spi.XFormFieldImpl; import org.jivesoftware.openfire.forms.spi.XFormFieldImpl;
...@@ -520,32 +517,10 @@ public class PubSubModule extends BasicModule implements ServerItemsProvider, Di ...@@ -520,32 +517,10 @@ public class PubSubModule extends BasicModule implements ServerItemsProvider, Di
public Iterator<DiscoServerItem> getItems() { public Iterator<DiscoServerItem> getItems() {
ArrayList<DiscoServerItem> items = new ArrayList<DiscoServerItem>(); ArrayList<DiscoServerItem> items = new ArrayList<DiscoServerItem>();
final DiscoServerItem item = new DiscoServerItem(new JID(
items.add(new DiscoServerItem() { getServiceDomain()), "Publish-Subscribe service", null, null, this,
public String getJID() { this);
return getServiceDomain(); items.add(item);
}
public String getName() {
return "Publish-Subscribe service";
}
public String getAction() {
return null;
}
public String getNode() {
return null;
}
public DiscoInfoProvider getDiscoInfoProvider() {
return PubSubModule.this;
}
public DiscoItemsProvider getDiscoItemsProvider() {
return PubSubModule.this;
}
});
return items.iterator(); return items.iterator();
} }
...@@ -688,18 +663,16 @@ public class PubSubModule extends BasicModule implements ServerItemsProvider, Di ...@@ -688,18 +663,16 @@ public class PubSubModule extends BasicModule implements ServerItemsProvider, Di
return false; return false;
} }
public Iterator<Element> getItems(String name, String node, JID senderJID) { public Iterator<DiscoItem> getItems(String name, String node, JID senderJID) {
List<Element> answer = new ArrayList<Element>(); List<DiscoItem> answer = new ArrayList<DiscoItem>();
String serviceDomain = getServiceDomain(); String serviceDomain = getServiceDomain();
if (name == null && node == null) { if (name == null && node == null) {
Element item;
// Answer all first level nodes // Answer all first level nodes
for (Node pubNode : rootCollectionNode.getNodes()) { for (Node pubNode : rootCollectionNode.getNodes()) {
if (canDiscoverNode(pubNode)) { if (canDiscoverNode(pubNode)) {
item = DocumentHelper.createElement("item"); final DiscoItem item = new DiscoItem(
item.addAttribute("jid", serviceDomain); new JID(serviceDomain), pubNode.getName(),
item.addAttribute("node", pubNode.getNodeID()); pubNode.getNodeID(), null);
item.addAttribute("name", pubNode.getName());
answer.add(item); answer.add(item);
} }
} }
...@@ -708,26 +681,19 @@ public class PubSubModule extends BasicModule implements ServerItemsProvider, Di ...@@ -708,26 +681,19 @@ public class PubSubModule extends BasicModule implements ServerItemsProvider, Di
Node pubNode = getNode(node); Node pubNode = getNode(node);
if (pubNode != null && canDiscoverNode(pubNode)) { if (pubNode != null && canDiscoverNode(pubNode)) {
if (pubNode.isCollectionNode()) { if (pubNode.isCollectionNode()) {
Element item;
// Answer all nested nodes as items // Answer all nested nodes as items
for (Node nestedNode : pubNode.getNodes()) { for (Node nestedNode : pubNode.getNodes()) {
if (canDiscoverNode(nestedNode)) { if (canDiscoverNode(nestedNode)) {
item = DocumentHelper.createElement("item"); final DiscoItem item = new DiscoItem(new JID(serviceDomain), nestedNode.getName(),
item.addAttribute("jid", serviceDomain); nestedNode.getNodeID(), null);
item.addAttribute("node", nestedNode.getNodeID());
item.addAttribute("name", nestedNode.getName());
answer.add(item); answer.add(item);
} }
} }
} }
else { else {
// This is a leaf node so answer the published items which exist on the service // This is a leaf node so answer the published items which exist on the service
Element item;
for (PublishedItem publishedItem : pubNode.getPublishedItems()) { for (PublishedItem publishedItem : pubNode.getPublishedItems()) {
item = DocumentHelper.createElement("item"); answer.add(new DiscoItem(new JID(serviceDomain), publishedItem.getID(), null, null));
item.addAttribute("jid", serviceDomain);
item.addAttribute("name", publishedItem.getID());
answer.add(item);
} }
} }
} }
......
...@@ -15,6 +15,7 @@ import org.jivesoftware.database.DbConnectionManager; ...@@ -15,6 +15,7 @@ import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.auth.AuthFactory; import org.jivesoftware.openfire.auth.AuthFactory;
import org.jivesoftware.openfire.event.UserEventDispatcher; import org.jivesoftware.openfire.event.UserEventDispatcher;
import org.jivesoftware.openfire.resultsetmanager.Result;
import org.jivesoftware.openfire.roster.Roster; import org.jivesoftware.openfire.roster.Roster;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.util.cache.CacheSizes; import org.jivesoftware.util.cache.CacheSizes;
...@@ -42,7 +43,7 @@ import java.util.concurrent.ConcurrentHashMap; ...@@ -42,7 +43,7 @@ import java.util.concurrent.ConcurrentHashMap;
* *
* @author Matt Tucker * @author Matt Tucker
*/ */
public class User implements Cacheable, Externalizable { public class User implements Cacheable, Externalizable, Result {
private static final String LOAD_PROPERTIES = private static final String LOAD_PROPERTIES =
"SELECT name, propValue FROM jiveUserProp WHERE username=?"; "SELECT name, propValue FROM jiveUserProp WHERE username=?";
...@@ -529,4 +530,13 @@ public class User implements Cacheable, Externalizable { ...@@ -529,4 +530,13 @@ public class User implements Cacheable, Externalizable {
creationDate = new Date(ExternalizableUtil.getInstance().readLong(in)); creationDate = new Date(ExternalizableUtil.getInstance().readLong(in));
modificationDate = new Date(ExternalizableUtil.getInstance().readLong(in)); modificationDate = new Date(ExternalizableUtil.getInstance().readLong(in));
} }
/*
* (non-Javadoc)
* @see org.jivesoftware.util.resultsetmanager.Result#getUID()
*/
public String getUID()
{
return username;
}
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment