mirror of
https://github.com/vanitasvitae/Smack.git
synced 2025-12-12 14:01:08 +01:00
Prefix subprojects with 'smack-'
instead of using the old baseName=smack appendix=project.name approach, we are now going convention over configuration and renaming the subprojects directories to the proper name. Having a prefix is actually very helpful, because the resulting libraries will be named like the subproject. And a core-4.0.0-rc1.jar is not as explicit about what it actually *is* as a smack-core-4.0.0-rc1.jar. SMACK-265
This commit is contained in:
parent
b6fb1f3743
commit
91fd15ad86
758 changed files with 42 additions and 42 deletions
|
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jivesoftware.smackx.disco;
|
||||
|
||||
import org.jivesoftware.smack.packet.PacketExtension;
|
||||
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
||||
import org.jivesoftware.smackx.disco.packet.DiscoverItems;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* The NodeInformationProvider is responsible for providing supported indentities, features
|
||||
* and hosted items (i.e. DiscoverItems.Item) about a given node. This information will be
|
||||
* requested each time this XMPPP client receives a disco info or items requests on the
|
||||
* given node. each time this XMPPP client receives a disco info or items requests on the
|
||||
* given node.
|
||||
*
|
||||
* @author Gaston Dombiak
|
||||
*/
|
||||
public interface NodeInformationProvider {
|
||||
|
||||
/**
|
||||
* Returns a list of the Items {@link org.jivesoftware.smackx.disco.packet.DiscoverItems.Item}
|
||||
* defined in the node. For example, the MUC protocol specifies that an XMPP client should
|
||||
* answer an Item for each joined room when asked for the rooms where the use has joined.
|
||||
*
|
||||
* @return a list of the Items defined in the node.
|
||||
*/
|
||||
List<DiscoverItems.Item> getNodeItems();
|
||||
|
||||
/**
|
||||
* Returns a list of the features defined in the node. For
|
||||
* example, the entity caps protocol specifies that an XMPP client
|
||||
* should answer with each feature supported by the client version
|
||||
* or extension.
|
||||
*
|
||||
* @return a list of the feature strings defined in the node.
|
||||
*/
|
||||
List<String> getNodeFeatures();
|
||||
|
||||
/**
|
||||
* Returns a list of the indentites defined in the node. For
|
||||
* example, the x-command protocol must provide an identity of
|
||||
* category automation and type command-node for each command.
|
||||
*
|
||||
* @return a list of the Identities defined in the node.
|
||||
*/
|
||||
List<DiscoverInfo.Identity> getNodeIdentities();
|
||||
|
||||
/**
|
||||
* Returns a list of the packet extensions defined in the node.
|
||||
*
|
||||
* @return a list of the packet extensions defined in the node.
|
||||
*/
|
||||
List<PacketExtension> getNodePacketExtensions();
|
||||
}
|
||||
|
|
@ -0,0 +1,702 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.disco;
|
||||
|
||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.ConnectionCreationListener;
|
||||
import org.jivesoftware.smack.Manager;
|
||||
import org.jivesoftware.smack.PacketListener;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.filter.PacketFilter;
|
||||
import org.jivesoftware.smack.filter.PacketTypeFilter;
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.packet.Packet;
|
||||
import org.jivesoftware.smack.packet.PacketExtension;
|
||||
import org.jivesoftware.smack.packet.XMPPError;
|
||||
import org.jivesoftware.smackx.caps.EntityCapsManager;
|
||||
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
||||
import org.jivesoftware.smackx.disco.packet.DiscoverItems;
|
||||
import org.jivesoftware.smackx.disco.packet.DiscoverInfo.Identity;
|
||||
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Manages discovery of services in XMPP entities. This class provides:
|
||||
* <ol>
|
||||
* <li>A registry of supported features in this XMPP entity.
|
||||
* <li>Automatic response when this XMPP entity is queried for information.
|
||||
* <li>Ability to discover items and information of remote XMPP entities.
|
||||
* <li>Ability to publish publicly available items.
|
||||
* </ol>
|
||||
*
|
||||
* @author Gaston Dombiak
|
||||
*/
|
||||
public class ServiceDiscoveryManager extends Manager {
|
||||
|
||||
private static final String DEFAULT_IDENTITY_NAME = "Smack";
|
||||
private static final String DEFAULT_IDENTITY_CATEGORY = "client";
|
||||
private static final String DEFAULT_IDENTITY_TYPE = "pc";
|
||||
private static DiscoverInfo.Identity defaultIdentity = new Identity(DEFAULT_IDENTITY_CATEGORY,
|
||||
DEFAULT_IDENTITY_NAME, DEFAULT_IDENTITY_TYPE);
|
||||
|
||||
private Set<DiscoverInfo.Identity> identities = new HashSet<DiscoverInfo.Identity>();
|
||||
private DiscoverInfo.Identity identity = defaultIdentity;
|
||||
|
||||
private EntityCapsManager capsManager;
|
||||
|
||||
private static Map<XMPPConnection, ServiceDiscoveryManager> instances =
|
||||
Collections.synchronizedMap(new WeakHashMap<XMPPConnection, ServiceDiscoveryManager>());
|
||||
|
||||
private final Set<String> features = new HashSet<String>();
|
||||
private DataForm extendedInfo = null;
|
||||
private Map<String, NodeInformationProvider> nodeInformationProviders =
|
||||
new ConcurrentHashMap<String, NodeInformationProvider>();
|
||||
|
||||
// Create a new ServiceDiscoveryManager on every established connection
|
||||
static {
|
||||
XMPPConnection.addConnectionCreationListener(new ConnectionCreationListener() {
|
||||
public void connectionCreated(XMPPConnection connection) {
|
||||
getInstanceFor(connection);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default identity all new connections will have. If unchanged the default identity is an
|
||||
* identity where category is set to 'client', type is set to 'pc' and name is set to 'Smack'.
|
||||
*
|
||||
* @param identity
|
||||
*/
|
||||
public static void setDefaultIdentity(DiscoverInfo.Identity identity) {
|
||||
defaultIdentity = identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ServiceDiscoveryManager for a given XMPPConnection. This means that the
|
||||
* service manager will respond to any service discovery request that the connection may
|
||||
* receive.
|
||||
*
|
||||
* @param connection the connection to which a ServiceDiscoveryManager is going to be created.
|
||||
*/
|
||||
private ServiceDiscoveryManager(XMPPConnection connection) {
|
||||
super(connection);
|
||||
// Register the new instance and associate it with the connection
|
||||
instances.put(connection, this);
|
||||
|
||||
addFeature(DiscoverInfo.NAMESPACE);
|
||||
addFeature(DiscoverItems.NAMESPACE);
|
||||
|
||||
// Listen for disco#items requests and answer with an empty result
|
||||
PacketFilter packetFilter = new PacketTypeFilter(DiscoverItems.class);
|
||||
PacketListener packetListener = new PacketListener() {
|
||||
public void processPacket(Packet packet) throws NotConnectedException {
|
||||
XMPPConnection connection = connection();
|
||||
if (connection == null) return;
|
||||
DiscoverItems discoverItems = (DiscoverItems) packet;
|
||||
// Send back the items defined in the client if the request is of type GET
|
||||
if (discoverItems != null && discoverItems.getType() == IQ.Type.GET) {
|
||||
DiscoverItems response = new DiscoverItems();
|
||||
response.setType(IQ.Type.RESULT);
|
||||
response.setTo(discoverItems.getFrom());
|
||||
response.setPacketID(discoverItems.getPacketID());
|
||||
response.setNode(discoverItems.getNode());
|
||||
|
||||
// Add the defined items related to the requested node. Look for
|
||||
// the NodeInformationProvider associated with the requested node.
|
||||
NodeInformationProvider nodeInformationProvider =
|
||||
getNodeInformationProvider(discoverItems.getNode());
|
||||
if (nodeInformationProvider != null) {
|
||||
// Specified node was found, add node items
|
||||
response.addItems(nodeInformationProvider.getNodeItems());
|
||||
// Add packet extensions
|
||||
response.addExtensions(nodeInformationProvider.getNodePacketExtensions());
|
||||
} else if(discoverItems.getNode() != null) {
|
||||
// Return <item-not-found/> error since client doesn't contain
|
||||
// the specified node
|
||||
response.setType(IQ.Type.ERROR);
|
||||
response.setError(new XMPPError(XMPPError.Condition.item_not_found));
|
||||
}
|
||||
connection.sendPacket(response);
|
||||
}
|
||||
}
|
||||
};
|
||||
connection.addPacketListener(packetListener, packetFilter);
|
||||
|
||||
// Listen for disco#info requests and answer the client's supported features
|
||||
// To add a new feature as supported use the #addFeature message
|
||||
packetFilter = new PacketTypeFilter(DiscoverInfo.class);
|
||||
packetListener = new PacketListener() {
|
||||
public void processPacket(Packet packet) throws NotConnectedException {
|
||||
XMPPConnection connection = connection();
|
||||
if (connection == null) return;
|
||||
DiscoverInfo discoverInfo = (DiscoverInfo) packet;
|
||||
// Answer the client's supported features if the request is of the GET type
|
||||
if (discoverInfo != null && discoverInfo.getType() == IQ.Type.GET) {
|
||||
DiscoverInfo response = new DiscoverInfo();
|
||||
response.setType(IQ.Type.RESULT);
|
||||
response.setTo(discoverInfo.getFrom());
|
||||
response.setPacketID(discoverInfo.getPacketID());
|
||||
response.setNode(discoverInfo.getNode());
|
||||
// Add the client's identity and features only if "node" is null
|
||||
// and if the request was not send to a node. If Entity Caps are
|
||||
// enabled the client's identity and features are may also added
|
||||
// if the right node is chosen
|
||||
if (discoverInfo.getNode() == null) {
|
||||
addDiscoverInfoTo(response);
|
||||
}
|
||||
else {
|
||||
// Disco#info was sent to a node. Check if we have information of the
|
||||
// specified node
|
||||
NodeInformationProvider nodeInformationProvider =
|
||||
getNodeInformationProvider(discoverInfo.getNode());
|
||||
if (nodeInformationProvider != null) {
|
||||
// Node was found. Add node features
|
||||
response.addFeatures(nodeInformationProvider.getNodeFeatures());
|
||||
// Add node identities
|
||||
response.addIdentities(nodeInformationProvider.getNodeIdentities());
|
||||
// Add packet extensions
|
||||
response.addExtensions(nodeInformationProvider.getNodePacketExtensions());
|
||||
}
|
||||
else {
|
||||
// Return <item-not-found/> error since specified node was not found
|
||||
response.setType(IQ.Type.ERROR);
|
||||
response.setError(new XMPPError(XMPPError.Condition.item_not_found));
|
||||
}
|
||||
}
|
||||
connection.sendPacket(response);
|
||||
}
|
||||
}
|
||||
};
|
||||
connection.addPacketListener(packetListener, packetFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the client that will be returned when asked for the client identity
|
||||
* in a disco request. The name could be any value you need to identity this client.
|
||||
*
|
||||
* @return the name of the client that will be returned when asked for the client identity
|
||||
* in a disco request.
|
||||
*/
|
||||
public String getIdentityName() {
|
||||
return identity.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the client that will be returned when asked for the client identity
|
||||
* in a disco request. The name could be any value you need to identity this client.
|
||||
*
|
||||
* @param name the name of the client that will be returned when asked for the client identity
|
||||
* in a disco request.
|
||||
*/
|
||||
public void setIdentityName(String name) {
|
||||
identity.setName(name);
|
||||
renewEntityCapsVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default identity the client will report.
|
||||
*
|
||||
* @param identity
|
||||
*/
|
||||
public void setIdentity(Identity identity) {
|
||||
if (identity == null) throw new IllegalArgumentException("Identity can not be null");
|
||||
this.identity = identity;
|
||||
renewEntityCapsVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default identity of the client.
|
||||
*
|
||||
* @return the default identity.
|
||||
*/
|
||||
public Identity getIdentity() {
|
||||
return identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of client that will be returned when asked for the client identity in a
|
||||
* disco request. The valid types are defined by the category client. Follow this link to learn
|
||||
* the possible types: <a href="http://xmpp.org/registrar/disco-categories.html#client">Jabber::Registrar</a>.
|
||||
*
|
||||
* @return the type of client that will be returned when asked for the client identity in a
|
||||
* disco request.
|
||||
*/
|
||||
public String getIdentityType() {
|
||||
return identity.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an further identity to the client.
|
||||
*
|
||||
* @param identity
|
||||
*/
|
||||
public void addIdentity(DiscoverInfo.Identity identity) {
|
||||
identities.add(identity);
|
||||
renewEntityCapsVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an identity from the client. Note that the client needs at least one identity, the default identity, which
|
||||
* can not be removed.
|
||||
*
|
||||
* @param identity
|
||||
* @return true, if successful. Otherwise the default identity was given.
|
||||
*/
|
||||
public boolean removeIdentity(DiscoverInfo.Identity identity) {
|
||||
if (identity.equals(this.identity)) return false;
|
||||
identities.remove(identity);
|
||||
renewEntityCapsVersion();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all identities of this client as unmodifiable Collection
|
||||
*
|
||||
* @return all identies as set
|
||||
*/
|
||||
public Set<DiscoverInfo.Identity> getIdentities() {
|
||||
Set<Identity> res = new HashSet<Identity>(identities);
|
||||
// Add the default identity that must exist
|
||||
res.add(defaultIdentity);
|
||||
return Collections.unmodifiableSet(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ServiceDiscoveryManager instance associated with a given XMPPConnection.
|
||||
*
|
||||
* @param connection the connection used to look for the proper ServiceDiscoveryManager.
|
||||
* @return the ServiceDiscoveryManager associated with a given XMPPConnection.
|
||||
*/
|
||||
public static synchronized ServiceDiscoveryManager getInstanceFor(XMPPConnection connection) {
|
||||
ServiceDiscoveryManager sdm = instances.get(connection);
|
||||
if (sdm == null) {
|
||||
sdm = new ServiceDiscoveryManager(connection);
|
||||
}
|
||||
return sdm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add discover info response data.
|
||||
*
|
||||
* @see <a href="http://xmpp.org/extensions/xep-0030.html#info-basic">XEP-30 Basic Protocol; Example 2</a>
|
||||
*
|
||||
* @param response the discover info response packet
|
||||
*/
|
||||
public void addDiscoverInfoTo(DiscoverInfo response) {
|
||||
// First add the identities of the connection
|
||||
response.addIdentities(getIdentities());
|
||||
|
||||
// Add the registered features to the response
|
||||
synchronized (features) {
|
||||
for (String feature : getFeatures()) {
|
||||
response.addFeature(feature);
|
||||
}
|
||||
response.addExtension(extendedInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the NodeInformationProvider responsible for providing information
|
||||
* (ie items) related to a given node or <tt>null</null> if none.<p>
|
||||
*
|
||||
* In MUC, a node could be 'http://jabber.org/protocol/muc#rooms' which means that the
|
||||
* NodeInformationProvider will provide information about the rooms where the user has joined.
|
||||
*
|
||||
* @param node the node that contains items associated with an entity not addressable as a JID.
|
||||
* @return the NodeInformationProvider responsible for providing information related
|
||||
* to a given node.
|
||||
*/
|
||||
private NodeInformationProvider getNodeInformationProvider(String node) {
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
return nodeInformationProviders.get(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the NodeInformationProvider responsible for providing information
|
||||
* (ie items) related to a given node. Every time this client receives a disco request
|
||||
* regarding the items of a given node, the provider associated to that node will be the
|
||||
* responsible for providing the requested information.<p>
|
||||
*
|
||||
* In MUC, a node could be 'http://jabber.org/protocol/muc#rooms' which means that the
|
||||
* NodeInformationProvider will provide information about the rooms where the user has joined.
|
||||
*
|
||||
* @param node the node whose items will be provided by the NodeInformationProvider.
|
||||
* @param listener the NodeInformationProvider responsible for providing items related
|
||||
* to the node.
|
||||
*/
|
||||
public void setNodeInformationProvider(String node, NodeInformationProvider listener) {
|
||||
nodeInformationProviders.put(node, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the NodeInformationProvider responsible for providing information
|
||||
* (ie items) related to a given node. This means that no more information will be
|
||||
* available for the specified node.
|
||||
*
|
||||
* In MUC, a node could be 'http://jabber.org/protocol/muc#rooms' which means that the
|
||||
* NodeInformationProvider will provide information about the rooms where the user has joined.
|
||||
*
|
||||
* @param node the node to remove the associated NodeInformationProvider.
|
||||
*/
|
||||
public void removeNodeInformationProvider(String node) {
|
||||
nodeInformationProviders.remove(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the supported features by this XMPP entity.
|
||||
*
|
||||
* @return a List of the supported features by this XMPP entity.
|
||||
*/
|
||||
public List<String> getFeatures() {
|
||||
synchronized (features) {
|
||||
return Collections.unmodifiableList(new ArrayList<String>(features));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the supported features by this XMPP entity.
|
||||
*
|
||||
* @return a copy of the List on the supported features by this XMPP entity.
|
||||
*/
|
||||
public List<String> getFeaturesList() {
|
||||
synchronized (features) {
|
||||
return new LinkedList<String>(features);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers that a new feature is supported by this XMPP entity. When this client is
|
||||
* queried for its information the registered features will be answered.<p>
|
||||
*
|
||||
* Since no packet is actually sent to the server it is safe to perform this operation
|
||||
* before logging to the server. In fact, you may want to configure the supported features
|
||||
* before logging to the server so that the information is already available if it is required
|
||||
* upon login.
|
||||
*
|
||||
* @param feature the feature to register as supported.
|
||||
*/
|
||||
public void addFeature(String feature) {
|
||||
synchronized (features) {
|
||||
features.add(feature);
|
||||
renewEntityCapsVersion();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified feature from the supported features by this XMPP entity.<p>
|
||||
*
|
||||
* Since no packet is actually sent to the server it is safe to perform this operation
|
||||
* before logging to the server.
|
||||
*
|
||||
* @param feature the feature to remove from the supported features.
|
||||
*/
|
||||
public void removeFeature(String feature) {
|
||||
synchronized (features) {
|
||||
features.remove(feature);
|
||||
renewEntityCapsVersion();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified feature is registered in the ServiceDiscoveryManager.
|
||||
*
|
||||
* @param feature the feature to look for.
|
||||
* @return a boolean indicating if the specified featured is registered or not.
|
||||
*/
|
||||
public boolean includesFeature(String feature) {
|
||||
synchronized (features) {
|
||||
return features.contains(feature);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers extended discovery information of this XMPP entity. When this
|
||||
* client is queried for its information this data form will be returned as
|
||||
* specified by XEP-0128.
|
||||
* <p>
|
||||
*
|
||||
* Since no packet is actually sent to the server it is safe to perform this
|
||||
* operation before logging to the server. In fact, you may want to
|
||||
* configure the extended info before logging to the server so that the
|
||||
* information is already available if it is required upon login.
|
||||
*
|
||||
* @param info
|
||||
* the data form that contains the extend service discovery
|
||||
* information.
|
||||
*/
|
||||
public void setExtendedInfo(DataForm info) {
|
||||
extendedInfo = info;
|
||||
renewEntityCapsVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data form that is set as extended information for this Service Discovery instance (XEP-0128)
|
||||
*
|
||||
* @see <a href="http://xmpp.org/extensions/xep-0128.html">XEP-128: Service Discovery Extensions</a>
|
||||
* @return the data form
|
||||
*/
|
||||
public DataForm getExtendedInfo() {
|
||||
return extendedInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data form as List of PacketExtensions, or null if no data form is set.
|
||||
* This representation is needed by some classes (e.g. EntityCapsManager, NodeInformationProvider)
|
||||
*
|
||||
* @return the data form as List of PacketExtensions
|
||||
*/
|
||||
public List<PacketExtension> getExtendedInfoAsList() {
|
||||
List<PacketExtension> res = null;
|
||||
if (extendedInfo != null) {
|
||||
res = new ArrayList<PacketExtension>(1);
|
||||
res.add(extendedInfo);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the data form containing extended service discovery information
|
||||
* from the information returned by this XMPP entity.<p>
|
||||
*
|
||||
* Since no packet is actually sent to the server it is safe to perform this
|
||||
* operation before logging to the server.
|
||||
*/
|
||||
public void removeExtendedInfo() {
|
||||
extendedInfo = null;
|
||||
renewEntityCapsVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the discovered information of a given XMPP entity addressed by its JID.
|
||||
* Use null as entityID to query the server
|
||||
*
|
||||
* @param entityID the address of the XMPP entity or null.
|
||||
* @return the discovered information.
|
||||
* @throws XMPPErrorException
|
||||
* @throws NoResponseException
|
||||
* @throws NotConnectedException
|
||||
*/
|
||||
public DiscoverInfo discoverInfo(String entityID) throws NoResponseException, XMPPErrorException, NotConnectedException {
|
||||
if (entityID == null)
|
||||
return discoverInfo(null, null);
|
||||
|
||||
// Check if the have it cached in the Entity Capabilities Manager
|
||||
DiscoverInfo info = EntityCapsManager.getDiscoverInfoByUser(entityID);
|
||||
|
||||
if (info != null) {
|
||||
// We were able to retrieve the information from Entity Caps and
|
||||
// avoided a disco request, hurray!
|
||||
return info;
|
||||
}
|
||||
|
||||
// Try to get the newest node#version if it's known, otherwise null is
|
||||
// returned
|
||||
EntityCapsManager.NodeVerHash nvh = EntityCapsManager.getNodeVerHashByJid(entityID);
|
||||
|
||||
// Discover by requesting the information from the remote entity
|
||||
// Note that wee need to use NodeVer as argument for Node if it exists
|
||||
info = discoverInfo(entityID, nvh != null ? nvh.getNodeVer() : null);
|
||||
|
||||
// If the node version is known, store the new entry.
|
||||
if (nvh != null) {
|
||||
if (EntityCapsManager.verifyDiscoverInfoVersion(nvh.getVer(), nvh.getHash(), info))
|
||||
EntityCapsManager.addDiscoverInfoByNode(nvh.getNodeVer(), info);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the discovered information of a given XMPP entity addressed by its JID and
|
||||
* note attribute. Use this message only when trying to query information which is not
|
||||
* directly addressable.
|
||||
*
|
||||
* @see <a href="http://xmpp.org/extensions/xep-0030.html#info-basic">XEP-30 Basic Protocol</a>
|
||||
* @see <a href="http://xmpp.org/extensions/xep-0030.html#info-nodes">XEP-30 Info Nodes</a>
|
||||
*
|
||||
* @param entityID the address of the XMPP entity.
|
||||
* @param node the optional attribute that supplements the 'jid' attribute.
|
||||
* @return the discovered information.
|
||||
* @throws XMPPErrorException if the operation failed for some reason.
|
||||
* @throws NoResponseException if there was no response from the server.
|
||||
* @throws NotConnectedException
|
||||
*/
|
||||
public DiscoverInfo discoverInfo(String entityID, String node) throws NoResponseException, XMPPErrorException, NotConnectedException {
|
||||
// Discover the entity's info
|
||||
DiscoverInfo disco = new DiscoverInfo();
|
||||
disco.setType(IQ.Type.GET);
|
||||
disco.setTo(entityID);
|
||||
disco.setNode(node);
|
||||
|
||||
Packet result = connection().createPacketCollectorAndSend(disco).nextResultOrThrow();
|
||||
|
||||
return (DiscoverInfo) result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the discovered items of a given XMPP entity addressed by its JID.
|
||||
*
|
||||
* @param entityID the address of the XMPP entity.
|
||||
* @return the discovered information.
|
||||
* @throws XMPPErrorException if the operation failed for some reason.
|
||||
* @throws NoResponseException if there was no response from the server.
|
||||
* @throws NotConnectedException
|
||||
*/
|
||||
public DiscoverItems discoverItems(String entityID) throws NoResponseException, XMPPErrorException, NotConnectedException {
|
||||
return discoverItems(entityID, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the discovered items of a given XMPP entity addressed by its JID and
|
||||
* note attribute. Use this message only when trying to query information which is not
|
||||
* directly addressable.
|
||||
*
|
||||
* @param entityID the address of the XMPP entity.
|
||||
* @param node the optional attribute that supplements the 'jid' attribute.
|
||||
* @return the discovered items.
|
||||
* @throws XMPPErrorException if the operation failed for some reason.
|
||||
* @throws NoResponseException if there was no response from the server.
|
||||
* @throws NotConnectedException
|
||||
*/
|
||||
public DiscoverItems discoverItems(String entityID, String node) throws NoResponseException, XMPPErrorException, NotConnectedException {
|
||||
// Discover the entity's items
|
||||
DiscoverItems disco = new DiscoverItems();
|
||||
disco.setType(IQ.Type.GET);
|
||||
disco.setTo(entityID);
|
||||
disco.setNode(node);
|
||||
|
||||
Packet result = connection().createPacketCollectorAndSend(disco).nextResultOrThrow();
|
||||
return (DiscoverItems) result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the server supports publishing of items. A client may wish to publish items
|
||||
* to the server so that the server can provide items associated to the client. These items will
|
||||
* be returned by the server whenever the server receives a disco request targeted to the bare
|
||||
* address of the client (i.e. user@host.com).
|
||||
*
|
||||
* @param entityID the address of the XMPP entity.
|
||||
* @return true if the server supports publishing of items.
|
||||
* @throws XMPPErrorException
|
||||
* @throws NoResponseException
|
||||
* @throws NotConnectedException
|
||||
*/
|
||||
public boolean canPublishItems(String entityID) throws NoResponseException, XMPPErrorException, NotConnectedException {
|
||||
DiscoverInfo info = discoverInfo(entityID);
|
||||
return canPublishItems(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the server supports publishing of items. A client may wish to publish items
|
||||
* to the server so that the server can provide items associated to the client. These items will
|
||||
* be returned by the server whenever the server receives a disco request targeted to the bare
|
||||
* address of the client (i.e. user@host.com).
|
||||
*
|
||||
* @param info the discover info packet to check.
|
||||
* @return true if the server supports publishing of items.
|
||||
*/
|
||||
public static boolean canPublishItems(DiscoverInfo info) {
|
||||
return info.containsFeature("http://jabber.org/protocol/disco#publish");
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes new items to a parent entity. The item elements to publish MUST have at least
|
||||
* a 'jid' attribute specifying the Entity ID of the item, and an action attribute which
|
||||
* specifies the action being taken for that item. Possible action values are: "update" and
|
||||
* "remove".
|
||||
*
|
||||
* @param entityID the address of the XMPP entity.
|
||||
* @param discoverItems the DiscoveryItems to publish.
|
||||
* @throws XMPPErrorException
|
||||
* @throws NoResponseException
|
||||
* @throws NotConnectedException
|
||||
*/
|
||||
public void publishItems(String entityID, DiscoverItems discoverItems) throws NoResponseException, XMPPErrorException, NotConnectedException {
|
||||
publishItems(entityID, null, discoverItems);
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes new items to a parent entity and node. The item elements to publish MUST have at
|
||||
* least a 'jid' attribute specifying the Entity ID of the item, and an action attribute which
|
||||
* specifies the action being taken for that item. Possible action values are: "update" and
|
||||
* "remove".
|
||||
*
|
||||
* @param entityID the address of the XMPP entity.
|
||||
* @param node the attribute that supplements the 'jid' attribute.
|
||||
* @param discoverItems the DiscoveryItems to publish.
|
||||
* @throws XMPPErrorException if the operation failed for some reason.
|
||||
* @throws NoResponseException if there was no response from the server.
|
||||
* @throws NotConnectedException
|
||||
*/
|
||||
public void publishItems(String entityID, String node, DiscoverItems discoverItems) throws NoResponseException, XMPPErrorException, NotConnectedException
|
||||
{
|
||||
discoverItems.setType(IQ.Type.SET);
|
||||
discoverItems.setTo(entityID);
|
||||
discoverItems.setNode(node);
|
||||
|
||||
connection().createPacketCollectorAndSend(discoverItems).nextResultOrThrow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the remote entity for it's features and returns true if the given feature is found.
|
||||
*
|
||||
* @param jid the JID of the remote entity
|
||||
* @param feature
|
||||
* @return true if the entity supports the feature, false otherwise
|
||||
* @throws XMPPErrorException
|
||||
* @throws NoResponseException
|
||||
* @throws NotConnectedException
|
||||
*/
|
||||
public boolean supportsFeature(String jid, String feature) throws NoResponseException, XMPPErrorException, NotConnectedException {
|
||||
DiscoverInfo result = discoverInfo(jid);
|
||||
return result.containsFeature(feature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Entity Capabilities
|
||||
*/
|
||||
|
||||
/**
|
||||
* Loads the ServiceDiscoveryManager with an EntityCapsManger that speeds up certain lookups.
|
||||
*
|
||||
* @param manager
|
||||
*/
|
||||
public void setEntityCapsManager(EntityCapsManager manager) {
|
||||
capsManager = manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the Entity Capabilities Verification String if EntityCaps is enabled.
|
||||
*/
|
||||
private void renewEntityCapsVersion() {
|
||||
if (capsManager != null && capsManager.entityCapsEnabled())
|
||||
capsManager.updateLocalEntityCaps();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,487 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.disco.packet;
|
||||
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A DiscoverInfo IQ packet, which is used by XMPP clients to request and receive information
|
||||
* to/from other XMPP entities.<p>
|
||||
*
|
||||
* The received information may contain one or more identities of the requested XMPP entity, and
|
||||
* a list of supported features by the requested XMPP entity.
|
||||
*
|
||||
* @author Gaston Dombiak
|
||||
*/
|
||||
public class DiscoverInfo extends IQ implements Cloneable {
|
||||
|
||||
public static final String NAMESPACE = "http://jabber.org/protocol/disco#info";
|
||||
|
||||
private final List<Feature> features = new LinkedList<Feature>();
|
||||
private final List<Identity> identities = new LinkedList<Identity>();
|
||||
private String node;
|
||||
|
||||
public DiscoverInfo() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor
|
||||
*
|
||||
* @param d
|
||||
*/
|
||||
public DiscoverInfo(DiscoverInfo d) {
|
||||
super(d);
|
||||
|
||||
// Set node
|
||||
setNode(d.getNode());
|
||||
|
||||
// Copy features
|
||||
for (Feature f : d.features) {
|
||||
addFeature(f.clone());
|
||||
}
|
||||
|
||||
// Copy identities
|
||||
for (Identity i : d.identities) {
|
||||
addIdentity(i.clone());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new feature to the discovered information.
|
||||
*
|
||||
* @param feature the discovered feature
|
||||
*/
|
||||
public void addFeature(String feature) {
|
||||
addFeature(new Feature(feature));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a collection of features to the packet. Does noting if featuresToAdd is null.
|
||||
*
|
||||
* @param featuresToAdd
|
||||
*/
|
||||
public void addFeatures(Collection<String> featuresToAdd) {
|
||||
if (featuresToAdd == null) return;
|
||||
for (String feature : featuresToAdd) {
|
||||
addFeature(feature);
|
||||
}
|
||||
}
|
||||
|
||||
private void addFeature(Feature feature) {
|
||||
features.add(feature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the discovered features of an XMPP entity.
|
||||
*
|
||||
* @return an unmodifiable list of the discovered features of an XMPP entity
|
||||
*/
|
||||
public List<Feature> getFeatures() {
|
||||
return Collections.unmodifiableList(features);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new identity of the requested entity to the discovered information.
|
||||
*
|
||||
* @param identity the discovered entity's identity
|
||||
*/
|
||||
public void addIdentity(Identity identity) {
|
||||
identities.add(identity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds identities to the DiscoverInfo stanza
|
||||
*
|
||||
* @param identitiesToAdd
|
||||
*/
|
||||
public void addIdentities(Collection<Identity> identitiesToAdd) {
|
||||
if (identitiesToAdd == null) return;
|
||||
identities.addAll(identitiesToAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the discovered identities of an XMPP entity.
|
||||
*
|
||||
* @return an unmodifiable list of the discovered identities
|
||||
*/
|
||||
public List<Identity> getIdentities() {
|
||||
return Collections.unmodifiableList(identities);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>
|
||||
*
|
||||
* Node attributes SHOULD be used only when trying to provide or query information which
|
||||
* is not directly addressable.
|
||||
*
|
||||
* @return the node attribute that supplements the 'jid' attribute
|
||||
*/
|
||||
public String getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets 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>
|
||||
*
|
||||
* Node attributes SHOULD be used only when trying to provide or query information which
|
||||
* is not directly addressable.
|
||||
*
|
||||
* @param node the node attribute that supplements the 'jid' attribute
|
||||
*/
|
||||
public void setNode(String node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified feature is part of the discovered information.
|
||||
*
|
||||
* @param feature the feature to check
|
||||
* @return true if the requestes feature has been discovered
|
||||
*/
|
||||
public boolean containsFeature(String feature) {
|
||||
for (Feature f : getFeatures()) {
|
||||
if (feature.equals(f.getVar()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getChildElementXML() {
|
||||
XmlStringBuilder xml = new XmlStringBuilder();
|
||||
xml.halfOpenElement("query");
|
||||
xml.xmlnsAttribute(NAMESPACE);
|
||||
xml.optAttribute("node", getNode());
|
||||
xml.rightAngelBracket();
|
||||
for (Identity identity : identities) {
|
||||
xml.append(identity.toXML());
|
||||
}
|
||||
for (Feature feature : features) {
|
||||
xml.append(feature.toXML());
|
||||
}
|
||||
// Add packet extensions, if any are defined.
|
||||
xml.append(getExtensionsXML());
|
||||
xml.closeElement("query");
|
||||
return xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a DiscoverInfo response contains duplicate identities.
|
||||
*
|
||||
* @return true if duplicate identities where found, otherwise false
|
||||
*/
|
||||
public boolean containsDuplicateIdentities() {
|
||||
List<Identity> checkedIdentities = new LinkedList<Identity>();
|
||||
for (Identity i : identities) {
|
||||
for (Identity i2 : checkedIdentities) {
|
||||
if (i.equals(i2))
|
||||
return true;
|
||||
}
|
||||
checkedIdentities.add(i);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a DiscoverInfo response contains duplicate features.
|
||||
*
|
||||
* @return true if duplicate identities where found, otherwise false
|
||||
*/
|
||||
public boolean containsDuplicateFeatures() {
|
||||
List<Feature> checkedFeatures = new LinkedList<Feature>();
|
||||
for (Feature f : features) {
|
||||
for (Feature f2 : checkedFeatures) {
|
||||
if (f.equals(f2))
|
||||
return true;
|
||||
}
|
||||
checkedFeatures.add(f);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiscoverInfo clone() {
|
||||
return new DiscoverInfo(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the identity of a given XMPP entity. An entity may have many identities but all
|
||||
* the identities SHOULD have the same name.<p>
|
||||
*
|
||||
* Refer to <a href="http://www.jabber.org/registrar/disco-categories.html">Jabber::Registrar</a>
|
||||
* in order to get the official registry of values for the <i>category</i> and <i>type</i>
|
||||
* attributes.
|
||||
*
|
||||
*/
|
||||
public static class Identity implements Comparable<Identity>, Cloneable {
|
||||
|
||||
private final String category;
|
||||
private String name;
|
||||
private final String type;
|
||||
private String lang; // 'xml:lang;
|
||||
|
||||
public Identity(Identity identity) {
|
||||
this(identity.category, identity.name, identity.type);
|
||||
lang = identity.lang;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new identity for an XMPP entity.
|
||||
* 'category' and 'type' are required by
|
||||
* <a href="http://xmpp.org/extensions/xep-0030.html#schemas">XEP-30 XML Schemas</a>
|
||||
*
|
||||
* @param category the entity's category (required as per XEP-30).
|
||||
* @param name the entity's name.
|
||||
* @param type the entity's type (required as per XEP-30).
|
||||
*/
|
||||
public Identity(String category, String name, String type) {
|
||||
if ((category == null) || (type == null))
|
||||
throw new IllegalArgumentException("category and type cannot be null");
|
||||
|
||||
this.category = category;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entity's category. To get the official registry of values for the
|
||||
* 'category' attribute refer to <a href="http://www.jabber.org/registrar/disco-categories.html">Jabber::Registrar</a>
|
||||
*
|
||||
* @return the entity's category.
|
||||
*/
|
||||
public String getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identity's name.
|
||||
*
|
||||
* @return the identity's name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the identity's name.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entity's type. To get the official registry of values for the
|
||||
* 'type' attribute refer to <a href="http://www.jabber.org/registrar/disco-categories.html">Jabber::Registrar</a>
|
||||
*
|
||||
* @return the entity's type.
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the natural language (xml:lang) for this identity (optional)
|
||||
*
|
||||
* @param lang the xml:lang of this Identity
|
||||
*/
|
||||
public void setLanguage(String lang) {
|
||||
this.lang = lang;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identities natural language if one is set
|
||||
*
|
||||
* @return the value of xml:lang of this Identity
|
||||
*/
|
||||
public String getLanguage() {
|
||||
return lang;
|
||||
}
|
||||
|
||||
public XmlStringBuilder toXML() {
|
||||
XmlStringBuilder xml = new XmlStringBuilder();
|
||||
xml.halfOpenElement("identity");
|
||||
xml.xmllangAttribute(lang);
|
||||
xml.attribute("category", category);
|
||||
xml.attribute("name", name);
|
||||
xml.optAttribute("type", type);
|
||||
xml.closeEmptyElement();
|
||||
return xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check equality for Identity for category, type, lang and name
|
||||
* in that order as defined by
|
||||
* <a href="http://xmpp.org/extensions/xep-0115.html#ver-proc">XEP-0015 5.4 Processing Method (Step 3.3)</a>
|
||||
*
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (obj.getClass() != getClass())
|
||||
return false;
|
||||
|
||||
DiscoverInfo.Identity other = (DiscoverInfo.Identity) obj;
|
||||
if (!this.category.equals(other.category))
|
||||
return false;
|
||||
|
||||
String otherLang = other.lang == null ? "" : other.lang;
|
||||
String thisLang = lang == null ? "" : lang;
|
||||
if (!otherLang.equals(thisLang))
|
||||
return false;
|
||||
|
||||
// This safeguard can be removed once the deprecated constructor is removed.
|
||||
String otherType = other.type == null ? "" : other.type;
|
||||
String thisType = type == null ? "" : type;
|
||||
if (!otherType.equals(thisType))
|
||||
return false;
|
||||
|
||||
String otherName = other.name == null ? "" : other.name;
|
||||
String thisName = name == null ? "" : other.name;
|
||||
if (!thisName.equals(otherName))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 1;
|
||||
result = 37 * result + category.hashCode();
|
||||
result = 37 * result + (lang == null ? 0 : lang.hashCode());
|
||||
result = 37 * result + (type == null ? 0 : type.hashCode());
|
||||
result = 37 * result + (name == null ? 0 : name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this identity with another one. The comparison order is: Category, Type, Lang.
|
||||
* If all three are identical the other Identity is considered equal. Name is not used for
|
||||
* comparison, as defined by XEP-0115
|
||||
*
|
||||
* @param other
|
||||
* @return a negative integer, zero, or a positive integer as this object is less than,
|
||||
* equal to, or greater than the specified object.
|
||||
*/
|
||||
public int compareTo(DiscoverInfo.Identity other) {
|
||||
String otherLang = other.lang == null ? "" : other.lang;
|
||||
String thisLang = lang == null ? "" : lang;
|
||||
|
||||
// This can be removed once the deprecated constructor is removed.
|
||||
String otherType = other.type == null ? "" : other.type;
|
||||
String thisType = type == null ? "" : type;
|
||||
|
||||
if (category.equals(other.category)) {
|
||||
if (thisType.equals(otherType)) {
|
||||
if (thisLang.equals(otherLang)) {
|
||||
// Don't compare on name, XEP-30 says that name SHOULD
|
||||
// be equals for all identities of an entity
|
||||
return 0;
|
||||
} else {
|
||||
return thisLang.compareTo(otherLang);
|
||||
}
|
||||
} else {
|
||||
return thisType.compareTo(otherType);
|
||||
}
|
||||
} else {
|
||||
return category.compareTo(other.category);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identity clone() {
|
||||
return new Identity(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the features offered by the item. This information helps requestors determine
|
||||
* what actions are possible with regard to this item (registration, search, join, etc.)
|
||||
* as well as specific feature types of interest, if any (e.g., for the purpose of feature
|
||||
* negotiation).
|
||||
*/
|
||||
public static class Feature implements Cloneable {
|
||||
|
||||
private final String variable;
|
||||
|
||||
public Feature(Feature feature) {
|
||||
this.variable = feature.variable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new feature offered by an XMPP entity or item.
|
||||
*
|
||||
* @param variable the feature's variable.
|
||||
*/
|
||||
public Feature(String variable) {
|
||||
if (variable == null)
|
||||
throw new IllegalArgumentException("variable cannot be null");
|
||||
this.variable = variable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the feature's variable.
|
||||
*
|
||||
* @return the feature's variable.
|
||||
*/
|
||||
public String getVar() {
|
||||
return variable;
|
||||
}
|
||||
|
||||
public XmlStringBuilder toXML() {
|
||||
XmlStringBuilder xml = new XmlStringBuilder();
|
||||
xml.halfOpenElement("feature");
|
||||
xml.attribute("var", variable);
|
||||
xml.closeEmptyElement();
|
||||
return xml;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (obj.getClass() != getClass())
|
||||
return false;
|
||||
|
||||
DiscoverInfo.Feature other = (DiscoverInfo.Feature) obj;
|
||||
return variable.equals(other.variable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 37 * variable.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Feature clone() {
|
||||
return new Feature(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,237 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.disco.packet;
|
||||
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A DiscoverItems IQ packet, which is used by XMPP clients to request and receive items
|
||||
* associated with XMPP entities.<p>
|
||||
*
|
||||
* The items could also be queried in order to discover if they contain items inside. Some items
|
||||
* may be addressable by its JID and others may require to be addressed by a JID and a node name.
|
||||
*
|
||||
* @author Gaston Dombiak
|
||||
*/
|
||||
public class DiscoverItems extends IQ {
|
||||
|
||||
public static final String NAMESPACE = "http://jabber.org/protocol/disco#items";
|
||||
|
||||
private final List<Item> items = new LinkedList<Item>();
|
||||
private String node;
|
||||
|
||||
/**
|
||||
* Adds a new item to the discovered information.
|
||||
*
|
||||
* @param item the discovered entity's item
|
||||
*/
|
||||
public void addItem(Item item) {
|
||||
items.add(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a collection of items to the discovered information. Does nothing if itemsToAdd is null
|
||||
*
|
||||
* @param itemsToAdd
|
||||
*/
|
||||
public void addItems(Collection<Item> itemsToAdd) {
|
||||
if (itemsToAdd == null) return;
|
||||
for (Item i : itemsToAdd) {
|
||||
addItem(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the discovered items of the queried XMPP entity.
|
||||
*
|
||||
* @return an unmodifiable list of the discovered entity's items
|
||||
*/
|
||||
public List<DiscoverItems.Item> getItems() {
|
||||
return Collections.unmodifiableList(items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>
|
||||
*
|
||||
* Node attributes SHOULD be used only when trying to provide or query information which
|
||||
* is not directly addressable.
|
||||
*
|
||||
* @return the node attribute that supplements the 'jid' attribute
|
||||
*/
|
||||
public String getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets 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>
|
||||
*
|
||||
* Node attributes SHOULD be used only when trying to provide or query information which
|
||||
* is not directly addressable.
|
||||
*
|
||||
* @param node the node attribute that supplements the 'jid' attribute
|
||||
*/
|
||||
public void setNode(String node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public XmlStringBuilder getChildElementXML() {
|
||||
XmlStringBuilder xml = new XmlStringBuilder();
|
||||
xml.halfOpenElement("query");
|
||||
xml.xmlnsAttribute(NAMESPACE);
|
||||
xml.optAttribute("node", getNode());
|
||||
xml.rightAngelBracket();
|
||||
|
||||
for (Item item : items) {
|
||||
xml.append(item.toXML());
|
||||
}
|
||||
|
||||
xml.closeElement("query");
|
||||
return xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* An item is associated with an XMPP Entity, usually thought of a children of the parent
|
||||
* entity and normally are addressable as a JID.<p>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
public static class Item {
|
||||
|
||||
/**
|
||||
* Request to create or update the item.
|
||||
*/
|
||||
public static final String UPDATE_ACTION = "update";
|
||||
|
||||
/**
|
||||
* Request to remove the item.
|
||||
*/
|
||||
public static final String REMOVE_ACTION = "remove";
|
||||
|
||||
private String entityID;
|
||||
private String name;
|
||||
private String node;
|
||||
private String action;
|
||||
|
||||
/**
|
||||
* Create a new Item associated with a given entity.
|
||||
*
|
||||
* @param entityID the id of the entity that contains the item
|
||||
*/
|
||||
public Item(String entityID) {
|
||||
this.entityID = entityID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entity's ID.
|
||||
*
|
||||
* @return the entity's ID.
|
||||
*/
|
||||
public String getEntityID() {
|
||||
return entityID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entity's name.
|
||||
*
|
||||
* @return the entity's name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the entity's name.
|
||||
*
|
||||
* @param name the entity's name.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>
|
||||
*
|
||||
* Node attributes SHOULD be used only when trying to provide or query information which
|
||||
* is not directly addressable.
|
||||
*
|
||||
* @return the node attribute that supplements the 'jid' attribute
|
||||
*/
|
||||
public String getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets 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>
|
||||
*
|
||||
* Node attributes SHOULD be used only when trying to provide or query information which
|
||||
* is not directly addressable.
|
||||
*
|
||||
* @param node the node attribute that supplements the 'jid' attribute
|
||||
*/
|
||||
public void setNode(String node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the action that specifies the action being taken for this item. Possible action
|
||||
* values are: "update" and "remove". Update should either create a new entry if the node
|
||||
* and jid combination does not already exist, or simply update an existing entry. If
|
||||
* "remove" is used as the action, the item should be removed from persistent storage.
|
||||
*
|
||||
* @return the action being taken for this item
|
||||
*/
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action that specifies the action being taken for this item. Possible action
|
||||
* values are: "update" and "remove". Update should either create a new entry if the node
|
||||
* and jid combination does not already exist, or simply update an existing entry. If
|
||||
* "remove" is used as the action, the item should be removed from persistent storage.
|
||||
*
|
||||
* @param action the action being taken for this item
|
||||
*/
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public XmlStringBuilder toXML() {
|
||||
XmlStringBuilder xml = new XmlStringBuilder();
|
||||
xml.halfOpenElement("item");
|
||||
xml.attribute("jid", entityID);
|
||||
xml.optAttribute("name", name);
|
||||
xml.optAttribute("node", node);
|
||||
xml.optAttribute("action", action);
|
||||
xml.closeEmptyElement();
|
||||
return xml;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jivesoftware.smackx.disco.provider;
|
||||
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.provider.IQProvider;
|
||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
/**
|
||||
* The DiscoverInfoProvider parses Service Discovery information packets.
|
||||
*
|
||||
* @author Gaston Dombiak
|
||||
*/
|
||||
public class DiscoverInfoProvider implements IQProvider {
|
||||
|
||||
public IQ parseIQ(XmlPullParser parser) throws Exception {
|
||||
DiscoverInfo discoverInfo = new DiscoverInfo();
|
||||
boolean done = false;
|
||||
DiscoverInfo.Identity identity = null;
|
||||
String category = "";
|
||||
String name = "";
|
||||
String type = "";
|
||||
String variable = "";
|
||||
String lang = "";
|
||||
discoverInfo.setNode(parser.getAttributeValue("", "node"));
|
||||
while (!done) {
|
||||
int eventType = parser.next();
|
||||
if (eventType == XmlPullParser.START_TAG) {
|
||||
if (parser.getName().equals("identity")) {
|
||||
// Initialize the variables from the parsed XML
|
||||
category = parser.getAttributeValue("", "category");
|
||||
name = parser.getAttributeValue("", "name");
|
||||
type = parser.getAttributeValue("", "type");
|
||||
lang = parser.getAttributeValue(parser.getNamespace("xml"), "lang");
|
||||
}
|
||||
else if (parser.getName().equals("feature")) {
|
||||
// Initialize the variables from the parsed XML
|
||||
variable = parser.getAttributeValue("", "var");
|
||||
}
|
||||
// Otherwise, it must be a packet extension.
|
||||
else {
|
||||
discoverInfo.addExtension(PacketParserUtils.parsePacketExtension(parser
|
||||
.getName(), parser.getNamespace(), parser));
|
||||
}
|
||||
} else if (eventType == XmlPullParser.END_TAG) {
|
||||
if (parser.getName().equals("identity")) {
|
||||
// Create a new identity and add it to the discovered info.
|
||||
identity = new DiscoverInfo.Identity(category, name, type);
|
||||
if (lang != null)
|
||||
identity.setLanguage(lang);
|
||||
discoverInfo.addIdentity(identity);
|
||||
}
|
||||
if (parser.getName().equals("feature")) {
|
||||
// Create a new feature and add it to the discovered info.
|
||||
discoverInfo.addFeature(variable);
|
||||
}
|
||||
if (parser.getName().equals("query")) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return discoverInfo;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jivesoftware.smackx.disco.provider;
|
||||
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.provider.IQProvider;
|
||||
import org.jivesoftware.smackx.disco.packet.DiscoverItems;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
/**
|
||||
* The DiscoverInfoProvider parses Service Discovery items packets.
|
||||
*
|
||||
* @author Gaston Dombiak
|
||||
*/
|
||||
public class DiscoverItemsProvider implements IQProvider {
|
||||
|
||||
public IQ parseIQ(XmlPullParser parser) throws Exception {
|
||||
DiscoverItems discoverItems = new DiscoverItems();
|
||||
boolean done = false;
|
||||
DiscoverItems.Item item;
|
||||
String jid = "";
|
||||
String name = "";
|
||||
String action = "";
|
||||
String node = "";
|
||||
discoverItems.setNode(parser.getAttributeValue("", "node"));
|
||||
while (!done) {
|
||||
int eventType = parser.next();
|
||||
|
||||
if (eventType == XmlPullParser.START_TAG && "item".equals(parser.getName())) {
|
||||
// Initialize the variables from the parsed XML
|
||||
jid = parser.getAttributeValue("", "jid");
|
||||
name = parser.getAttributeValue("", "name");
|
||||
node = parser.getAttributeValue("", "node");
|
||||
action = parser.getAttributeValue("", "action");
|
||||
}
|
||||
else if (eventType == XmlPullParser.END_TAG && "item".equals(parser.getName())) {
|
||||
// Create a new Item and add it to DiscoverItems.
|
||||
item = new DiscoverItems.Item(jid);
|
||||
item.setName(name);
|
||||
item.setNode(node);
|
||||
item.setAction(action);
|
||||
discoverItems.addItem(item);
|
||||
}
|
||||
else if (eventType == XmlPullParser.END_TAG && "query".equals(parser.getName())) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
return discoverItems;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue