1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $RCSfile$
3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Revision$
4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Date$
5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Copyright 2003-2007 Jive Software.
7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * you may not use this file except in compliance with the License.
10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * You may obtain a copy of the License at
11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *     http://www.apache.org/licenses/LICENSE-2.0
13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Unless required by applicable law or agreed to in writing, software
15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * distributed under the License is distributed on an "AS IS" BASIS,
16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * See the License for the specific language governing permissions and
18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * limitations under the License.
19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage org.jivesoftware.smackx;
22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.*;
24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.filter.PacketFilter;
25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.filter.PacketIDFilter;
26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.filter.PacketTypeFilter;
27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.IQ;
28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.Packet;
29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.PacketExtension;
30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.XMPPError;
31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.entitycaps.EntityCapsManager;
32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.packet.DiscoverInfo;
33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.packet.DiscoverInfo.Identity;
34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.packet.DiscoverItems;
35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.packet.DataForm;
36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.*;
38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.concurrent.ConcurrentHashMap;
39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Manages discovery of services in XMPP entities. This class provides:
42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <ol>
43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <li>A registry of supported features in this XMPP entity.
44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <li>Automatic response when this XMPP entity is queried for information.
45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <li>Ability to discover items and information of remote XMPP entities.
46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <li>Ability to publish publicly available items.
47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * </ol>
48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Gaston Dombiak
50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic class ServiceDiscoveryManager {
52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private static final String DEFAULT_IDENTITY_NAME = "Smack";
54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private static final String DEFAULT_IDENTITY_CATEGORY = "client";
55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private static final String DEFAULT_IDENTITY_TYPE = "pc";
56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private static List<DiscoverInfo.Identity> identities = new LinkedList<DiscoverInfo.Identity>();
58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private EntityCapsManager capsManager;
60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private static Map<Connection, ServiceDiscoveryManager> instances =
62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            new ConcurrentHashMap<Connection, ServiceDiscoveryManager>();
63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private Connection connection;
65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private final Set<String> features = new HashSet<String>();
66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private DataForm extendedInfo = null;
67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private Map<String, NodeInformationProvider> nodeInformationProviders =
68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            new ConcurrentHashMap<String, NodeInformationProvider>();
69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    // Create a new ServiceDiscoveryManager on every established connection
71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    static {
72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        Connection.addConnectionCreationListener(new ConnectionCreationListener() {
73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            public void connectionCreated(Connection connection) {
74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                new ServiceDiscoveryManager(connection);
75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        });
77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        identities.add(new Identity(DEFAULT_IDENTITY_CATEGORY, DEFAULT_IDENTITY_NAME, DEFAULT_IDENTITY_TYPE));
78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Creates a new ServiceDiscoveryManager for a given Connection. This means that the
82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * service manager will respond to any service discovery request that the connection may
83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * receive.
84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param connection the connection to which a ServiceDiscoveryManager is going to be created.
86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public ServiceDiscoveryManager(Connection connection) {
88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.connection = connection;
89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        init();
91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the ServiceDiscoveryManager instance associated with a given Connection.
95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param connection the connection used to look for the proper ServiceDiscoveryManager.
97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the ServiceDiscoveryManager associated with a given Connection.
98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public static ServiceDiscoveryManager getInstanceFor(Connection connection) {
100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return instances.get(connection);
101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the name of the client that will be returned when asked for the client identity
105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * in a disco request. The name could be any value you need to identity this client.
106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the name of the client that will be returned when asked for the client identity
108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *          in a disco request.
109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public static String getIdentityName() {
111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        DiscoverInfo.Identity identity = identities.get(0);
112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (identity != null) {
113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return identity.getName();
114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        } else {
115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return null;
116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Sets the name of the client that will be returned when asked for the client identity
121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * in a disco request. The name could be any value you need to identity this client.
122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param name the name of the client that will be returned when asked for the client identity
124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *          in a disco request.
125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public static void setIdentityName(String name) {
127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        DiscoverInfo.Identity identity = identities.remove(0);
128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        identity = new DiscoverInfo.Identity(DEFAULT_IDENTITY_CATEGORY, name, DEFAULT_IDENTITY_TYPE);
129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        identities.add(identity);
130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the type of client that will be returned when asked for the client identity in a
134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * disco request. The valid types are defined by the category client. Follow this link to learn
135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * the possible types: <a href="http://xmpp.org/registrar/disco-categories.html#client">Jabber::Registrar</a>.
136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the type of client that will be returned when asked for the client identity in a
138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *          disco request.
139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public static String getIdentityType() {
141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        DiscoverInfo.Identity identity = identities.get(0);
142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (identity != null) {
143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return identity.getType();
144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        } else {
145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return null;
146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Sets the type of client that will be returned when asked for the client identity in a
151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * disco request. The valid types are defined by the category client. Follow this link to learn
152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * the possible types: <a href="http://xmpp.org/registrar/disco-categories.html#client">Jabber::Registrar</a>.
153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param type the type of client that will be returned when asked for the client identity in a
155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *          disco request.
156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public static void setIdentityType(String type) {
158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        DiscoverInfo.Identity identity = identities.get(0);
159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (identity != null) {
160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            identity.setType(type);
161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        } else {
162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            identity = new DiscoverInfo.Identity(DEFAULT_IDENTITY_CATEGORY, DEFAULT_IDENTITY_NAME, type);
163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            identities.add(identity);
164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns all identities of this client as unmodifiable Collection
169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return
171d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public static List<DiscoverInfo.Identity> getIdentities() {
173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return Collections.unmodifiableList(identities);
174d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
176d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
177d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Initializes the packet listeners of the connection that will answer to any
178d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * service discovery request.
179d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
180d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private void init() {
181d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Register the new instance and associate it with the connection
182d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        instances.put(connection, this);
183d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
184d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        addFeature(DiscoverInfo.NAMESPACE);
185d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        addFeature(DiscoverItems.NAMESPACE);
186d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
187d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Add a listener to the connection that removes the registered instance when
188d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // the connection is closed
189d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        connection.addConnectionListener(new ConnectionListener() {
190d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            public void connectionClosed() {
191d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                // Unregister this instance since the connection has been closed
192d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                instances.remove(connection);
193d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
194d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
195d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            public void connectionClosedOnError(Exception e) {
196d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                // ignore
197d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
198d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
199d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            public void reconnectionFailed(Exception e) {
200d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                // ignore
201d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
202d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
203d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            public void reconnectingIn(int seconds) {
204d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                // ignore
205d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
206d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
207d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            public void reconnectionSuccessful() {
208d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                // ignore
209d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
210d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        });
211d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
212d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Listen for disco#items requests and answer with an empty result
213d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        PacketFilter packetFilter = new PacketTypeFilter(DiscoverItems.class);
214d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        PacketListener packetListener = new PacketListener() {
215d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            public void processPacket(Packet packet) {
216d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                DiscoverItems discoverItems = (DiscoverItems) packet;
217d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                // Send back the items defined in the client if the request is of type GET
218d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (discoverItems != null && discoverItems.getType() == IQ.Type.GET) {
219d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    DiscoverItems response = new DiscoverItems();
220d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    response.setType(IQ.Type.RESULT);
221d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    response.setTo(discoverItems.getFrom());
222d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    response.setPacketID(discoverItems.getPacketID());
223d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    response.setNode(discoverItems.getNode());
224d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
225d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    // Add the defined items related to the requested node. Look for
226d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    // the NodeInformationProvider associated with the requested node.
227d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    NodeInformationProvider nodeInformationProvider =
228d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            getNodeInformationProvider(discoverItems.getNode());
229d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    if (nodeInformationProvider != null) {
230d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        // Specified node was found, add node items
231d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        response.addItems(nodeInformationProvider.getNodeItems());
232d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        // Add packet extensions
233d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        response.addExtensions(nodeInformationProvider.getNodePacketExtensions());
234d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    } else if(discoverItems.getNode() != null) {
235d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        // Return <item-not-found/> error since client doesn't contain
236d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        // the specified node
237d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        response.setType(IQ.Type.ERROR);
238d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        response.setError(new XMPPError(XMPPError.Condition.item_not_found));
239d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
240d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    connection.sendPacket(response);
241d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
242d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
243d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        };
244d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        connection.addPacketListener(packetListener, packetFilter);
245d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
246d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Listen for disco#info requests and answer the client's supported features
247d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // To add a new feature as supported use the #addFeature message
248d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        packetFilter = new PacketTypeFilter(DiscoverInfo.class);
249d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        packetListener = new PacketListener() {
250d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            public void processPacket(Packet packet) {
251d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                DiscoverInfo discoverInfo = (DiscoverInfo) packet;
252d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                // Answer the client's supported features if the request is of the GET type
253d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (discoverInfo != null && discoverInfo.getType() == IQ.Type.GET) {
254d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    DiscoverInfo response = new DiscoverInfo();
255d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    response.setType(IQ.Type.RESULT);
256d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    response.setTo(discoverInfo.getFrom());
257d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    response.setPacketID(discoverInfo.getPacketID());
258d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    response.setNode(discoverInfo.getNode());
259d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    // Add the client's identity and features only if "node" is null
260d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    // and if the request was not send to a node. If Entity Caps are
261d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    // enabled the client's identity and features are may also added
262d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    // if the right node is chosen
263d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    if (discoverInfo.getNode() == null) {
264d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        addDiscoverInfoTo(response);
265d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
266d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    else {
267d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        // Disco#info was sent to a node. Check if we have information of the
268d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        // specified node
269d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        NodeInformationProvider nodeInformationProvider =
270d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                getNodeInformationProvider(discoverInfo.getNode());
271d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        if (nodeInformationProvider != null) {
272d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            // Node was found. Add node features
273d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            response.addFeatures(nodeInformationProvider.getNodeFeatures());
274d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            // Add node identities
275d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            response.addIdentities(nodeInformationProvider.getNodeIdentities());
276d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            // Add packet extensions
277d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            response.addExtensions(nodeInformationProvider.getNodePacketExtensions());
278d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        }
279d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        else {
280d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            // Return <item-not-found/> error since specified node was not found
281d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            response.setType(IQ.Type.ERROR);
282d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            response.setError(new XMPPError(XMPPError.Condition.item_not_found));
283d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        }
284d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
285d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    connection.sendPacket(response);
286d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
287d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
288d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        };
289d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        connection.addPacketListener(packetListener, packetFilter);
290d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
291d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
292d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
293d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Add discover info response data.
294d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
295d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @see <a href="http://xmpp.org/extensions/xep-0030.html#info-basic">XEP-30 Basic Protocol; Example 2</a>
296d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
297d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param response the discover info response packet
298d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
299d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void addDiscoverInfoTo(DiscoverInfo response) {
300d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // First add the identities of the connection
301d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        response.addIdentities(identities);
302d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
303d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Add the registered features to the response
304d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        synchronized (features) {
305d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            for (Iterator<String> it = getFeatures(); it.hasNext();) {
306d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                response.addFeature(it.next());
307d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
308d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            response.addExtension(extendedInfo);
309d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
310d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
311d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
312d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
313d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the NodeInformationProvider responsible for providing information
314d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * (ie items) related to a given node or <tt>null</null> if none.<p>
315d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
316d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * In MUC, a node could be 'http://jabber.org/protocol/muc#rooms' which means that the
317d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * NodeInformationProvider will provide information about the rooms where the user has joined.
318d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
319d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param node the node that contains items associated with an entity not addressable as a JID.
320d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the NodeInformationProvider responsible for providing information related
321d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * to a given node.
322d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
323d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private NodeInformationProvider getNodeInformationProvider(String node) {
324d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (node == null) {
325d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return null;
326d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
327d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return nodeInformationProviders.get(node);
328d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
329d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
330d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
331d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Sets the NodeInformationProvider responsible for providing information
332d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * (ie items) related to a given node. Every time this client receives a disco request
333d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * regarding the items of a given node, the provider associated to that node will be the
334d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * responsible for providing the requested information.<p>
335d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
336d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * In MUC, a node could be 'http://jabber.org/protocol/muc#rooms' which means that the
337d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * NodeInformationProvider will provide information about the rooms where the user has joined.
338d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
339d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param node the node whose items will be provided by the NodeInformationProvider.
340d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param listener the NodeInformationProvider responsible for providing items related
341d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *      to the node.
342d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
343d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setNodeInformationProvider(String node, NodeInformationProvider listener) {
344d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        nodeInformationProviders.put(node, listener);
345d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
346d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
347d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
348d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Removes the NodeInformationProvider responsible for providing information
349d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * (ie items) related to a given node. This means that no more information will be
350d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * available for the specified node.
351d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
352d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * In MUC, a node could be 'http://jabber.org/protocol/muc#rooms' which means that the
353d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * NodeInformationProvider will provide information about the rooms where the user has joined.
354d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
355d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param node the node to remove the associated NodeInformationProvider.
356d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
357d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void removeNodeInformationProvider(String node) {
358d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        nodeInformationProviders.remove(node);
359d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
360d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
361d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
362d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the supported features by this XMPP entity.
363d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
364d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return an Iterator on the supported features by this XMPP entity.
365d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
366d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public Iterator<String> getFeatures() {
367d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        synchronized (features) {
368d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return Collections.unmodifiableList(new ArrayList<String>(features)).iterator();
369d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
370d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
371d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
372d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
373d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the supported features by this XMPP entity.
374d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
375d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return a copy of the List on the supported features by this XMPP entity.
376d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
377d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public List<String> getFeaturesList() {
378d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        synchronized (features) {
379d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return new LinkedList<String>(features);
380d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
381d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
382d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
383d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
384d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Registers that a new feature is supported by this XMPP entity. When this client is
385d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * queried for its information the registered features will be answered.<p>
386d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
387d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Since no packet is actually sent to the server it is safe to perform this operation
388d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * before logging to the server. In fact, you may want to configure the supported features
389d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * before logging to the server so that the information is already available if it is required
390d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * upon login.
391d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
392d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param feature the feature to register as supported.
393d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
394d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void addFeature(String feature) {
395d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        synchronized (features) {
396d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            features.add(feature);
397d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            renewEntityCapsVersion();
398d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
399d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
400d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
401d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
402d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Removes the specified feature from the supported features by this XMPP entity.<p>
403d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
404d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Since no packet is actually sent to the server it is safe to perform this operation
405d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * before logging to the server.
406d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
407d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param feature the feature to remove from the supported features.
408d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
409d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void removeFeature(String feature) {
410d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        synchronized (features) {
411d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            features.remove(feature);
412d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            renewEntityCapsVersion();
413d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
414d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
415d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
416d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
417d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns true if the specified feature is registered in the ServiceDiscoveryManager.
418d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
419d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param feature the feature to look for.
420d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return a boolean indicating if the specified featured is registered or not.
421d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
422d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public boolean includesFeature(String feature) {
423d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        synchronized (features) {
424d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return features.contains(feature);
425d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
426d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
427d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
428d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
429d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Registers extended discovery information of this XMPP entity. When this
430d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * client is queried for its information this data form will be returned as
431d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * specified by XEP-0128.
432d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * <p>
433d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
434d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Since no packet is actually sent to the server it is safe to perform this
435d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * operation before logging to the server. In fact, you may want to
436d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * configure the extended info before logging to the server so that the
437d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * information is already available if it is required upon login.
438d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
439d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param info
440d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *            the data form that contains the extend service discovery
441d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *            information.
442d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
443d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setExtendedInfo(DataForm info) {
444d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen      extendedInfo = info;
445d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen      renewEntityCapsVersion();
446d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
447d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
448d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
449d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the data form that is set as extended information for this Service Discovery instance (XEP-0128)
450d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
451d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @see <a href="http://xmpp.org/extensions/xep-0128.html">XEP-128: Service Discovery Extensions</a>
452d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return
453d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
454d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public DataForm getExtendedInfo() {
455d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return extendedInfo;
456d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
457d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
458d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
459d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the data form as List of PacketExtensions, or null if no data form is set.
460d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * This representation is needed by some classes (e.g. EntityCapsManager, NodeInformationProvider)
461d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
462d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return
463d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
464d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public List<PacketExtension> getExtendedInfoAsList() {
465d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        List<PacketExtension> res = null;
466d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (extendedInfo != null) {
467d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            res = new ArrayList<PacketExtension>(1);
468d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            res.add(extendedInfo);
469d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
470d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return res;
471d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
472d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
473d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
474d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Removes the data form containing extended service discovery information
475d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * from the information returned by this XMPP entity.<p>
476d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
477d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Since no packet is actually sent to the server it is safe to perform this
478d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * operation before logging to the server.
479d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
480d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void removeExtendedInfo() {
481d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen       extendedInfo = null;
482d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen       renewEntityCapsVersion();
483d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
484d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
485d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
486d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the discovered information of a given XMPP entity addressed by its JID.
487d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Use null as entityID to query the server
488d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
489d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param entityID the address of the XMPP entity or null.
490d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the discovered information.
491d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @throws XMPPException if the operation failed for some reason.
492d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
493d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public DiscoverInfo discoverInfo(String entityID) throws XMPPException {
494d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (entityID == null)
495d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return discoverInfo(null, null);
496d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
497d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Check if the have it cached in the Entity Capabilities Manager
498d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        DiscoverInfo info = EntityCapsManager.getDiscoverInfoByUser(entityID);
499d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
500d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (info != null) {
501d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // We were able to retrieve the information from Entity Caps and
502d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // avoided a disco request, hurray!
503d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return info;
504d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
505d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
506d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Try to get the newest node#version if it's known, otherwise null is
507d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // returned
508d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        EntityCapsManager.NodeVerHash nvh = EntityCapsManager.getNodeVerHashByJid(entityID);
509d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
510d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Discover by requesting the information from the remote entity
511d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Note that wee need to use NodeVer as argument for Node if it exists
512d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        info = discoverInfo(entityID, nvh != null ? nvh.getNodeVer() : null);
513d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
514d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // If the node version is known, store the new entry.
515d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (nvh != null) {
516d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (EntityCapsManager.verifyDiscoverInfoVersion(nvh.getVer(), nvh.getHash(), info))
517d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                EntityCapsManager.addDiscoverInfoByNode(nvh.getNodeVer(), info);
518d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
519d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
520d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return info;
521d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
522d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
523d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
524d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the discovered information of a given XMPP entity addressed by its JID and
525d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * note attribute. Use this message only when trying to query information which is not
526d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * directly addressable.
527d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
528d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @see <a href="http://xmpp.org/extensions/xep-0030.html#info-basic">XEP-30 Basic Protocol</a>
529d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @see <a href="http://xmpp.org/extensions/xep-0030.html#info-nodes">XEP-30 Info Nodes</a>
530d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
531d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param entityID the address of the XMPP entity.
532d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param node the optional attribute that supplements the 'jid' attribute.
533d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the discovered information.
534d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @throws XMPPException if the operation failed for some reason.
535d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
536d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public DiscoverInfo discoverInfo(String entityID, String node) throws XMPPException {
537d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Discover the entity's info
538d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        DiscoverInfo disco = new DiscoverInfo();
539d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        disco.setType(IQ.Type.GET);
540d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        disco.setTo(entityID);
541d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        disco.setNode(node);
542d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
543d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Create a packet collector to listen for a response.
544d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        PacketCollector collector =
545d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            connection.createPacketCollector(new PacketIDFilter(disco.getPacketID()));
546d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
547d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        connection.sendPacket(disco);
548d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
549d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Wait up to 5 seconds for a result.
550d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
551d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Stop queuing results
552d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        collector.cancel();
553d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (result == null) {
554d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new XMPPException("No response from the server.");
555d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
556d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (result.getType() == IQ.Type.ERROR) {
557d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new XMPPException(result.getError());
558d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
559d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return (DiscoverInfo) result;
560d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
561d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
562d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
563d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the discovered items of a given XMPP entity addressed by its JID.
564d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
565d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param entityID the address of the XMPP entity.
566d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the discovered information.
567d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @throws XMPPException if the operation failed for some reason.
568d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
569d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public DiscoverItems discoverItems(String entityID) throws XMPPException {
570d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return discoverItems(entityID, null);
571d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
572d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
573d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
574d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the discovered items of a given XMPP entity addressed by its JID and
575d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * note attribute. Use this message only when trying to query information which is not
576d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * directly addressable.
577d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
578d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param entityID the address of the XMPP entity.
579d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param node the optional attribute that supplements the 'jid' attribute.
580d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the discovered items.
581d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @throws XMPPException if the operation failed for some reason.
582d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
583d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public DiscoverItems discoverItems(String entityID, String node) throws XMPPException {
584d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Discover the entity's items
585d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        DiscoverItems disco = new DiscoverItems();
586d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        disco.setType(IQ.Type.GET);
587d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        disco.setTo(entityID);
588d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        disco.setNode(node);
589d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
590d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Create a packet collector to listen for a response.
591d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        PacketCollector collector =
592d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            connection.createPacketCollector(new PacketIDFilter(disco.getPacketID()));
593d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
594d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        connection.sendPacket(disco);
595d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
596d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Wait up to 5 seconds for a result.
597d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
598d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Stop queuing results
599d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        collector.cancel();
600d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (result == null) {
601d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new XMPPException("No response from the server.");
602d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
603d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (result.getType() == IQ.Type.ERROR) {
604d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new XMPPException(result.getError());
605d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
606d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return (DiscoverItems) result;
607d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
608d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
609d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
610d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns true if the server supports publishing of items. A client may wish to publish items
611d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * to the server so that the server can provide items associated to the client. These items will
612d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * be returned by the server whenever the server receives a disco request targeted to the bare
613d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * address of the client (i.e. user@host.com).
614d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
615d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param entityID the address of the XMPP entity.
616d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return true if the server supports publishing of items.
617d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @throws XMPPException if the operation failed for some reason.
618d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
619d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public boolean canPublishItems(String entityID) throws XMPPException {
620d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        DiscoverInfo info = discoverInfo(entityID);
621d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return canPublishItems(info);
622d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     }
623d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
624d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     /**
625d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen      * Returns true if the server supports publishing of items. A client may wish to publish items
626d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen      * to the server so that the server can provide items associated to the client. These items will
627d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen      * be returned by the server whenever the server receives a disco request targeted to the bare
628d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen      * address of the client (i.e. user@host.com).
629d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen      *
630d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen      * @param DiscoverInfo the discover info packet to check.
631d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen      * @return true if the server supports publishing of items.
632d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen      */
633d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     public static boolean canPublishItems(DiscoverInfo info) {
634d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         return info.containsFeature("http://jabber.org/protocol/disco#publish");
635d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     }
636d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
637d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
638d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Publishes new items to a parent entity. The item elements to publish MUST have at least
639d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * a 'jid' attribute specifying the Entity ID of the item, and an action attribute which
640d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * specifies the action being taken for that item. Possible action values are: "update" and
641d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * "remove".
642d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
643d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param entityID the address of the XMPP entity.
644d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param discoverItems the DiscoveryItems to publish.
645d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @throws XMPPException if the operation failed for some reason.
646d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
647d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void publishItems(String entityID, DiscoverItems discoverItems)
648d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throws XMPPException {
649d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        publishItems(entityID, null, discoverItems);
650d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
651d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
652d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
653d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Publishes new items to a parent entity and node. The item elements to publish MUST have at
654d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * least a 'jid' attribute specifying the Entity ID of the item, and an action attribute which
655d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * specifies the action being taken for that item. Possible action values are: "update" and
656d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * "remove".
657d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
658d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param entityID the address of the XMPP entity.
659d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param node the attribute that supplements the 'jid' attribute.
660d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param discoverItems the DiscoveryItems to publish.
661d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @throws XMPPException if the operation failed for some reason.
662d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
663d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void publishItems(String entityID, String node, DiscoverItems discoverItems)
664d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throws XMPPException {
665d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        discoverItems.setType(IQ.Type.SET);
666d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        discoverItems.setTo(entityID);
667d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        discoverItems.setNode(node);
668d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
669d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Create a packet collector to listen for a response.
670d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        PacketCollector collector =
671d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            connection.createPacketCollector(new PacketIDFilter(discoverItems.getPacketID()));
672d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
673d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        connection.sendPacket(discoverItems);
674d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
675d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Wait up to 5 seconds for a result.
676d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
677d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Stop queuing results
678d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        collector.cancel();
679d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (result == null) {
680d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new XMPPException("No response from the server.");
681d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
682d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (result.getType() == IQ.Type.ERROR) {
683d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new XMPPException(result.getError());
684d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
685d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
686d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
687d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
688d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Entity Capabilities
689d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
690d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
691d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
692d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Loads the ServiceDiscoveryManager with an EntityCapsManger
693d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * that speeds up certain lookups
694d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param manager
695d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
696d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setEntityCapsManager(EntityCapsManager manager) {
697d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        capsManager = manager;
698d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
699d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
700d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
701d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Updates the Entity Capabilities Verification String
702d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * if EntityCaps is enabled
703d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
704d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private void renewEntityCapsVersion() {
705d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (capsManager != null && capsManager.entityCapsEnabled())
706d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            capsManager.updateLocalEntityCaps();
707d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
708d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
709