====== 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.