.NET

18 set, 2009

Interoperabilidade na prática – Parte 01

Publicidade

O desenvolvimento de software corporativo de hoje tem que suportar a
interoperabilidade de serviços entre diversas plataformas. Veremos aqui como podemos fazer serviços/aplicações escritas em Java com
JEE 5 no Jboss 5.1 conversar com uma aplicação C# com .net Framework 3.5.

Vou realizar esta conversa
usando Webservice. Tanto a solução do lado do Java como a solução do
lado do .Net precisam implementar WS-I Basic Profile 1.1.
Quando criamos um Webservice com C# no .net Framework 3.5, ele já
implementa WS-I Basic profile 1.1. O mesmo acontece ao utilizarmos do
lado do Java o Jax-WS 2.x. Como vou rodar a solução Java no JBoss AS 5.01GA, vamos utilizar o JBoss WS.

Interoperabilidade de Webservices

Na prática, webservices não são 100% interoperáveis. Ainda existem
diversos gaps para realizar a comunicação, mas existe uma organização, a WS-I, que define
os padrões de comunicação para padronização de interoperabilidade de
webservices. No total existem mais de 50 especificações de Webservices
mantidas por 3 organizações(W3C, OASIS, WS-I). O WS-Basic profile 1.1
não cobre todas as especificações de webservices,mas cobre especificações como SOAP, WSDL, UDDI, XML e HTTP.

Visão geral dos padrões de Webservices

Requisitos para a solução

Como vamos realizar a conversação de uma aplicação Java EE5 com uma
aplicação .net fw 3.5, vamos ter algumas dependências. São elas:

  • Java JDK 6_16
  • JBoss AS 5.1.0.GA
  • eclipse 3.4.x + WTP
  • Visual Studio 2008
  • SoapUI

Vamos
começar com o seguinte cenário: uma aplicação Java EE5 rodando no
JBoss AS 5.1.0.GA com EJB3 sendo exposto como um Webservice através de
anotações. Esta aplicação vai ser consumida por uma aplicação Windows
Forms usando .net 3.5 com C#.

Em outro artigo vou mostrar o caminho inverso, uma aplicação Asp.net
Webservice escrita com C# também e sendo consumida por uma aplicação
Java com SOAP e com Jax-WS puro, sendo que a aplicação SOAP vai rodar
no ORACLE OC4J 10.1.3.4 e Jax-Ws vai ser uma aplicação Plain Java sem
Application Server.

Aplicação Java EE5 rodando no JBoss AS 5.1 com EJB3

Criei 3 projetos no eclipse utilizando o plugin do WTP. Os projetos e suas responsabilidades são os seguintes:

  • java-ee-test-web: projeto web empacotado em um war que contém uma página que faz lookup JNDI para acessar o EJB3 que é um serviço.
  • java-ee-test-ejb: projeto (módulo EJB3) que contém a implementação de um serviço do tipo stateless que é exposto como Webservice.
  • java-ee-test: projeto (módulo EAR) que serve para empacotar toda esta solução e realizar o deploy no JBoss AS 5.1.

Vamos à definição do EJB3 focando primeiramente na sua implementação. Em um
segundo momento vou mostrar as modificações neste EJB3 para expor o
mesmo como um Webservice.

Vamos à definição da interface DateService.java:

package com.blogspot.diegopacheco.eefive.ejb;

import java.rmi.Remote;

/**
* Interface de contrato do serviço de datas.
*
* @author Diego Pacheco
* @version 1.0
* @since 30/08/2009
*
*/
public interface DateService extends Remote {
public String getDate();
}

Este é um exemplo simples que costumo usar para simplificar a
compreensão do cenário completo da solução. Agora vamos à implementação
deste EJB 3.

Vamos à definição da implementação do Serviço DateServiceImpl.java:

package com.blogspot.diegopacheco.eefive.ejb;

import java.util.Date;

import javax.ejb.Remote;
import javax.ejb.Stateless;

/**
* Implementação do serviço de Datas através de um EJB3 Stateless.
*
* @author Diego Pacheco
* @version 1.0
* @since 30/08/2009
*
*/
@Stateless
@Remote(DateService.class)
public class DateServiceImpl implements DateService {

@Override
public String getDate() {
return new Date().toString();
}

}

Como o leitor pode ver, é bem simples a implementação, apenas estou
retornando a data de um objeto Date do Java. Estou definindo este EJB
como sendo do tipo Stateless, ou seja, sem estado, e estou dizendo que ele
implementa a interface remota DateService que também é o nosso
contrato.

Agora vamos voltar à aplicação web, onde vou criar um simples scriplet para consumir o nosso EJB3, confira o código:

index.jsp 

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"	pageEncoding="ISO-8859-1"%>
<%@ page import="javax.naming.*" %>
<%@ page import="com.blogspot.diegopacheco.eefive.ejb.*" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Teste</title>
</head>
<body>
<b>Ola Mundo EE 5 !</b> Data: <span style="color:green;">
<% try{ InitialContext ic = new InitialContext(); DateService ds = (DateService)ic.lookup("java-ee-test/DateServiceImpl/remote"); String dt = ds.getDate(); out.print(dt); }catch(Exception e){ out.print(e.getMessage()); } %>
</span>
</body>
</html>

Ao rodar fazer o deploy nesta aplicação no JBoss AS 5.1 e abrir a
aplicação no browser, você irá receber o seguinte resultado semelhante
ao que segue abaixo:

Aplicação Web Consumindo o EJB3

Agora vamos modificar a nossa
aplicação para expor o EJB 3 como Webservice, para isto vamos utilizar
anotações. Vamos adicionar duas anotações ao Contrato do Serviço
chamado DataService, são as anotações:

  • @WebService: Que indica que esta interface deve ser exposta como um Webservice.
  • @SOAPBinding(style = Style.DOCUMENT):
    Que indica o estilo de formando da mensagem que será enviada. Estou
    usando o estilo de documento, se você quiser saber sobre as diferenças
    de Documento para RPC confirma este link.

Vamos ver como fica a interface depois destas modificações.

package com.blogspot.diegopacheco.eefive.ejb;

import java.rmi.Remote;

import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

/**
* Interface de contrato do serviço de datas.
*
* @author Diego Pacheco
* @version 1.0
* @since 30/08/2009
*
*/
@WebService
@SOAPBinding(style = Style.DOCUMENT)
public interface DateService extends Remote {
public String getDate();
}

Ok, agora vamos ver a implementação do EJB chamada de
DateServiceImpl que também ira sofrer alterações. Vamos adicionar as
seguintes anotações:

  • @WebService(endpointInterface = “com.blogspot.diegopacheco.eefive.ejb.DateService”):
    Esta anotação de nível de classe indica que esta é a implementação do
    webservice de interface que está sendo passada por parâmetro.
  • @WebMethod: É uma interface em nível de métodos que indica que o método será exposto como uma operação do webservice.

Agora vou mostrar como fica a classe completa depois destas alterações:

package com.blogspot.diegopacheco.eefive.ejb;

import java.util.Date;

import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebService;

/**
* Implementação do serviço de Datas através de um EJB3 Stateless.
*
* @author Diego Pacheco
* @version 1.0
* @since 30/08/2009
*
*/
@Stateless
@Remote(DateService.class)
@WebService(endpointInterface = "com.blogspot.diegopacheco.eefive.ejb.DateService")
public class DateServiceImpl implements DateService {

@Override
@WebMethod
public String getDate() {
return new Date().toString();
}

}

Para testar a exposição do EJB3 como Webservice vou utilizar a
ferramenta SoapUI a fim de testar se o Webservice está no ar e
funciona. Antes de ir para a ferramenta é necessário fazer o deploy
desta solução no Jboss AS 5.1 e obter o WSDL que pode ser baixado neste
endereço:

http://localhost:8080/java-ee-test-java-ee-test-ejb/DateServiceImpl?wsdl

A partir deste ponto é possível criar um projeto no SoapUI
utilizando o WSDL salvo. Ao chamar o método getDate() você deve receber
um retorno como o que segue abaixo:

Consumo do WS no SoapUI 3

Aplicação .net

Abra o seu Visual Studio 2008 e crie um projeto do tipo
WindowsFormsApplication. Clique no menu Project e depois no sub-menu
Add Service Reference. Após isso, uma janela vai abrir para você
informar o endereço. Informe o endereço web do WSDL do Webservice que é o
seguinte:

http://localhost:8080/java-ee-test-java-ee-test-ejb/DateServiceImpl?wsdl

Selecione o service DataServiceImplService e Depois DateService, ao
mesmo tempo irão aparecer os métodos deste serviço na caixa de operações
ao lado, modifique o namespace para DateServiceProxy e clique em ok,
conforme a figura abaixo:

Adicionando Referência de Webservice no Visual Studio 2008

Com isso o Visual Studio ira criar
as referências necessárias para você consumir o WS na sua aplicação. Eu
criei um formulário bem simples, apenas para mostrar qual é o endpoint a
ser chamado, bem como um botão para o usuário consumir o WS e uma
caixa de texto multi-linhas para mostrar o resultado do consumo.

Formulário feito para consumir o WS feito escrito em Java

Agora vamos ao que mais importa, o
código .net para consumir este Webservice escrito em Java. Para isso
confira o código escrito em C# que segue abaixo:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ws_java_ee5_jboss_client
{
public partial class frmWsClient : Form
{
private DateServiceProxy.DateService ds;

public frmWsClient()
{
InitializeComponent();
txtEndpoint.Text = "http://127.0.0.1:8080/java-ee-test-java-ee-test-ejb/DateServiceImpl";

try
{
ds = new DateServiceProxy.DateServiceClient();
}
catch (Exception e)
{
txtWsResult.Text = e.Message;
}

}

private void btnConsumir_Click(object sender, EventArgs e)
{
try
{
txtWsResult.Text = ds.getDate();
}
catch (Exception ex)
{
txtWsResult.Text = ex.Message;
}
}

}
}

Explicando o código:

Criei uma
variável de classe chamada ‘ds’ do tipo DateServiceProxy.DateService e
no construtor do formulário eu instanciei este objeto da seguinte
maneira: new DateServiceProxy.DateServiceClient(); uma vez feito isso,
basta chamar o método getDate() que retorna um string.

Ao rodar a aplicação .net você receberá um retorno mais ou menos como o que segue abaixo:

Aplicação em Execução.

Se você quiser, pode baixar os fontes
das duas aplicações – a aplicação Java EE5 ou a aplicação C# no meu
repositório do Subversion nos seguintes endereços:

Aplicação Java:

Aplicação .net:

No próximo artigo vou mostrar o caminho inverso: irei criar um
Webservice com Aspx e consumir o mesmo com SOAP em uma aplicação
rodando no ORACLE OC4J/OAS e outra aplicação Jax-Ws plain Java rodando
no console.

Abraços e até a próxima.

PS: Quem estiver tendo problemas para rodar a solução no JBoss AS 5.1
precisa *endorsar* a biblioteca *jbossws-native-saaj.jar* que está
dentro da pasta $JBOSS_HOME\common\lib\jbossws-native-saaj.jar para a
pasta $JAVA_HOME\jre\lib\endorsed.