Commit 93f63ed9 authored by guus's avatar guus

Currently, there's an interface defining a DiscoItem object. There's no...

Currently, there's an interface defining a DiscoItem object. There's no implementation of it, other than in-line implementations in methods (the same goes for the sub-interface, DiscoServerItem). Where manipulations of DiscoItem objects are done, Dom4J Element instances are used instead. The DiscoItem interface has been replaced by an implementation of that interface (again, same goes for the sub-interface, which is now a subclass). As I assumed there would not be other implementations of the same interface (which would give you 'another kind' of DiscoItem objects, but what's the point?), I removed the interface completely.

As a result of the changed representation, the DiscoItemsProvider interface now declares a method that returns an Iterator of DiscoItem objects, instead of Elements. This caused changes in a number of classes.

Result Set Management functionality has been added, which causes all disco#items request to be result set managable (this is, for instance, useful for large listings or MUC rooms).

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/branches/rsm@9166 b35dd754-fafc-0310-a699-88a17e54d16e
parent 4bc5ef9d
...@@ -112,23 +112,19 @@ public class AdHocCommandHandler extends IQHandler ...@@ -112,23 +112,19 @@ 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()); answer.add(item);
item.addAttribute("name", command.getLabel()); }
answer.add(item);
}
} }
} }
return answer.iterator(); return answer.iterator();
......
...@@ -167,7 +167,7 @@ public class InternalComponentManager extends BasicModule implements ComponentMa ...@@ -167,7 +167,7 @@ public class InternalComponentManager extends BasicModule implements ComponentMa
// Remove the disco item from the server for the component that is being removed // Remove the disco item from the server for the component that is being removed
IQDiscoItemsHandler iqDiscoItemsHandler = XMPPServer.getInstance().getIQDiscoItemsHandler(); IQDiscoItemsHandler iqDiscoItemsHandler = XMPPServer.getInstance().getIQDiscoItemsHandler();
if (iqDiscoItemsHandler != null) { if (iqDiscoItemsHandler != null) {
iqDiscoItemsHandler.removeComponentItem(componentJID.toBareJID()); iqDiscoItemsHandler.removeComponentItem(componentJID);
} }
// Ask the component to shutdown // Ask the component to shutdown
...@@ -445,8 +445,8 @@ public class InternalComponentManager extends BasicModule implements ComponentMa ...@@ -445,8 +445,8 @@ public class InternalComponentManager extends BasicModule implements ComponentMa
return; return;
} }
try { try {
XMPPServer.getInstance().getIQDiscoItemsHandler().addComponentItem(packet.getFrom() XMPPServer.getInstance().getIQDiscoItemsHandler().addComponentItem(new JID(packet.getFrom()
.toBareJID(), .toBareJID()),
identity.attributeValue("name")); identity.attributeValue("name"));
if (component instanceof ComponentSession.ExternalComponent) { if (component instanceof ComponentSession.ExternalComponent) {
ComponentSession.ExternalComponent externalComponent = ComponentSession.ExternalComponent externalComponent =
......
...@@ -11,51 +11,169 @@ ...@@ -11,51 +11,169 @@
package org.jivesoftware.openfire.disco; package org.jivesoftware.openfire.disco;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jivesoftware.util.resultsetmanager.Result;
import org.xmpp.packet.JID;
/** /**
* An item is associated with an XMPP Entity, usually thought of a children of the parent * <p>
* entity and normally are addressable as a JID.<p> * An item is associated with an XMPP Entity, usually thought of a children of
* <p/> * the parent entity and normally are addressable as a JID.
* An item associated with an entity may not be addressable as a JID. In order to handle * </p>
* such items, Service Discovery uses an optional 'node' attribute that supplements the * <p>
* 'jid' attribute. * An item associated with an entity may not be addressable as a JID. In order
* * to handle such items, Service Discovery uses an optional 'node' attribute
* that supplements the 'jid' attribute.
* </p>
*
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public interface DiscoItem { public class DiscoItem implements Result {
/** private final JID jid;
* Returns the entity's ID.
* private final String name;
* @return the entity's ID.
*/ private final String node;
public abstract String getJID();
private final String action;
/**
* Returns the node attribute that supplements the 'jid' attribute. A node is merely /**
* something that is associated with a JID and for which the JID can provide information.<p> * <p>
* <p/> * Creates a new DiscoItem instance.
* Node attributes SHOULD be used only when trying to provide or query information which * </p>
* is not directly addressable. *
* * @param jid
* @return the node attribute that supplements the 'jid' attribute * specifies the Jabber ID of the item "owner" or location
*/ * (required).
public abstract String getNode(); * @param name
* specifies a natural-language name for the item (can be null).
/** * @param node
* Returns the entity's name. The entity's name specifies in natural-language the name for the * specifies the particular node associated with the JID of the
* item. * item "owner" or location (can be null).
* * @param action
* @return the entity's name. * specifies the action to be taken for the item.
*/ * @throws IllegalArgumentException
public abstract String getName(); * If a required parameter was null, or if the supplied 'action'
* parameter has another value than 'null', "update" or
/** * "remove".
* 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 public DiscoItem(JID jid, String name, String node, String action) {
* "remove" action requests to remove the item. if (jid == null) {
* throw new IllegalArgumentException("Argument 'jid' cannot be null.");
* @return the action (i.e. update or remove) that indicates what must be done with this item or }
* null if none.
*/ if (action != null && !action.equals("update")
public abstract String getAction(); && !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;
}
/**
* <p>
* Returns the entity's ID.
* </p>
*
* @return the entity's ID.
*/
public JID getJID() {
return jid;
}
/**
* <p>
* Returns the node attribute that supplements the 'jid' attribute. A node
* is merely something that is associated with a JID and for which the JID
* can provide information.
* </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
*/
public String getNode() {
return node;
}
/**
* <p>
* Returns the entity's name. The entity's name specifies in
* natural-language the name for the item.
* </p>
*
* @return the entity's name.
*/
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 a dom4j element that represents this DiscoItem object.
*
* @return element representing this object.
*/
public Element getElement() {
final Element element = DocumentHelper.createElement("item");
if (action != null) {
element.addAttribute("action", action);
}
if (jid != null) {
element.addAttribute("jid", jid.toString());
}
if (name != null) {
element.addAttribute("name", name);
}
if (node != null) {
element.addAttribute("node", node);
}
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,11 +11,10 @@ ...@@ -11,11 +11,10 @@
package org.jivesoftware.openfire.disco; package org.jivesoftware.openfire.disco;
import org.dom4j.Element;
import org.xmpp.packet.JID;
import java.util.Iterator; import java.util.Iterator;
import org.xmpp.packet.JID;
/** /**
* A DiscoItemsProvider is responsible for providing the items associated with a JID's name and * A DiscoItemsProvider is responsible for providing the items associated with a JID's name and
* node. For example, the room service could implement this interface in order to provide * node. For example, the room service could implement this interface in order to provide
...@@ -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,8 +28,28 @@ package org.jivesoftware.openfire.disco; ...@@ -26,8 +28,28 @@ 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.
* The DiscoInfoProvider will be automatically included in IQDiscoInfoHandler as the provider * The DiscoInfoProvider will be automatically included in IQDiscoInfoHandler as the provider
...@@ -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;
}
} }
...@@ -11,37 +11,26 @@ ...@@ -11,37 +11,26 @@
package org.jivesoftware.openfire.disco; package org.jivesoftware.openfire.disco;
import org.dom4j.DocumentHelper;
import org.dom4j.Element; import org.dom4j.Element;
import org.dom4j.QName; import org.dom4j.QName;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.IQHandlerInfo; import org.jivesoftware.openfire.IQHandlerInfo;
import org.jivesoftware.openfire.SessionManager; import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.cluster.ClusterEventListener;
import org.jivesoftware.openfire.cluster.ClusterManager;
import org.jivesoftware.openfire.cluster.NodeID;
import org.jivesoftware.openfire.handler.IQHandler; import org.jivesoftware.openfire.handler.IQHandler;
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;
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.cache.Cache; import org.jivesoftware.util.resultsetmanager.ResultSet;
import org.jivesoftware.util.cache.CacheFactory; import org.jivesoftware.util.resultsetmanager.ResultSetImpl;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.jivesoftware.util.lock.LockManager;
import org.xmpp.packet.IQ; import org.xmpp.packet.IQ;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import org.xmpp.packet.PacketError; import org.xmpp.packet.PacketError;
import org.xmpp.packet.PacketError.Condition;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
/** /**
* IQDiscoItemsHandler is responsible for handling disco#items requests. This class holds a map with * IQDiscoItemsHandler is responsible for handling disco#items requests. This class holds a map with
...@@ -65,18 +54,19 @@ import java.util.concurrent.locks.Lock; ...@@ -65,18 +54,19 @@ import java.util.concurrent.locks.Lock;
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProvider, ClusterEventListener { public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProvider {
private Map<String,DiscoItemsProvider> entities = new HashMap<String,DiscoItemsProvider>(); public static final String NAMESPACE_DISCO_ITEMS = "http://jabber.org/protocol/disco#items";
private Map<String, Element> localServerItems = new HashMap<String, Element>(); private Map<String,DiscoItemsProvider> entities = new HashMap<String,DiscoItemsProvider>();
private Cache<String, ClusteredServerItem> serverItems; private List<DiscoItem> serverItems = new ArrayList<DiscoItem>();
private Map<String, DiscoItemsProvider> serverNodeProviders = new ConcurrentHashMap<String, DiscoItemsProvider>(); private Map<String, DiscoItemsProvider> serverNodeProviders =
new ConcurrentHashMap<String, DiscoItemsProvider>();
private IQHandlerInfo info; private IQHandlerInfo info;
private IQDiscoInfoHandler infoHandler; private IQDiscoInfoHandler infoHandler;
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() {
...@@ -113,19 +103,72 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv ...@@ -113,19 +103,72 @@ 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,
if (itemsItr != null) { packet.getFrom());
reply.setChildElement(iq.createCopy()); if (itemsItr != null) {
Element queryElement = reply.getChildElement(); reply.setChildElement(iq.createCopy());
Element queryElement = reply.getChildElement();
// Add to the reply all the items provided by the DiscoItemsProvider
Element item; // See if the requesting entity would like to apply 'result set
while (itemsItr.hasNext()) { // management'
item = itemsItr.next(); final Element rsmElement = packet.getChildElement().element(
item.setQName(new QName(item.getName(), queryElement.getNamespace())); QName.get("set",
queryElement.add(item.createCopy()); 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(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(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
Element item;
while (itemsItr.hasNext()) {
item = itemsItr.next().getElement();
item.setQName(new QName(item.getName(), queryElement
.getNamespace()));
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
...@@ -196,7 +239,7 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv ...@@ -196,7 +239,7 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv
addComponentItem(discoItem.getJID(), discoItem.getNode(), discoItem.getName()); addComponentItem(discoItem.getJID(), 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());
} }
...@@ -220,7 +263,7 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv ...@@ -220,7 +263,7 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv
removeComponentItem(discoItem.getJID()); removeComponentItem(discoItem.getJID());
// 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);
} }
...@@ -257,7 +300,7 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv ...@@ -257,7 +300,7 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv
* @param jid the jid of the component. * @param jid the jid of the component.
* @param name the discovered name of the component. * @param name the discovered name of the component.
*/ */
public void addComponentItem(String jid, String name) { public void addComponentItem(JID jid, String name) {
addComponentItem(jid, null, name); addComponentItem(jid, null, name);
} }
...@@ -269,31 +312,15 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv ...@@ -269,31 +312,15 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv
* @param node the node that complements the jid address. * @param node the node that complements the jid address.
* @param name the discovered name of the component. * @param name the discovered name of the component.
*/ */
public void addComponentItem(String jid, String node, String name) { public synchronized void addComponentItem(JID jid, String node, String name) {
Lock lock = LockManager.getLock(jid + "item"); // A component may send his disco#info many times and we only want to have one item
try { // for the component so remove any element under the requested jid
lock.lock(); removeComponentItem(jid);
ClusteredServerItem item = serverItems.get(jid);
if (item == null) { // Create a new element based on the provided DiscoItem
// First time a node registers a server item for this component final DiscoItem item = new DiscoItem(jid, name, node, null);
item = new ClusteredServerItem(); // Add the element to the list of items related to the server
serverItems.add(item);
Element element = DocumentHelper.createElement("item");
element.addAttribute("jid", jid);
element.addAttribute("node", node);
element.addAttribute("name", name);
item.element = element;
}
if (item.nodes.add(XMPPServer.getInstance().getNodeID())) {
// Update the cache with latest info
serverItems.put(jid, item);
}
// Keep track of the new server item added by this JVM
localServerItems.put(jid, item.element);
}
finally {
lock.unlock();
}
} }
/** /**
...@@ -301,37 +328,20 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv ...@@ -301,37 +328,20 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv
* *
* @param jid the jid of the component being removed. * @param jid the jid of the component being removed.
*/ */
public void removeComponentItem(String jid) { public synchronized void removeComponentItem(JID jid) {
Lock lock = LockManager.getLock(jid + "item"); for (Iterator<DiscoItem> it = serverItems.iterator(); it.hasNext();) {
try { if (jid.equals(it.next().getJID())) {
lock.lock(); it.remove();
ClusteredServerItem item = serverItems.get(jid);
if (item != null && item.nodes.remove(XMPPServer.getInstance().getNodeID())) {
// Update the cache with latest info
if (item.nodes.isEmpty()) {
serverItems.remove(jid);
}
else {
serverItems.put(jid, item);
}
} }
} }
finally {
lock.unlock();
}
// Remove locally added server item
localServerItems.remove(jid);
} }
public void initialize(XMPPServer server) { public void initialize(XMPPServer server) {
super.initialize(server); super.initialize(server);
serverItems = CacheFactory.createCache("Disco Server Items");
// Track the implementors of ServerItemsProvider so that we can collect the items // Track the implementors of ServerItemsProvider so that we can collect the items
// provided by the server // provided by the server
infoHandler = server.getIQDiscoInfoHandler(); infoHandler = server.getIQDiscoInfoHandler();
setProvider(server.getServerInfo().getName(), getServerItemsProvider()); setProvider(server.getServerInfo().getName(), getServerItemsProvider());
// Listen to cluster events
ClusterManager.addListener(this);
} }
public void start() throws IllegalStateException { public void start() throws IllegalStateException {
...@@ -343,82 +353,15 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv ...@@ -343,82 +353,15 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv
public Iterator<String> getFeatures() { public Iterator<String> getFeatures() {
List<String> features = new ArrayList<String>(); List<String> features = new ArrayList<String>();
features.add("http://jabber.org/protocol/disco#items"); features.add(NAMESPACE_DISCO_ITEMS);
// TODO Comment out this line when publishing of client items is implemented // TODO Comment out this line when publishing of client items is implemented
//features.add("http://jabber.org/protocol/disco#publish"); //features.add("http://jabber.org/protocol/disco#publish");
return features.iterator(); return features.iterator();
} }
public void joinedCluster() {
restoreCacheContent();
}
public void joinedCluster(byte[] nodeID) {
// Do nothing
}
public void leftCluster() {
if (!XMPPServer.getInstance().isShuttingDown()) {
restoreCacheContent();
}
}
public void leftCluster(byte[] nodeID) {
if (ClusterManager.isSeniorClusterMember()) {
NodeID leftNode = NodeID.getInstance(nodeID);
for (Map.Entry<String, ClusteredServerItem> entry : serverItems.entrySet()) {
String jid = entry.getKey();
Lock lock = LockManager.getLock(jid + "item");
try {
lock.lock();
ClusteredServerItem item = entry.getValue();
if (item.nodes.remove(leftNode)) {
// Update the cache with latest info
if (item.nodes.isEmpty()) {
serverItems.remove(jid);
}
else {
serverItems.put(jid, item);
}
}
}
finally {
lock.unlock();
}
}
}
}
public void markedAsSeniorClusterMember() {
// Do nothing
}
private void restoreCacheContent() {
for (Map.Entry<String, Element> entry : localServerItems.entrySet()) {
String jid = entry.getKey();
Element element = entry.getValue();
Lock lock = LockManager.getLock(jid + "item");
try {
lock.lock();
ClusteredServerItem item = serverItems.get(jid);
if (item == null) {
// First time a node registers a server item for this component
item = new ClusteredServerItem();
item.element = element;
}
if (item.nodes.add(XMPPServer.getInstance().getNodeID())) {
// Update the cache with latest info
serverItems.put(jid, item);
}
}
finally {
lock.unlock();
}
}
}
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) {
...@@ -427,52 +370,26 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv ...@@ -427,52 +370,26 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv
return null; return null;
} }
if (name == null) { if (name == null) {
List<Element> answer = new ArrayList<Element>(); return serverItems.iterator();
for (ClusteredServerItem item : serverItems.values()) {
answer.add(item.element);
}
return answer.iterator();
} }
else { final List<DiscoItem> answer = new ArrayList<DiscoItem>();
List<Element> answer = new ArrayList<Element>(); try {
try { User user = UserManager.getInstance().getUser(name);
User user = UserManager.getInstance().getUser(name); RosterItem item = user.getRoster().getRosterItem(senderJID);
RosterItem item = user.getRoster().getRosterItem(senderJID); // If the requesting entity is subscribed to the account's presence then
// If the requesting entity is subscribed to the account's presence then // answer the user's "available resources"
// answer the user's "available resources" if (item.getSubStatus() == RosterItem.SUB_FROM ||
if (item.getSubStatus() == RosterItem.SUB_FROM || item.getSubStatus() == RosterItem.SUB_BOTH) {
item.getSubStatus() == RosterItem.SUB_BOTH) { for (Session session : SessionManager.getInstance().getSessions(name)) {
for (Session session : SessionManager.getInstance().getSessions(name)) { answer.add(new DiscoItem(session.getAddress(), null, null, null));
Element element = DocumentHelper.createElement("item");
element.addAttribute("jid", session.getAddress().toString());
answer.add(element);
}
} }
return answer.iterator();
}
catch (UserNotFoundException e) {
return answer.iterator();
} }
return answer.iterator();
}
catch (UserNotFoundException e) {
return answer.iterator();
} }
} }
}; };
} }
}
private static class ClusteredServerItem implements Externalizable {
private Element element;
private Set<NodeID> nodes = new HashSet<NodeID>();
public ClusteredServerItem() {
}
public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) element);
ExternalizableUtil.getInstance().writeExternalizableCollection(out, nodes);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
element = (Element) ExternalizableUtil.getInstance().readSerializable(in);
ExternalizableUtil.getInstance().readExternalizableCollection(in, nodes, getClass().getClassLoader());
}
}
}
\ No newline at end of file
...@@ -17,6 +17,7 @@ import org.jivesoftware.openfire.*; ...@@ -17,6 +17,7 @@ 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.DiscoInfoProvider;
import org.jivesoftware.openfire.disco.DiscoItem;
import org.jivesoftware.openfire.disco.DiscoItemsProvider; import org.jivesoftware.openfire.disco.DiscoItemsProvider;
import org.jivesoftware.openfire.disco.DiscoServerItem; import org.jivesoftware.openfire.disco.DiscoServerItem;
import org.jivesoftware.openfire.disco.ServerItemsProvider; import org.jivesoftware.openfire.disco.ServerItemsProvider;
...@@ -206,7 +207,7 @@ public class FileTransferProxy extends BasicModule ...@@ -206,7 +207,7 @@ public class FileTransferProxy extends BasicModule
super.stop(); super.stop();
XMPPServer.getInstance().getIQDiscoItemsHandler() XMPPServer.getInstance().getIQDiscoItemsHandler()
.removeComponentItem(getAddress().toString()); .removeComponentItem(getAddress());
routingTable.removeComponentRoute(getAddress()); routingTable.removeComponentRoute(getAddress());
connectionManager.disable(); connectionManager.disable();
} }
...@@ -284,31 +285,11 @@ public class FileTransferProxy extends BasicModule ...@@ -284,31 +285,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 +319,9 @@ public class FileTransferProxy extends BasicModule ...@@ -338,9 +319,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,25 +159,20 @@ public class IQOfflineMessagesHandler extends IQHandler implements ServerFeature ...@@ -159,25 +159,20 @@ 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"); final DiscoItem item;
item.addAttribute("jid", senderJID.toBareJID());
item.addAttribute("name", offlineMessage.getFrom().toString());
synchronized (dateFormat) { synchronized (dateFormat) {
item.addAttribute("node", dateFormat.format(offlineMessage.getCreationDate())); item = new DiscoItem(senderJID, offlineMessage.getFrom().toString(), dateFormat.format(offlineMessage.getCreationDate()), null);
} }
answer.add(item); answer.add(item);
} }
return answer.iterator(); return answer.iterator();
} }
public void initialize(XMPPServer server) { public void initialize(XMPPServer server) {
super.initialize(server); super.initialize(server);
infoHandler = server.getIQDiscoInfoHandler(); infoHandler = server.getIQDiscoInfoHandler();
......
...@@ -17,6 +17,7 @@ import org.jivesoftware.openfire.*; ...@@ -17,6 +17,7 @@ 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.DiscoInfoProvider;
import org.jivesoftware.openfire.disco.DiscoItem;
import org.jivesoftware.openfire.disco.DiscoItemsProvider; import org.jivesoftware.openfire.disco.DiscoItemsProvider;
import org.jivesoftware.openfire.disco.DiscoServerItem; import org.jivesoftware.openfire.disco.DiscoServerItem;
import org.jivesoftware.openfire.disco.ServerItemsProvider; import org.jivesoftware.openfire.disco.ServerItemsProvider;
...@@ -98,14 +99,14 @@ public class MediaProxyService extends BasicModule ...@@ -98,14 +99,14 @@ public class MediaProxyService extends BasicModule
XMPPServer.getInstance().getIQDiscoItemsHandler().addServerItemsProvider(this); XMPPServer.getInstance().getIQDiscoItemsHandler().addServerItemsProvider(this);
} else { } else {
if (echo != null) echo.cancel(); if (echo != null) echo.cancel();
XMPPServer.getInstance().getIQDiscoItemsHandler().removeComponentItem(getAddress().toString()); XMPPServer.getInstance().getIQDiscoItemsHandler().removeComponentItem(getAddress());
} }
} }
public void stop() { public void stop() {
super.stop(); super.stop();
mediaProxy.stopProxy(); mediaProxy.stopProxy();
XMPPServer.getInstance().getIQDiscoItemsHandler().removeComponentItem(getAddress().toString()); XMPPServer.getInstance().getIQDiscoItemsHandler().removeComponentItem(getAddress());
routingTable.removeComponentRoute(getAddress()); routingTable.removeComponentRoute(getAddress());
if (echo != null) echo.cancel(); if (echo != null) echo.cancel();
} }
...@@ -117,9 +118,9 @@ public class MediaProxyService extends BasicModule ...@@ -117,9 +118,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,39 +288,19 @@ public class MediaProxyService extends BasicModule ...@@ -287,39 +288,19 @@ 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>(); {
if (!isEnabled()) { List<DiscoServerItem> items = new ArrayList<DiscoServerItem>();
return items.iterator(); if (!isEnabled())
} {
return items.iterator();
items.add(new DiscoServerItem() { }
public String getJID() {
return getServiceDomain(); final DiscoServerItem item = new DiscoServerItem(new JID(
} getServiceDomain()), "Media Proxy Service", null, null, this, this);
items.add(item);
public String getName() { return items.iterator();
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();
}
public Iterator<Element> getIdentities(String name, String node, JID senderJID) { public Iterator<Element> getIdentities(String name, String node, JID senderJID) {
List<Element> identities = new ArrayList<Element>(); List<Element> identities = new ArrayList<Element>();
......
...@@ -19,6 +19,7 @@ import org.jivesoftware.openfire.cluster.ClusterEventListener; ...@@ -19,6 +19,7 @@ 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.DiscoInfoProvider;
import org.jivesoftware.openfire.disco.DiscoItem;
import org.jivesoftware.openfire.disco.DiscoItemsProvider; import org.jivesoftware.openfire.disco.DiscoItemsProvider;
import org.jivesoftware.openfire.disco.DiscoServerItem; import org.jivesoftware.openfire.disco.DiscoServerItem;
import org.jivesoftware.openfire.disco.ServerItemsProvider; import org.jivesoftware.openfire.disco.ServerItemsProvider;
...@@ -1073,44 +1074,32 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -1073,44 +1074,32 @@ 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.
return null; if (!isServiceEnabled())
} {
ArrayList<DiscoServerItem> items = new ArrayList<DiscoServerItem>(); return null;
items.add(new DiscoServerItem() { }
public String getJID() {
return getServiceDomain(); final ArrayList<DiscoServerItem> items = new ArrayList<DiscoServerItem>();
} final String name;
// Check if there is a system property that overrides the default value
public String getName() { String serviceName = JiveGlobals.getProperty("muc.service-name");
// Check if there is a system property that overrides the default value if (serviceName != null && serviceName.trim().length() > 0)
String serviceName = JiveGlobals.getProperty("muc.service-name"); {
if (serviceName != null && serviceName.trim().length() > 0) { name = serviceName;
return serviceName; }
} else
// Return the default service name based on the current locale {
return LocaleUtils.getLocalizedString("muc.service-name"); // Return the default service name based on the current locale
} name = LocaleUtils.getLocalizedString("muc.service-name");
}
public String getAction() {
return null; final DiscoServerItem item = new DiscoServerItem(new JID(
} getServiceDomain()), name, null, null, this, this);
items.add(item);
public String getNode() { return items.iterator();
return null; }
}
public DiscoInfoProvider getDiscoInfoProvider() {
return MultiUserChatServerImpl.this;
}
public DiscoItemsProvider getDiscoItemsProvider() {
return MultiUserChatServerImpl.this;
}
});
return items.iterator();
}
public Iterator<Element> getIdentities(String name, String node, JID senderJID) { public Iterator<Element> getIdentities(String name, String node, JID senderJID) {
ArrayList<Element> identities = new ArrayList<Element>(); ArrayList<Element> identities = new ArrayList<Element>();
...@@ -1266,36 +1255,31 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha ...@@ -1266,36 +1255,31 @@ 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); }
} }
} }
}
else if (name != null && node == null) { else if (name != null && node == null) {
// 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,6 +22,7 @@ import org.jivesoftware.openfire.cluster.ClusterManager; ...@@ -22,6 +22,7 @@ import org.jivesoftware.openfire.cluster.ClusterManager;
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.DiscoInfoProvider;
import org.jivesoftware.openfire.disco.DiscoItem;
import org.jivesoftware.openfire.disco.DiscoItemsProvider; import org.jivesoftware.openfire.disco.DiscoItemsProvider;
import org.jivesoftware.openfire.disco.DiscoServerItem; import org.jivesoftware.openfire.disco.DiscoServerItem;
import org.jivesoftware.openfire.disco.ServerItemsProvider; import org.jivesoftware.openfire.disco.ServerItemsProvider;
...@@ -468,33 +469,11 @@ public class PubSubModule extends BasicModule implements ServerItemsProvider, Di ...@@ -468,33 +469,11 @@ 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);
} return items.iterator();
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();
} }
public Iterator<Element> getIdentities(String name, String node, JID senderJID) { public Iterator<Element> getIdentities(String name, String node, JID senderJID) {
...@@ -636,18 +615,16 @@ public class PubSubModule extends BasicModule implements ServerItemsProvider, Di ...@@ -636,18 +615,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);
} }
} }
...@@ -656,25 +633,21 @@ public class PubSubModule extends BasicModule implements ServerItemsProvider, Di ...@@ -656,25 +633,21 @@ 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(
item.addAttribute("jid", serviceDomain); serviceDomain), nestedNode.getName(),
item.addAttribute("node", nestedNode.getNodeID()); nestedNode.getNodeID(), null);
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"); final DiscoItem item = new DiscoItem(new JID(
item.addAttribute("jid", serviceDomain); serviceDomain), publishedItem.getID(), null, null);
item.addAttribute("name", publishedItem.getID());
answer.add(item); answer.add(item);
} }
} }
......
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