Guia para o cliente XMPP Smack

Guia para o cliente XMPP Smack

1. Introdução

XMPP é um protocolo de mensagens instantâneas rico e complexo.

Em vez de escrever nosso próprio cliente do zero,in this tutorial, we’ll take a look at Smack, a modular and portable open source XMPP client written in Java that fez grande parte do trabalho pesado para nós.

2. Dependências

Smack is organized as several modules to provide more flexibility, para que possamos incluir facilmente os recursos de que precisamos.

Alguns destes incluem:

  • Módulo XMPP sobre TCP

  • Um módulo para suportar muitas das extensões definidas pela XMPP Standards Foundation

  • Suporte a extensões herdadas

  • Um módulo para depurar

Podemos encontrar todos os módulos suportados emXMPP’s documentation.

No entanto, neste tutorial, usaremos apenas os módulostcp,im,extensions ejava7:


    org.igniterealtime.smack
    smack-tcp


    org.igniterealtime.smack
    smack-im


    org.igniterealtime.smack
    smack-extensions


    org.igniterealtime.smack
    smack-java7

As versões mais recentes podem ser encontradas emMaven Central.

3. Configuração

Para testar o cliente, precisamos de um servidor XMPP. Para fazer isso, vamos criar uma conta emjabber.hot-chilli.net, um serviço Jabber / XMPP gratuito para todos.

Depois, podemos configurar o Smack usando o sclassXMPPTCPConnectionConfiguration que fornece um construtor para configurar os parâmetros da conexão:

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

The builder allows us to set the basic information needed to perform a connection. Se necessário, também podemos definir outros parâmetros, como porta, protocolos SSL e tempos limite.

4. Conexão

Fazer uma conexão é simplesmente feito usando a classeXMPPTCPConnection:

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

A classe contém um construtor que aceita a configuração criada anteriormente. Ele também fornece métodos para conectar-se ao servidor e efetuar login.

Once a connection has been established, we can use Smack’s features, comochat, que descreveremos na próxima seção.

No caso em que a conexão foi interrompida repentinamente, por padrão, o Smack tentará se reconectar.

OReconnectionManager tentará se reconectar imediatamente ao servidor e aumentar o atraso entre as tentativas, pois as reconexões sucessivas continuam falhando.

5. Chat

Um dos principais recursos da biblioteca é - suporte por chat.

O uso da classeChat torna possível criar um novo encadeamento de mensagens entre dois usuários:

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

Observe que, para construir umChat, usamos umChatManagere, obviamente, especificamos com quem conversar. Conseguimos o último usando o objetoEntityBareJid, que  * envolve um endereço XMPP —aka um JID— * composto por uma parte local (example2) e uma parte do domínio (jabb3r.org).

Depois disso, podemos enviar uma mensagem usando o métodosend():

chat.send("Hello!");

E receba mensagens configurando um ouvinte:

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. quartos

Bem como bate-papo de usuário ponta a ponta,Smack provides support for group chats through the use of rooms.

Existem dois tipos de salas, salas instantâneas e salas reservadas.

As salas instantâneas estão disponíveis para acesso imediato e são criadas automaticamente com base em algumas configurações padrão. Por outro lado, as salas reservadas são configuradas manualmente pelo proprietário da sala antes que alguém possa entrar.

Vamos dar uma olhada em como criar uma sala instantânea usandoMultiUserChatManager:

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

De maneira semelhante, podemos criar uma sala reservada:

Set owners = JidUtil.jidSetFrom(
  new String[] { "[email protected]", "[email protected]" });

muc.create(room)
  .getConfigFormManger()
  .setRoomOwners(owners)
  .submitConfigurationForm();

6. Lista

Outro recurso que o Smack oferece é a possibilidade de rastrear a presença de outros usuários.

ComRoster.getInstanceFor(), we pode obter uma instânciaRoster:

Roster roster = Roster.getInstanceFor(connection);

ORoster é uma lista de contatos que representa os usuários como objetosRosterEntry e nos permite organizar os usuários em grupos.

Podemos imprimir todas as entradas emRoster usando o métodogetEntries():

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

Além disso, permite-nos ouvir as alterações em suas entradas e dados de presença com umRosterListener:

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 }
});

Ele também fornece uma maneira de proteger a privacidade do usuário, garantindo que apenas os usuários aprovados possam se inscrever em uma lista. To do so, Smack implements a permissions-based model.

Existem três maneiras de lidar com as solicitações de inscrição de presença com o métodoRoster.setSubscriptionMode():

  • Roster.SubscriptionMode.accept_all - Aceita todos os pedidos de inscrição

  • Roster.SubscriptionMode.reject_all – Rejeitar todos os pedidos de inscrição

  • Roster.SubscriptionMode.manual – Processar solicitações de inscrição de presença manualmente

Se escolhermos lidar com as solicitações de assinatura manualmente, precisaremos registrar umStanzaListener (descrito na próxima seção) e lidar com pacotes com o tipoPresence.Type.subscribe.

7. Estrofe

Além do bate-papo, o Smack fornece uma estrutura flexível para enviar uma estrofe e ouvir a recebida.

Para esclarecer, uma estrofe é uma unidade de significado semântica discreta em XMPP. São informações estruturadas enviadas de uma entidade para outra por meio de um fluxo XML.

Podemos transmitir umStanza através de umConnection de acordo com o métodosend():

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

No exemplo acima, enviamos uma estrofePresence para se inscrever em uma lista.

Por outro lado, para processar as sub-rotinas recebidas, a biblioteca fornece duas construções:

  • StanzaCollector

  • StanzaListener

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

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

EnquantoStanzaListener 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. Filtros

Além disso,the library provides a built-in set of filters to process incoming stanzas.

Podemos filtrar estrofes por tipo usandoStanzaTypeFilter ou por ID comStanzaIdFilter:

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

Ou, discernindo por endereço específico:

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

E podemos usar o operador de filtro lógico (AndFilter,OrFilter,NotFilter) para criar filtros complexos:

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

8. Conclusão

Neste artigo, abordamos as classes mais úteis fornecidas pelo Smack.

Aprendemos como configurar a biblioteca para enviar e receber a estrofe do XMPP.

Posteriormente, aprendemos como lidar com bate-papos em grupo usando os recursosChatManagereRoster.

Como de costume, todos os exemplos de código mostrados neste tutorial estão disponíveisover on GitHub.