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.

As informações a seguir incluem problemas que você poderá ter ao migrar de JAX-RPC para JAX-WS e JAXB.
Nota: Quando os termos migrar, migrando e migração são utilizados neste tópico, a menos que haja alguma instrução que indique o contrário, a mudança de um ambiente JAX-RPC para um JAX-WS e JAXB está sendo descrita.

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: Comparar Modelos de Desenvolvimento

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.

A imagem exibe os seguintes componentes:
  • 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.

O código de amostra a seguir neste tópico foi testado no seguinte ambiente de tempo de execução:
  • 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:

Conforme mostrado na imagem, as cinco operações oferecidas são:
  • 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)
Suponha também que Person seja definido pelo seguinte fragmento de esquema no arquivo WSDL:
<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. Serviço de Amostra

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.

Versão JAX-RPC do SampleService.java:
/**  
* 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; }   
Para JAX-WS e JAXB, a ferramenta aceita o arquivo WSDL como entrada, e como no caso de JAX-RPC, gera as interfaces SampleService.java e SampleServiceImpl.java. Como com o JAX-RPC, a interface SampleService.java também define uma interface conforme mostrado no bloco de código a seguir. A interface SampleServiceImpl.java fornece o esboço de uma implementação, e você normalmente modifica para incluir sua própria lógica.
Nota: O código foi anotado pela ferramenta.
Versão JAX-WS e JAXB da interface SampleService.java:
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

À primeira vista, pode parecer que há pouca semelhança entre as interfaces. Se você desconsiderar as informações adicionais incluídas pelas anotações para JAX-WS e JAXB, as amostras de código serão semelhantes. Por exemplo, o método calcShippingCost, na versão JAX-WS e JAXB, existem as seguintes linhas 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:

Para JAX-RPC:
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 
Nota: Talvez você ache mais fácil comparar os arquivos de implementação do esboço, já que as anotações não estão presentes em SampleServiceImpl.java.:
  • SampleServiceSoapBindingImpl.java
  • SampleServiceImpl.java
As diferenças nas assinaturas se devem aos seguintes motivos:
  • 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:
    <element maxOccurs="unbounded" name="itemNumbers" type="xsd:int"/>
    <element maxOccurs="unbounded" name="itemAvailability" type="xsd:string"/>
    Os elementos anteriores são mapeados para a seguinte origem Java:
    int[] itemNumbers
    java.lang.String[] itemAvailability
    JAX-WS e JAXB mapeiam os seguintes elementos WSDL:
    List<Integer> itemNumbers 
    List<String> ckAvailability
  • Mapeamentos diferentes de exceções
    Para o método ckAvailability, o código JAX-RPC gerou o seguinte erro:
    simple.InvalidDateFault
    O código JAX-WS gera o seguinte erro:
    InvalidDateFault_Exception
    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:
    throw new InvalidDateFault("this is an InvalidDateFault");
    Para JAX-WS, o código utiliza um comando semelhante para o seguinte exemplo::
    throw new InvalidDateFault_Exception( "this is an InvalidDateFault_Exception", new InvalidDateFault()); 
    Nos casos que utilizam exceções, o código que o utiliza precisa ser alterado.

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.

Suponha que o código de implementação original (JAX-RPC) seja semelhante ao seguinte:
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;
}
Ao migrar o código para o método ckAvailability, foram necessárias alterações por causa da maneira com que as matrizes e exceções são mapeadas do XML ser diferente entre JAX-RPC e JAX-WS. Suponha que o código de serviço da Web JAX-RPC original seja semelhante ao seguinte exemplo:
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.
Isso significa que você deve substituir throw new simple.InvalidDateFault(“InvalidDateFault”); por algum outro código. Por isso, a seguinte linha é utilizada para o novo código:
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.

Ícone que indica o tipo de tópico Tópico de Referência



Ícone de registro de data e hora Última atualização: last_date
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=rwbs_migjaxrpc2jaxws
Nome do arquivo: rwbs_migjaxrpc2jaxws.html