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