Casos de ejemplo de migración de servicios web: JAX-RPC a JAX-WS y JAXB

Este tema explica casos de ejemplo para la migración de sus servicios web JAX-RPC (API Java™ para RPC basadas en XML) a JAX-WS (API Java para servicios web basados en XML) a JAXB (Arquitectura Java para enlace XML).

Los cambios en las herramientas se pueden ocultar en gran medida al usuario mediante un entorno de desarrollo como las herramientas de ensamblaje disponibles con WebSphere Application Server. Además, según los datos especificados en XML, algunos métodos que se utilizaban para el servicio JAX-RPC se pueden utilizar con muy pocos (o ningún) cambios en un servicio JAX-WS. También hay condiciones que precisan de cambios en el servicio JAX-WS.

Como los entornos Java EE hacen énfasis en la compatibilidad, la mayoría de los servidores de aplicaciones que ofrecen soporte para especificaciones JAX-WS y JAXB más nuevas siguen teniendo soporte para la especificación JAX-RPC anterior. Una consecuencia de esto es que es probable que los servicios web existentes permanezcan basados en JAX-RPC, mientras que los servicios web nuevos se desarrollen utilizando modelos de programación JAX-WS y JAXB.

No obstante, a medida que pasa el tiempo y las aplicaciones se revisan y reescriben, podría haber situaciones en las que la mejor estrategia es migrar un servicio web basado en JAX-RPC a uno basado en los modelos de programación JAX-WS y JAXB. Así, un proveedor podría optar por proporcionar mejoras sobre las cualidades del servicio que sólo estuviesen a disposición de los nuevos modelos de programación. Por ejemplo, el soporte para SOAP 1.2 y MTOM (SOAP Message Transmission Optimization Mechanism) sólo está disponible en los modelos de programación JAX-WS 2.x y JAXB 2.x, y no en JAX-RPC.

La información siguiente incluye problemas que puede tener en la migración de JAX-RPC a JAX-WS y JAXB.
Nota: Cuando en este tema se utilicen los términos migrar, migrando y migración, a menos que haya alguna sentencia que indique lo contrario, se describe el cambio de un entorno JAX-RPC a JAX-WS y JAXB.

Comparación de los modelos de programación JAX-RPC a JAX-WS y JAXB

Si busca información adicional que describa los cambios entre los modelos de programación JAX-RPC, JAX-WS y JAXB, IBM developerWorks ha publicado varios temas de sugerencias y consejos de servicios web.

Modelos de desarrollo

Los modelos de desarrollo combinados de alto nivel para JAX-RPC, JAX-WS y JAXB se muestran en la imagen siguiente: Comparar modelos de desarrollo

A un alto nivel, los modelos son muy parecidos. La única diferencia es que el modelo JAX-RPC produce artefactos portables y no portables; los modelos de programación JAX-WS y JAXB no producen artefactos no portables.

La imagen muestra los componentes siguientes:
  • Archivo Web Services Description Language (WSDL): Un documento que cumple la recomendación WSDL según publicación por la organización W3C.
  • (Opcional) Archivos de configuración
    • Herramienta de generación WSDL a Java: Las especificaciones describen las correlaciones necesarias, no el nombre de las herramientas. Por lo general, la herramienta para JAX-WS y JAXB es wsimport, y para JAX-RPC las herramientas wscompile y wsdeploy.
    • Artefactos portables: son archivos generados por la herramienta de generación WSDL a Java que tiene correlaciones bien definidas en la especificación JAX-RPC, o JAX-WS y JAXB, lo que sea aplicable. Estos artefactos se pueden utilizar sin modificación entre las distintas implementaciones de JAX-RPC, o JAX-WS y JAXB.
    • Artefactos no portables: son archivos generados por la herramienta de generación WSDL a Java que no tiene correlaciones bien definidas en la especificación JAX-RPC, o JAX-WS y JAXB, lo que sea aplicable. Estos artefactos suelen precisar de modificación entre las distintas implementaciones de JAX-RPC o JAX-WS/JAXB.
    • Código de implementación: es el código que necesita para cumplir requisitos concretos para implementación.
    • Información de despliegue: información adicional necesaria para ejecutar la aplicación en un entorno concreto.
    • Archivo WAR (Web Archive): en el contexto de la imagen SampleService, un archivo WAR es un archivo de archivado que contiene todos los elementos necesarios para desplegar un servicio web en un entorno concreto. Esto a veces se denomina archivo WAR preparado.

Los entornos de ejecución y desarrollo

Un entorno de desarrollo especializado simplifica la migración de servicios web mediante la automatización de varias de las tareas. Para el desarrollo de aplicaciones basadas en WebSphere, incluidos los servicios web, puede utilizar las herramientas de ensamblaje que se proporcionan con WebSphere Application Server.

El código de ejemplo siguiente en este tema se ha probado en el entorno de ejecución siguiente:
  • IBM WebSphere Application Server V6.1, que incluye soporte para la especificación JAX-RPC.
  • Paquete de características de IBM WebSphere Application Server V6.1 para servicios web, que incluye soporte para las especificaciones JAX-WS y JAXB.

Ejemplos

Los ejemplos de migración siguientes muestran algunos cambios del código que son necesarios para migrar los servicios web JAX-RPC a servicios web JAX-WS y JAXB. En concreto, hay que hacer énfasis en los cambios en el código de implementación que debe desarrollar, tanto para el cliente como para el servidor. Si no se introduce una función nueva, los cambios necesarios para pasar de JAX-RPC a JAX-WS y JAXB deben ser pocos.

El primer ejemplo es un ejemplo de servicio web basado en JAX-RPC que se ha creado desde un archivo WSDL (desarrollo descendente); el mismo archivo WSDL se utiliza para generar el servicio basado en JAX-WS y JAXB. El archivo WSDL describe el servicio web, SampleService, con estas operaciones descritas en la imagen siguiente:

Según se muestra en la imagen, las cinco operaciones que se ofrecen son:
  • 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)
Suponga también que Person está definido por el fragmento de esquema siguiente en el archivo 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>
La dirección está definida 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>
La imagen también muestra que la operación, ckAvailability(xsd:int), que produce una excepción invalidDateFault. Servicio de ejemplo

Revise el código de servicio creado por la herramienta. La información siguiente incluye revisar qué se ha creado para el tiempo de ejecución JAX-RPC y también para un tiempo de ejecución JAX-WS y JAXB.

Para JAX-RPC, la herramienta acepta el archivo WSDL como entrada y, entre otros archivos, genera las interfaces SampleService.java y SampleServiceImpl.java. La interfaz SampleService.java define una interfaz y el código generado se puede revisar en el bloque de código siguiente. La interfaz SampleServiceSoapBindingImpl.java proporciona el esqueleto de una implementación y, por lo general, el usuario tendrá que modificarlo para añadir su propia lógica.

Versión JAX-RPC de SampleService.java:
/**  
* SampleService.java  
*  
* Este archivo ha sido generado automáticamente desde WSDL
* por el emisor WSDL2Java de servicios web de 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 y JAXB, la herramienta acepta el archivo WSDL como entrada, y como en el caso de JAX-RPC, genera las interfaces SampleService.java y SampleServiceImpl.java. Como con JAX-RPC, la interfaz SampleService.java también define una interfaz según se muestra en el bloque de código siguiente. La interfaz SampleServiceImpl.java proporciona el esqueleto de una implementación y por lo general tendrá que modificar para añadir su propia lógica.
Nota: El código ha sido anotado por la herramienta.
Versión JAX-WS y JAXB de la interfaz 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;   

/**  
* Esta clase ha sido generada por la SI JAX-WS.  
* JAX-WS RI IBM 2.0_03-06/12/2007 07:44 PM(Raja)-fcs  
* Versión de origen generada: 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);  

}   

Comparación de los ejemplos de código

A simple vista, puede parecer que hay pocos parecidos entre las interfaces. Si no tiene en cuenta la información adicional añadida por las anotaciones para JAX-WS y JAXB, los ejemplos de código son similares. Por ejemplo, el método calcShippingCost en la versión JAX-WS y JAXB de las líneas de código siguientes está presente:
@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);
Pero si no tiene en cuenta las anotaciones, las líneas de código siguiente son:
public Integer calcShippingCost(
        Integer shippingWt,
        Integer shippingZone);      
Estas líneas son casi idénticas a las generadas por JAX-RPC. La única diferencia es que el código JAX-RPC puede producir el error java.rmi.RemoteException de la siguiente manera:
public java.lang.Integer calcShippingCost(java.lang.Integer shippingWt,
			java.lang.Integer shippingZone) throws java.rmi.RemoteException;  	
Siguiendo esta lógica, los tres métodos tienen básicamente las mismas signaturas:
public Integer calcShippingCost(Integer shippingWt, Integer shippingZone)
	public String getAccountNumber(String accountName)
		public Person findSalesRep(String saleRepName) 
Esto quiere decir que la migración de JAX-RPC a JAX-WS no afecta directamente a estos métodos y el código de implementación original que se ejecuta correctamente en el entorno basado en JAX-WS puede probablemente utilizarse sin cambios para estos métodos.

No obstante, ´ dos de los métodos tiene signaturas distintas:

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 y JAXB:
public XMLGregorianCalendar calculateShippingDate( 			
	XMLGregorianCalendar requestedDate)  	
public List<String> ckAvailability(List<Integer> itemNumbers) 
	throws InvalidDateFault_Exception 
Nota: Le resultará más sencillo comparar archivos de implementación de esqueletos, ya que las anotaciones no están presentes en SampleServiceImpl.java:
  • SampleServiceSoapBindingImpl.java
  • SampleServiceImpl.java
Las diferencias en signaturas son debida a los motivos siguientes:
  • Correlaciones distintas de nombres XML a nombres Java

    Para el método calculateShippingDate, ambos parámetros de entrada y el parámetro de retorno han cambiado del tipo java.util.Calendar al tipo XMLGregorianCalendar. Esto es debido a que WSDL ha especificado estos parámetros para que sean del tipo xsd:dateTime; JAX-RPC correlaciona este tipo de datos con java.util.Calendar, mientras que JAX-WS y JAXB lo correlacionan con XMLGregorianCalendar.

  • Distintas correlaciones de matrices de XML a Java

    Para el método ckAvailability, el cambio es debido a las correlaciones de datos para matrices XML.

    JAX-RPC correlaciona los elementos WSDL siguientes:
    <element maxOccurs="unbounded" name="itemNumbers" type="xsd:int"/>
    <element maxOccurs="unbounded" name="itemAvailability" type="xsd:string"/>
    Los elementos anteriores se correlacionan con el siguiente código fuente en Java:
    int[] itemNumbers
    java.lang.String[] itemAvailability
    JAX-WS y JAXB correlacionan los elementos WSDL siguientes:
    List<Integer> itemNumbers 
    List<String> ckAvailability
  • Distintas correlaciones de excepciones
    Para el método ckAvailability, el código JAX-RPC ha generado el error siguiente:
    simple.InvalidDateFault
    El código de JAX-WS genera el error siguiente:
    InvalidDateFault_Exception
    Salvo por los nombres, los constructores para estas excepciones son distintos. Por lo tanto,el código real de JAX-RPC que produce el error se debe visualizar como:
    throw new InvalidDateFault("this is an InvalidDateFault");
    Para JAX-WS, el código utiliza un mandato parecido al ejemplo siguiente:
    throw new InvalidDateFault_Exception( "this is an InvalidDateFault_Exception", new InvalidDateFault()); 
    En casos que utilizan excepciones, el código que las utiliza debe cambiar.

Migración del código

Ahora que se han explicado las diferencias de código, revise el código original en busca de los métodos que hay que cambiar y cómo cambiar el código, de forma que funcione en un entorno JAX-WS y JAXB.

Presuponga que el código de implementación (JAX-RPC) original es parecido a lo siguiente:
public java.util.Calendar calculateShippingDate(
     java.util.Calendar requestedDate) throws java.rmi.RemoteException {
// Establecer la fecha en la fecha en que se nos ha enviado y añadir 7 días.
requestedDate.add(java.util.Calendar.DAY_OF_MONTH, 7);

// . . .

return requestedDate;
}
Puede escribir el código nuevo de forma que utilice directamente los tipos nuevos como en los ejemplos siguientes:
public XMLGregorianCalendar calculateShippingDate(
XMLGregorianCalendar requestedDate) {
try {
// Crear una fábrica de tipo de datos.
DatatypeFactory df = DatatypeFactory.newInstance();
// Establecer la fecha en la fecha en que se nos ha enviado y añadir 7 días.
Duration duration = df.newDuration("P7D");
requestedDate.add(duration);

} catch (DatatypeConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

// . . .

return requestedDate;
}
Cuando se migra el código para el método ckAvailability, los cambios eran necesarios porque la forma en que las matrices y excepciones se correlacionan desde XML es distinta entre JAX-RPC y JAX-WS. Presuponga que el código de servicio web JAX-RPC original es parecido al ejemplo siguiente:
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;
}
El código anterior acepta un int[] como entrada y devuelve String[]. Para la versión de JAX-WS y JAXB, éstos son elementos List<Integer> y List<String > respectivamente. El procesamiento de estas matrices y descartar el código Exception code, el código JAX-RPC es parecido a lo siguiente:
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;
}
El código equivalente JAX-WS y JAXB siguiente existe utilizando listas en vez de matrices:
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;
}
Las diferencias en las correlaciones de excepciones de XML a Java fuerza al código JAX-WS a utilizar. InvalidDateFault_Exception en vez de InvalidDateFault.
Esto quiere decir que debe sustituir throw new simple.InvalidDateFault(“InvalidDateFault”); por algún otro código. Por lo tanto, la línea siguiente se utiliza para el código nuevo:
throw new InvalidDateFault_Exception( "test InvalidDateFault_Exception", new InvalidDateFault());  
La implementación JAX-WS y JAXB final del método podría ser parecido al código siguiente:
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;
}
Hay varias formas en las que puede elegir migrar el código. Con práctica y un entorno de desarrollo eficaz, la migración de JAX-RPC a JAX-WS puede ser sencilla.

Icon that indicates the type of topic Reference topic



Timestamp icon Last updated: last_date
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=rwbs_migjaxrpc2jaxws
File name: rwbs_migjaxrpc2jaxws.html