Gostaria de compartilhar aqui alguns elementos da arquitetura de um sistema que criamos, as razões por trás dessa arquitetura e as decisões tomadas. Porque gostei do resultado e para abrir uma eventual discussão. Afinal, arquitetura de sistemas se discute.
O Projeto
Novas tecnologias tem aparecido (VoIP, ...), criando uma onda de integração entre sistemas e telefonia (Computer Telephony Integration - CTI). O movimento é liderado pelos call centers e vários grandes atores ja se disputam esse mercado.
Ao mesmo tempo, muitas empresas poderiam se beneficiar de funcionalidades de CTI sem que as soluções desenvolvidas para call centers sejam aplicaveis.
Nasceu então o projeto de criar um middleware de integração de sistemas com telefonia, oferecendo funcionalidades de CTI.
Objetivos Arquiteturais
O primeiro objetivo é, claro, funcional: poder iniciar ligações a partir de virtualmente qualquer sistema (ativo) e receber notificações de chamadas em andamento ou entrando (por exemplo, para o sistema "cliente" poder reagir a chamadas entrando)
Além disso, os objetivos não funcionais eram fundamentais:
- Possibilidade de se interfacear com sistemas independentemente de plataformas ou linguagens.
- Agnosticismo dos clientes a respeito da implementação dos serviços, de telefonia no caso. O cliente deve poder iniciar uma ligação usando apenas conceitos de alto nível.
- Independência do middleware a respeito da topologia da telefonia.
- Sistema distribuido, com grande flexibilidade de implantação dos componentes nos nós da rede.
- Alta disponibilidade, com possibilidade de replicação/clusterização.
- Escalabilidade: possibilidade de usar a solução em clientes pequenos como em soluções de grande porte.
Para o objetivo 3, o protocolo de sinalização natural para tal sistema é o SIP (Session Initiation Protocol, RFC 3261), por ser amplamente usado, inclusive pelo PBX open source mais usado, o Asterisk, e por ter implementações prontas em Java.
Trabalhando no mundo Java EE, usamos SIP Servlets (JSR 116) para interagir com o lado de telefonia, usando o Mobicents como container. Baseado no JBoss, essa plataforma permite atender os objetivos 4, 5 e 6.
Os objetivos 1 e 2 são típicos de arquiteturas orientadas a serviço. Para o objetivo 1 basta expor uma camada de serviços web usando protocolos permitindo a interoperabilidade (por exemplo SOAP). Para o objetivo 2 basta definir a semântica dos serviços em termos de alto nivel que façam sentido para os clientes. Assim, os serviços usam "atendida", "não atendida", "falha" para o status de uma ligação, sem entrar nos detalhes de status SIP.
Uma importante característica da arquitetura é a sua asincronicidade. Ao contrário do modelo request/response tradicional em aplicativos web, uma mesma chamada pode ter várias respostas no tempo, eventualmente bem distantes (por exemplo, um INVITE SIP terá várias respostas : primeiro RINGING (chamando) e depois OK (atendida). Essa asincronicidade foi implementada usando queues (JMS).
O maior desafio do desenvolvimento foram as funcionalidades "passivas". Como transmitir notificações do aplicativo CTI para o sistema cliente na recepção de uma resposta ou de uma nova chamada. Ter um "polling" do cliente é um anti-pattern. Catastrófico em termos de performance e escalabilidade. Ter o servidor CTI chamar o aplicativo cliente é introduzir uma dependência do nosso sistema para o cliente (tudo que não queremos). A solução foi aceitar uma dependência do sistema cliente, mas reduzida para um componente apenas, eventualmente instalado independentemente. Esse componente é o "service adapter", encarregado de transmitir informações para o cliente - e dependendo dele pelo menos na sua configuração. Para implementações simples, esse adaptador é instalado junto com o aplicativo CTI. Para soluções maiores, esse adaptador pode ser colocado em um ESB (Enterprise Service Bus).

