====== Integração entre Sistemas ======
Devido à alta necessidade de integração entre os sistemas institucionais, em certas ocasiões é preciso que um sistema realize operações pertencentes a outros sistemas. Um exemplo é o cancelamento da matrícula de alunos no SIGAA, que chama o cancelamento de bolsas no SIPAC para que, ao cancelar o aluno, a sua bolsa também seja cancelada. Para que um sistema possa ter suas operações realizadas por outro, é necessário que essas operações sejam expostas como serviços remotos.
Este documento trata da forma como a integração entre sistemas deve ser feita, mostrando como expor serviços em um sistema, como acessar serviços remotos de outro sistema e todas as padronizações envolvidas.
===== Tecnologias utilizadas =====
A integração entre os sistemas deve ser realizada através da utilização de Web Services SOAP com o JAX-WS e o Apache CXF.
===== Implementação =====
A implementação de um serviço remoto consiste de três elementos: as interfaces remotas, as implementações locais e os data transfer objects. Esses elementos serão descritos nas seções a seguir.
==== Interfaces remotas ====
As interfaces remotas são interfaces que contém as assinaturas dos métodos do serviço remoto. As interfaces remotas devem ficar no projeto ''Arq_UFRN'', source folder ''integracao'', pacote ''br.ufrn.integracao.interfaces''. As interfaces devem ter o sufixo ''RemoteService''.
==== Implementações locais ====
A implementação do serviço remoto deve ficar no projeto do qual o serviço faz parte e implementar a interface remota correspondente ao serviço. As implementações devem ser stateless (ou seja, não devem possuir atributos, apenas métodos) e devem ser um bean do spring anotado com @Component ou declarado no remote-services.xml de cada aplicação, seguindo a padronização do Spring para declaração de beans. O escopo dos beans deve ser o padrão, ou seja, singleton (não colocar o ''@Scope'' ou colocar ''@Scope("singleton")'', no caso de anotações; ou nao declarar o scope="..." ou usar scope="singleton", no caso de XML).
==== Data Transfer Objects (DTOs) ====
Os Data Transfer Objects são classes que possuem apenas atributos e getters e setters. Têm como função realizar a transferência de dados entre um sistema e outro, dai o nome //Data Transfer//. Os métodos de um serviço remoto normalmente recebem DTOs como parâmetros. Os DTOs devem ser colocados no projeto ''ServicosIntegrados'', source folder ''integracao'', pacote ''br.ufrn.integracao.dto''. Além disso, as classes devem ter o sufixo ''Dto'', devem implementar ''Serializable'' e ter o seu ''serialVersionUID'' declarado.
Os DTOs só podem conter tipos de dados que possam ser representados por XML. Isso exclui, por exemplo, a coleção Map e todas as suas implementações, InetAddress e outros tipos binários, a não ser arrays de bytes, etc.
===== Como expor serviços =====
No ''remote-services.xml'' do sistema que irá expor o serviço, deve-se declarar um bean utilizando a tag '''' e cujo nome deve descrever o serviço e ter o sufixo ''Exporter'' (Ex: integracaoBolsasExporter). Deve-se ainda declarar as propriedades ''implementor'' e ''address'', com a primeira fazendo uma referência ao bean que contém a implementação do serviço (utilizando o nome do bean precedido de um #) e o segundo contendo o endereço que será utilizado para acessar o serviço.
===== Como acessar serviços remotos =====
Para acessar serviços remotos deve-se criar um bean no remote-services.xml utilizando a tag '''', com um id que descreve o serviço que será chamado e o sufixo ''Invoker''. Além disso deve-se declarar as propriedades ''address'' e ''serviceClass'', que deverá conter a URL para o serviço remoto e o nome completo da interface remota. A URL do serviço remoto deve começar com um parâmetro que indica qual o sistema que será chamado. Os possíveis valores do parâmetro estão definidos no arquivo de configuração ''remotehosts.properties''.
Para chamar o serviço remoto deve-se considerar três casos: quanto deseja-se chamar o serviço em uma action do Struts, em um managed bean do JSF ou em um processador. Caso o cliente seja uma action do Struts, deve-se utilizar o método getBean(), definido em AbstractAction.
public class ExemploIntegracaoAction extends AbstractAction {
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest req, HttpServletResponse res) throws Exception {
IntegracaoBolsasRemoteService bolsasService = getBean(req, "integracaoBolsasInvoker");
bolsasService.metodoRemoto();
}
}
Caso o cliente seja um managed bean do JSF, deve-se criar um atributo no managed bean do tipo da interface remota e utilizar a anotação @Resource, para que o bean seja injetado no managed bean.
@Component @Scope("request")
public class ExemploIntegracaoMBean {
@Resource(name="integracaoBolsasInvoker")
private IntegracaoBolsasRemoteService bolsasService;
public String exemploMetodo() {
bolsasService.metodoRemoto();
}
}
Caso o cliente seja um Processador, deve-se usar o método getBean(), definido em AbstractProcessador.
public class ProcessadorExemploIntegracao extends AbstractProcessador {
public Object execute(Movimento mov) throws NegocioException, ArqException, RemoteException {
IntegracaoBolsasRemoteService bolsasService = getBean("integracaoBolsasInvoker", mov);
bolsasService.metodoRemoto();
}
...
}
===== Segurança =====
Para implementar segurança na chamada aos web services, deve-se adicionar interceptors tanto nos endpoints quanto nos clients. O interceptor ''br.ufrn.integracao.seguranca.WebServiceTokenProducer'', antes de realizar a chamada HTTP para acessar o serviço remoto, gera um [[desenvolvimento:especificacoes:arquitetura:servicos:autenticacao_por_token|token de autenticação]] utilizando como base para a criação da chave o nome do serviço, o sistema de origem, a url do serviço e o usuário que está fazendo a solicitação.
Ao receber a requisição do serviço, o interceptor ''br.ufrn.integracao.seguranca.WebServiceTokenProducer'' verifica se o token de autenticação é válido. Se for, executa o serviço; se não for, significa que a chamada ao serviço foi feita de forma indevida, então ela responde com um erro HTTP 403 (forbidden). O cliente do serviço, ao receber o erro 403, dispara uma exceção TokenNaoValidadoException, que é capturada pelo ExceptionHandler da arquitetura e exibe uma mensagem amigável para o usuário.
Para declarar o interceptor no cliente deve-se usar a seguinte sintaxe:
No endpoint, usa-se:
Serviços utilizados em sistemas desktop não necessitam da utilização do token de autenticação.