Guía de XMPP Smack Client

1. Introducción

XMPP es un protocolo de mensajería instantánea rico y complejo.

En lugar de escribir nuestro propio cliente desde cero, en este tutorial, echaremos un vistazo a Smack, un cliente XMPP modular y portátil de código abierto escrito en Java que ha hecho gran parte del trabajo pesado por nosotros.

2. Dependencias

Smack está organizado en varios módulos para proporcionar más flexibilidad , por lo que podemos incluir fácilmente las funciones que necesitamos.

Algunos de estos incluyen:

  • Módulo XMPP sobre TCP
  • Un módulo para admitir muchas de las extensiones definidas por XMPP Standards Foundation
  • Soporte de extensiones heredadas
  • Un módulo para depurar

Podemos encontrar todos los módulos compatibles en la documentación de XMPP.

Sin embargo, en este tutorial, solo haremos uso de los módulos tcp , im , extensions y java7 :

 org.igniterealtime.smack smack-tcp   org.igniterealtime.smack smack-im   org.igniterealtime.smack smack-extensions   org.igniterealtime.smack smack-java7 

Las últimas versiones se pueden encontrar en Maven Central.

3. Configuración

Para probar el cliente, necesitaremos un servidor XMPP. Para hacerlo, crearemos una cuenta en jabber.hot-chilli.net, un servicio gratuito de Jabber / XMPP para todos.

Luego, podemos configurar Smack usando la clase XMPPTCPConnectionConfiguration que proporciona un constructor para configurar los parámetros de la conexión:

XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder() .setUsernameAndPassword("baeldung","baeldung") .setXmppDomain("jabb3r.org") .setHost("jabb3r.org") .build();

El constructor nos permite configurar la información básica necesaria para realizar una conexión . Si es necesario, también podemos establecer otros parámetros como puerto, protocolos SSL y tiempos de espera.

4. Conexión

Hacer una conexión simplemente se logra usando la clase XMPPTCPConnection :

AbstractXMPPConnection connection = new XMPPTCPConnection(config); connection.connect(); //Establishes a connection to the server connection.login(); //Logs in 

La clase contiene un constructor que acepta la configuración previamente construida. También proporciona métodos para conectarse al servidor e iniciar sesión.

Una vez que se ha establecido una conexión, podemos usar las funciones de Smack , como el chat , que describiremos en la siguiente sección.

En el caso de que la conexión se interrumpa repentinamente, de forma predeterminada, Smack intentará volver a conectarse.

El ReconnectionManager intentará reconectarse inmediatamente al servidor y aumentará la demora entre intentos, ya que las reconexiones sucesivas siguen fallando.

5. Chat

Una de las principales características de la biblioteca es la compatibilidad con chat.

El uso de la clase Chat hace posible crear un nuevo hilo de mensajes entre dos usuarios:

ChatManager chatManager = ChatManager.getInstanceFor(connection); EntityBareJid jid = JidCreate.entityBareFrom("[email protected]"); Chat chat = chatManager.chatWith(jid);

Tenga en cuenta que, para crear un chat , usamos un ChatManager y, obviamente, especificamos con quién conversar. Logramos lo último utilizando el objeto EntityBareJid , queenvuelve una dirección XMPP, también conocida como JID, compuesta por una parte local ( baeldung2 ) y una parte de dominio ( jabb3r.org ).

Después de eso, podemos enviar un mensaje usando el método send () :

chat.send("Hello!");

Y reciba mensajes configurando un oyente:

chatManager.addIncomingListener(new IncomingChatMessageListener() { @Override public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) { System.out.println("New message from " + from + ": " + message.getBody()); } });

5.1. Habitaciones

Además del chat de usuario de extremo a extremo, Smack brinda soporte para chats grupales a través del uso de salas .

Hay dos tipos de salas, salas instantáneas y salas reservadas.

Las salas instantáneas están disponibles para acceso inmediato y se crean automáticamente en función de alguna configuración predeterminada. Por otro lado, las habitaciones reservadas son configuradas manualmente por el propietario de la habitación antes de que alguien pueda ingresar.

Echemos un vistazo a cómo crear una sala instantánea usando MultiUserChatManager :

MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection); MultiUserChat muc = manager.getMultiUserChat(jid); Resourcepart room = Resourcepart.from("baeldung_room"); muc.create(room).makeInstant();

De manera similar podemos crear una habitación reservada:

Set owners = JidUtil.jidSetFrom( new String[] { "[email protected]", "[email protected]" }); muc.create(room) .getConfigFormManger() .setRoomOwners(owners) .submitConfigurationForm();

6. Lista

Otra característica que ofrece Smack es la posibilidad de rastrear la presencia de otros usuarios.

Con Roster.getInstanceFor (), podemos obtener una instancia de Roster :

Roster roster = Roster.getInstanceFor(connection);

El Roster es una lista de contactos que representa a los usuarios como objetos RosterEntry y nos permite organizar a los usuarios en grupos.

Podemos imprimir todas las entradas en la lista usando el método getEntries () :

Collection entries = roster.getEntries(); for (RosterEntry entry : entries) { System.out.println(entry); }

Además, nos permite escuchar cambios en sus entradas y datos de presencia con un RosterListener:

roster.addRosterListener(new RosterListener() { public void entriesAdded(Collection addresses) { // handle new entries } public void entriesDeleted(Collection addresses) { // handle deleted entries } public void entriesUpdated(Collection addresses) { // handle updated entries } public void presenceChanged(Presence presence) { // handle presence change } });

También proporciona una forma de proteger la privacidad del usuario asegurándose de que solo los usuarios aprobados puedan suscribirse a una lista. Para hacerlo, Smack implementa un modelo basado en permisos.

Hay tres formas de manejar las solicitudes de suscripción de presencia con el método Roster.setSubscriptionMode () :

  • Roster.SubscriptionMode.accept_all : acepta todas las solicitudes de suscripción
  • Roster.SubscriptionMode.reject_all: rechaza todas las solicitudes de suscripción
  • Roster.SubscriptionMode.manual: procesa las solicitudes de suscripción de presencia manualmente

Si elegimos manejar las solicitudes de suscripción manualmente, necesitaremos registrar un StanzaListener (descrito en la siguiente sección) y manejar paquetes con el tipo Presence.Type.subscribe .

7. Estrofa

Además del chat, Smack proporciona un marco flexible para enviar una estrofa y escuchar una entrante.

Para aclarar, una estrofa es una unidad semántica discreta de significado en XMPP. Es información estructurada que se envía de una entidad a otra a través de un flujo XML.

Podemos transmitir una estrofa a través de una conexión usando el método send () :

Stanza presence = new Presence(Presence.Type.subscribe); connection.sendStanza(presence);

In the example above, we sent a Presence stanza to subscribe to a roster.

On the other hand, to process the incoming stanzas, the library provides two constructs:

  • StanzaCollector
  • StanzaListener

In particular, StanzaCollector let us wait synchronously for new stanzas:

StanzaCollector collector = connection.createStanzaCollector(StanzaTypeFilter.MESSAGE); Stanza stanza = collector.nextResult();

While StanzaListener is an interface for asynchronously notifying us of incoming stanzas:

connection.addAsyncStanzaListener(new StanzaListener() { public void processStanza(Stanza stanza) throws SmackException.NotConnectedException,InterruptedException, SmackException.NotLoggedInException { // handle stanza } }, StanzaTypeFilter.MESSAGE);

7.1. Filters

Moreover, the library provides a built-in set of filters to process incoming stanzas.

We can filter stanza by type using StanzaTypeFilter or by ID with StanzaIdFilter:

StanzaFilter messageFilter = StanzaTypeFilter.MESSAGE; StanzaFilter idFilter = new StanzaIdFilter("123456");

Or, discerning by particular address:

StanzaFilter fromFilter = FromMatchesFilter.create(JidCreate.from("[email protected]")); StanzaFilter toFilter = ToMatchesFilter.create(JidCreate.from("[email protected]"));

Y podemos usar el operador de filtro lógico ( AndFilter , OrFilter , NotFilter ) para crear filtros complejos:

StanzaFilter filter = new AndFilter(StanzaTypeFilter.Message, FromMatchesFilter.create("[email protected]"));

8. Conclusión

En este artículo, cubrimos las clases más útiles que ofrece Smack.

Aprendimos cómo configurar la biblioteca para enviar y recibir estrofas XMPP.

Posteriormente, aprendimos cómo manejar los chats grupales usando las funciones de ChatManager y Roster .

Como de costumbre, todos los ejemplos de código que se muestran en este tutorial están disponibles en GitHub.