001/**
002 *
003 * Copyright 2009 Jive Software.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smack;
018
019import java.util.concurrent.TimeUnit;
020
021import javax.xml.namespace.QName;
022
023import org.jivesoftware.smack.SmackException.NoResponseException;
024import org.jivesoftware.smack.SmackException.NotConnectedException;
025import org.jivesoftware.smack.XMPPException.XMPPErrorException;
026import org.jivesoftware.smack.filter.IQReplyFilter;
027import org.jivesoftware.smack.filter.StanzaFilter;
028import org.jivesoftware.smack.iqrequest.IQRequestHandler;
029import org.jivesoftware.smack.packet.ExtensionElement;
030import org.jivesoftware.smack.packet.FullyQualifiedElement;
031import org.jivesoftware.smack.packet.IQ;
032import org.jivesoftware.smack.packet.Message;
033import org.jivesoftware.smack.packet.MessageBuilder;
034import org.jivesoftware.smack.packet.Nonza;
035import org.jivesoftware.smack.packet.Presence;
036import org.jivesoftware.smack.packet.PresenceBuilder;
037import org.jivesoftware.smack.packet.Stanza;
038import org.jivesoftware.smack.packet.StanzaFactory;
039import org.jivesoftware.smack.util.Consumer;
040import org.jivesoftware.smack.util.Predicate;
041import org.jivesoftware.smack.util.XmppElementUtil;
042
043import org.jxmpp.jid.DomainBareJid;
044import org.jxmpp.jid.EntityFullJid;
045
046/**
047 * The XMPPConnection interface provides an interface for connections to an XMPP server and
048 * implements shared methods which are used by the different types of connections (e.g.
049 * <code>XMPPTCPConnection</code> or <code>XMPPBOSHConnection</code>). To create a connection to an XMPP server
050 * a simple usage of this API might look like the following:
051 *
052 * <pre>
053 * // Create a connection to the igniterealtime.org XMPP server.
054 * XMPPTCPConnection con = new XMPPTCPConnection("igniterealtime.org");
055 * // Connect to the server
056 * con.connect();
057 * // Most servers require you to login before performing other tasks.
058 * con.login("jsmith", "mypass");
059 * // Start a new conversation with John Doe and send him a message.
060 * ChatManager chatManager = ChatManager.getInstanceFor(con);
061 * chatManager.addIncomingListener(new IncomingChatMessageListener() {
062 *     public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
063 *         // Print out any messages we get back to standard out.
064 *         System.out.println("Received message: " + message);
065 *     }
066 * });
067 * Chat chat = chatManager.chatWith("jdoe@igniterealtime.org");
068 * chat.send("Howdy!");
069 * // Disconnect from the server
070 * con.disconnect();
071 * </pre>
072 * <p>
073 * Note that the XMPPConnection interface does intentionally not declare any methods that manipulate
074 * the connection state, e.g. <code>connect()</code>, <code>disconnect()</code>. You should use the
075 * most specific connection type, e.g. <code>XMPPTCPConnection</code> as declared type and use the
076 * XMPPConnection interface when you don't need to manipulate the connection state.
077 * </p>
078 * <p>
079 * XMPPConnections can be reused between connections. This means that an Connection may be connected,
080 * disconnected and then connected again. Listeners of the XMPPConnection will be retained across
081 * connections.
082 * </p>
083 * <h2>Incoming Stanza Listeners</h2>
084 * Most callbacks (listeners, handlers, …) than you can add to a connection come in three different variants:
085 * <ul>
086 * <li>standard</li>
087 * <li>async (asynchronous)</li>
088 * <li>sync (synchronous)</li>
089 * </ul>
090 * <p>
091 * Standard callbacks are invoked concurrently, but it is ensured that the same callback is never run concurrently.
092 * The callback's identity is used as key for that. The events delivered to the callback preserve the order of the
093 * causing events of the connection.
094 * </p>
095 * <p>
096 * Asynchronous callbacks are run decoupled from the connections main event loop. Hence a callback triggered by
097 * stanza B may (appear to) invoked before a callback triggered by stanza A, even though stanza A arrived before B.
098 * </p>
099 * <p>
100 * Synchronous callbacks are run synchronous to the main event loop of a connection. Hence they are invoked in the
101 * exact order of how events happen there, most importantly the arrival order of incoming stanzas. You should only
102 * use synchronous callbacks in rare situations.
103 * </p>
104 *
105 * @author Matt Tucker
106 * @author Guenther Niess
107 */
108public interface XMPPConnection {
109
110    /**
111     * Returns the XMPP Domain of the service provided by the XMPP server and used for this connection. After
112     * authenticating with the server the returned value may be different.
113     *
114     * @return the XMPP domain of this XMPP session.
115     */
116    DomainBareJid getXMPPServiceDomain();
117
118    /**
119     * Returns the host name of the server where the XMPP server is running. This would be the
120     * IP address of the server or a name that may be resolved by a DNS server.
121     *
122     * @return the host name of the server where the XMPP server is running or null if not yet connected.
123     */
124    String getHost();
125
126    /**
127     * Returns the port number of the XMPP server for this connection. The default port
128     * for normal connections is 5222.
129     *
130     * @return the port number of the XMPP server or 0 if not yet connected.
131     */
132    int getPort();
133
134    /**
135     * Returns the full XMPP address of the user that is logged in to the connection or
136     * <code>null</code> if not logged in yet. An XMPP address is in the form
137     * username@server/resource.
138     *
139     * @return the full XMPP address of the user logged in.
140     */
141    EntityFullJid getUser();
142
143    /**
144     * Returns the stream ID for this connection, which is the value set by the server
145     * when opening an XMPP stream. This value will be <code>null</code> if not connected to the server.
146     *
147     * @return the ID of this connection returned from the XMPP server or <code>null</code> if
148     *      not connected to the server.
149     * @see <a href="http://xmpp.org/rfcs/rfc6120.html#streams-attr-id">RFC 6120 § 4.7.3. id</a>
150     */
151    String getStreamId();
152
153    /**
154     * Returns true if currently connected to the XMPP server.
155     *
156     * @return true if connected.
157     */
158    boolean isConnected();
159
160    /**
161     * Returns true if currently authenticated by successfully calling the login method.
162     *
163     * @return true if authenticated.
164     */
165    boolean isAuthenticated();
166
167    /**
168     * Returns true if currently authenticated anonymously.
169     *
170     * @return true if authenticated anonymously.
171     */
172    boolean isAnonymous();
173
174    /**
175     * Returns true if the connection to the server has successfully negotiated encryption.
176     *
177     * @return true if a secure connection to the server.
178     */
179    boolean isSecureConnection();
180
181    /**
182     * Returns true if network traffic is being compressed. When using stream compression network
183     * traffic can be reduced up to 90%. Therefore, stream compression is ideal when using a slow
184     * speed network connection. However, the server will need to use more CPU time in order to
185     * un/compress network data so under high load the server performance might be affected.
186     *
187     * @return true if network traffic is being compressed.
188     */
189    boolean isUsingCompression();
190
191    StanzaFactory getStanzaFactory();
192
193    /**
194     * Sends the specified stanza to the server.
195     *
196     * @param stanza the stanza to send.
197     * @throws NotConnectedException if the connection is not connected.
198     * @throws InterruptedException if the calling thread was interrupted.
199     * */
200    void sendStanza(Stanza stanza) throws NotConnectedException, InterruptedException;
201
202    /**
203     * Try to send the given stanza. Returns {@code true} if the stanza was successfully put into the outgoing stanza
204     * queue, otherwise, if {@code false} is returned, the stanza could not be scheduled for sending (for example
205     * because the outgoing element queue is full). Note that this means that the stanza possibly was not put onto the
206     * wire, even if {@code true} is returned, it just has been successfully scheduled for sending.
207     * <p>
208     * <b>Note:</b> Implementations are not required to provide that functionality. In that case this method is mapped
209     * to {@link #sendStanza(Stanza)} and will possibly block until the stanza could be scheduled for sending.
210     * </p>
211     *
212     * @param stanza the stanza to send.
213     * @return {@code true} if the stanza was successfully scheduled to be send, {@code false} otherwise.
214     * @throws NotConnectedException if the connection is not connected.
215     * @since 4.4.0
216     */
217    boolean trySendStanza(Stanza stanza) throws NotConnectedException;
218
219    /**
220     * Try to send the given stanza. Returns {@code true} if the stanza was successfully put into the outgoing stanza
221     * queue within the given timeout period, otherwise, if {@code false} is returned, the stanza could not be scheduled
222     * for sending (for example because the outgoing element queue is full). Note that this means that the stanza
223     * possibly was not put onto the wire, even if {@code true} is returned, it just has been successfully scheduled for
224     * sending.
225     * <p>
226     * <b>Note:</b> Implementations are not required to provide that functionality. In that case this method is mapped
227     * to {@link #sendStanza(Stanza)} and will possibly block until the stanza could be scheduled for sending.
228     * </p>
229     *
230     * @param stanza the stanza to send.
231     * @param timeout how long to wait before giving up, in units of {@code unit}.
232     * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter.
233     * @return {@code true} if the stanza was successfully scheduled to be send, {@code false} otherwise.
234     * @throws NotConnectedException if the connection is not connected.
235     * @throws InterruptedException if the calling thread was interrupted.
236     * @since 4.4.0
237     */
238    boolean trySendStanza(Stanza stanza, long timeout, TimeUnit unit)  throws NotConnectedException, InterruptedException;
239
240    /**
241     * Send a Nonza.
242     * <p>
243     * <b>This method is not meant for end-user usage!</b> It allows sending plain stream elements, which should not be
244     * done by a user manually. <b>Doing so may result in a unstable or unusable connection.</b> Certain Smack APIs use
245     * this method to send plain stream elements.
246     * </p>
247     *
248     * @param nonza the Nonza to send.
249     * @throws NotConnectedException if the XMPP connection is not connected.
250     * @throws InterruptedException if the calling thread was interrupted.
251     */
252    void sendNonza(Nonza nonza) throws NotConnectedException, InterruptedException;
253
254    /**
255     * Adds a connection listener to this connection that will be notified when
256     * the connection closes or fails.
257     *
258     * @param connectionListener a connection listener.
259     */
260    void addConnectionListener(ConnectionListener connectionListener);
261
262    /**
263     * Removes a connection listener from this connection.
264     *
265     * @param connectionListener a connection listener.
266     */
267    void removeConnectionListener(ConnectionListener connectionListener);
268
269    /**
270     * Send an IQ request and wait for the response.
271     *
272     * @param request the IQ request
273     * @param <I> the type of the expected result IQ.
274     * @return an IQ with type 'result'
275     * @throws NoResponseException if there was no response from the remote entity.
276     * @throws XMPPErrorException if there was an XMPP error returned.
277     * @throws NotConnectedException if the XMPP connection is not connected.
278     * @throws InterruptedException if the calling thread was interrupted.
279     * @since 4.3
280     */
281    <I extends IQ> I sendIqRequestAndWaitForResponse(IQ request)
282            throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException;
283
284    /**
285     * Creates a new stanza collector collecting IQ responses that are replies to the IQ <code>request</code>.
286     * Does also send the <code>request</code> IQ. The stanza filter for the collector is an
287     * {@link IQReplyFilter}, guaranteeing that stanza id and JID in the 'from' address have
288     * expected values.
289     *
290     * @param request the IQ request to filter responses from
291     * @return a new stanza collector.
292     * @throws NotConnectedException if the XMPP connection is not connected.
293     * @throws InterruptedException if the calling thread was interrupted.
294     */
295    StanzaCollector createStanzaCollectorAndSend(IQ request) throws NotConnectedException, InterruptedException;
296
297    /**
298     * Creates a new stanza collector for this connection. A stanza filter determines
299     * which stanzas will be accumulated by the collector. A StanzaCollector is
300     * more suitable to use than a {@link StanzaListener} when you need to wait for
301     * a specific result.
302     *
303     * @param stanzaFilter the stanza filter to use.
304     * @param stanza the stanza to send right after the collector got created
305     * @return a new stanza collector.
306     * @throws InterruptedException if the calling thread was interrupted.
307     * @throws NotConnectedException if the XMPP connection is not connected.
308     */
309    StanzaCollector createStanzaCollectorAndSend(StanzaFilter stanzaFilter, Stanza stanza)
310                    throws NotConnectedException, InterruptedException;
311
312    /**
313     * Creates a new stanza collector for this connection. A stanza filter
314     * determines which stanzas will be accumulated by the collector. A
315     * StanzaCollector is more suitable to use than a {@link StanzaListener}
316     * when you need to wait for a specific result.
317     * <p>
318     * <b>Note:</b> If you send a Stanza right after using this method, then
319     * consider using
320     * {@link #createStanzaCollectorAndSend(StanzaFilter, Stanza)} instead.
321     * Otherwise make sure cancel the StanzaCollector in every case, e.g. even
322     * if an exception is thrown, or otherwise you may leak the StanzaCollector.
323     * </p>
324     *
325     * @param stanzaFilter the stanza filter to use.
326     * @return a new stanza collector.
327     */
328    StanzaCollector createStanzaCollector(StanzaFilter stanzaFilter);
329
330    /**
331     * Create a new stanza collector with the given stanza collector configuration.
332     * <p>
333     * Please make sure to cancel the collector when it is no longer required. See also
334     * {@link #createStanzaCollector(StanzaFilter)}.
335     * </p>
336     *
337     * @param configuration the stanza collector configuration.
338     * @return a new stanza collector.
339     * @since 4.1
340     */
341    StanzaCollector createStanzaCollector(StanzaCollector.Configuration configuration);
342
343    /**
344     * Remove a stanza collector of this connection.
345     *
346     * @param collector a stanza collectors which was created for this connection.
347     */
348    void removeStanzaCollector(StanzaCollector collector);
349
350    /**
351     * Registers a stanza listener with this connection. The listener will be invoked when a (matching) incoming stanza
352     * is received. The stanza filter determines which stanzas will be delivered to the listener. It is guaranteed that
353     * the same listener will not be invoked concurrently and the the order of invocation will reflect the order in
354     * which the stanzas have been received. If the same stanza listener is added again with a different filter, only
355     * the new filter will be used.
356     *
357     * @param stanzaListener the stanza listener to notify of new received stanzas.
358     * @param stanzaFilter the stanza filter to use.
359     * @since 4.4.0
360     */
361    void addStanzaListener(StanzaListener stanzaListener, StanzaFilter stanzaFilter);
362
363    /**
364     * Removes a stanza listener for received stanzas from this connection.
365     *
366     * @param stanzaListener the stanza listener to remove.
367     * @return true if the stanza listener was removed.
368     * @since 4.4.0
369     */
370    boolean removeStanzaListener(StanzaListener stanzaListener);
371
372    /**
373     *  Registers a <b>synchronous</b> stanza listener with this connection. A stanza listener will be invoked only when
374     * an incoming stanza is received. A stanza filter determines which stanzas will be delivered to the listener. If
375     * the same stanza listener is added again with a different filter, only the new filter will be used.
376     * <p>
377     * <b>Important:</b> This stanza listeners will be called in the same <i>single</i> thread that processes all
378     * incoming stanzas. Only use this kind of stanza filter if it does not perform any XMPP activity that waits for a
379     * response. Consider using {@link #addAsyncStanzaListener(StanzaListener, StanzaFilter)} when possible, i.e. when
380     * the invocation order doesn't have to be the same as the order of the arriving stanzas. If the order of the
381     * arriving stanzas, consider using a {@link StanzaCollector} when possible.
382     * </p>
383     *
384     * @param stanzaListener the stanza listener to notify of new received stanzas.
385     * @param stanzaFilter the stanza filter to use.
386     * @see #addStanzaInterceptor(StanzaListener, StanzaFilter)
387     * @since 4.1
388     */
389    void addSyncStanzaListener(StanzaListener stanzaListener, StanzaFilter stanzaFilter);
390
391    /**
392     * Removes a stanza listener for received stanzas from this connection.
393     *
394     * @param stanzaListener the stanza listener to remove.
395     * @return true if the stanza listener was removed
396     * @since 4.1
397     */
398    boolean removeSyncStanzaListener(StanzaListener stanzaListener);
399
400    /**
401     * Registers an <b>asynchronous</b> stanza listener with this connection. A stanza listener will be invoked only
402     * when an incoming stanza is received. A stanza filter determines which stanzas will be delivered to the listener.
403     * If the same stanza listener is added again with a different filter, only the new filter will be used.
404     * <p>
405     * Unlike {@link #addAsyncStanzaListener(StanzaListener, StanzaFilter)} stanza listeners added with this method will be
406     * invoked asynchronously in their own thread. Use this method if the order of the stanza listeners must not depend
407     * on the order how the stanzas where received.
408     * </p>
409     *
410     * @param stanzaListener the stanza listener to notify of new received stanzas.
411     * @param stanzaFilter the stanza filter to use.
412     * @see #addStanzaInterceptor(StanzaListener, StanzaFilter)
413     * @since 4.1
414    */
415    void addAsyncStanzaListener(StanzaListener stanzaListener, StanzaFilter stanzaFilter);
416
417    /**
418     * Removes an <b>asynchronous</b> stanza listener for received stanzas from this connection.
419     *
420     * @param stanzaListener the stanza listener to remove.
421     * @return true if the stanza listener was removed
422     * @since 4.1
423     */
424    boolean removeAsyncStanzaListener(StanzaListener stanzaListener);
425
426    /**
427     * Registers a stanza listener with this connection. The listener will be
428     * notified of every stanza that this connection sends. A stanza filter determines
429     * which stanzas will be delivered to the listener. Note that the thread
430     * that writes stanzas will be used to invoke the listeners. Therefore, each
431     * stanza listener should complete all operations quickly or use a different
432     * thread for processing.
433     *
434     * @param stanzaListener the stanza listener to notify of sent stanzas.
435     * @param stanzaFilter   the stanza filter to use.
436     */
437    void addStanzaSendingListener(StanzaListener stanzaListener, StanzaFilter stanzaFilter);
438
439    /**
440     * Removes a stanza listener for sending stanzas from this connection.
441     *
442     * @param stanzaListener the stanza listener to remove.
443     */
444    void removeStanzaSendingListener(StanzaListener stanzaListener);
445
446    /**
447     * Registers a stanza interceptor with this connection. The interceptor will be
448     * invoked every time a stanza is about to be sent by this connection. Interceptors
449     * may modify the stanza to be sent. A stanza filter determines which stanzas
450     * will be delivered to the interceptor.
451     *
452     * <p>
453     * NOTE: For a similar functionality on incoming stanzas, see {@link #addAsyncStanzaListener(StanzaListener, StanzaFilter)}.
454     * </p>
455     *
456     * @param stanzaInterceptor the stanza interceptor to notify of stanzas about to be sent.
457     * @param stanzaFilter      the stanza filter to use.
458     * @deprecated use {@link #addMessageInterceptor(Consumer, Predicate)} or {@link #addPresenceInterceptor(Consumer, Predicate)} instead.
459     */
460    @Deprecated
461    // TODO: Remove in Smack 4.5.
462    void addStanzaInterceptor(StanzaListener stanzaInterceptor, StanzaFilter stanzaFilter);
463
464    /**
465     * Removes a stanza interceptor.
466     *
467     * @param stanzaInterceptor the stanza interceptor to remove.
468     * @deprecated use {@link #removeMessageInterceptor(Consumer)} or {@link #removePresenceInterceptor(Consumer)} instead.
469     */
470    @Deprecated
471    // TODO: Remove in Smack 4.5.
472    void removeStanzaInterceptor(StanzaListener stanzaInterceptor);
473
474    /**
475     * Registers a stanza interceptor with this connection. The interceptor will be
476     * invoked every time a stanza is about to be sent by this connection. Interceptors
477     * may modify the stanza to be sent. A stanza filter determines which stanzas
478     * will be delivered to the interceptor.
479     *
480     * <p>
481     * NOTE: For a similar functionality on incoming stanzas, see {@link #addAsyncStanzaListener(StanzaListener, StanzaFilter)}.
482     * </p>
483     *
484     * @param messageInterceptor the stanza interceptor to notify of stanzas about to be sent.
485     * @param messageFilter      the stanza filter to use.
486     */
487    void addMessageInterceptor(Consumer<MessageBuilder> messageInterceptor, Predicate<Message> messageFilter);
488
489    /**
490     * Removes a message interceptor.
491     *
492     * @param messageInterceptor the message interceptor to remove.
493     */
494    void removeMessageInterceptor(Consumer<MessageBuilder> messageInterceptor);
495
496    /**
497     * Registers a stanza interceptor with this connection. The interceptor will be
498     * invoked every time a stanza is about to be sent by this connection. Interceptors
499     * may modify the stanza to be sent. A stanza filter determines which stanzas
500     * will be delivered to the interceptor.
501     *
502     * <p>
503     * NOTE: For a similar functionality on incoming stanzas, see {@link #addAsyncStanzaListener(StanzaListener, StanzaFilter)}.
504     * </p>
505     *
506     * @param presenceInterceptor the stanza interceptor to notify of stanzas about to be sent.
507     * @param presenceFilter      the stanza filter to use.
508     */
509    void addPresenceInterceptor(Consumer<PresenceBuilder> presenceInterceptor, Predicate<Presence> presenceFilter);
510
511    /**
512     * Removes a presence interceptor.
513     *
514     * @param presenceInterceptor the stanza interceptor to remove.
515     */
516    void removePresenceInterceptor(Consumer<PresenceBuilder> presenceInterceptor);
517    /**
518     * Returns the current value of the reply timeout in milliseconds for request for this
519     * XMPPConnection instance.
520     *
521     * @return the reply timeout in milliseconds
522     */
523    long getReplyTimeout();
524
525    /**
526     * Set the stanza reply timeout in milliseconds. In most cases, Smack will throw a
527     * {@link NoResponseException} if no reply to a request was received within the timeout period.
528     *
529     * @param timeout for a reply in milliseconds
530     */
531    void setReplyTimeout(long timeout);
532
533    /**
534     * Get the connection counter of this XMPPConnection instance. Those can be used as ID to
535     * identify the connection, but beware that the ID may not be unique if you create more then
536     * <code>2*Integer.MAX_VALUE</code> instances as the counter could wrap.
537     *
538     * @return the connection counter of this XMPPConnection
539     */
540    int getConnectionCounter();
541
542    enum FromMode {
543        /**
544         * Leave the 'from' attribute unchanged. This is the behavior of Smack &lt; 4.0
545         */
546        UNCHANGED,
547        /**
548         * Omit the 'from' attribute. According to RFC 6120 8.1.2.1 1. XMPP servers "MUST (...)
549         * override the 'from' attribute specified by the client". It is therefore safe to specify
550         * FromMode.OMITTED here.
551         */
552        OMITTED,
553        /**
554         * Set the from to the clients full JID. This is usually not required.
555         */
556        USER
557    }
558
559    /**
560     * Set the FromMode for this connection instance. Defines how the 'from' attribute of outgoing
561     * stanzas should be populated by Smack.
562     *
563     * @param fromMode TODO javadoc me please
564     */
565    void setFromMode(FromMode fromMode);
566
567    /**
568     * Get the currently active FromMode.
569     *
570     * @return the currently active {@link FromMode}
571     */
572    FromMode getFromMode();
573
574    /**
575     * Get the feature stanza extensions for a given stream feature of the
576     * server, or <code>null</code> if the server doesn't support that feature.
577     *
578     * @param <F> {@link ExtensionElement} type of the feature.
579     * @param element TODO javadoc me please
580     * @param namespace TODO javadoc me please
581     * @return a stanza extensions of the feature or <code>null</code>
582     * @deprecated use {@link #getFeature(Class)} instead.
583     */
584    // TODO: Remove in Smack 4.5.
585    @Deprecated
586    default <F extends FullyQualifiedElement> F getFeature(String element, String namespace) {
587        QName qname = new QName(namespace, element);
588        return getFeature(qname);
589    }
590
591    /**
592     * Get the feature stanza extensions for a given stream feature of the
593     * server, or <code>null</code> if the server doesn't support that feature.
594     *
595     * @param <F> {@link ExtensionElement} type of the feature.
596     * @param qname the qualified name of the XML element of feature.
597     * @return a stanza extensions of the feature or <code>null</code>
598     * @since 4.4
599     */
600    <F extends FullyQualifiedElement> F getFeature(QName qname);
601
602    /**
603     * Get the feature stanza extensions for a given stream feature of the
604     * server, or <code>null</code> if the server doesn't support that feature.
605     *
606     * @param <F> {@link ExtensionElement} type of the feature.
607     * @param featureClass the class of the feature.
608     * @return a stanza extensions of the feature or <code>null</code>
609     * @since 4.4
610     */
611    default <F extends FullyQualifiedElement> F getFeature(Class<F> featureClass) {
612        QName qname = XmppElementUtil.getQNameFor(featureClass);
613        return getFeature(qname);
614    }
615
616    /**
617     * Return true if the server supports the given stream feature.
618     *
619     * @param element TODO javadoc me please
620     * @param namespace TODO javadoc me please
621     * @return true if the server supports the stream feature.
622     */
623    default boolean hasFeature(String element, String namespace) {
624        QName qname = new QName(namespace, element);
625        return hasFeature(qname);
626    }
627
628    /**
629     * Return true if the server supports the given stream feature.
630     *
631     * @param qname the qualified name of the XML element of feature.
632     * @return true if the server supports the stream feature.
633     */
634    boolean hasFeature(QName qname);
635
636    /**
637     * Send an IQ request asynchronously. The connection's default reply timeout will be used.
638     *
639     * @param request the IQ request to send.
640     * @return a SmackFuture for the response.
641     */
642    SmackFuture<IQ, Exception> sendIqRequestAsync(IQ request);
643
644    /**
645     * Send an IQ request asynchronously.
646     *
647     * @param request the IQ request to send.
648     * @param timeout the reply timeout in milliseconds.
649     * @return a SmackFuture for the response.
650     */
651    SmackFuture<IQ, Exception> sendIqRequestAsync(IQ request, long timeout);
652
653    /**
654     * Send a stanza asynchronously, waiting for exactly one response stanza using the given reply filter. The
655     * connection's default reply timeout will be used.
656     *
657     * @param stanza the stanza to send.
658     * @param replyFilter the filter used for the response stanza.
659     * @param <S> the type of the stanza to send.
660     * @return a SmackFuture for the response.
661     */
662    <S extends Stanza> SmackFuture<S, Exception> sendAsync(S stanza, StanzaFilter replyFilter);
663
664    /**
665     * Send a stanza asynchronously, waiting for exactly one response stanza using the given reply filter.
666     *
667     * @param stanza the stanza to send.
668     * @param replyFilter the filter used for the response stanza.
669     * @param timeout the reply timeout in milliseconds.
670     * @param <S> the type of the stanza to send.
671     * @return a SmackFuture for the response.
672     */
673    <S extends Stanza> SmackFuture<S, Exception> sendAsync(S stanza, StanzaFilter replyFilter, long timeout);
674
675    /**
676     * Add a callback that is called exactly once and synchronously with the incoming stanza that matches the given
677     * stanza filter.
678     *
679     * @param callback the callback invoked once the stanza filter matches a stanza.
680     * @param stanzaFilter the filter to match stanzas or null to match all.
681     */
682    void addOneTimeSyncCallback(StanzaListener callback, StanzaFilter stanzaFilter);
683
684    /**
685     * Register an IQ request handler with this connection.
686     * <p>
687     * IQ request handler process incoming IQ requests, i.e. incoming IQ stanzas of type 'get' or 'set', and return a result.
688     * </p>
689     * @param iqRequestHandler the IQ request handler to register.
690     * @return the previously registered IQ request handler or null.
691     */
692    IQRequestHandler registerIQRequestHandler(IQRequestHandler iqRequestHandler);
693
694    /**
695     * Convenience method for {@link #unregisterIQRequestHandler(String, String, org.jivesoftware.smack.packet.IQ.Type)}.
696     *
697     * @param iqRequestHandler TODO javadoc me please
698     * @return the previously registered IQ request handler or null.
699     */
700    IQRequestHandler unregisterIQRequestHandler(IQRequestHandler iqRequestHandler);
701
702    /**
703     * Unregister an IQ request handler with this connection.
704     *
705     * @param element the IQ element the IQ request handler is responsible for.
706     * @param namespace the IQ namespace the IQ request handler is responsible for.
707     * @param type the IQ type the IQ request handler is responsible for.
708     * @return the previously registered IQ request handler or null.
709     */
710    IQRequestHandler unregisterIQRequestHandler(String element, String namespace, IQ.Type type);
711
712    /**
713     * Returns the timestamp in milliseconds when the last stanza was received.
714     *
715     * @return the timestamp in milliseconds
716     */
717    long getLastStanzaReceived();
718}