En esta p�gina veremos algunos t�picos m�s avanzados incluyendo el manejo de tipos complejos en SOAP, el procesamiento de errores y las referencias remotas.
�SOAP y los Tipos Complejos
Hasta ahora, nuestros Servicios Web s�lo intercambiaban tipos de datos primitivos como strings, int o double. Ahora veremos c�mo se traducen los tipos complejos en el mensaje SOAP.
El protocolo SOAP recomienda el uso de la llamada codificaci�n SOAP para traducir tipos complejos a XML. Normalmente, las siguientes traduciones ocurren autom�ticamente:
- Tipos primitivos de Java 2.
- Clases personalizadas, que son mapeadas usando un patr�n de JavaBean bien-conocido. Todos los campos p�blicos y los campos con m�todos get/set son traducidos a XML mediante el serializador de reflexi�n Java.
- Colecciones de Java 2 (HashMap, Hashtable, Vector, List etc.).
La siguiente demostraci�n muestra el patr�n de serializaci�n JavaBean por defecto y la serializaci�n de collection de Java 2.
Pasaremos una simple estructura OrderRequest al Servicio Web. Esta estructura est� implementada con el JavaBean m�s simple posible, con m�todos get y set para symbol, limitPrice y volume. El m�todo de servicio processOrder acepta la clase Java OrderRequest como �nico par�metro. Mostraremos como la estructura OrderRequest se representa en el mensaje SOAP. Tambi�n codificaremos el m�todo getOrders que devuelve la colecci�n de todos los pedidos aceptados desde el Servicio Web para el cliente. Usaremos el contenedor java.util.Hashtable como el valor de retorno para el m�todo getOrders y veremos su representaci�n XML.
En este ejemplo, continuamos con nuestro servicio de mercado de stocks a�adiendo un sencillo servicio de pedidos:
package com.systinet.demos.mapping; public class OrderService { private java.util.HashMap orders = new java.util.HashMap(); public String processOrder(OrderRequest order) { String result = "PROCESSING ORDER"; Long id = new Long(System.currentTimeMillis()); result += "\n----------------------------"; result += "\nID: "+id; result += "\nTYPE: "+ ((order.getType()==order.ORDER_TYPE_SELL)?("SELL"):("BUY")); result += "\nSYMBOL: "+order.getSymbol(); result += "\nLIMIT PRICE: "+order.getLimitPrice(); result += "\nVOLUME: "+order.getVolume(); this.orders.put(id,order); return result; } public java.util.HashMap getOrders() { return this.orders; } }
Encontrar�s todos los scripts en el subdirectorio bin del archivo de las fuentes
Compilaremos y desplegaremos el servicio de pedidos ejecutando el script deployMapping.bat. La aplicaci�n del lado del cliente simplemente crea dos solicitudes de pedido y las env�a al Servicio Web. Luego recupera el Hashtable relleno con estas dos solicitudes y las muestra en la consola. Veamos el c�digo de la aplicaci�n cliente, donde de nuevo estamos especulando con stocks de tecnolog�a:
package com.systinet.demos.mapping; import org.idoox.wasp.Context; import org.idoox.webservice.client.WebServiceLookup; public final class TradingClient { public static void main( String[] args ) throws Exception { WebServiceLookup lookup = (WebServiceLookup)Context.getInstance(Context.WEBSERVICE_LOOKUP); OrderServiceProxy service = (OrderServiceProxy)lookup.lookup("http://localhost:6060/MappingService/", OrderServiceProxy.class); com.systinet.demos.mapping.struct.OrderRequest order = new com.systinet.demos.mapping.struct.OrderRequest(); order.symbol = "SUNW"; order.type = com.systinet.demos.mapping.OrderRequest.ORDER_TYPE_BUY; order.limitPrice = 10; order.volume = 100000; String result = service.processOrder(order); System.out.println(result); order = new com.systinet.demos.mapping.struct.OrderRequest(); order.symbol = "BEAS"; order.type = com.systinet.demos.mapping.OrderRequest.ORDER_TYPE_BUY; order.limitPrice = 13; order.volume = 213000; result = service.processOrder(order); System.out.println(result); java.util.HashMap orders = service.getOrders(); java.util.Iterator iter = orders.keySet().iterator(); while(iter.hasNext()) { Long id = (Long)iter.next(); OrderRequest req = (OrderRequest)orders.get(id); System.out.println("\n----------------------------"); System.out.println("\nID: "+id); System.out.println("\nTYPE: "+ ((req.getType()==com.systinet.demos.mapping.OrderRequest.ORDER_TYPE_SELL)?("SELL"):("BUY"))); System.out.println("\nSYMBOL: "+req.getSymbol()); System.out.println("\nLIMIT PRICE: "+req.getLimitPrice()); System.out.println("\nVOLUME: "+req.getVolume()); } } }
�Mapeo de Tipos Complejos -- Mirada en Profundidad
La primero a descubrir es el fichero WSDL que se gener� en tiempo de despliegue. Si hemos desplegado el servicio mapeado, podemos ver el fichero WSDL completo en http://localhost:6060/MappingService/
Como recordar�s de la p�gina anterior, el WSDL describe qu� funcionalidad ofrece el Servicio Web, c�mo se comunica, y d�nde se puede acceder. WSDL proporciona un mecanismo estructurado para describir las operaciones que puede realizar un Servicio Web. En nuestro ejemplo, la parte m�s importante es la definici�n del mapeo del tipo Java OrderRequest:
<xsd:complexType name="OrderRequest"> <xsd:sequence> <xsd:element name="limitPrice" type="xsd:double"/> <xsd:element name="symbol" type="xsd:string"/> <xsd:element name="type" type="xsd:short"/> <xsd:element name="volume" type="xsd:long"/> </xsd:sequence> </xsd:complexType>
El mapeo de OrderRequest a XML est� definido como un conjunto de campos de tipos primitivos. El HashMap devuelto por el mapeo getOrders se importa como el tipo de dato http://idoox.com/containers:HashMap. Nuestro fichero WSDL importa la siguiente definici�n:
<complexType name="HashMap"> <sequence> <element name="item" minOccurs="0" maxOccurs="unbounded"> <complexType> <sequence> <element name="key" type="anyType" /> <element name="value" type="anyType" /> </sequence> </complexType> </element> </sequence> </complexType>
Ahora veamos los mensajes SOAP intercambiados entre el cliente y el Servicio Web. Primero arrancaremos el trazado de mensajes en el servidor SOAP abriendo la consola de administraci�n en http://localhost:6060/admin/console en el navegador HTTP, pulsando en el bot�n Refresh y pulsando sobre el enlace enable de la secci�n MappingService de la consola. Luego ejecutaremos la aplicaci�n cliente, llamando al script runMappingClient.bat y veremos los mensajes SOAP. El mensaje de abajo es una invocaci�n del m�todo processOrder con un ejemplar de OrderRequest como par�metro:
<?xml version="1.0" encoding="UTF-8"?> <ns0:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/"> <ns0:Body ns0:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"> <ns0:processOrder xmlns:ns0="http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/mapping/OrderService"> <p0 xsi:type= "ns1:OrderRequest" xmlns:ns1="http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/mapping/"> <limitPrice xsi:type="xsd:double">10.0</limitPrice> <symbol xsi:type="xsd:string">SUNW</symbol> <type xsi:type="xsd:short">1</type> <volume xsi:type="xsd:long">100000</volume> </p0> </ns0:processOrder> </ns0:Body> </ns0:Envelope>
El siguiente mensaje representa el valor de retorno (un HashMap relleno con las solicitudes de pedido procesadas) del m�todo getOrders:
<?xml version="1.0" encoding="UTF-8"?> <ns0:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/"> <ns0:Body ns0:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"> <ns0:getOrdersResponse xmlns:ns0= "http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/mapping/OrderService"> <response xsi:type="ns1:HashMap" xmlns:ns1="http://idoox.com/containers"> <item> <key xsi:type="xsd:long">1006209071080</key> <value xsi:type= "ns2:com.systinet.demos.mapping.OrderRequest" xmlns:ns2="http://idoox.com/package/"> <volume xsi:type="xsd:long">100000</volume> <symbol xsi:type="xsd:string">SUNW</symbol> <limitPrice xsi:type="xsd:double">10.0</limitPrice> <type xsi:type="xsd:short">1</type> </value> </item> <item> <key xsi:type="xsd:long">1006209071130</key> <value xsi:type="ns3:com.systinet.demos.mapping.OrderRequest" xmlns:ns3="http://idoox.com/package/"> <volume xsi:type="xsd:long">213000</volume> <symbol xsi:type="xsd:string">BEAS</symbol> <limitPrice xsi:type="xsd:double">13.0</limitPrice> <type xsi:type="xsd:short">1</type> </value> </item></response> </ns0:getOrdersResponse></ns0:Body> </ns0:Envelope>
El mapeo de Java a XML es sencillo, Podemos ver la definici�n exterior de HashMap con los elementos clave y valor. Observa que hay una definici�n XML interna del tipo de dato OrderRequest.
Como paso final eliminaremos el servicio web del servidor ejecutando el script undeployMapping.bat.
�Procesamiento de Errores SOAP
Cuando las cosas van mal, SOAP define una construci�n llamada SOAP Fault XML que representa un error que ha ocurrido en el lado del servidor. Brevemente presentamos estos mensajes de error en la p�gina anterior. Aqu� los examinaremos en m�s detalle. El Fallo SOAP contiene tres elementos b�sicos:
- FAULTCODE con contiene el c�digo del error o ID.
- FAULTSTRING que contiene una breve descripci�n del error.
- DETAIL que describe el error en m�s detalle.
Para ilustrar el procesamiento de errores a�adiremos algunas excepciones a nuestro ejemplo del servicio de stocks. Primero, haremos que el m�todo getQuote lance una StockNotFoundException si no puede encontrar unos de nuestros tres stocks:
package com.systinet.demos.fault; public class StockQuoteService { public double getQuote(String symbol) throws StockNotFoundException { if(symbol!=null && symbol.equalsIgnoreCase("SUNW")) return 10; if(symbol!=null && symbol.equalsIgnoreCase("MSFT")) return 50; if(symbol!=null && symbol.equalsIgnoreCase("BEAS")) return 11; throw new StockNotFoundException("Stock symbol "+symbol+" not found."); } public java.util.LinkedList getAvailableStocks() { java.util.LinkedList list = new java.util.LinkedList(); list.add("SUNW"); list.add("MSFT"); list.add("BEAS"); return list; } }
Luego desplegaremos el Servicio Web usando el script de l�nea de comandos deployFault.bat.
Usaremos el trazado de mensajes SOAP en el servidor siguiendo los pasos que hemos visto anteriormente. Ahora chequearemos el fichero WSDL generado por el servidor SOAP. Arimos la URL http://localhost:6060/StockQuoteService/ en nuestro navegador.
Observa la definici�n del mensaje de fallo SOAP en el fichero WSDL:
<wsdl:message name='StockQuoteService_getQuote_com.systinet.demos.fault.StockNotFoundException_Fault'> <wsdl:part name='idoox-java-mapping.com.systinet.demos.fault.StockNotFoundException' type='xsd:string'/> </wsdl:message>
El mensaje de fallo es referenciado en la operaci�n getQuote en el elemento portype del WSDL:
<wsdl:operation name='getQuote' parameterOrder='p0'> <wsdl:input name='getQuote' message='tns:StockQuoteService_getQuote_Request'/> <wsdl:output name='getQuote' message='tns:StockQuoteService_getQuote_Response'/> <wsdl:fault name='getQuote_fault1' message= 'tns:StockQuoteService_getQuote_com.systinet.demos.fault.StockNotFoundException_Fault'/> </wsdl:operation>
y en el elemento binding:
<wsdl:operation name='getQuote'> <soap:operation soapAction='' style='rpc'/> <wsdl:input name='getQuote'> <soap:body use='encoded' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' namespace='http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/fault/'/> </wsdl:input> <wsdl:output name='getQuote'> <soap:body use='encoded' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' namespace='http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/fault/'/> </wsdl:output> <wsdl:fault name='getQuote_fault1'> <soap:fault name='getQuote_fault1' use='encoded' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' namespace='http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/fault/'/> </wsdl:fault> </wsdl:operation>
Sumarizando, la excepci�n Java del lado del servidor se representa con un simple mensaje SOAP que se devuelve al lado del cliente si ocurre la excepci�n.
El siguiente paso es crear una aplicaci�n cliente del Servicio Web:
package com.systinet.demos.fault; import org.idoox.wasp.Context; import org.idoox.webservice.client.WebServiceLookup; public final class StockClient { public static void main( String[] args ) throws Exception { // lookup service WebServiceLookup lookup = (WebServiceLookup)Context.getInstance( Context.WEBSERVICE_LOOKUP); // bind to StockQuoteService StockQuoteServiceProxy quoteService = (StockQuoteServiceProxy)lookup.lookup( "http://localhost:6060/StockQuoteService/", StockQuoteServiceProxy.class ); // use StockQuoteService System.out.println("Getting available stocks"); System.out.println("------------------------"); java.util.LinkedList list = quoteService.getAvailableStocks(); java.util.Iterator iter = list.iterator(); while(iter.hasNext()) { System.out.println(iter.next()); } System.out.println(""); System.out.println("Getting SUNW quote"); System.out.println("------------------------"); System.out.println("SUNW "+quoteService.getQuote("SUNW")); System.out.println(""); System.out.println("Getting IBM quote (warning, this one doesn't exist, so we will get an exception)"); System.out.println("------------------------"); System.out.println("SUNW "+quoteService.getQuote("IBM")); System.out.println(""); } }
Necesitaremos generar el interface del cliente Java, compilar todas las clases y ejecutar la aplicaci�n cliente. Todas est�s tareas se llevan a cabo en el script runFaultClient.bat.
Nuestra cartera de stocks es bastante pobre y no incluye IBM. El cliente primero deber�a mostrar todos los simbolos disponibles, recuperar el valor del s�mbolo SUNW y finalmente lanzar la excepci�n StockNotFoundException indicando que no se ha encontrado el s�mbolo IBM. Ahora veamos la consola de adminstraci�n (en http://localhost:6060/admin/console) y pulsemos en el enlace show SOAP conversation. En una nueva ventana se mostrar� el siguiente mensaje (las partes importantes est�n en negrita):
==== INPUT ==== http://localhost:6060/StockQuoteService/ ==== 11/14/01 4:44 PM = <?xml version="1.0" encoding="UTF-8"?> <ns0:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/"> <ns0:Body ns0:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"> <ns0:getQuote xmlns:ns0= "http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/fault/"> <p0 xsi:type="xsd:string">IBM</p0> </ns0:getQuote> </ns0:Body> </ns0:Envelope> ==== CLOSE ===================================================================== ==== OUTPUT ==== http://localhost:6060/StockQuoteService/ ====================== <?xml version="1.0" encoding="UTF-8"?> <ns0:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/"> <ns0:Body ns0:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"> <ns0:Fault xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/"> <faultcode>ns0:Server</faultcode> <faultstring>Stock symbol IBM not found.</faultstring> <detail xmlns:ijm="urn:idoox-java-mapping"> <ijm:idoox-java-mapping.com.systinet.demos.fault.StockNotFoundException> <ijm:stack-trace> com.systinet.demos.fault.StockNotFoundException: Stock symbol IBM not found. at com.systinet.demos.fault.StockQuoteService. getQuote(StockQuoteService.java:24) at java.lang.reflect.Method.invoke(Native Method) at com.idoox.wasp.server.adaptor.JavaAdaptorInvoker. invokeService(JavaAdaptorInvoker.java:387) at com.idoox.wasp.server.adaptor.JavaAdaptorInvoker. invoke(JavaAdaptorInvoker.java:239) at com.idoox.wasp.server.adaptor.JavaAdaptorImpl. dispatch(JavaAdaptorImpl.java:164) at com.idoox.wasp.server.AdaptorTemplate. dispatch(AdaptorTemplate.java:178) at com.idoox.wasp.server.ServiceConnector. dispatch(ServiceConnector.java:217) at com.idoox.wasp.server.ServiceManager. dispatch(ServiceManager.java:231) at com.idoox.wasp.server.ServiceManager$DispatcherConnHandler. handlePost(ServiceManager.java:1359) at com.idoox.transport.http.server.Jetty$WaspHttpHandler. handle(Jetty.java:94) at com.mortbay.HTTP.HandlerContext. handle(HandlerContext.java:1087) at com.mortbay.HTTP.HttpServer. service(HttpServer.java:675) at com.mortbay.HTTP.HttpConnection. service(HttpConnection.java:457) at com.mortbay.HTTP.HttpConnection. handle(HttpConnection.java:317) at com.mortbay.HTTP.SocketListener. handleConnection(SocketListener.java:99) at com.mortbay.Util.ThreadedServer. handle(ThreadedServer.java:254) at com.mortbay.Util.ThreadPool$PoolThreadRunnable. run(ThreadPool.java:601) at java.lang.Thread.run(Thread.java:484) </ijm:stack-trace> </ijm:idoox-java-mapping.com.systinet.demos.fault.StockNotFoundException> </detail> </ns0:Fault> </ns0:Body> </ns0:Envelope> ==== CLOSE =====================================================================
Observa el mensaje SOAP de salida y en particular la construcci�n FAULT. El FAULTCODE contiene el c�digo de error gen�rico, el elemento FAULTSTRING contiene el mensaje de excepci�n y el elemento DETAIL contiene todo el seguimiento de pila de la excepci�n.
Finalmente podemos eliminar el servicio usando el script undeployFault.bat.
�Referencias Remotas
Las referencias remotas son una construcci�n usada en la mayor�a de sistemas de objetos distribuidos, como RMI, CORBA y DCOM. Asume que tenemos un cliente que est� invocando m�todos de un objeto servidor. Aqu� est� como trabajan. Digamos que el objeto servidor crea otro objeto, y que tiene alguna forma de pasar el nuevo objeto al cliente (ver la siguiente figura). Puede pasar el nuevo objeto por "valor" o por "referencia". Si pasamos el objeto por valor, estamos pasando todo el objeto. Si lo pasamos por referencia, s�lo pasamos un puntero al objeto. Una referencia remota es un referencia que funciona a trav�s de la red. Las referencias remotas son cr�ticas para muchos patrones de dise�o en la programaci�n distribuida, particularmente en el patr�n Factory. A pesar de ser una caracter�stica cr�tica para muchas aplicaciones distribuidas, no todas las implementaciones SOAP la soportan.

Por ejemplo, podr�amos definir un m�todo createLineItem en un Servicio Web de Pedidos. Este m�todo crear� un nuevo objeto LineItem que contendr� el n�mero de cat�logo y el precio del producto pedido y la cantidad pedida. El Pedido potencialmente referenciar� muchos objetos LineItem. El objeto LineItem deber�a ser devuelto a la aplicaci�n cliente como una referencia remota para poder especificar todos los datos necesarios.
�Implementar Sencillas Referencias Remotas
Para ilustrar la caracter�stica de la referencias remotas vamos a crear un nuevo ejemplo, y gastaremos nuestras ganancias del mercado de stocks pidiendo algunos productos. Empezaremos con la definici�n de dos interfaces Java: Order y LineItem que usaremos para referenciar el Servicio Web en el lado del cliente:
package com.systinet.demos.interref; public interface LineItem extends java.rmi.Remote { public String getID(); public long getCount(); public String getProductID(); public void close(); }
y
package com.systinet.demos.interref; public interface Order { public LineItem addItem(String productID, long count); public LineItem getItem(String id); public void removeItem(String id); }
Observa que el interface LineItem extiende el interface java.rmi.Remote. Este es el m�todo m�s simple de manejar referencias remotas usando WASP. Por otro lado, el interface LineItem es bastante obvio. El m�todo addItem del interface Order crea y devuelve un nuevo �tem de pedido. El m�todo getItem devuelve un �tem existente y removeItem elimina el �tem especificado del pedido.
Ahora implementaremos los dos interfaces LineItem y Order:
package com.systinet.demos.interref; import org.idoox.webservice.server.WebServiceContext; import org.idoox.webservice.server.LifeCycleService; public class LineItemImpl implements LineItem { private String pid; private String id; private long count; public LineItemImpl(String pid, long count) { System.err.println("Creating new LineItem."); this.id = pid+System.currentTimeMillis(); this.pid = pid; this.count = count; } public void close() { System.err.println("close()"); WebServiceContext context = WebServiceContext.getInstance(); LifeCycleService lc = context.getLifeCycleService(); lc.disposeServiceInstance(this); } public long getCount() { System.err.println("getCount()"); return this.count; } public String getProductID() { System.err.println("getProductID()"); return this.pid; } public String getID() { System.err.println("getID()"); return this.id; } }
y
public class OrderImpl implements Order { private java.util.HashMap items = new java.util.HashMap(); public LineItem getItem(String id) { return (LineItem)this.items.get(id); } public LineItem addItem(java.lang.String pid, long count) { LineItem item = new LineItemImpl(pid, count); this.items.put(item.getID(), item); return item; } public void removeItem(java.lang.String id) { LineItem item = (LineItem)this.items.remove(id); item.close(); } }
Una implementaci�n est�ndar, sin sorpresas. Observa que LineItem imprime mensajes de seguimiento de llamadas a m�todos. El c�digo del cliente tambi�n es bastante est�ndar:
package com.systinet.demos.interref; import javax.wsdl.QName; import org.idoox.wasp.Context; import org.idoox.webservice.client.WebServiceLookup; public final class OrderClient { public static void main( String[] args ) throws Exception { // lookup service WebServiceLookup lookup = (WebServiceLookup)Context.getInstance(Context.WEBSERVICE_LOOKUP); Order order = (Order)lookup.lookup("http://localhost:6060/OrderService/", new QName("http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/interref/", "OrderService"), "OrderImpl", Order.class); String id1 = order.addItem("THNKPDT23", 2).getID(); String id2 = order.addItem("THNKPDT22", 2).getID(); System.out.println("ID1 "+id1); System.out.println("ID2 "+id2); LineItem item = order.getItem(id1); System.out.println("Line ITEM"); System.out.println("---------"); System.out.println("ID: "+item.getID()); System.out.println("Product ID: "+item.getProductID()); System.out.println("Count: "+item.getCount()); item = order.getItem(id2); System.out.println("Line ITEM"); System.out.println("---------"); System.out.println("ID: "+item.getID()); System.out.println("Product ID: "+item.getProductID()); System.out.println("Count: "+item.getCount()); } }
Esta simple aplicaci�n cliente crea el proxy din�mico para el Servicio Web de pedidos y luego crea dos �tems de pedido, THNKPDT23 y THNKPDT22. Deber�amos ver en la consola del servidor que todas las llamadas a m�todos de estos �tems de pedidos tienen lugar en el lado del servidor. Porque estos dos �tems se han creado din�micamente en el servidor, mientras que el cliente s�lo obtiene sus referencias. Este es un buen ejemplo de patr�n Factory mencionado anteriormente. En nuestro caso, el servicio de pedidos act�a como la factor�a para los dos �tems del pedido.
Observa que las l�neas de �tem tienen estado, por lo que pueden mantener datos particulares del �tem.
�Borrar Referencias Remotas
Al contrario que los Servicio Web sin estado, los servicios web con estado requieren c�digo de manejo especiales para borrar elementos. Nosotros usamos explicitamente la eliminaci�n de ejemplares en nuestro ejemplo. Esto se hace llamando al m�todo disposeServiceInstance sobre el Servicio Web LifeCycle del sistema. Puedes ver el m�todo close de LineItemImpl para ver como borrar expl�citamente un servicio:
public void close() { System.err.println("close()"); WebServiceContext context = WebServiceContext.getInstance(); LifeCycleService lc = context.getLifeCycleService(); lc.disposeServiceInstance(this); }
El �ltimo paso es elimiar el servicio usando el script undeployInterref.bat.