Cenários de Migração de Serviços da Web: JAX-RPC para JAX-WS e JAXB
Esse tópico explica os cenários para migrar seus serviços da WebJava™ API for XML-based RPC (JAX-RPC) ou Java API for XML-Based Web Services (JAX-WS) e os serviços da WebJava Architecture for XML Binding (JAXB).
As mudanças no conjunto de ferramentas podem ser amplamente ocultadas do usuário por um ambiente de desenvolvimento, como as ferramentas do conjunto disponíveis com o WebSphere Application Server. Além disso, dependendo dos dados especificados no XML, alguns métodos que eram utilizados para o serviço JAX-RPC podem ser utilizados com pouca ou nenhuma alteração em um serviço JAX-WS. Existem também condições que exigem alterações no serviço JAX-WS.
Como os ambientes Java EE enfatizam a compatibilidade, a maioria dos servidores de aplicativos que oferecem suporte para as especificações JAX-WS e JAXB mais novas continua suportando a especificação JAX-RPC anterior. Uma consequência disso é que os serviços da Web existentes podem persistir o JAX-RPC enquanto novos serviços da Web forem desenvolvidos usando os modelos de programação JAX-WS e JAXB.
Entretanto, conforme o tempo passa e os aplicativos são revisados e regravados, poderá haver vezes em que a melhor estratégia é migrar um serviço da Web baseado no JAX-RPC para um serviço que seja baseado nos modelos de programação JAX-WS e JAXB. Isso pode resultar em fornecedores optando por fornecer aprimoramentos para qualidades de serviço que estejam disponíveis apenas nos novos modelos de programação. Por exemplo, o suporte ao SOAP 1.2 e ao SOAP MTOM (Message Transmission Optimization Mechanism) está disponível apenas nos modelos de programação JAX-WS 2.x e JAXB 2.x e não no JAX-RPC.
Comparação dos Modelos de Programação JAX-RPC para JAX-WS e JAXB
Se você estiver procurando por informações adicionais que descrevem as mudanças entre os modelos de programação JAX-RPC, JAX-WS e JAXB, consulte os vários tópicos sobre dicas e sugestões de serviços da Web publicados pela IBM developerWorks.
Modelos de Desenvolvimento
Os modelos de desenvolvimento
combinados de alto nível para JAX-RPC, JAX-WS e JAXB são mostrados na imagem a seguir:
Em um nível alto, os modelos são muito semelhantes. A única diferença é que o modelo JAX-RPC produz artefatos portáveis e não portáveis; os modelos JAX-WS e JAXB não produzem artefatos não portáveis.
- O arquivo Web Services Description Language (WSDL): um documento de acordo com a recomendação de WSDL como publicado pela organização de W3C.
- (Opcional) Arquivos de configuração:
- WSDL para ferramenta de geração de Java: as especificações descrevem os mapeamentos necessários, não o nome da ferramentas. Normalmente, a ferramenta para JAX-WS e JAXB é wsimport; e para JAX-RPC, wscompile e wsdeploy.
- Artefatos móveis: estes arquivos gerados pelo WSDL para ferramenta de geração de Java que possui mapeamentos bem definidos nas especificações de JAX-RPC ou JAX-WS e JAXB, o que for aplicável. Esses artefatos podem ser utilizados sem modificação entre as diferentes implementações de JAX-RPC ou JAX-WS e JAXB.
- Artefatos não móveis: estes arquivos gerados pelo WSDL para ferramenta de geração de Java que não possui mapeamentos bem definidos nas especificações de JAX-RPC ou JAX-WS e JAXB, o que for aplicável. Esses artefatos geralmente exigem modificação entre as diferentes implementações de JAX-RPC ou JAX-WS/JAXB.
- Código de implementação: este é o código necessário para satisfazer requisitos em particular para implementação.
- Informações de implementação: informações adicionais necessárias para executar o aplicativo em um ambiente em particular.
- Arquivo de archive web (WAR): no contexto da imagem SampleService, um arquivo WAR é um archive que contém todos os itens necessários para implementar um serviço da web em um ambiente em particular. Isso às vezes é chamado de arquivo WAR em cookie.
Os Ambientes de Desenvolvimento e Tempo de Execução
Um ambiente de desenvolvimento especializado simplifica a migração de serviços da Web ao automatizar a maioria das tarefas. Para o desenvolvimento de aplicativos baseados no WebSphere, incluindo serviços da Web, é possível usar as ferramentas do conjunto fornecidas com o WebSphere Application Server.
- IBM WebSphere Application Server V6.1, que inclui suporte para a especificação JAX-RPC.
- IBM WebSphere Application Server V6.1 Feature Pack for Web Services, que inclui suporte para as especificações JAX-WS e JAXB.
Exemplos
Os seguintes exemplos mostram algumas das mudanças de código que podem ser necessárias para migrar os serviços da Web JAX-RPC para os serviços da Web JAX-WS e JAXB. Especificamente, há uma ênfase sobre as mudanças no código de implementação que você deverá anotar, no lado do cliente e do servidor. Se nenhuma função será introduzida, as mudanças necessárias para mover do JAX-RPC para JAX-WS e JAXB poderão ser poucas.
O primeiro exemplo é um serviço da Web baseado no JAX-RPC de amostra que foi criado a partir de um arquivo WSDL (desenvolvimento descendente); o mesmo arquivo WSDL é usado para gerar o serviço baseado no JAX-WS e no JAXB. O arquivo WSDL descreve o serviço da Web, SampleService, com essas operações descritas pela seguinte imagem:
- xsd:int calcShippingCost(xsd:int, xsd:int)
- xsd:string getAccountNumber(xsd:string)
- xsd:dateTime calculateShippingDate(xsd:dateTime)
- xsd:string ckAvailability(xsd:int) creates invalidDateFault
- Person findSalesRep(xsd:string)
<complexType name="Person">
<sequence>
<element name="name" type="xsd:string"/>
<element name="age" type="xsd:int"/>
<element name="location" type="impl:Address/>
</sequence>
</complexType>
O endereço é definido por: <complexType name="Address">
<sequence>
<element name="street" type="xsd:string"/>
<element name="city" type="xsd:string"/>
<element name ="state" type="xsd:string"/>
<element name="zip" type="xsd:int"/>
</sequence>
</complexType>
A imagem a seguir mostra também que a operação,
ckAvailability(xsd:int), produz uma exceção invalidDateFault. 
Revise o código de serviço criado pela ferramenta. As seguintes informações incluem examinar o que é criado para um tempo de execução JAX-RPC e também para um tempo de execução JAX-WS e JAXB.
Para JAX-RPC, a ferramenta aceita o arquivo WSDL como entrada e, entre outros arquivos, gera as interfaces SampleService.java e SampleServiceImpl.java. A interface SampleService.java define uma interface e o código gerado pode ser revisto no seguinte bloco de código. A interface SampleServiceSoapBindingImpl.java fornece o esboço de uma implementação, e você normalmente modifica para incluir sua própria lógica.
/**
* SampleService.java
*
* Este arquivo foi gerado automaticamente a partir do WSDL
* pelo emissor WSDL2Java de serviços da web da IBM.
* cf20633.22 v82906122346
*/
package simple;
public interface SampleService extends java.rmi.Remote {
public java.lang.Integer calcShippingCost(java.lang.Integer shippingWt,
java.lang.Integer shippingZone) throws java.rmi.RemoteException;
public java.lang.String getAccountNumber(java.lang.String accountName)
throws java.rmi.RemoteException;
public java.lang.String[] ckAvailability(int[] itemNumbers)
throws java.rmi.RemoteException, simple.InvalidDateFault;
public java.util.Calendar calculateShippingDate(
java.util.Calendar requestedDate)
throws java.rmi.RemoteException;
public simple.Person findSalesRep(java.lang.String saleRepName)
throws java.rmi.RemoteException; }
package simple;
import java.util.List;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
/**
* Essa classe foi gerada pelo JAX-WS SI.
* JAX-WS RI IBM 2.0_03-06/12/2007 07:44 PM(Raja)-fcs * Versão de origem gerada: 2.0
*
*/
@WebService(name = "SampleService", targetNamespace = "http://simple") public interface SampleService {
/**
*
* @param shippingWt
* @param shippingZone
* @return
* returns java.lang.Integer
*/
@WebMethod
@WebResult(name = "shippingCost", targetNamespace = "")
@RequestWrapper(localName = "calcShippingCost", targetNamespace = "http://simple", className = "simple.CalcShippingCost")
@ResponseWrapper(localName = "calcShippingCostResponse", targetNamespace = "http://simple",
className = "simple.CalcShippingCostResponse")
public Integer calcShippingCost(
@WebParam(name = "shippingWt", targetNamespace = "")
Integer shippingWt,
@WebParam(name = "shippingZone", targetNamespace = "")
Integer shippingZone);
/**
*
*
@param accountName
* @return
* returns java.lang.String
*/
@WebMethod
@WebResult(name = "accountNumber", targetNamespace = "")
@RequestWrapper(localName = "getAccountNumber", targetNamespace = "http://simple",
className = "simple.GetAccountNumber")
@ResponseWrapper(localName = "getAccountNumberResponse", targetNamespace = "http://simple",
className = "simple.GetAccountNumberResponse")
public String getAccountNumber(
@WebParam(name = "accountName", targetNamespace = "")
String accountName);
/**
*
* @param requestedDate
* @return
* returns javax.xml.datatype.XMLGregorianCalendar
*/
@WebMethod
@WebResult(name = "actualDate", targetNamespace = "")
@RequestWrapper(localName = "calculateShippingDate", targetNamespace = "http://simple",
className = "simple.CalculateShippingDate")
@ResponseWrapper(localName = "calculateShippingDateResponse", targetNamespace = "http://simple",
className = "simple.CalculateShippingDateResponse")
public XMLGregorianCalendar calculateShippingDate(
@WebParam(name = "requestedDate", targetNamespace = "")
XMLGregorianCalendar requestedDate);
/**
*
* @param itemNumbers
* @return
* returns java.util.List<java.lang.String>
* @throws InvalidDateFault_Exception
*/
@WebMethod
@WebResult(name = "itemAvailability", targetNamespace = "")
@RequestWrapper(localName = "ckAvailability", targetNamespace = "http://simple", className = "simple.CkAvailability")
@ResponseWrapper(localName = "ckAvailabilityResponse", targetNamespace = "http://simple",
className = "simple.CkAvailabilityResponse")
public List<String> ckAvailability(
@WebParam(name = "itemNumbers", targetNamespace = "")
List<Integer> itemNumbers)
throws InvalidDateFault_Exception
;
/**
*
* @param saleRepName
* @return
* returns simple.Person
*/
@WebMethod
@WebResult(name = "salesRepInfo", targetNamespace = "")
@RequestWrapper(localName = "findSalesRep", targetNamespace = "http://simple", className = "simple.FindSalesRep")
@ResponseWrapper(localName = "findSalesRepResponse", targetNamespace = "http://simple",
className = "simple.FindSalesRepResponse")
public Person findSalesRep(
@WebParam(name = "saleRepName", targetNamespace = "")
String saleRepName);
}
Comparando os Exemplos de Código
@WebMethod
@WebResult(name = "shippingCost", targetNamespace = "")
@RequestWrapper(localName = "calcShippingCost", targetNamespace = "http://simple", className = "simple.CalcShippingCost")
@ResponseWrapper(localName = "calcShippingCostResponse", targetNamespace = "http://simple",
className = "simple.CalcShippingCostResponse")
public Integer calcShippingCost(
@WebParam(name = "shippingWt", targetNamespace = "")
Integer shippingWt,
@WebParam(name = "shippingZone", targetNamespace = "")
Integer shippingZone);
Mas, se você descartar as anotações, as seguintes
linhas de código serão: public Integer calcShippingCost(
Integer shippingWt,
Integer shippingZone);
Essas linhas são quase idênticas à que foi gerada para JAX-RPC. A única diferença é que o código JAX-RPC pode produzir o erro java.rmi.RemoteException
conforme a seguir:public java.lang.Integer calcShippingCost(java.lang.Integer shippingWt,
java.lang.Integer shippingZone) throws java.rmi.RemoteException;
Seguindo essa lógica, três dos métodos têm essencialmente as mesmas
assinaturas:public Integer calcShippingCost(Integer shippingWt, Integer shippingZone)
public String getAccountNumber(String accountName)
public Person findSalesRep(String saleRepName)
Isso significa que a migração de JAX-RPC para JAX-WS não afeta diretamente
esses métodos e o código de implementação original que está sendo executado com êxito no
ambiente baseado em JAX-RPC provavelmente pode ser utilizado sem modificação desses
métodos.Entretanto, dois dos métodos na verdade têm assinaturas diferentes:
public java.util.Calendar calculateShippingDate(
java.util.Calendar requestedDate)
public java.lang.String[] ckAvailability(int[] itemNumbers)
throws java.rmi.RemoteException,
simple.InvalidDateFault
JAX-WS e JAXB: public XMLGregorianCalendar calculateShippingDate(
XMLGregorianCalendar requestedDate)
public List<String> ckAvailability(List<Integer> itemNumbers)
throws InvalidDateFault_Exception
- SampleServiceSoapBindingImpl.java
- SampleServiceImpl.java
- Diferenças de mapeamento de nomes XML para nomes Java
Para o método calculateShippingDate, os parâmetros de entrada e de retorno foram alterados do tipo java.util.Calendar para o tipo XMLGregorianCalendar. Ou seja, como o WSDL especificou esses parâmetros como sendo do tipo xsd:dateTime, o JAX-RPC mapeia esse tipo de dados para java.util.Calendar, enquanto JAX-WS e JAXB o mapeiam para XMLGregorianCalendar.
- Mapeamentos diferentes de matrizes de XML para Java
Para o método ckAvailability, a alteração se deve aos mapeamentos de dados para matrizes XML.
O JAX-RPC mapeia os seguintes elementos WSDL:
Os elementos anteriores são mapeados para a seguinte origem Java:<element maxOccurs="unbounded" name="itemNumbers" type="xsd:int"/> <element maxOccurs="unbounded" name="itemAvailability" type="xsd:string"/>
JAX-WS e JAXB mapeiam os seguintes elementos WSDL:int[] itemNumbers java.lang.String[] itemAvailability
List<Integer> itemNumbers List<String> ckAvailability
- Mapeamentos diferentes de exceçõesPara o método ckAvailability, o código JAX-RPC gerou o seguinte erro:
O código JAX-WS gera o seguinte erro:simple.InvalidDateFault
Exceto para os nomes, os construtores dessas exceções são diferentes. Portanto, o código JAX-RPC real que produz o erro poderá ser exibido como:InvalidDateFault_Exception
Para JAX-WS, o código utiliza um comando semelhante para o seguinte exemplo::throw new InvalidDateFault("this is an InvalidDateFault");
Nos casos que utilizam exceções, o código que o utiliza precisa ser alterado.throw new InvalidDateFault_Exception( "this is an InvalidDateFault_Exception", new InvalidDateFault());
Migrando o Código
Agora que as diferenças entre código foram explicadas, revise o código original para os métodos que precisam de mudança e como alterar esse código para que ele funcione em um ambiente JAX-WS e JAXB.
public java.util.Calendar calculateShippingDate(
java.util.Calendar requestedDate) throws java.rmi.RemoteException {
// Definir a data como a que foi enviada para nós e incluir 7 dias.
requestedDate.add(java.util.Calendar.DAY_OF_MONTH, 7);
// . . .
return requestedDate;
}
Você pode escrever o novo código para usar diretamente os novos tipos
como nos exemplos a seguir:public XMLGregorianCalendar calculateShippingDate(
XMLGregorianCalendar requestedDate) {
try {
// Criar um factory de tipo de dados.
DatatypeFactory df = DatatypeFactory.newInstance();
// Definir a data como a que foi enviada para nós e incluir 7 dias.
Duration duration = df.newDuration("P7D");
requestedDate.add(duration);
} catch (DatatypeConfigurationException e) {
// Bloco de captura auto-gerado TODO
e.printStackTrace();
}
// . . .
return requestedDate;
}
public java.lang.String[] ckAvailability(int[] itemNumbers)
{
String[] myString = new String[itemNumbers.length];
for (int j = 0; j < myString.length; j++) {
. . .
if ( ... )
throw new simple.InvalidDateFault(“InvalidDateFault”);
. . .
if ( . . .)
myString[j] = “available: “ + jitemNumbers[j] ;
else
myString[j] = “not available: “ + jitemNumbers[j];
}
return myString;
}
O código anterior aceita um int[] como entrada e retorna um String[]. Para a versão de JAX-WS e JAXB, estes são os elementos List<Integer>
e List<String>, respectivamente. Processando essas matrizes e descartando o código de Exceção, o
código JAX-RPC é semelhante ao seguinte:public java.lang.String[] ckAvailability(int[] itemNumbers)
{
String[] myString = new String[itemNumbers.length];
for (int j = 0; j < jitemNumbers.length; j++) {
. . .
if ( . . .)
myString[j] = “available: “ + itemNumbers.get(j);
else
myString[j] = “not available: “ + itemNumbers.get(j);
}
return myString;
}
O seguinte código equivalente JAX-WS e JAXB existe utilizando Listas em vez
de matrizes:List <String> ckAvailability(List <Integer> itemNumbers)
{
ArrayList<String> retList = new ArrayList<String>();
for (int count = 0; count < itemNumbers.size(); count++) {
. . .
if ( . . .)
retList.add(“available: “ + itemNumbers.get(j));
else
retList.add(“not available: “ + itemNumbers.get(j));
}
return retList;
}
As diferenças nos mapeamentos de exceções de XML para Java força o uso do
código JAX-WS. InvalidDateFault_Exception em vez de InvalidDateFault. throw new InvalidDateFault_Exception( "test InvalidDateFault_Exception", new InvalidDateFault());
A
implementação JAX-WS e JAXB final do método poderá ser semelhante ao seguinte código:List <String> ckAvailability(List <Integer> itemNumbers)
{
ArrayList<String> retList = new ArrayList<String>();
for (int count = 0; count < itemNumbers.size(); count++) {
if ( . . . ) {
throw new InvalidDateFault_Exception(
"test InvalidDateFault_Exception",
new InvalidDateFault());
}
. . .
if ( . . .)
retList.add(“available: “ + itemNumbers.get(count));
else
retList.add(“not available: “ + itemNumbers.get(count));
}
return retList;
}
Há várias maneiras de migrar o código dentre as quais escolher. Com prática e um ambiente de desenvolvimento efetivo, a migração de JAX-RPC para JAX-WS
pode ser simples e direta.