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 <jaxws:endpoint/>
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.
<jaxws:endpoint id="basePesquisaLaboratorioExporter" implementor="#basePesquisaLaboratorio" address="/BasePesquisaLaboratorioService"/>
Como acessar serviços remotos
Para acessar serviços remotos deve-se criar um bean no remote-services.xml utilizando a tag <jaxws:client />
, 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
.
<jaxws:client id="cadastroUsuarioInvoker" serviceClass="br.ufrn.integracao.interfaces.UsuarioRemoteService" address="${sigadminRemoteHost}/services/CadastroUsuarioService"/>
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 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:
<jaxws:client id="cadastroUsuarioInvoker" serviceClass="br.ufrn.integracao.interfaces.UsuarioRemoteService" address="${sigadminRemoteHost}/services/CadastroUsuarioService"> <jaxws:outInterceptors><ref bean="tokenProducer"/></jaxws:outInterceptors> </jaxws:client>
No endpoint, usa-se:
<jaxws:endpoint id="dadosBibliotecaExporter" implementor="#dadosBiblioteca" address="/DadosBibliotecaService"> <jaxws:inInterceptors><ref bean="tokenConsumer"/></jaxws:inInterceptors> </jaxws:endpoint>
Serviços utilizados em sistemas desktop não necessitam da utilização do token de autenticação.