• Nenhum resultado encontrado

Exemplo de um objeto JSON com um pacote com uma resposta de média

O pacote mostrado na Listagem 4.3 mostra a transmissão de dados com a informação sobre os bytes que representa, os tipos de respostas que pretende receber, ocontent-type e os identificadores que vão ajudar a relacionar possíveis respostas e mensagens.

Uma resposta do tipo REPORT traz também informação sobre o estado de uma dada parte dos dados, en- quanto que uma resposta do tipo ACKNOWLEDGEMENT transporta apenas os identificadores e um campostatus com um código de resposta semelhante aos do protocolo SIP.

4.1.2 WebSockets

Para a transmissão dos objetos definidos na API entre o servidor e as aplicações Web, foram utilizados Web- Sockets. Para incluir a tecnologia no contexto da aplicação foi necessária a integração desta num componente do servidor da empresa, e portanto utilizando Java. Osbrowsers vão ganhando suporte nativo para WebSockets, mas dado que o protocolo serve para uma comunicação cliente-servidor, o suporte para o protocolo tem de ser implementado em outros componentes que não osbrowsers, para se poder integrar em servidores.

Para além do estabelecimento da ligação bidirecional, a implementação do protocolo de comunicação através de WebSockets deveria também permitir alguma abstração tanto no servidor como no cliente. Tarefas como a identificação e junção de pedidos da mesma aplicação já com a informação relevante do cliente, e a possibilidade de obter já um objeto de sessão a partir do qual se possa interagir de forma genérica para a receção e envio de pacotes para uma dada ligação, são mais valias interessantes e necessárias para a implementação do canal.

A tecnologia é recente mas já vários projetos estão a utilizar o mecanismo tais são as vantagens que traz às aplicações Web, em termos de funcionalidades em tempo real. Uma biblioteca que atualmente abstrai a complexidade e ajuda na criação de aplicações que utilizem WebSockets é ajWebSocket2. Esta bibliotecaopen-

source foi utilizada para simplificar a criação dos componentes do servidor, permitindo que através da inclusão desta se obtivesse uma simples API através do qual os pedidos e as sessões dos clientes chegassem ao servidor. Com esta biblioteca problemas como a limitação do acesso a aplicações disponíveis em dados domínios ficam resolvidos. Uma vasta lista de configurações fica acessível para facilmente configurar a forma como o acesso por WebSockets ao servidor deve ser feito. Mas o projeto onde esta biblioteca Java se insere tem também uma pequena biblioteca em Javascript para facilitar a integração com o componente do servidor. Parte deste código foi também utilizado na aplicação Web para simplificar a criação do canal de comunicação.

A inclusão da biblioteca Javascript permite que se adicionem funções para serem chamadas na resposta de um dado pedido, e abstrai as diferenças entrebrowsers nas funcionalidades dos WebSockets.

4.1.3 HTTP - Long Polling

Para ser possível suportar os browsers mais antigos, foi implementada a comunicação baseada em HTTP, utilizando um mecanismo de Long Polling para a transmissão de pedidos iniciados pelo servidor para o cliente. A arquitetura deste componente foi baseada no módulo de WebSockets, no sentido em que os mesmos campos dos objetos JSON são utilizados para o mapeamento de pedidos e respostas. No entanto a lógica do processa- mento de pedidos, as diferenças entre cadabrowser e o relacionamento entre cada pedido e as suas respostas foram construídos de raiz, ao contrário do módulo de WebSockets, que é baseado numa biblioteca.

Na aplicação Web, na camada de comunicação foram utilizados pedidos assíncronosXMLHttpRequest3para

suportar a comunicação nos dois sentidos.

No Gateway, a implementação foi baseada noGrizzly WebServer4por ser um componente leve e que permite

a recepção de pedidos HTTP sem um grandeoverhead associado a cada pedido, por possibilitar a não utilização

2http://jwebsocket.org/

3O componenteXMLHttpRequest foi especificado pelo W3C para ser implementado nativamente pelos browsers de forma a que as

aplicações Web possam fazer pedidos assíncronos ao servidor. Apesar do nome conterXML por motivos de retrocompatibilidade, este componente suporta o transporte de qualquer tipo de dados textuais através de HTTP ou Hypertext Transfer Protocol Secure (HTTPS). -http://www.w3.org/TR/XMLHttpRequest/

de sessões. Desta forma os pedidos podem ser tratados dentro do contexto de uma sessão apenas quando chegam à aplicação.

Inerente ao Long Polling foi implementado o canal de notificações, que é criado a partir de um pedido que o cliente envia para o servidor, e que este guarda sem responder até ter algo para enviar para o cliente.

Para cada pedido que tenha de sair da aplicação Web, é criado um novo pedido HTTP com o conteúdo do comando a enviar.

Na forma de funcionamento do SIP, cada pedido pode ter várias respostas e isto não é mapeável para um simples pedido-resposta HTTP, dado este protocolo ser baseado numa resposta por pedido. No entanto, dada a ineficiência associada ao mecanismo de Long Polling quando comparada com WebSockets[55], a implementação foi feita na tentativa de utilizar todos os pedidos possíveis para transportar dados relevantes para a aplicação. Um dos pontos onde é possível melhorar o mecanismo é no aproveitamento da resposta de um pedido normal, para transportar dados que seriam enviados pelo canal de notificações, diminuindo assim o número de vezes que o canal tem de ser re-estabelecido.

Em SIP a resposta provisória100 Trying é enviada sempre que o pedido INVITE chega a um ponto na rede capaz de processar SIP. Isto significa que se o cliente apenas recebesse dados do servidor através do canal de notificações, assim que enviasse um pedido INVITE, o canal de notificações seria disparado logo de seguida para enviar a resposta provisória.

No caso de envio, após um pedido genérico ser recebido pela camada de comunicação, este é transformado no objetoJSON e enviado através de um pedido HTTP. Quando chega ao servidor, este pedido é guardado durante breves instantes para aguardar por qualquer dado que tenha de ser enviado para o cliente.

Assim, desta forma foi criado tanto no cliente como no servidor uma forma abstrata de comunicação, em que sempre que o cliente deseja enviar algo para o servidor cria um novo pedido HTTP. Para receber dados do servidor, a aplicação está preparada para os receber a partir de qualquer uma das respostas, ou de um pedido feito para o envio de pacotes, ou do canal de notificações. Para o servidor, os dados podem ser recebidos através de novos pedidos enviados pelo cliente, mas quando tem alguma informação para entregar, verifica primeiro se existe algum pedido pendente para utilizar, e em caso negativo utiliza o canal de notificações.

Uma possibilidade de implementação com um menor número de ligações TCP poderia passar pela utilização de mecanismos de respostas incrementais, em que o servidor não envia uma resposta definitiva durante algum tempo, mas vai escrevendo na ligação criada os dados que tem para enviar para a aplicação. No entanto, este mecanismo de processamento de respostas parciais em pedidos Ajax está ainda a ser definido e apenas as versões mais recentes dosbrowsers têm suporte para este mecanismo. A título de exemplo, o IE suporta este mecanismo a partir da versão 10, sendo portanto a mesma versão a partir da qual suporta WebSockets. Perdia-se assim a grande vantagem de utilizar HTTP Long Poling, para suportar osbrowsers mais antigos com o suporte para pedidos HTTP simples.

4.2 Aplicação Web

Após a definição das formas de comunicação entre a aplicação Web e o servidor, foi definida a estrutura da aplicação baseada em HTML5 e Javascript de forma a respeitar a arquitetura referida no capítulo anterior. A implementação foi dividida em dois grandes componentes para permitir a reutilização de uma grande parte do código na construção de uma interface para diferentesbrowsers e dispositivos.

O primeiro componente implementado foi a SDK que trata da lógica de negócio de cada uma das funcionali- dades e da comunicação com o servidor, abstraindo toda a complexidade da nova tecnologia WebRTC e também as diferenças entre cadabrowser. O segundo componente a ser criado foi a interface gráfica baseada em HTML5 e que foi implementada seguindo um padrão MVC, utilizando a SDK na disponibilização de cada uma das fun- cionalidades.

As primeiras páginas Web eram baseadas em páginas estáticas que eram obtidas do servidor prontas a mostrar, e a navegação era feita através do acesso a um novo link, que traria outra página pronta do servi- dor. Hoje em dia as aplicações Web seguem outra metodologia de desenvolvimento, carregando a página base em HTML, e utilizando pedidos Ajax para obter os dados a mostrar. As aplicações Web deste tipo têm a lógica da aplicação no cliente, dependendo assim muito mais dosbrowsers e menos dos servidores.

Figura 4.1: Aplicação após registo

Esta alteração de paradigmas trouxe a necessidade de se criarem ferramentas tanto para facilitar a imple- mentação de aplicações em Javascript, como para que se consiga obter código modular e facilmente e testável. Uma das maiores preocupações a ter nestas aplicações é a disponibilidade do código fonte, dada a natureza do código Javascript, por não ser compilado. Assim, uma das primeiras preocupações na elaboração da aplicação foi a análise de ferramentas para ofuscar e minimizar o código fonte.

Para simplificar a implementação da aplicação, foi utilizada a ferramenta Yeoman5que através da instalação

5Yeoman é um conjunto de ferramentas para ajudar na construção rápida de aplicações Web. Existe por exemplo a possibilidade da

disponibilização de um servidor Web muito leve baseado em Noje.js, que permite testes locais e instantâneos, através da execução automática descripts. O programador tem à sua disponibilidade inúmeros plugins que pode instalar, para depois construir a lista de tarefas a fazer quando se verifica um dado evento, diminuindo assim todo um leque de ações repetitivas associadas ao desenvolvimento Web. -http://yeoman.io/

de algunsplugins, possibilitou que a aplicação fosse construída em diferentes módulos, sendo sempre o ficheiro final produzido pela junção de todos os elementos da aplicação.

Durante o desenvolvimento, esta ferramenta permitiu atualizar a página Web automaticamente após ter con- struído todo o código, sempre que se verificassem alterações num dos ficheiros. Para colocar o código em produção a utilidade deste componente foi ainda mais evidente, na medida em que além de juntar os vários ficheiros de CSS, Javascript e HTML, cumpria tarefas como a remoção de todos os comentários e linhas de logs, a compressão e ofuscação do código, a cópia das imagens e outros recursos para uma mesma pasta e o renomeamento dos ficheiros com valores aleatórios para evitar que osbrowsers façam cache no próximo acesso.

4.2.1 SDK

Para definir a SDK, começou-se pela separação de cada uma das funcionalidades globais que se pretendia implementar, para se conseguir sintetizar quais os métodos que estariam disponíveis para cada uma delas. Os métodos para algumas das funcionalidades estão apresentadas no Anexo A. O código representa aquilo que fica disponível para a UI poder utilizar, sendo que o código interno da lógica de negócio não fica acessível externamente.

O resultado final da SDK é um ficheiro que apenas disponibiliza o construtor para um objecto, que quando chamado com a configuração inicial como parâmetro, retorna uma instância desta com a configuração recebida. Este objecto retornado inclui os vários módulos e os métodos respectivos e permite a interação da UI específica do dispositivo com o servidor, usando a lógica da funcionalidade em questão.

A arquitetura apresentada na Figura 3.9 foi respeitada nesta implementação, e por isso para além dos módulos dependentes de cada funcionalidade, são inicializados também a camada de comunicação, o gestor dos eventos e um módulo de configuração. Estes três estão sempre presentes na instância devolvida, pois são globais a todos os outros módulos e estes utilizam-nos no seu interior.

A lógica de cada módulo está definida em objetos denominados deManagers, que contém toda a lógica e mapeamentos necessários para cumprir os requisitos de cada funcionalidade. Todos estes têm em comum o métodohandleRequest(request) que é chamado pela camada de comunicação, quando um pedido é recebido do servidor. Assim, para uma integração com esta camada, após a criação da instância de cadaManager, estes são registados na camada de comunicação através do métodoregisterRequestHandler(), que guardará o objecto como um componente interessado em receber os pedidos que chegam do servidor. Esta forma de implementar o tratamento de pedidos através de uma distribuição sincronizada das chamadas a funções foi criada com base nodesign pattern Reactor[59].

Desta forma é possível que se adicionem e se removam funcionalidades retirando apenas o ficheiro respectivo à mesma, sem que seja necessário alterar o código da SDK. Isto é possível devido à automatização da construção do ficheiro final através da ferramenta Yeoman, que permite que toda a aplicação seja construída em vários ficheiros Javascript em diferentes pastas para uma melhor organização do projeto. No Anexo A é possível ver nos comentários que o código é proveniente de vários ficheiros diferentes (e.g. call.js, session.js, ...).

Na Listagem 4.5 é possível ver um exemplo de como se utiliza a SDK para iniciar uma sessão SIP num dado servidor, com os métodos que ficam disponíveis externamente. Como parâmetro para o construtor é passado um objeto com informações sobre o servidor destino, e após esta inicialização, é chamado o métodoconnect() seguido pelo registo no servidor com as credenciais do utilizador.

Os métodos são chamados com recurso à biblioteca Q6 que permite uma inversão do controlo através da

chamada assíncrona de código para os casos de sucesso ou falha da função chamada. Esta biblioteca permite uma apresentação mais limpa do código, com a garantia que o resultado será chamado assincronamente, sem a necessidade de mapeamento de funções para cada pedido. Cada método da API tornado público devolve para a UI umapromise para ser usada para tratar os casos de resposta do pedido feito. Desta forma é também garantido que a aplicação não é bloqueada pela espera síncrona do resultado de um dado pedido, e que o código da UI é sempre executado a partir do código da biblioteca, não permitindo assim que terceiros que utilizem esta SDK possam parar a execução do seu código e verificar o seu percurso até ali, descobrindo assim a estrutura do código.

server = { ”name”: ”WCAS-LAB”,

”serverHost”: ”wcas.wit-software.com”,

”serverPort”: ”8077”,

”proxyServerHost”: ””, ”proxyServerPort”: ””,

”iceServers”: [{ ”url”: ”stun:stun.ekiga.net:3478” }],

”serverDomain”: ”wcas.wit-software.com”

};

var wwc = new WWC(server);

wwc.session.connect().then(function () { wwc.session.register(username, password)

.then( // registered handling )

.then( // get addressbook addressBookSvc.getAddressBook ) .then( // start processing capabilities capabilitiesSvc.

processAddressBook(addressBookSvc.addressBook);)

.then( function (value) {

// login complete -> change UI to show logged in view

deferred.resolve(); })

.fail(function (params) {

// login failed -> show error messages in login view

deferred.reject(); });

}).fail(function (params) {

// failed to connect to server -> show error messages in login view

deferred.reject(); });

Documentos relacionados