Tabela de conteúdos

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.