Diferencia entre revisiones de «MTOM con Spring Web Services»

De Dos Ideas.
Saltar a: navegación, buscar
(Procesar invocación)
Línea 94: Línea 94:
 
== Cliente ==
 
== Cliente ==
  
En breve...
+
Si bien el cliente podría ser un test del servidor, vamos a crear en este ejemplo otro modulo web, por un lado para no confundir la configuración entre cliente y servidor y por el otro para poder visualizar en el browser el pdf.
 +
 
 +
Básicamente vamos a tener un servlet, que invoca al servicio y luego escribe el pdf a la pagina.
 +
 
 +
=== Configurar cliente ===
 +
 
 +
En el ejemplo que se pueden bajar, van a encontrar dos implementaciones, una con Saaj (SOAP with Attachments API for Java) y otra con Axiom (Axis Object Model). A continuación vamos a detallar la implementación con Saaj.
 +
 
 +
Primero definimos un bean, indicando donde esta el servicio:
 +
 
 +
<code xml>
 +
<!-- Indicar donde esta el servicio que nos brinda el pdf -->
 +
<bean id="client" abstract="true">
 +
    <property name="defaultUri" value="http://localhost:7001/mtom-pdf/ws/pdf"/>
 +
</bean>
 +
</code>
 +
 
 +
Luego definimos el cliente:
 +
 
 +
<code xml>
 +
<!-- cliente con la implementacion de SAAJ -->
 +
<bean id="saajClient" class="com.dosideas.mtom.ws.SaajMtomClient" parent="client">
 +
    <constructor-arg>
 +
      <bean class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
 +
    </constructor-arg>
 +
    <property name="marshaller" ref="marshaller"/>
 +
    <property name="unmarshaller" ref="marshaller"/>
 +
</bean>
 +
</code>
 +
 
 +
En el caso de utilizar Saaj, vamos a necesitar indicarle un serializador, y al igual que en el servidor, vamos a utilizar JAXB:
 +
 
 +
<code xml>
 +
<!-- Serializador que utiliza SAAJ para enviar y leer la respuesta del servicio -->
 +
<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
 +
    <property name="contextPath" value="com.dosideas.mtom.cliente.sws"/>
 +
    <property name="mtomEnabled" value="true"/>
 +
</bean>
 +
</code>
 +
 
 +
=== Implementar el cliete ===
 +
 
 +
Para invocar servicios, Spring Web Services provee de una clase utilitaria que facilita bastante las cosas: '''WebServiceTemplate'''. En la configuración que realizamos en el paso anterior nos adelantamos a esto, indicándole a nuestro cliente donde estaba el servicio.
 +
 
 +
El WebServiceTemplate lo podemos obtener, heredando de ''WebServiceGatewaySupport''':
 +
 
 +
<code java5>
 +
public class SaajMtomClient extends WebServiceGatewaySupport {
 +
    /**
 +
    * object factory creada por JAXB para bindear clases con el schema.
 +
    */
 +
    private ObjectFactory objectFactory = new ObjectFactory();
 +
    /**
 +
    * Construye el cliente a traves de la message factory.
 +
    * @param messageFactory message factory que utiliza SAAJ.
 +
    */
 +
    public SaajMtomClient(SaajSoapMessageFactory messageFactory) {
 +
        super(messageFactory);
 +
    }
 +
</code>
 +
 
 +
Lo que resta es el método principal que se encargue de enviar el pedido y procesar la respuesta:
 +
 
 +
<code java5>
 +
/**
 +
* Carga un pdf en un DataHandler para luego poder leerlo.
 +
* @param path donde se encuentra el pdf.
 +
* @return un DataHandler que contiene el pdf.
 +
*/
 +
public DataHandler loadPdf(String path) {
 +
  //pedido
 +
  JAXBElement<String> loadPdfRequest = objectFactory.createLoadPdfRequest(StringUtils.getFilename(path));
 +
  //respuesta
 +
  JAXBElement<Pdf> loadPdfResponse =
 +
                (JAXBElement<Pdf>) getWebServiceTemplate().marshalSendAndReceive(loadPdfRequest);
 +
       
 +
  Pdf pdf = loadPdfResponse.getValue();
 +
   
 +
  return pdf.getFile();
 +
}
 +
<code>
 +
 
 +
La clase '''DataHandler''' nos permite obtener un '''InputStream''' para ir leyendo el pdf.
  
 
== Ver también ==
 
== Ver también ==

Revisión del 13:46 22 mar 2010

Spring Web Services tiene soporte para poder publicar y consumir web services que adjuntan un archivo, utilizando el protocolo MTOM.

A continuación vamos a ver un ejemplo concreto de publicación e invocación a un Web Service de prueba.

Servidor

Para el servidor, vamos a crear un modulo web. La configuración del servlet de Spring Web Services es la estándar y vamos a hacer foco en los pasos siguientes.

Publicacion del servicio

La idea para este ejemplo es crear un servicio que sea la interfaz de un repositorio de archivos pdf, por lo tanto, deberíamos poder pasarle el nombre de un archivo y éste debería retornar el mismo en caso de encontrarlo. Teniendo en mente esto, creamos nuestro contrato (contract-first):

<element name="LoadPdfRequest" type="string"/>

<element name="LoadPdfResponse" type="tns:Pdf"/>

<complexType name="Pdf">

  <sequence>
    <element name="name" type="string"/>
    <element name="file" type="base64Binary" xmime:expectedContentTypes="application/pdf"/>
  </sequence>

</complexType>

De lo anterior, debemos prestar atención a la definición del archivo, en donde le indicamos que es del tipo "base64Binary". Una vez resuelto el contrato, debemos decirle a Spring Web Services que lo publique. Esto lo hacemos a traves de un bean especifico que a partir de un schema, crea el WSDL:

<bean id="mtom" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">

       <property name="schema" ref="schema"/>
       <property name="portTypeName" value="PdfRepository"/>
       <property name="locationUri" value="/ws/pdf"/>

</bean>

Procesar invocación

Debemos configurar la aplicación, para que pueda procesar pedidos del servicio que publicamos en el paso anterior.

Primero definimos un bean que busca la anotacion @Endpoint (un endpoint es el encargado de procesar el pedido):

<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping" />

Luego definimos un adaptador, para que procese el pedido de forma que el endpoint lo pueda entender. Lo mismo hace con la respuesta:

<bean class="org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter">

       <constructor-arg ref="marshaller"/>

</bean>

Este adaptador necesita de un serializador. Aca es donde entra el manejo del archivo binario. Vamos a utilizar JAXB:

<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">

 <property name="contextPath" value="com.dosideas.springws.ejemplos.mtom.schema"/>
 <property name="mtomEnabled" value="true"/>

</bean>

El próximo paso es generar a partir del esquema, las clases de 'bindeo' de JAXB. Para esto hay varias herramientas. En nuestro caso utilizamos el NetBeans (6.8): click derecho en el proyecto -> New.. -> Xml -> JAXB Binding. Entre las opciones que figuran, por un lado debemos elegir el .xsd que definimos anteriormente y por el otro el Package Name, que debe concordar con el valor del contextPath que le pusimos en la configuración al Jaxb2Marshaller (en nuestro caso "com.dosideas.springws.ejemplos.mtom.schema").

Una vez configurado JAXB, podemos proceder a implementar el endpoint:

@Endpoint public class PdfRepositorioEndPoint {

   /**
    * object factory creada por JAXB para bindear clases con el schema.
    */
   private ObjectFactory objectFactory = new ObjectFactory();
   @PayloadRoot(localPart = "LoadPdfRequest", namespace = "http://www.dosideas.com/spring-ws/ejemplos/mtom")
   public JAXBElement<Pdf> pedidoPdf(JAXBElement<String> requestElement) throws IOException {
       String nombrePdf = requestElement.getValue();
       Pdf response = new Pdf();
       response.setName(nombrePdf);
       //Se puede crear un DataHandler de muchas formas. Aca una simple para el ejemplo.
       response.setFile(new DataHandler(getClass().getResource(nombrePdf)));
       return objectFactory.createLoadPdfResponse(response);
   }

}

Debemos prestarle atención a la creación del DataHandler, el cual se encarga de nuestro archivo binario. Luego es manejo trivial de Spring Web Services y JAXB.

Cliente

Si bien el cliente podría ser un test del servidor, vamos a crear en este ejemplo otro modulo web, por un lado para no confundir la configuración entre cliente y servidor y por el otro para poder visualizar en el browser el pdf.

Básicamente vamos a tener un servlet, que invoca al servicio y luego escribe el pdf a la pagina.

Configurar cliente

En el ejemplo que se pueden bajar, van a encontrar dos implementaciones, una con Saaj (SOAP with Attachments API for Java) y otra con Axiom (Axis Object Model). A continuación vamos a detallar la implementación con Saaj.

Primero definimos un bean, indicando donde esta el servicio:

<bean id="client" abstract="true">

   <property name="defaultUri" value="http://localhost:7001/mtom-pdf/ws/pdf"/>

</bean>

Luego definimos el cliente:

<bean id="saajClient" class="com.dosideas.mtom.ws.SaajMtomClient" parent="client">

   <constructor-arg>
      <bean class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
   </constructor-arg>
   <property name="marshaller" ref="marshaller"/>
   <property name="unmarshaller" ref="marshaller"/>

</bean>

En el caso de utilizar Saaj, vamos a necesitar indicarle un serializador, y al igual que en el servidor, vamos a utilizar JAXB:

<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">

   <property name="contextPath" value="com.dosideas.mtom.cliente.sws"/>
   <property name="mtomEnabled" value="true"/>

</bean>

Implementar el cliete

Para invocar servicios, Spring Web Services provee de una clase utilitaria que facilita bastante las cosas: WebServiceTemplate. En la configuración que realizamos en el paso anterior nos adelantamos a esto, indicándole a nuestro cliente donde estaba el servicio.

El WebServiceTemplate lo podemos obtener, heredando de WebServiceGatewaySupport':

public class SaajMtomClient extends WebServiceGatewaySupport {

   /**
    * object factory creada por JAXB para bindear clases con el schema.
    */
   private ObjectFactory objectFactory = new ObjectFactory();
   /**
    * Construye el cliente a traves de la message factory.
    * @param messageFactory message factory que utiliza SAAJ.
    */
   public SaajMtomClient(SaajSoapMessageFactory messageFactory) {
       super(messageFactory);
   }

Lo que resta es el método principal que se encargue de enviar el pedido y procesar la respuesta:

/**

* Carga un pdf en un DataHandler para luego poder leerlo.
* @param path donde se encuentra el pdf.
* @return un DataHandler que contiene el pdf.
  • /

public DataHandler loadPdf(String path) {

  //pedido
  JAXBElement<String> loadPdfRequest = objectFactory.createLoadPdfRequest(StringUtils.getFilename(path));
  //respuesta
  JAXBElement<Pdf> loadPdfResponse =
               (JAXBElement<Pdf>) getWebServiceTemplate().marshalSendAndReceive(loadPdfRequest);
       
  Pdf pdf = loadPdfResponse.getValue();
    
  return pdf.getFile();

} <code>

La clase DataHandler nos permite obtener un InputStream para ir leyendo el pdf.

Ver también